Wichtig

Übersetzen ist eine Gemeinschaftsleistung Sie können mitmachen. Diese Seite ist aktuell zu 100.00% übersetzt.

27.9. Schreiben neuer Verarbeitungs-Algorithmen als Python-Skripte

Es gibt zwei Möglichkeiten, Processing-Algorithmen mit Python zu schreiben.

In QGIS können Sie mit Neues Skript erstellen im Menü Skripte oben in der Verarbeitungs-Werkzeugkiste den Verarbeitungsskript-Editor öffnen, wo Sie Ihren Code schreiben können. Um die Aufgabe zu vereinfachen, können Sie mit einer Skriptvorlage beginnen, indem Sie Neues Skript aus Vorlage erstellen aus demselben Menü wählen. Dies öffnet eine Vorlage, die QgsProcessingAlgorithm erweitert.

Wenn Sie das Skript im Ordner scripts (dem Standardspeicherort) mit der Erweiterung .py speichern, wird der Algorithmus in der Verarbeitungs-Werkzeugkiste verfügbar.

27.9.1. Erweitern von QgsProcessingAlgorithm

Der folgende Code

  1. verwendet einen Vektor Layer als Eingabe

  2. zählt die Anzahl der Objekte

  3. führt eine Puffer-Operation durch

  4. erzeugt einen Raster Layer aus dem Ergebnis der Puffer-Operation

  5. gibt den Puffer-Layer, den Rasterlayer und die Anzahl der Objekte zurück

  1from qgis.PyQt.QtCore import QCoreApplication
  2from qgis.core import (QgsProcessing,
  3                       QgsProcessingAlgorithm,
  4                       QgsProcessingException,
  5                       QgsProcessingOutputNumber,
  6                       QgsProcessingParameterDistance,
  7                       QgsProcessingParameterFeatureSource,
  8                       QgsProcessingParameterVectorDestination,
  9                       QgsProcessingParameterRasterDestination)
 10from qgis import processing
 11
 12
 13class ExampleProcessingAlgorithm(QgsProcessingAlgorithm):
 14    """
 15    This is an example algorithm that takes a vector layer,
 16    creates some new layers and returns some results.
 17    """
 18
 19    def tr(self, string):
 20        """
 21        Returns a translatable string with the self.tr() function.
 22        """
 23        return QCoreApplication.translate('Processing', string)
 24
 25    def createInstance(self):
 26        # Must return a new copy of your algorithm.
 27        return ExampleProcessingAlgorithm()
 28
 29    def name(self):
 30        """
 31        Returns the unique algorithm name.
 32        """
 33        return 'bufferrasterextend'
 34
 35    def displayName(self):
 36        """
 37        Returns the translated algorithm name.
 38        """
 39        return self.tr('Buffer and export to raster (extend)')
 40
 41    def group(self):
 42        """
 43        Returns the name of the group this algorithm belongs to.
 44        """
 45        return self.tr('Example scripts')
 46
 47    def groupId(self):
 48        """
 49        Returns the unique ID of the group this algorithm belongs
 50        to.
 51        """
 52        return 'examplescripts'
 53
 54    def shortHelpString(self):
 55        """
 56        Returns a localised short help string for the algorithm.
 57        """
 58        return self.tr('Example algorithm short description')
 59
 60    def initAlgorithm(self, config=None):
 61        """
 62        Here we define the inputs and outputs of the algorithm.
 63        """
 64        # 'INPUT' is the recommended name for the main input
 65        # parameter.
 66        self.addParameter(
 67            QgsProcessingParameterFeatureSource(
 68                'INPUT',
 69                self.tr('Input vector layer'),
 70                types=[QgsProcessing.TypeVectorAnyGeometry]
 71            )
 72        )
 73        self.addParameter(
 74            QgsProcessingParameterVectorDestination(
 75                'BUFFER_OUTPUT',
 76                self.tr('Buffer output'),
 77            )
 78        )
 79        # 'OUTPUT' is the recommended name for the main output
 80        # parameter.
 81        self.addParameter(
 82            QgsProcessingParameterRasterDestination(
 83                'OUTPUT',
 84                self.tr('Raster output')
 85            )
 86        )
 87        self.addParameter(
 88            QgsProcessingParameterDistance(
 89                'BUFFERDIST',
 90                self.tr('BUFFERDIST'),
 91                defaultValue = 1.0,
 92                # Make distance units match the INPUT layer units:
 93                parentParameterName='INPUT'
 94            )
 95        )
 96        self.addParameter(
 97            QgsProcessingParameterDistance(
 98                'CELLSIZE',
 99                self.tr('CELLSIZE'),
100                defaultValue = 10.0,
101                parentParameterName='INPUT'
102            )
103        )
104        self.addOutput(
105            QgsProcessingOutputNumber(
106                'NUMBEROFFEATURES',
107                self.tr('Number of features processed')
108            )
109        )
110
111    def processAlgorithm(self, parameters, context, feedback):
112        """
113        Here is where the processing itself takes place.
114        """
115        # First, we get the count of features from the INPUT layer.
116        # This layer is defined as a QgsProcessingParameterFeatureSource
117        # parameter, so it is retrieved by calling
118        # self.parameterAsSource.
119        input_featuresource = self.parameterAsSource(parameters,
120                                                     'INPUT',
121                                                     context)
122        numfeatures = input_featuresource.featureCount()
123
124        # Retrieve the buffer distance and raster cell size numeric
125        # values. Since these are numeric values, they are retrieved
126        # using self.parameterAsDouble.
127        bufferdist = self.parameterAsDouble(parameters, 'BUFFERDIST',
128                                            context)
129        rastercellsize = self.parameterAsDouble(parameters, 'CELLSIZE',
130                                                context)
131        if feedback.isCanceled():
132            return {}
133        buffer_result = processing.run(
134            'native:buffer',
135            {
136                # Here we pass on the original parameter values of INPUT
137                # and BUFFER_OUTPUT to the buffer algorithm.
138                'INPUT': parameters['INPUT'],
139                'OUTPUT': parameters['BUFFER_OUTPUT'],
140                'DISTANCE': bufferdist,
141                'SEGMENTS': 10,
142                'DISSOLVE': True,
143                'END_CAP_STYLE': 0,
144                'JOIN_STYLE': 0,
145                'MITER_LIMIT': 10
146            },
147            # Because the buffer algorithm is being run as a step in
148            # another larger algorithm, the is_child_algorithm option
149            # should be set to True
150            is_child_algorithm=True,
151            #
152            # It's important to pass on the context and feedback objects to
153            # child algorithms, so that they can properly give feedback to
154            # users and handle cancelation requests.
155            context=context,
156            feedback=feedback)
157
158        # Check for cancelation
159        if feedback.isCanceled():
160            return {}
161
162        # Run the separate rasterization algorithm using the buffer result
163        # as an input.
164        rasterized_result = processing.run(
165            'qgis:rasterize',
166            {
167                # Here we pass the 'OUTPUT' value from the buffer's result
168                # dictionary off to the rasterize child algorithm.
169                'LAYER': buffer_result['OUTPUT'],
170                'EXTENT': buffer_result['OUTPUT'],
171                'MAP_UNITS_PER_PIXEL': rastercellsize,
172                # Use the original parameter value.
173                'OUTPUT': parameters['OUTPUT']
174            },
175            is_child_algorithm=True,
176            context=context,
177            feedback=feedback)
178
179        if feedback.isCanceled():
180            return {}
181
182        # Return the results
183        return {'OUTPUT': rasterized_result['OUTPUT'],
184                'BUFFER_OUTPUT': buffer_result['OUTPUT'],
185                'NUMBEROFFEATURES': numfeatures}

