23.7. Processing algoritmen gebruiken vanaf de console

De console stelt gevorderde gebruikers in staat hun productiviteit te vergroten en complexe bewerkingen uit te voeren die niet kunnen worden uitgevoerd met een van de andere elementen van de GUI van het framework Processing. Modellen die verscheidene algoritmen omvatten kunnen worden gedefinieerd met behulp van de interface voor de opdrachtregel, en aanvullende bewerkingen, zoals lussen en voorwaardelijke zinnen, kunnen worden toegevoegd om meer flexibele en meer krachtige werkstromen te maken.

Er is geen console voor Processing in QGIS, maar alle opdrachten voor Processing zijn in plaats daarvan beschikbaar vanuit de in QGIS ingebouwde console voor Python. Dat betekent dat u die opdrachten in uw werk op de console kunt inpassen en algoritmen van Processing kunt verbinden aan alle andere mogelijkheden (inclusief methoden uit de API van QGIS) die van daaruit beschikbaar zijn.

De code die u kunt uitvoeren vanuit de console van Python, zelfs als het geen specifieke methode voor Processing aanroept, kan worden geconverteerd naar een nieuw algoritme dat u later kunt aanroepen vanuit de Toolbox, Grafische modellen bouwen of enige andere component, net zoals u doet met een andere algoritme. In feite zijn enkele algoritmen, die u in de Toolbox aantreft, eenvoudige scripts.

In dit gedeelte zullen we zien hoe we algoritmen van Processing gebruiken vanuit de console voor Python in QGIS, en ook hoe we algoritmen schrijven met behulp van Python.

23.7.1. Algoritmen aanroepen van de console van Python

Het eerste dat u moet doen is de functies voor Processing importeren met de volgende regel:

>>> from qgis import processing

Wel, er is in de basis slechts één (interessant) ding dat u daarmee kunt doen vanaf de console: een algoritme uitvoeren. Dat wordt gedaan met de methode run(), die de naam van het uit te voeren algoritme als zijn eerste parameter opneemt, en dan een variabel aantal aanvullende parameters, afhankelijk van de vereisten van het algoritme. Dus het eerste wat u moet weten is de naam van het uit te voeren algoritme. Dat is niet de naam die u ziet in de Toolbox, maar eerder een unieke naam voor de opdrachtregel. U kunt het processingRegistry gebruiken om de juiste naam voor uw algoritme te zoeken. Typ de volgende regel in uw console:

>>> for alg in QgsApplication.processingRegistry().algorithms():
        print(alg.id(), "->", alg.displayName())

U zult iets als dit zien (met enkele extra toegevoegde streepjes om de leesbaarheid te vergroten).

3d:tessellate --------------> Tessellate
gdal:aspect ----------------> Aspect
gdal:assignprojection ------> Assign projection
gdal:buffervectors ---------> Buffer vectors
gdal:buildvirtualraster ----> Build Virtual Raster
gdal:cliprasterbyextent ----> Clip raster by extent
gdal:cliprasterbymasklayer -> Clip raster by mask layer
gdal:clipvectorbyextent ----> Clip vector by extent
gdal:clipvectorbypolygon ---> Clip vector by mask layer
gdal:colorrelief -----------> Color relief
gdal:contour ---------------> Contour
gdal:convertformat ---------> Convert format
gdal:dissolve --------------> Dissolve
...

Dat is een lijst met alle ID’s voor beschikbare algoritmen, gesorteerd op naam van de provider en naam van het algoritme, samen met hun corresponderende namen.

Als u eenmaal de naam voor de opdrachtregel van het algoritme kent, is het volgende om te bepalen wat de juiste syntaxis is om het uit te voeren. Dat betekent weten welke parameters nodig zijn bij het aanroepen van de methode run().

