24.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.
24.9.1. QgsProcessingAlgorithm uitbreiden
De volgende code
neemt een vectorlaag als invoer
telt het aantal objecten
doet een bewerking voor een buffer
maakt een rasterlaag als resultaat van de bewerking voor de buffer
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
enOUTPUT
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
enparameterAsDouble
.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 opTrue
bij het uitvoeren van een algoritme vanuit een ander algoritme.context
enfeedback
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.
24.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
een vectorlaag als invoer te gebruiken
het aantal objecten te tellen
een bewerking voor een buffer uit te voeren
een rasterlaag te maken uit het resultaat van de bewerking voor de buffer
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. Zij 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 maken.
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.
24.9.3. Typen invoer en uitvoer voor algoritmes van Processing
Hier is de lijst van typen invoer en uitvoer die in Processing worden ondersteund, met hun overeenkomende alg decorator constanten (het bestand algfactory.py bevat de volledige lijst met alg constanten). Gesorteerd op naam van de klasse.
24.9.3.1. Typen invoer
Klasse |
Alg constante |
Beschrijving |
---|---|---|
|
Een laag met annotaties |
|
|
Stelt gebruikers in staat om te selecteren uit beschikbare configuraties voor authenticatie of nieuwe configuraties voor authenticatie te maken |
|
|
Een band van een rasterlaag |
|
|
Een Booleaanse waarde |
|
|
Een kleur |
|
|
Een bewerking van coördinaten (voor CRS transformaties) |
|
|
Een Coördinaten ReferentieSysteem |
|
|
Een databaseschema |
|
|
Een databasetabel |
|
|
Een datum & tijd ‘datetime’ (of een pure datum of tijd) |
|
|
Een numerieke parameter Double voor waarden voor afstanden. |
|
|
Een enumeratie, wat het mogelijk maakt te selecteren uit een set vooraf gedefinieerde waarden |
|
|
Een expressie |
|
|
Een ruimtelijk bereik gedefinieerd door xmin, xmax, ymin, ymax |
|
|
Een veld in de attributentabel van een vectorlaag |
|
|
Een bestandsnaam van een bestaand bestand |
|
|
Een bestandsnaam voor een nieuw gemaakt bestand voor uitvoer |
|
|
Een map (doelmap) |
|
|
Een geometrie |
|
|
Een integer (geheel getal) |
|
|
Een lay-out |
|
|
Een item voor lay-out |
|
|
Een kaartlaag |
|
|
Een project kaartthema |
|
|
Een matrix |
|
|
Een laag met mazen |
|
|
Een set lagen |
|
|
Een numerieke waarde |
|
|
Een punt |
|
|
Een puntenwolkenlaag |
|
|
Een beschikbare verbinding voor een databaseprovider |
|
|
Een nummerreeks |
|
|
Een rasterlaag |
|
|
Een rasterlaag |
|
|
Een schaal voor de kaart |
|
|
Een object afvoer |
|
|
Een object bron |
|
|
Een teksttekenreeks |
|
|
Een vectorlaag |
|
|
Een vectorlaag |
24.9.3.2. Typen uitvoer
Klasse |
Alg constante |
Beschrijving |
---|---|---|
|
Een Booleaanse waarde |
|
|
Een numerieke parameter Double voor waarden voor afstanden. |
|
|
Een bestandsnaam van een bestaand bestand |
|
|
Een map |
|
|
HTML |
|
|
Een integer (geheel getal) |
|
|
Een laag-definitie |
|
|
Een kaartlaag |
|
|
Een set lagen |
|
|
Een numerieke waarde |
|
|
Een rasterlaag |
|
|
Een teksttekenreeks |
|
|
Een vectorlaag |
24.9.4. 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.
24.9.5. 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, …)
24.9.6. Documenteren van uw scripts
U kunt uw scripts documenteren door het overladen van de methoden helpString()
en helpUrl()
van QgsProcessingAlgorithm
.
24.9.7. 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.
24.9.8. 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 eenQgsProcessingException <qgis.core.QgsProcessingException>`
op.
Er zijn al heel veel algoritmes voor Processing beschikbaar in QGIS. U kunt de code vinden op https://github.com/qgis/QGIS/blob/release-3_22/python/plugins/processing/algs/qgis.