Standardfunktionen des Verarbeitungsalgorithmus:

  • createInstance (obligatorisch)

    Muss eine neue Kopie Ihres Algorithmus zurückgeben. Wenn Sie den Namen der Klasse ändern, stellen Sie sicher, dass Sie auch den hier zurückgegebenen Wert entsprechend aktualisieren!

  • name (obligatorisch)

    Gibt den eindeutigen Algorithmusnamen zurück, der zur Identifizierung des Algorithmus dient.

  • displayName (obligatorisch)

    Gibt den übersetzten Algorithmusnamen zurück.

  • group

    Gibt den Namen der Gruppe zurück, zu der dieser Algorithmus gehört.

  • groupId

    Gibt die eindeutige ID der Gruppe zurück, zu der dieser Algorithmus gehört.

  • shortHelpString

    Gibt eine kurze Hilfezeichenkette für den Algorithmus zurück.

  • initAlgorithm (obligatorisch)

    Hier werden die Ein- und Ausgaben des Algorithmus definiert.

    INPUT und OUTPUT sind empfohlene Namen für die Haupteingabe- bzw. Hauptausgabeparameter.

    Wenn ein Parameter von einem anderen Parameter abhängt, wird parentParameterName verwendet, um diese Beziehung zu spezifizieren (könnte das Feld / Band eines Layers oder die Entfernungseinheiten eines Layers sein).

  • processAlgorithm (obligatorisch)

    Hier findet die Verarbeitung statt.

    Parameter werden mit speziellen Funktionen abgerufen, zum Beispiel parameterAsSource und parameterAsDouble.

    processing.run kann verwendet werden, um andere Verarbeitungsalgorithmen von einem Verarbeitungsalgorithmus auszuführen. Der erste Parameter ist der Name des Algorithmus, der zweite ist ein Wörterbuch mit den Parametern des Algorithmus. Der Parameter is_child_algorithm wird normalerweise auf True gesetzt, wenn ein Algorithmus aus einem anderen Algorithmus heraus gestartet wird. Context und Feedback informieren den Algorithmus über die Umgebung, in der er laufen soll, und den Kanal für die Kommunikation mit dem Benutzer (Abbruch einer Anfrage, Meldung des Fortschritts, textuelles Feedback). Wenn die Parameter des (übergeordneten) Algorithmus als Parameter für „untergeordnete“ Algorithmen verwendet werden, sollten die ursprünglichen Parameterwerte verwendet werden (z.B. parameters['OUTPUT']).

    Es ist eine gute Praxis, das Feedback-Objekt so oft wie möglich auf Abbruch zu prüfen! Dies ermöglicht eine schnelle Beendigung, anstatt den Benutzer zu zwingen, auf eine unerwünschte Verarbeitung zu warten.

    Der Algorithmus sollte Werte für alle Ausgabeparameter zurückgeben, die er in einem Verzeichnis definiert hat. In diesem Fall sind das die Puffer- und gerasterten Output-Layer sowie die Anzahl der verarbeiteten Objekte. Die Verzeichnisschlüssel müssen mit den ursprünglichen Namen der Parameter/Ausgaben übereinstimmen.