Er bestaat een methode om een algoritme in detail te beschrijven, die kan worden gebruikt om een lijst van de parameters te verkrijgen die een algoritme vereist en de soorten uitvoer die het zal maken. U kunt de methode algorithmHelp(id_van_het_algoritme) gebruiken om deze informatie te krijgen. Gebruik het ID van het algoritme, niet de volledige beschrijvende naam.

De methode aanroepen met native:buffer als parameter (qgis:buffer is een alias voor native:buffer en zal ook werken), geeft u de volgende beschrijving:

>>> processing.algorithmHelp("native:buffer")
Buffer (native:buffer)

This algorithm computes a buffer area for all the features in an
input layer, using a fixed or dynamic distance.

The segments parameter controls the number of line segments to
use to approximate a quarter circle when creating rounded
offsets.

The end cap style parameter controls how line endings are handled
in the buffer.

The join style parameter specifies whether round, miter or
beveled joins should be used when offsetting corners in a line.

The miter limit parameter is only applicable for miter join
styles, and controls the maximum distance from the offset curve
to use when creating a mitered join.


----------------
Input parameters
----------------

INPUT: Input layer

   Parameter type: QgsProcessingParameterFeatureSource

   Accepted data types:
           - str: layer ID
           - str: layer name
           - str: layer source
           - QgsProcessingFeatureSourceDefinition
           - QgsProperty
           - QgsVectorLayer

DISTANCE: Distance

   Parameter type: QgsProcessingParameterDistance

   Accepted data types:
           - int
           - float
           - QgsProperty

SEGMENTS: Segments

   Parameter type: QgsProcessingParameterNumber

   Accepted data types:
           - int
           - float
           - QgsProperty

END_CAP_STYLE: End cap style

   Parameter type: QgsProcessingParameterEnum

   Available values:
           - 0: Round
           - 1: Flat
           - 2: Square

   Accepted data types:
           - int
           - str: as string representation of int, e.g. '1'
           - QgsProperty

JOIN_STYLE: Join style

   Parameter type: QgsProcessingParameterEnum

   Available values:
           - 0: Round
           - 1: Miter
           - 2: Bevel

   Accepted data types:
           - int
           - str: as string representation of int, e.g. '1'
           - QgsProperty

MITER_LIMIT: Miter limit

   Parameter type: QgsProcessingParameterNumber

   Accepted data types:
           - int
           - float
           - QgsProperty

DISSOLVE: Dissolve result

   Parameter type: QgsProcessingParameterBoolean

   Accepted data types:
           - bool
           - int
           - str
           - QgsProperty

OUTPUT: Buffered

   Parameter type: QgsProcessingParameterFeatureSink

   Accepted data types:
           - str: destination vector file, e.g. 'd:/test.shp'
           - str: 'memory:' to store result in temporary memory layer
           - str: using vector provider ID prefix and destination URI,
                  e.g. 'postgres:...' to store result in PostGIS table
           - QgsProcessingOutputLayerDefinition
           - QgsProperty

----------------
Outputs
----------------

OUTPUT:  <QgsProcessingOutputVectorLayer>
   Buffered

Nu heeft u alles wat u nodig heeft om een algoritme uit te voeren. Zoals we al eerder hebben verteld kunnen algoritmen worden uitgevoerd met: run(). De syntaxis ervan is als volgt:

>>> processing.run(name_of_the_algorithm, parameters)

Waar parameters een woordenboek van parameters is, dat afhankelijk is van het algoritme dat u wilt uitvoeren, en is exact de lijst die de methode algorithmHelp() u geeft.

1
2
3
4
5
6
7
8
 >>> processing.run("native:buffer", {'INPUT': '/data/lines.shp',
               'DISTANCE': 100.0,
               'SEGMENTS': 10,
               'DISSOLVE': True,
               'END_CAP_STYLE': 0,
               'JOIN_STYLE': 0,
               'MITER_LIMIT': 10,
               'OUTPUT': '/data/buffers.shp'})

Wanneer een parameter optioneel is en u wilt hem niet gebruiken, neem die dan niet op in het woordenboek.

