Nieuwe algoritmen voor Processing schrijven als scripts voor Python¶
In QGIS 3.4 is de enige manier om algoritmes voor Processing met behulp van Python te schrijven is om de klasse QgsProcessingAlgorithm
uit te breiden.
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 standaard locatie) met de extensie .py
, zal het algoritme beschikbaar komen in de Processing Toolbox.
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
from qgis.PyQt.QtCore import QCoreApplication
from qgis.core import (QgsProcessing,
QgsProcessingAlgorithm,
QgsProcessingException,
QgsProcessingOutputNumber,
QgsProcessingParameterDistance,
QgsProcessingParameterFeatureSource,
QgsProcessingParameterVectorDestination,
QgsProcessingParameterRasterDestination)
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}
Standaard functies 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.
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 (algfactory.py
bevat de volledige lijst met alg constanten). Gesorteerd op naam van de klasse.
Klasse |
Beschrijving |
---|---|
Een band van een rasterlaag |
|
Een Booleaanse waarde |
|
Een Coördinaten ReferentieSysteem |
|
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 object afvoer |
|
Een object bron |
|
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 |
|
Een kaartlaag |
|
Een matrix |
|
Een set lagen |
|
Een numerieke waarde |
|
Een punt |
|
Een nummerreeks |
|
Een rasterlaag |
|
Een rasterlaag |
|
Een teksttekenreeks |
|
Een vectorlaag |
|
Een vectorlaag |
Klasse |
Beschrijving |
---|---|
Een bestandsnaam van een bestaand bestand |
|
Een map |
|
HTML |
|
Een laag-definitie |
|
Een kaartlaag |
|
Een set lagen |
|
Een numerieke waarde |
|
Een rasterlaag |
|
Een teksttekenreeks |
|
Een vectorlaag |
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.
Uitvoer rasterlaag: QgsProcessingParameterRasterDestination.
Uitvoer vectorlaag: QgsProcessingParameterVectorDestination.
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 (laag met buffer en rasterlaag) worden geladen, omdat zij zijn opgeslagen op de doelbestemming die de gebruiker heeft ingevoerd (of op tijdelijke doelbestemmingen als de gebruiker geen doelbestemming specificeertn
).
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.
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 aan de gebruiker verstrekken met behulp van 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, …)
Documenteren van uw scripts¶
U kunt uw scripts documenteren door het overladen van de methoden helpString()
en helpUrl()
van QgsProcessingAlgorithm
.
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 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.
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_4/python/plugins/processing/algs/qgis.