27.9.2. Der @alg decorator

Mit dem @alg decorator können Sie Ihre eigenen Algorithmen erstellen, indem Sie den Python-Code schreiben und ein paar zusätzliche Zeilen hinzufügen, um zusätzliche Informationen zu liefern, die erforderlich sind, um ihn zu einem richtigen Processing-Algorithmus zu machen. Dies vereinfacht die Erstellung von Algorithmen und die Angabe von Eingaben und Ausgaben.

Eine wichtige Einschränkung des Decorator-Ansatzes ist, dass Algorithmen, die auf diese Weise erstellt werden, immer zum Processing Scripts Provider eines Benutzers hinzugefügt werden – es ist nicht möglich, diese Algorithmen zu einem benutzerdefinierten Provider hinzuzufügen, z.B. zur Verwendung in Plugins.

Der folgende Code verwendet den @alg decorater, um

  1. einen Vektorlayer als Eingabe verwenden

  2. die Anzahl der Objekte zählen

  3. eine Puffer-Operation durchzuführen

  4. einen Raster Layer aus dem Ergebnis der Pufferoperation erstellen

  5. gibt den Puffer-Layer, den Rasterlayer und die Anzahl der Objekte zurück

 1from qgis import processing
 2from qgis.processing import alg
 3from qgis.core import QgsProject
 4
 5@alg(name='bufferrasteralg', label='Buffer and export to raster (alg)',
 6     group='examplescripts', group_label='Example scripts')
 7# 'INPUT' is the recommended name for the main input parameter
 8@alg.input(type=alg.SOURCE, name='INPUT', label='Input vector layer')
 9# 'OUTPUT' is the recommended name for the main output parameter