Wanneer een parameter niet gespecificeerd is zal de standaardwaarde worden gebruikt.

Afhankelijk van het type parameter dienen waarden verschillend te worden ingevoerd. De volgende lijst geeft een snel overzicht van hoe waarden in te voeren voor elk type parameter:

  • Raster Layer, Vector Layer of Table. Gebruik eenvoudigweg een tekenreeks met de naam die het te gebruiken gegevensobject identificeert (de naam die het heeft in de inhoudsopgave van QGIS) of een bestandsnaam (als de betreffende laag niet is geopend, hij zal worden geopend, maar niet worden toegevoegd aan het kaartvenster). Als u een instantie van een object van QGIS heeft dat de laag vertegenwoordigt, kunt u die ook doorgeven als parameter.

  • Enumeratie. Als een algoritme een parameter voor enumeratie heeft moet de waarde van die parameter worden ingevuld met een waarde integer. U kunt de opdracht algorithmHelp() gebruiken om de beschikbare opties te weten te komen, zoals hierboven. Het algoritme native:buffer heeft bijvoorbeeld een enumeratie genaamd JOIN_STYLE:

    JOIN_STYLE: Join style
    
       Parameter type: QgsProcessingParameterEnum
    
       Available values:
               - 0: Round
               - 1: Miter
               - 2: Bevel
    
       Accepted data types:
               - int
               - str: as string representation of int, e.g. '1'
               - QgsProperty
    

    In dit geval heeft de parameter drie opties. Onthoud dat de volgorde begint met nul.

  • Booleaanse waarde. Gebruik True of False.

  • Multiple input. De waarde is een tekenreeks met beschrijvingen voor de invoer die zijn gescheiden door puntkomma’s (;). Net als in het geval van enkele lagen of tabellen, kan elke beschrijving voor de invoer de naam van het gegevensobject of het bestandspad zijn.

  • Table Field from XXX. Gebruik een tekenreeks met de naam van het te gebruiken veld. Deze parameter is hoofdlettergevoelig.

  • Fixed Table. Type de lijst voor alle waarden voor de tabel, gescheiden door komma’s (,) en omsluit ze met aanhalingstekens ("). Waarden beginnen op de bovenste rij en gaan van rechts naar links. U kunt ook een 2D-array van waarden gebruiken die de tabel vertegenwoordigt.

  • CRS. Voer het EPSG-codenummer van het gewenste CRS in.

  • Extent. U dient een tekenreeks te gebruiken met de waarden xmin, xmax, ymin en ymax, gescheiden door komma’s (,).

Booleaanse waarden, bestand, tekenreeks en numerieke parameters behoeven geen aanvullende uitleg.

Parameters voor invoer, zoals tekenreeksen, Booleaanse waarden of numerieke waarden hebben standaardwaarden. De standaardwaarde wordt gebruikt als de corresponderende parameter ontbreekt.

Typ, voor gegevensobjecten voor de uitvoer, het te gebruiken bestandspad om ze op te slaan, net zoals wordt gedaan in de Toolbox. Als het object voor de uitvoer niet is gespecificeerd, zal het resultaat worden opgeslagen naar een tijdelijk bestand (of overgeslagen als het een optionele uitvoer is). De extensie van het bestand bepaalt de indeling van het bestand. Als u een extensie invoert die niet wordt ondersteund door het algoritme, zal de standaardindeling voor het bestand voor dat type uitvoer worden gebruikt en de corresponderende extensie worden toegevoegd aan het opgegeven bestandspad.

Anders dan wanneer een algoritme wordt uitgevoerd vanuit de Toolbox, wordt uitvoer niet toegevoegd aan het kaartvenster als u datzelfde algoritme uitvoert vanaf de console voor Python met run(), maar runAndLoadResults() zal dat wel doen.

De methode run() geeft een woordenboek terug met een of meer namen voor de uitvoer (die welke worden weergegeven in de beschrijving van het algoritme) als sleutels en de bestandspaden van die uitvoer als waarden.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
 >>> myresult = processing.run("native:buffer", {'INPUT': '/data/lines.shp',
               'DISTANCE': 100.0,
               'SEGMENTS': 10,
               'DISSOLVE': True,
               'END_CAP_STYLE': 0,
               'JOIN_STYLE': 0,
               'MITER_LIMIT': 10,
               'OUTPUT': '/data/buffers.shp'})
 >>> myresult['OUTPUT']
 /data/buffers.shp

U kunt uitvoer van objecten laden door de corresponderende bestandspaden door te geven aan de methode load(). Of u zou runAndLoadResults() kunnen gebruiken in plaats van run() om ze onmiddellijk te laden.

Wanneer u een dialoogvenster voor een algoritme wilt openen vanuit de console, kunt u de methode createAlgorithmDialog gebruiken. De enige verplichte parameter is de naam van het algoritme, maar u kunt ook het woordenboek van de parameters definiëren, zodat het dialoogvenster automatisch zal worden gevuld:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
 >>> my_dialog = processing.createAlgorithmDialog("native:buffer", {
               'INPUT': '/data/lines.shp',
               'DISTANCE': 100.0,
               'SEGMENTS': 10,
               'DISSOLVE': True,
               'END_CAP_STYLE': 0,
               'JOIN_STYLE': 0,
               'MITER_LIMIT': 10,
               'OUTPUT': '/data/buffers.shp'})
 >>> my_dialog.show()

De methode execAlgorithmDialog opent het dialoogvenster onmiddellijk:

1
2
3
4
5
6
7
8
9
 >>> processing.execAlgorithmDialog("native:buffer", {
               'INPUT': '/data/lines.shp',
               'DISTANCE': 100.0,
               'SEGMENTS': 10,
               'DISSOLVE': True,
               'END_CAP_STYLE': 0,
               'JOIN_STYLE': 0,
               'MITER_LIMIT': 10,
               'OUTPUT': '/data/buffers.shp'})

23.7.2. Scripts maken en die uitvoeren vanuit de Toolbox

U kunt uw eigen algoritmen maken door de corresponderende code voor Python te schrijven. Scripts voor Processing breiden QgsProcessingAlgorithm uit, dus u dient een paar extra regels toe te voegen om verplichte functies te implementeren. U vindt een menu Nieuw script maken (blanco blad) en Nieuw script uit sjabloon maken (sjabloon dat de verplichte functies van QgsProcessingAlgorithm bevat) in het keuzemenu Scripts boven in de Toolbox van Processing. De Processing Script Editor zal openen en dat is waar u uw code moet schrijven. Sla het script daar vandaan op in de map scripts (de standaardmap wanneer u het dialoogvenster Bestand opslaan opent) met de extensie .py zou het corresponderende algoritme moeten maken.

De naam van het algoritme (die welke u zult zien in de Toolbox) wordt gedefinieerd in de code.

Laten we eens kijken naar de volgende code, die een algoritme voor Processing definieert die een bewerking voor een buffer uitvoert met een door de gebruiker gedefinieerde afstand voor de buffer op een vectorlaag die is gespecificeerd door de gebruiker, na eerste de laag afgevlakt te hebben.

 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
from qgis.core import (QgsProcessingAlgorithm,
       QgsProcessingParameterNumber,
       QgsProcessingParameterFeatureSource,
       QgsProcessingParameterFeatureSink)

from qgis import processing

class algTest(QgsProcessingAlgorithm):
    INPUT_BUFFERDIST = 'BUFFERDIST'
    OUTPUT_BUFFER = 'OUTPUT_BUFFER'
    INPUT_VECTOR = 'INPUT_VECTOR'

    def __init__(self):
        super().__init__()

    def name(self):
        return "algTest"

    def displayName(self):
        return "algTest script"

    def createInstance(self):
        return type(self)()

    def initAlgorithm(self, config=None):
        self.addParameter(QgsProcessingParameterFeatureSource(
            self.INPUT_VECTOR, "Input vector"))
        self.addParameter(QgsProcessingParameterNumber(
            self.INPUT_BUFFERDIST, "Buffer distance",
            QgsProcessingParameterNumber.Double,
            100.0))
        self.addParameter(QgsProcessingParameterFeatureSink(
            self.OUTPUT_BUFFER, "Output buffer"))

    def processAlgorithm(self, parameters, context, feedback):
        #DO SOMETHING
        algresult = processing.run("native:smoothgeometry",
            {'INPUT': parameters[self.INPUT_VECTOR],
             'ITERATIONS':2,
             'OFFSET':0.25,
             'MAX_ANGLE':180,
             'OUTPUT': 'memory:'},
            context=context, feedback=feedback, is_child_algorithm=True)
        smoothed = algresult['OUTPUT']
        algresult = processing.run('native:buffer',
            {'INPUT': smoothed,
            'DISTANCE': parameters[self.INPUT_BUFFERDIST],
            'SEGMENTS': 5,
            'END_CAP_STYLE': 0,
            'JOIN_STYLE': 0,
            'MITER_LIMIT': 10,
            'DISSOLVE': True,
            'OUTPUT': parameters[self.OUTPUT_BUFFER]},
            context=context, feedback=feedback, is_child_algorithm=True)
        buffered = algresult['OUTPUT']
        return {self.OUTPUT_BUFFER: buffered}

Na de nodige import zijn de volgende functies voor QgsProcessingAlgorithm gespecificeerd:

  • name(): Het ID van het algoritme (kleine letters).

  • displayName(): Een door mensen te lezen naam voor het algoritme.

  • createInstance(): Maak een nieuwe instance van de klasse van het algoritme.

  • initAlgorithm(): Configureer de parameterDefinitions en outputDefinitions.

    Hier beschrijft u de parameters en uitvoer van het algoritme. In dit geval een bronobject voor de invoer, een afvoer voor het object voor het resultaat en een getal voor de afstand van de buffer.

  • processAlgorithm(): Voer het werk uit.

    Hier voeren we eerst het algoritme smoothgeometry uit om de geometrie af te vlakken en dan voeren we het algoritme buffer uit op de afgevlakte uitvoer. We moeten de parameter is_child_algorithm instellen op True, om algoritmen te kunnen uitvoeren vanuit andere algoritmen. U kunt zien hoe de parameters voor invoer en uitvoer worden gebruikt als parameters voor de algoritmen smoothgeometry en buffer.

Er zijn een aantal verschillende typen parameter beschikbaar voor in- en uitvoer. Hieronder staat een alfabetisch gesorteerde lijst:

De eerste parameter naar de constructeurs is de naam van de parameter, en de tweede is de beschrijving van de parameter (voor de gebruikersinterface). De rest van de parameters voor constructie zijn specifiek voor het type parameter.

De invoer kan worden omgezet naar klassen voor QGIS met de functies parameterAs van QgsProcessingAlgorithm. Bijvoorbeeld om het opgegeven getal voor de afstand van de buffer te krijgen als een double:

self.parameterAsDouble(parameters, self.INPUT_BUFFERDIST, context)).

