Belangrijk

Vertalen is een inspanning van de gemeenschap waaraan u deel kunt nemen. Deze pagina is momenteel voor 100.00% vertaald.

27.9. Nieuwe algoritmes voor Processing schrijven als scripts voor Python

Er bestaan twee opties voor het schrijven van algoritmes voor Processing met Python.

In QGIS kunt u Nieuw script maken in het menu Scripts boven in de Processing Toolbox gebruiken om de Processing Script bewerken te openen waar u uw code kunt schrijven. U kunt, om de taak te vereenvoudigen, beginnen met een sjabloon voor een script door Nieuw script uit sjabloon maken uit hetzelfde menu te gebruiken. Dat opent een sjabloon dat QgsProcessingAlgorithm uitbreidt.

Als u het script opslaat in de map scripts (de standaardlocatie) met de extensie .py, zal het algoritme beschikbaar komen in de Processing Toolbox.

27.9.1. QgsProcessingAlgorithm uitbreiden

De volgende code

  1. neemt een vectorlaag als invoer

  2. telt het aantal objecten

  3. doet een bewerking voor een buffer

  4. maakt een rasterlaag als resultaat van de bewerking voor de buffer

  5. geeft de laag voor de buffer, de rasterlaag en het aantal objecten terug

  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}

Standaardfuncties voor algoritmes van Processing

  • createInstance (verplicht)

    Moet een nieuwe kopie van uw algoritme teruggeven. Als u de naam van de klasse wijzigt, zorg er dan voor dat u ook de hier teruggegeven waarde bijwerkt zodat die overeenkomt!

  • name (verplicht)

    Geeft de unieke naam van het algoritme terug, gebruikt voor het identificeren van het algoritme.

  • displayName (verplicht)

    Geeft de vertaalde naam van het algoritme terug.

  • group

    Geeft de naam van de groep terug waartoe dit algoritme behoort.

  • groupId

    Geeft de unieke ID van de groep terug waartoe dit algoritme behoort.

  • shortHelpString

    Geeft een gelokaliseerde korte tekenreeks voor Help voor het algoritme terug.

  • initAlgorithm (verplicht)

    Hier definiëren we de in- en uitvoer voor het algoritme.

    INPUT en OUTPUT zijn aanbevolen namen voor de parameters voor de respectievelijke hoofdinvoer en hoofduitvoer.

    Als een parameter afhankelijk is van een andere parameter, wordt parentParameterName gebruikt om deze relatie te specificeren (zou het veld / band van een laag of de eenheden voor afstand van een laag kunnen zijn).

  • processAlgorithm (verplicht)

    Dit is waar de verwerking plaatsvindt.

    Parameters worden opgehaald met behulp van functies voor speciale doelen, bijvoorbeeld parameterAsSource en parameterAsDouble.

    processing.run kan worden gebruikt om andere algoritmes van Processing uit te voeren vanuit een algoritme van Processing. De eerste parameter is de naam van het algoritme, de tweede is een woordenboek van de parameters voor het algoritme. is_child_algorithm is normaal ingesteld op True bij het uitvoeren van een algoritme vanuit een ander algoritme. context en feedback informeert het algoritme over de omgeving waarin het moet worden uitgevoerd en het kanaal voor het communiceren met de gebruiker (opvangen verzoek tot annuleren, voortgang rapporteren, tekstuele terugkoppeling geven). Bij het gebruiken van de parameters van (ouder) algoritmes als parameters voor “kind”-algoritmes, zouden de originele waarden voor de parameter moeten worden gebruikt (bijv. parameters['OUTPUT']).

    Het is goed gebruik om het object feedback te controleren op annuleren zo vaak als enigszins mogelijk is! Door dit te doen maakt het reageren op annuleren mogelijk, in plaats van gebruikers te forceren te wachten tot ongewenste verwerking optreedt.

    Het algoritme zou waarden terug moeten geven voor alle waarden van de parameters voor de uitvoer die zijn gedefinieerd als een woordenboek. In dit geval zijn dat de buffer en de gerasteriseerde uitvoerlagen, en het aantal verwerkte objecten. De sleutels voor het woordenboek moeten overeen komen met de originele parameters/namen van de uitvoer.

27.9.2. De decorator @alg

Door de decorator @alg te gebruiken kunt u uw eigen algoritmes maken door de code voor Python te schrijven en een aantal extra regels toe te voegen, om aanvullende informatie te verschaffen die nodig is om een correct algoritme voor Processing te maken. Dit vereenvoudigt het maken van algoritmes en het specificeren van in- en uitvoer.

Één belangrijke beperking met de benadering van de decorator is dat algoritmes die op deze manier worden gemaakt worden toegevoegd aan de Processing Scriptsprovider van de gebruiker – het is niet mogelijk om deze algoritmes toe te voegen aan een aangepaste provider, bijv om in plug-ins te gebruiken.

De volgende code gebruikt de decorator @alg om

  1. een vectorlaag als invoer te gebruiken

  2. het aantal objecten te tellen

  3. een bewerking voor een buffer uit te voeren

  4. een rasterlaag te maken uit het resultaat van de bewerking voor de buffer

  5. geeft de laag voor de buffer, de rasterlaag en het aantal objecten terug

 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}

Zoals u kunt zien zijn twee algoritmes betrokken (‘native:buffer’ en ‘qgis:rasterize’). De laatste (‘qgis:rasterize’) maakt een rasterlaag uit de bufferlaag die werd gemaakt door het eerste (‘native:buffer’).