10@alg.input(type=alg.RASTER_LAYER_DEST, name='OUTPUT',
11           label='Raster output')
12@alg.input(type=alg.VECTOR_LAYER_DEST, name='BUFFER_OUTPUT',
13           label='Buffer output')
14@alg.input(type=alg.DISTANCE, name='BUFFERDIST', label='BUFFER DISTANCE',
15           default=1.0)
16@alg.input(type=alg.DISTANCE, name='CELLSIZE', label='RASTER CELL SIZE',
17           default=10.0)
18@alg.output(type=alg.NUMBER, name='NUMBEROFFEATURES',
19            label='Number of features processed')
20
21def bufferrasteralg(instance, parameters, context, feedback, inputs):
22    """
23    Description of the algorithm.
24    (If there is no comment here, you will get an error)
25    """
26    input_featuresource = instance.parameterAsSource(parameters,
27                                                     'INPUT', context)
28    numfeatures = input_featuresource.featureCount()
29    bufferdist = instance.parameterAsDouble(parameters, 'BUFFERDIST',
30                                            context)
31    rastercellsize = instance.parameterAsDouble(parameters, 'CELLSIZE',
32                                                context)
33    if feedback.isCanceled():
34        return {}
35    buffer_result = processing.run('native:buffer',
36                               {'INPUT': parameters['INPUT'],
37                                'OUTPUT': parameters['BUFFER_OUTPUT'],
38                                'DISTANCE': bufferdist,
39                                'SEGMENTS': 10,
40                                'DISSOLVE': True,
41                                'END_CAP_STYLE': 0,
42                                'JOIN_STYLE': 0,
43                                'MITER_LIMIT': 10
44                                },
45                               is_child_algorithm=True,
46                               context=context,
47                               feedback=feedback)
48    if feedback.isCanceled():
49        return {}
50    rasterized_result = processing.run('qgis:rasterize',
51                               {'LAYER': buffer_result['OUTPUT'],
52                                'EXTENT': buffer_result['OUTPUT'],
53                                'MAP_UNITS_PER_PIXEL': rastercellsize,
54                                'OUTPUT': parameters['OUTPUT']
55                               },
56                               is_child_algorithm=True, context=context,
57                               feedback=feedback)
58    if feedback.isCanceled():
59        return {}
60    return {'OUTPUT': rasterized_result['OUTPUT'],
61            'BUFFER_OUTPUT': buffer_result['OUTPUT'],
62            'NUMBEROFFEATURES': numfeatures}

Wie Sie sehen können, handelt es sich um zwei Algorithmen (‚native:buffer‘ und ‚qgis:rasterize‘). Der letzte (‚qgis:rasterize‘) erzeugt einen Raster Layer aus dem Puffer Layer, der durch den ersten (‚native:buffer‘) erzeugt wurde.

Der Teil des Codes, in dem diese Verarbeitung stattfindet, ist nicht schwer zu verstehen, wenn Sie das vorherige Kapitel gelesen haben. Die ersten Zeilen bedürfen jedoch einiger zusätzlicher Erläuterungen. Sie liefern die Informationen, die benötigt werden, um Ihren Code in einen Algorithmus zu verwandeln, der von jeder der GUI-Komponenten, wie der Toolbox oder dem Modelldesigner, ausgeführt werden kann.

Diese Zeilen sind allesamt Aufrufe der @alg-decorator-Funktionen, die die Codierung des Algorithmus vereinfachen.

  • Der @alg decorator wird verwendet, um den Namen und die Position des Algorithmus in der Werkzeugkiste zu definieren.

  • Der @alg.input decorator wird verwendet, um die Eingaben des Algorithmus zu definieren.

  • Der @alg.output decorator wird verwendet, um die Ausgaben des Algorithmus zu definieren.

Für die vorhandenen Parameter und ihre Entsprechung lesen Sie bitte Eingabe- und Ausgabetypen für Verarbeitungsalgorithmen.

27.9.3. Handhabung der Algorithmus-Ausgabe

Wenn Sie eine Ausgabe deklarieren, die einen Layer (Raster oder Vektor) darstellt, wird der Algorithmus versuchen, diesen in QGIS einzufügen, sobald er fertig ist.

  • Ausgabe eines Rasterlayers: QgsProcessingParameterRasterDestination / alg.RASTER_LAYER_DEST.

  • Ausgabe eines Vektorlayers: QgsProcessingParameterVectorDestination / alg.VECTOR_LAYER_DEST.

Selbst wenn also die Methode processing.run() die von ihr erzeugten Layer nicht zum aktuellen Projekt des Benutzers hinzufügt, werden die beiden Ausgabelayer (Puffer und Rasterpuffer) geladen, da sie an den vom Benutzer eingegebenen Zielen gespeichert werden (oder an temporären Zielen, wenn der Benutzer keine Ziele angibt).