De functie processAlgorithm zou een woordenboek moeten teruggeven dat waarden bevat voor elke uitvoer die wordt gedefinieerd door het algoritme. Dat maakt het mogelijk om toegang te krijgen tot deze uitvoer vanuit andere algoritmen, inclusief andere algoritmen die in hetzelfde model zijn opgenomen.

Zich goed gedragende algoritmen zouden net zoveel uitvoeren definiëren en teruggeven als zin heeft. Niet-object uitvoer, zoals getallen en tekenreeksen, zijn zeer nuttig bij het uitvoeren van uw algoritme als deel van een groter model, omdat deze waarden kunnen worden gebruikt als parameters voor invoer voor opvolgende algoritmen in het model. Overweeg het toevoegen van numerieke uitvoer voor dingen als het aantal verwerkte objecten, het aantal ongeldige objecten dat werd tegengekomen, het aantal uitgevoerde objecten, etc. Hoe meer uitvoer u teruggeeft des te nuttiger uw algoritme wordt!

23.7.2.1. Terugkoppeling

Het object feedback dat wordt doorgegeven aan processAlgorithm zou moeten worden gebruikt voor terugkoppeling van/interactie met de gebruiker. U kunt de functie setProgress() van het object feedback gebruiken om de voortgangsbalk (0 tot 100) bij te werken om de gebruiker over de voortgang van het algoritme te informeren. Dit is bijzonder nuttig als uw algoritme veel tijd nodig heeft om te voltooien.

