Hallo Christiane, Folgendes fällt mir auf: In der Funktion „processAlgorithm“ beim Einlesen der Parameter gibt der Aufruf „self.parameterAsSink(…)“ ein Tupel[QgsFeatureSink, str] zurück, du hast es aber nur in eine Variable aufgelöst (auf folgender Seite in der Doku mal nach parameterAsSink suchen - die Permalinks funktionieren leider nicht richtig: https://qgis.org/pyqgis/master/core/QgsProcessingAlgorithm.html?highlight=self%20parameterassink#module-QgsProcessingAlgorithm).
Du hast in deinem Skript folgende Zeile stehen: dest_id = self.parameterAsSink(parameters, self.OUTPUT, context, source_input.fields(), source_input.wkbType(), source_input.sourceCrs()) Meiner Meinung nach müsste es wie folgt lauten (Variablennamen sind natürlich frei wählbar): (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context, source_input.fields(), source_input.wkbType(), source_input.sourceCrs()) Ich habe das ganze nicht getestet, daher keine Garantie, dass dies wirklich die Lösung ist :) Viele Grüße, Christoph > Am 22.03.2021 um 15:59 schrieb Chr. Enderle <[email protected]>: > > Liebe Liste, > > ich habe mit QGIS 3.16 und der Python-Konsole ein lauffähiges Skript zustande > gebracht, das eine Abwandlung des Standardtools "Differenz" ist. Das > besondere ist, dass die Differenz nur zwischen Polygonen erfolgt, bei denen > ein bestimmter Attribut-Wert im Input und im Overlay gleich ist. Dafür wird > über den Input-Layer iteriert, bei dem jeder Attribut-Wert genau einmal > vorkommt. Durch SelectByExpression werden aus dem Overlay-Layer die passenden > Polygone ausgewählt und dann die Differenz durchgeführt. Anschließend werden > alle produzierten Differenz-Layer per Standardtool "Vektorlayer > zusammenführen" in einen einzigen neuen Layer geschrieben. > > Wie gesagt, in der Konsole funktioniert das prima. > > Ich brauche das ganze aber als Processing Plugin, damit ich es in ein Modell > integrieren kann. Das Tutorial > http://www.qgistutorials.com/de/docs/3/processing_python_plugin.html > <http://www.qgistutorials.com/de/docs/3/processing_python_plugin.html> habe > ich mir angesehen und für meine Zwecke umgesetzt. Problematisch ist für mich > die Schnittstelle der Ein- und Ausgabe, weil ich den Code nicht verstehe, > auch nicht mit der QGIS Python API Doku. Aktuell bricht das Tool mit der > zweifachen Meldung ab: > > Kann Algorithmus nicht ausführen > Konnte Ziellayer für OUTPUT nicht anlegen: ungültiger Wert > Kann Algorithmus nicht ausführen > Konnte Ziellayer für OUTPUT nicht anlegen: ungültiger Wert > > Im Anhang ist das Skript und das Protokoll. > > Über Unterstützung oder Hinweise auf Tutorials, die die Objekte und Methoden > von pygis verständlich erklären, würde ich mich sehr freuen. > > Viele Grüße, > > Christiane > > -- > Christiane Enderle, MSc > Philipps-Universität Marburg > Fachbereich Geographie > Deutschhausstr. 10 > 35037 Marburg > Tel. +49 (0)6421-2822179 > Fax +49 (0)6421-2828950 > > -------------- nächster Teil -------------- > QGIS-Version: 3.16.4-Hannover > QGIS-Codeversion: 654e76b3cb > Qt-Version: 5.11.2 > GDAL-Version: 3.1.4 > GEOS-Version: 3.8.1-CAPI-1.13.3 > PROJ-Version: Rel. 6.3.2, May 1st, 2020 > Verarbeite Algorithmus… > Algorithmus Use Difference by common ID startet… > Eingabeparameter: > { 'INPUT' : 'X:/Extern/Maxima_Parts.shp', 'OUTPUT' : 'TEMPORARY_OUTPUT', > 'OVERLAY' : 'X:/Extern/Loecher.shp' } > > Kann Algorithmus nicht ausführen > Konnte Ziellayer für OUTPUT nicht anlegen: ungültiger Wert > Kann Algorithmus nicht ausführen > Konnte Ziellayer für OUTPUT nicht anlegen: ungültiger Wert > Ausführung nach 0.01 Sekunden gescheitert > > Lade Ergebnis Layer > Algorithmus 'Use Difference by common ID' beendet > -------------- nächster Teil -------------- > # -*- coding: utf-8 -*- > > """ > /*************************************************************************** > DifferenceByID > A QGIS plugin > This plugin selects polygons and overlapping polygons inside of them by a > common ID and performs a difference. Generated by Plugin Builder: > http://g-sherman.github.io/Qgis-Plugin-Builder/ > ------------------- > begin : 2021-03-16 > copyright : (C) 2021 by Christiane Enderle > email : [email protected] > ***************************************************************************/ > > /*************************************************************************** > * * > * This program is free software; you can redistribute it and/or modify * > * it under the terms of the GNU General Public License as published by * > * the Free Software Foundation; either version 2 of the License, or * > * (at your option) any later version. * > * * > ***************************************************************************/ > """ > > __author__ = 'Christiane Enderle' > __date__ = '2021-03-16' > __copyright__ = '(C) 2021 by Christiane Enderle' > > # This will get replaced with a git SHA1 when you do a git archive > > __revision__ = '$Format:%H$' > > from qgis.PyQt.QtCore import QCoreApplication > from qgis.core import (QgsProcessing, > QgsFeatureSink, > QgsProcessingAlgorithm, > QgsProcessingParameterFeatureSource, > QgsProcessingParameterFeatureSink, > QgsVectorLayer) > import processing > > > class DifferenceByIDAlgorithm(QgsProcessingAlgorithm): > """ > This is an example algorithm that takes a vector layer and > creates a new identical one. > > It is meant to be used as an example of how to create your own > algorithms and explain methods and variables used to do it. An > algorithm like this will be available in all elements, and there > is not need for additional work. > > All Processing algorithms should extend the QgsProcessingAlgorithm > class. > """ > > # Constants used to refer to parameters and outputs. They will be > # used when calling the algorithm from another algorithm, or when > # calling from the QGIS console. > > OUTPUT = 'OUTPUT' > INPUT = 'INPUT' > OVERLAY = 'OVERLAY' > > def initAlgorithm(self, config): > """ > Here we define the inputs and output of the algorithm, along > with some other properties. > """ > > # We add the input vector features source. It can have any kind of > # geometry. > self.addParameter( > QgsProcessingParameterFeatureSource( > self.INPUT, > # Folgende Zeile gibt den Text ueber dem Eingabefeld an: > self.tr('Input layer'), > [QgsProcessing.TypeVectorAnyGeometry] > ) > ) > self.addParameter( > QgsProcessingParameterFeatureSource( > self.OVERLAY, > # Folgende Zeile gibt den Text ueber dem Eingabefeld an: > self.tr('Overlay layer'), > [QgsProcessing.TypeVectorAnyGeometry] > ) > ) > > # We add a feature sink in which to store our processed features (this > # usually takes the form of a newly created vector layer when the > # algorithm is run in QGIS). > self.addParameter( > QgsProcessingParameterFeatureSink( > self.OUTPUT, > # Folgende Zeile gibt den Text ueber dem Ausgabefeld an: > self.tr('Output layer') > ) > ) > > def processAlgorithm(self, parameters, context, feedback): > """ > Here is where the processing itself takes place. > """ > > # Retrieve the feature source and sink. The 'dest_id' variable is used > # to uniquely identify the feature sink, and must be included in the > # dictionary returned by the processAlgorithm function. > source_input = self.parameterAsSource(parameters, self.INPUT, context) > print ('input') > source_overlay = self.parameterAsSource(parameters, self.OVERLAY, > context) > print ('overlay') > dest_id = self.parameterAsSink(parameters, self.OUTPUT, context, > source_input.fields(), source_input.wkbType(), source_input.sourceCrs()) > print ('output') > maxima = QgsVectorLayer(self.INPUT, 'maxima', 'ogr') > loecher = QgsVectorLayer(self.OVERLAY, 'loecher', 'ogr') > > # # Compute the number of steps to display within the progress bar and > # # get features from source > # total = 100.0 / maxima.featureCount() if maxima.featureCount() else 0 > # features = maxima.getFeatures() > > # for current, feature in enumerate(features): > # # Stop the algorithm if cancel button has been clicked > # if feedback.isCanceled(): > # break > > # # Add a feature in the sink > # sink.addFeature(feature, QgsFeatureSink.FastInsert) > > # # Update the progress bar > # feedback.setProgress(int(current * total)) > # Differenzbildung nach ID: > difflayers = [] > print ('Es folgt die Differenzenbildung...') > > for m in maxima.getFeatures(): p = m['Part_ID'] > print ('Part_ID = ' + str(p)) > maxima.selectByExpression('\"Part_ID\" = ' + str(p), > QgsVectorLayer.SetSelection) > loecher.selectByExpression('\"Part_ID\" = ' + str(p), > QgsVectorLayer.SetSelection) > diff = processing.run("native:difference", > {'INPUT': QgsProcessingFeatureSourceDefinition(maxima.id(), True), > 'OVERLAY': QgsProcessingFeatureSourceDefinition(loecher.id(), > True), 'OUTPUT':'memory:'}, is_child_algorithm=True, > context=context, > feedback=feedback > )['OUTPUT'] > difflayers.append(diff) > print ('Differenzbildung abgeschlossen') > > # -> FUNKTIONIERT, WIE ES SOLL! D.h. auch Polygone ohne Inseln werden > ausgegeben (ohne Loecher) > > > # Zusammenfuehren der Differenz-Layer: > result = processing.run("native:mergevectorlayers", > {'LAYERS':difflayers, 'OUTPUT': dest_id}, > is_child_algorithm=True, > context=context, > feedback=feedback)['Output'] > # QgsProject.instance().addMapLayer(result) > > > # Loeschen der Differenz-Layer - sie werden nicht mehr gebraucht: > # difflayers = QgsProject.instance().mapLayersByName('Differenz') > # for d in difflayers: # > QgsProject.instance().removeMapLayer(d.id()) > # Return the results of the algorithm. In this case our only result is > # the feature sink which contains the processed features, but some > # algorithms may return multiple feature sinks, calculated numeric > # statistics, etc. These should all be included in the returned > # dictionary, with keys matching the feature corresponding parameter > # or output names. > return {self.OUTPUT: result} > > def name(self): > """ > Returns the algorithm name, used for identifying the algorithm. This > string should be fixed for the algorithm, and must not be localised. > The name should be unique within each provider. Names should contain > lowercase alphanumeric characters only and no spaces or other > formatting characters. > """ > return 'Use Difference by common ID' > > def displayName(self): > """ > Returns the translated algorithm name, which should be used for any > user-visible display of the algorithm name. > """ > return self.tr(self.name()) > > def group(self): > """ > Returns the name of the group this algorithm belongs to. This string > should be localised. > """ > return self.tr(self.groupId()) > > def groupId(self): > """ > Returns the unique ID of the group this algorithm belongs to. This > string should be fixed for the algorithm, and must not be localised. > The group id should be unique within each provider. Group id should > contain lowercase alphanumeric characters only and no spaces or other > formatting characters. > """ > return '' > > def tr(self, string): > return QCoreApplication.translate('Processing', string) > > def createInstance(self): > return DifferenceByIDAlgorithm() > -- > .................................................................... > FOSSGIS Veranstaltungen > https://www.fossgis.de/news/fossgis-events/ > > FOSSGIS e.V, der Verein zur Förderung von Freier Software aus dem > GIS-Bereich und Freier Geodaten! > https://www.fossgis.de/ https://twitter.com/fossgis_eV > > ____________________________________________________________________ > FOSSGIS-Talk-Liste mailing list > [email protected] > https://lists.fossgis.de/mailman/listinfo/fossgis-talk-liste -- .................................................................... FOSSGIS Veranstaltungen https://www.fossgis.de/news/fossgis-events/ FOSSGIS e.V, der Verein zur Förderung von Freier Software aus dem GIS-Bereich und Freier Geodaten! https://www.fossgis.de/ https://twitter.com/fossgis_eV ____________________________________________________________________ FOSSGIS-Talk-Liste mailing list [email protected] https://lists.fossgis.de/mailman/listinfo/fossgis-talk-liste