Het deel van de code waar deze verwerking plaatsvindt is niet moeilijk te begrijpen, als u het vorige hoofdstuk hebt gelezen. De eerste regels moeten echter even nader worden uitgelegd. Ze verschaffen de informatie die nodig is om van uw code een algoritme te maken dat kan worden uitgevoerd vanuit elk van de componenten van de GUI, zoals de Toolbox of Grafische modellen ontwerpen.

Deze regels zijn allemaal aanroepen naar functies van de decorator @alg, die helpen de codering van het algoritme te vereenvoudigen.

  • De decorator @alg wordt gebruikt om de naam en locatie te definiëren van het algoritme in de Toolbox.

  • De decorator @alg.input wordt gebruikt om de invoer voor het algoritme te definiëren.

  • De decorator @alg.output wordt gebruikt om de uitvoer voor het algoritme te definiëren.

Voor bestaande parameters en hun overeenkomsten, lees Typen invoer en uitvoer voor algoritmes van Processing.

27.9.3. Uitvoer algoritme afhandelen

Wanneer u een uitvoer declareert die een laag weergeeft (raster of vector), zal het algoritme proberen het toe te voegen aan QGIS als het eenmaal voltooid is.

  • Rasterlaag uitvoer: QgsProcessingParameterRasterDestination / alg.RASTER_LAYER_DEST.

  • Vectorlaag uitvoer: QgsProcessingParameterVectorDestination / alg.VECTOR_LAYER_DEST.

Dus, zelfs als de methode processing.run() de lagen die het maakt niet toevoegt aan het huidige project van de gebruiker, zullen de twee uitvoerlagen (buffer en rasterbuffer) worden geladen, omdat zij zijn opgeslagen naar de doelen die zijn ingevoerd door de gebruiker (of naar tijdelijke doelen als de gebruiker geen doelen specificeert).

Als een laag wordt gemaakt als uitvoer van een algoritme, zou het ook zo moeten worden gedefinieerd. Anders zult u niet in staat zijn het algoritme op de juiste manier te gebruiken in Grafische modellen bouwen, omdat wat is gedefinieerd niet overeenkomt met wat het algoritme in werkelijkheid maakt.

U kunt tekenreeks, getallen en meer teruggeven door ze te specificeren in het woordenboek van het resultaat (zoals gedemonstreerd voor “NUMBEROFFEATURES”), maar ze zouden altijd expliciet moeten worden gedefinieerd als uitvoer vanuit uw algoritme. We propageren om algoritmes zoveel nuttige waarden als mogelijk uit te laten voeren, omdat die waardevol kunnen zijn bij later gebruik in algoritmes wanneer uw algoritme wordt gebruikt als deel van een model.

27.9.4. Communiceren met de gebruiker

Als uw algoritme er lang over doet om te worden verwerkt, is het een goed idee om de gebruiker over de voortgang te informeren. U kunt feedback (QgsProcessingFeedback) hiervoor gebruiken.

De tekst voor de voortgang en de voortgangsbalk kunnen worden bijgewerkt met behulp van twee methoden: setProgressText(text) en setProgress(percent).

U kunt meer informatie verschaffen door te gebruiken pushCommandInfo(text), pushDebugInfo(text), pushInfo(text) en reportError(text).

Als uw script problemen heeft, is de juiste manier om door te gaan het een uitzondering te laten opkomen van een QgsProcessingException. U kunt een bericht doorgeven als argument aan de constructor van de uitzondering. Processing zal zorg dragen voor de afhandeling ervan en communiceren met de gebruiker, afhankelijk van waaruit het algoritme wordt uitgevoerd (Toolbox, Grafische modellen bouwen, console van Python, …)

27.9.5. Documenteren van uw scripts

U kunt uw scripts documenteren door het overladen van de methoden helpString() en helpUrl() van QgsProcessingAlgorithm.

27.9.6. Vlaggen

U kunt de methode flags() van QgsProcessingAlgorithm overschrijven om QGIS meer te vertellen over uw algoritme. U kunt bijvoorbeeld QGIS vertellen dat het script moet worden verborgen in Grafische modellen bouwen, dat het kan worden geannuleerd, dat het niet veilig met threads is, en meer.

Tip

Standaard voert Processing algoritmes uit in een afzonderlijke thread om QGIS te kunnen laten reageren als de taak voor processing wordt uitgevoerd. Als uw algoritme regelmatig crasht, gebruikt u waarschijnlijk aanroepen naar de API die niet veilig kunnen worden uitgevoerd in een thread op de achtergrond. Probeer om de vlag QgsProcessingAlgorithm.FlagNoThreading terug te laten geven vanuit uit algoritmes methode flags() om Processing te forceren om uw algoritme in plaats daarvan in de hoofdthread uit te laten voeren.

27.9.7. Best practices voor het schrijven van algoritmes als scripts

Hier is een snelle samenvatting van ideeën om te overwegen wanneer u uw algoritmes als scripts maakt en, in het bijzonder, als u ze wilt delen met andere gebruikers van QGIS. Volgen van deze eenvoudige regels zal zorgen voor consistentie in de verschillende elementen van Processing, zoals de Toolbox, Grafische modellen bouwen of de interface voor Batch-processing.

  • Laad geen resulterende lagen. Laat Processing uw resultaten afhandelen en lagen laden als dat nodig is.

  • Definieer altijd de uitvoer die uw algoritme maakt.

  • Geef geen berichtenvensters weer of gebruik een element van de GUI vanuit het script. Als u wilt communiceren met de gebruiker, gebruik dan de methoden van het object feedback (QgsProcessingFeedback) of werp een QgsProcessingException op.

Er zijn al heel veel algoritmes voor Processing beschikbaar in QGIS. U kunt de code vinden in de opslagplaats van QGIS