Het object feedback verschaft een methode isCanceled() die zou moeten worden gemonitord om annuleren van het algoritme door de gebruiker in te schakelen. De methode pushInfo() van feedback kan worden gebruikt om informatie naar de gebruiker te verzenden, en reportError() is handig voor het pushen van niet-fatale fouten naar gebruikers.

Algoritmen zouden andere vormen van het verschaffen van terugkoppeling aan gebruikers moeten vermijden, zoals afdrukken van argumenten of loggen naar QgsMessageLog, en zouden in plaats daarvan altijd het object feedback moeten gebruiken. Dat maakt uitgebreide logging voor het algoritme mogelijk, en is ook thread-veilig (wat belangrijk is, omdat algoritmen gewoonlijk worden uitgevoerd in een thread op de achtergrond).

23.7.2.2. Fouten afhandelen

Als uw algoritme een fout tegenkomt die verhindert dat het wordt uitgevoerd, zoals ongeldige waarden voor invoer of een andere voorwaarde waardoor het niet wil of kan herstellen, dan zou u een QgsProcessingException moeten opwerpen. Bijv.:

if feature['value'] < 20:
  raise QgsProcessingException('Invalid input value {}, must be >= 20'.format(feature['value']))

Probeer het opwerpen van een QgsProcessingException voor niet-fatale fouten te voorkomen (bijv. als een object een geometrie null heeft), en rapporteer in plaats daarvan deze fouten via feedback.reportError() en sla het object over. Dat helpt bij het “model-vriendelijk” maken van uw algoritme, omdat het het stopzetten van de uitvoering van een geheel algoritme vermijdt als een niet-fatale fout wordt tegengekomen.