Wenn ein Layer als Ausgabe eines Algorithmus erstellt wird, sollte er auch als solcher deklariert werden. Andernfalls können Sie den Algorithmus im Modellierer nicht richtig verwenden, da das, was deklariert wird, nicht mit dem übereinstimmt, was der Algorithmus tatsächlich erzeugt.

Sie können Zeichenketten, Zahlen und mehr zurückgeben, indem Sie sie im Ergebniswörterbuch angeben (wie für „NUMBEROFFEATURES“ gezeigt), aber sie sollten immer ausdrücklich als Ausgaben Ihres Algorithmus definiert werden. Wir ermutigen Algorithmen, so viele nützliche Werte wie möglich auszugeben, da diese für die Verwendung in späteren Algorithmen wertvoll sein können, wenn Ihr Algorithmus als Teil eines Modells verwendet wird.

27.9.4. Kommunikation mit dem Nutzer.

Wenn Ihr Algorithmus eine lange Zeit für die Verarbeitung benötigt, ist es eine gute Idee, den Benutzer über den Fortschritt zu informieren. Hierfür können Sie Feedback (QgsProcessingFeedback) verwenden.

Der Fortschrittstext und die Fortschrittsleiste können mit zwei Methoden aktualisiert werden: setProgressText(text) und setProgress(percent).

Sie können weitere Informationen bereitstellen, indem Sie pushCommandInfo(text), pushDebugInfo(text), pushInfo(text) oder reportError(text) verwenden.

Wenn in Ihrem Skript ein Problem auftritt, besteht die korrekte Art der Behandlung darin, eine QgsProcessingException auszulösen. Sie können eine Nachricht als Argument an den Konstruktor der Ausnahme übergeben. Die Verarbeitung kümmert sich um die Behandlung und die Kommunikation mit dem Benutzer, je nachdem, von wo aus der Algorithmus ausgeführt wird (Toolbox, Modeler, Python-Konsole, …)

27.9.5. Ihre Scripte dokumentieren

Sie können Ihre Skripte unter Verwendung von helpString() und helpUrl(), Methoden von QgsProcessingAlgorithm dokumentieren.

27.9.6. Flags

Sie können die Methode flags() von QgsProcessingAlgorithm überschreiben, um QGIS mehr über Ihren Algorithmus zu erzählen. Sie können QGIS zum Beispiel mitteilen, dass das Skript vor dem Modellierer verborgen werden soll, dass es abgebrochen werden kann, dass es nicht thread-sicher ist und vieles mehr.

Tipp

Standardmäßig führt Processing Algorithmen in einem separaten Thread aus, damit QGIS während der Ausführung des Processing-Tasks ansprechbar bleibt. Wenn Ihr Algorithmus regelmäßig abstürzt, verwenden Sie wahrscheinlich API-Aufrufe, die nicht sicher in einem Hintergrund-Thread ausgeführt werden können. Versuchen Sie, das Flag QgsProcessingAlgorithm.FlagNoThreading aus der flags()-Methode Ihres Algorithmus zurückzugeben, um Processing zu zwingen, Ihren Algorithmus stattdessen im Hauptthread auszuführen.

27.9.7. Bewährte Verfahren für das Schreiben von Skript-Algorithmen

Hier finden Sie eine kurze Zusammenfassung von Ideen, die Sie bei der Erstellung Ihrer Skript-Algorithmen berücksichtigen sollten, vor allem, wenn Sie sie mit anderen QGIS-Benutzern teilen möchten. Wenn Sie diese einfachen Regeln befolgen, wird die Konsistenz zwischen den verschiedenen Verarbeitungselementen wie der Werkzeugkiste, dem Modellierer oder der Stapelverarbeitungsschnittstelle gewährleistet.

  • Laden Sie keine Ergebnislayer. Lassen Sie die Verarbeitung Ihrer Ergebnisse abarbeiten und laden Sie Ihre Layer, wenn nötig.

  • Geben Sie immer die Ausgaben an, die Ihr Algorithmus erzeugt.

  • Zeigen Sie keine Meldungsfelder an und verwenden Sie keine GUI-Elemente aus dem Skript. Wenn Sie mit dem Benutzer kommunizieren möchten, verwenden Sie die Methoden des Feedback-Objekts (QgsProcessingFeedback) oder werfen Sie eine QgsProcessingException.

Es sind bereits viele Verarbeitungsalgorithmen in QGIS verfügbar. Sie können Code auf der QGIS Repo finden.