23.9. Nieuwe algoritmen voor Processing schrijven als scripts voor Python¶
Er bestaan twee opties voor het schrijven van algoritmen 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.
23.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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 | from qgis.PyQt.QtCore import QCoreApplication
from qgis.core import (QgsProcessing,
QgsProcessingAlgorithm,
QgsProcessingException,
QgsProcessingOutputNumber,
QgsProcessingParameterDistance,
QgsProcessingParameterFeatureSource,
QgsProcessingParameterVectorDestination,
QgsProcessingParameterRasterDestination)
from qgis import processing
class ExampleProcessingAlgorithm(QgsProcessingAlgorithm):
"""
This is an example algorithm that takes a vector layer,
creates some new layers and returns some results.
"""
def tr(self, string):
"""
Returns a translatable string with the self.tr() function.
"""
return QCoreApplication.translate('Processing', string)
def createInstance(self):
# Must return a new copy of your algorithm.
return ExampleProcessingAlgorithm()
def name(self):
"""
Returns the unique algorithm name.
"""
return 'bufferrasterextend'
def displayName(self):
"""
Returns the translated algorithm name.
"""
return self.tr('Buffer and export to raster (extend)')
def group(self):
"""
Returns the name of the group this algorithm belongs to.
"""
return self.tr('Example scripts')
def groupId(self):
"""
Returns the unique ID of the group this algorithm belongs
to.
"""
return 'examplescripts'
def shortHelpString(self):
"""
Returns a localised short help string for the algorithm.
"""
return self.tr('Example algorithm short description')
def initAlgorithm(self, config=None):
"""
Here we define the inputs and outputs of the algorithm.
"""
# 'INPUT' is the recommended name for the main input
# parameter.
self.addParameter(
QgsProcessingParameterFeatureSource(
'INPUT',
self.tr('Input vector layer'),
types=[QgsProcessing.TypeVectorAnyGeometry]
)
)
self.addParameter(
QgsProcessingParameterVectorDestination(
'BUFFER_OUTPUT',
self.tr('Buffer output'),
)
)
# 'OUTPUT' is the recommended name for the main output
# parameter.
self.addParameter(
QgsProcessingParameterRasterDestination(
'OUTPUT',
self.tr('Raster output')
)
)
self.addParameter(
QgsProcessingParameterDistance(
'BUFFERDIST',
self.tr('BUFFERDIST'),
defaultValue = 1.0,
# Make distance units match the INPUT layer units:
parentParameterName='INPUT'
)
)
self.addParameter(
QgsProcessingParameterDistance(
'CELLSIZE',
self.tr('CELLSIZE'),
defaultValue = 10.0,
parentParameterName='INPUT'
)
)
self.addOutput(
QgsProcessingOutputNumber(
'NUMBEROFFEATURES',
self.tr('Number of features processed')
)
)
def processAlgorithm(self, parameters, context, feedback):
"""
Here is where the processing itself takes place.
"""
# First, we get the count of features from the INPUT layer.
# This layer is defined as a QgsProcessingParameterFeatureSource
# parameter, so it is retrieved by calling
# self.parameterAsSource.
input_featuresource = self.parameterAsSource(parameters,
'INPUT',
context)
numfeatures = input_featuresource.featureCount()
# Retrieve the buffer distance and raster cell size numeric
# values. Since these are numeric values, they are retrieved
# using self.parameterAsDouble.
bufferdist = self.parameterAsDouble(parameters, 'BUFFERDIST',
context)
rastercellsize = self.parameterAsDouble(parameters, 'CELLSIZE',
context)
if feedback.isCanceled():
return {}
buffer_result = processing.run(
'native:buffer',
{
# Here we pass on the original parameter values of INPUT
# and BUFFER_OUTPUT to the buffer algorithm.
'INPUT': parameters['INPUT'],
'OUTPUT': parameters['BUFFER_OUTPUT'],
'DISTANCE': bufferdist,
'SEGMENTS': 10,
'DISSOLVE': True,
'END_CAP_STYLE': 0,
'JOIN_STYLE': 0,
'MITER_LIMIT': 10
},
# Because the buffer algorithm is being run as a step in
# another larger algorithm, the is_child_algorithm option
# should be set to True
is_child_algorithm=True,
#
# It's important to pass on the context and feedback objects to
# child algorithms, so that they can properly give feedback to
# users and handle cancelation requests.
context=context,
feedback=feedback)
# Check for cancelation
if feedback.isCanceled():
return {}
# Run the separate rasterization algorithm using the buffer result
# as an input.
rasterized_result = processing.run(
'qgis:rasterize',
{
# Here we pass the 'OUTPUT' value from the buffer's result
# dictionary off to the rasterize child algorithm.
'LAYER': buffer_result['OUTPUT'],
'EXTENT': buffer_result['OUTPUT'],
'MAP_UNITS_PER_PIXEL': rastercellsize,
# Use the original parameter value.
'OUTPUT': parameters['OUTPUT']
},
is_child_algorithm=True,
context=context,
feedback=feedback)
if feedback.isCanceled():
return {}
# Return the results
return {'OUTPUT': rasterized_result['OUTPUT'],
'BUFFER_OUTPUT': buffer_result['OUTPUT'],
'NUMBEROFFEATURES': numfeatures}
|
Standaardfuncties voor algoritmen 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 algoritmen 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) algoritmen als parameters voor “kind”-algoritmen, 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.
23.9.2. De decorator @alg¶
Door de decorator @alg te gebruiken kunt u uw eigen algoritmen 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 algoritmen en het specificeren van in- en uitvoer.
Één belangrijke beperking met de benadering van de decorator is dat algoritmen die op deze manier worden gemaakt worden toegevoegd aan de Processing Scriptsprovider van de gebruiker – het is niet mogelijk om deze algoritmen 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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 | from qgis import processing
from qgis.processing import alg
from qgis.core import QgsProject
@alg(name='bufferrasteralg', label='Buffer and export to raster (alg)',
group='examplescripts', group_label='Example scripts')
# 'INPUT' is the recommended name for the main input parameter
@alg.input(type=alg.SOURCE, name='INPUT', label='Input vector layer')
# 'OUTPUT' is the recommended name for the main output parameter
@alg.input(type=alg.RASTER_LAYER_DEST, name='OUTPUT',
label='Raster output')
@alg.input(type=alg.VECTOR_LAYER_DEST, name='BUFFER_OUTPUT',
label='Buffer output')
@alg.input(type=alg.DISTANCE, name='BUFFERDIST', label='BUFFER DISTANCE',
default=1.0)
@alg.input(type=alg.DISTANCE, name='CELLSIZE', label='RASTER CELL SIZE',
default=10.0)
@alg.output(type=alg.NUMBER, name='NUMBEROFFEATURES',
label='Number of features processed')
def bufferrasteralg(instance, parameters, context, feedback, inputs):
"""
Description of the algorithm.
(If there is no comment here, you will get an error)
"""
input_featuresource = instance.parameterAsSource(parameters,
'INPUT', context)
numfeatures = input_featuresource.featureCount()
bufferdist = instance.parameterAsDouble(parameters, 'BUFFERDIST',
context)
rastercellsize = instance.parameterAsDouble(parameters, 'CELLSIZE',
context)
if feedback.isCanceled():
return {}
buffer_result = processing.run('native:buffer',
{'INPUT': parameters['INPUT'],
'OUTPUT': parameters['BUFFER_OUTPUT'],
'DISTANCE': bufferdist,
'SEGMENTS': 10,
'DISSOLVE': True,
'END_CAP_STYLE': 0,
'JOIN_STYLE': 0,
'MITER_LIMIT': 10
},
is_child_algorithm=True,
context=context,
feedback=feedback)
if feedback.isCanceled():
return {}
rasterized_result = processing.run('qgis:rasterize',
{'LAYER': buffer_result['OUTPUT'],
'EXTENT': buffer_result['OUTPUT'],
'MAP_UNITS_PER_PIXEL': rastercellsize,
'OUTPUT': parameters['OUTPUT']
},
is_child_algorithm=True, context=context,
feedback=feedback)
if feedback.isCanceled():
return {}
return {'OUTPUT': rasterized_result['OUTPUT'],
'BUFFER_OUTPUT': buffer_result['OUTPUT'],
'NUMBEROFFEATURES': numfeatures}
|
Zoals u kunt zien zijn twee algoritmen 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.
23.9.3. Typen invoer en uitvoer voor algoritmen van Processing¶
Hier is de lijst van typen invoer en uitvoer die in Processing worden ondersteund, met hun overeenkomende alg decorator constanten (algfactory.py
bevat de volledige lijst met alg constanten). Gesorteerd op naam van de klasse.
23.9.3.1. Typen invoer¶
Klasse |
Alg constante |
Beschrijving |
---|---|---|
|
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 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 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 |
23.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 |
23.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 algoritmen zoveel nuttige waarden als mogelijk uit te laten voeren, omdat die waardevol kunnen zijn bij later gebruik in algoritmen wanneer uw algoritme wordt gebruikt als deel van een model.
23.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, …)
23.9.6. Documenteren van uw scripts¶
U kunt uw scripts documenteren door het overladen van de methoden helpString()
en helpUrl()
van QgsProcessingAlgorithm
.
23.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 algoritmen 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 algoritmen methode flags() om Processing te forceren om uw algoritme in plaats daarvan in de hoofdthread uit te laten voeren.
23.9.8. Best practices voor het schrijven van algoritmen als scripts¶
Hier is een snelle samenvatting van ideeën om te overwegen wanneer u uw algoritmen 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 algoritmen voor Processing beschikbaar in QGIS. U kunt de code vinden op https://github.com/qgis/QGIS/blob/release-3_16/python/plugins/processing/algs/qgis.