23.7.2.3. Documenteren van uw scripts

In het geval van modellen kunt u aanvullende documentatie voor uw scripts maken om uit te leggen wat zij doen en hoe zij werken.

QgsProcessingAlgorithm verschaft de functies helpString(), shortHelpString() en helpUrl() voor dat doel. Specificeer / overschrijf deze om meer hulp te geven aan de gebruiker.

shortDescription() wordt gebruikt in de helptip wanneer over het algoritme in de Toolbox wordt gegaan.

23.7.3. Haken voor vóór- en na-uitvoering van scripts

Scripts kunnen ook worden gebruikt als haken om voor pre- en post-uitvoering, die respectievelijk worden uitgevoerd vóórdat of nadat een algoritme is uitgevoerd. Dit kan worden gebruikt om taken te automatiseren die zouden moeten worden uitgevoerd wanneer een algoritme wordt uitgevoerd.

De syntaxis is identiek aan de hierboven uitgelegde syntaxis, maar een aanvullende globale variabele genaamd alg is beschikbaar, die het algoritme vertegenwoordigt dat zojuist is (of op het punt staat te worden) uitgevoerd.

In de groep Algemeen van het dialoogvenster Opties van Processing vindt u twee items genaamd Vóór-uitvoering script en Na-uitvoering script waar de bestandsnamen van de uit te voeren scripts in elk geval kunnen worden ingevoerd.