24.7. Usare gli algoritmi di Processing dalla console dei comandi

La console permette ad utenti esperti di aumentare la propria produttività e di eseguire operazioni complesse che non possono essere eseguite utilizzando uno qualsiasi degli altri elementi dell’interfaccia grafica di Processing. I modelli che richiamano diversi algoritmi possono essere definiti utilizzando l’interfaccia della riga di comando, e le operazioni aggiuntive, come i loop e le frasi condizionali possono essere aggiunte per creare flussi di lavoro più flessibili e potenti.

Non c’è una console di processing in QGIS, ma tutti i comandi di processing sono invece resi disponibili dalla predefinita QGIS Python console. Ciò significa che puoi incorporare tali comandi nellal tuo console operativa e collegare gli algoritmi di elaborazione a tutte le altre funzionalità (inclusi i metodi delle API di QGIS) lì disponibili.

Il codice che puoi eseguire dalla console di python, anche se non richiama un metodo specifico di Processing, può essere convertito in un nuovo algoritmo che potrai richiamare in seguito dagli Strumenti, dal Modellatore grafico o da qualunque altra parte, proprio come ogni altro algoritmo. Alcuni algoritmi che trovi in Strumenti sono in effetti degli script semplici.

In questa sezione verrà spiegato come usare gli algoritmi di Processing dalla console di Python e anche come scrivere un algoritmo usando Python.

24.7.1. Richiamare algoritmi dalla console di python

La prima cosa da fare è importare le funzioni di Processing con la seguente istruzione:

>>> from qgis import processing

Ora, c’è fondamentalmente solo una cosa (interessante) che puoi fare dalla console: eseguire un algoritmo. Questo viene fatto usando il metodo run(), che prende il nome dell’algoritmo da eseguire come primo parametro, e poi un numero variabile di parametri aggiuntivi a seconda dei requisiti dell’algoritmo. Quindi la prima cosa che devi conoscere è il nome dell’algoritmo da eseguire. Questo non è il nome che vedi nella casella degli strumenti, ma piuttosto un nome unico a riga di comando. Per trovare il nome giusto per il tuo algoritmo, puoi usare la processingRegistry. Digita la seguente linea nella tua console:

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

Vedrai qualcosa del genere (con qualche trattino in più aggiunto per migliorare la leggibilità).

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
...

Questa è una lista di tutti gli ID degli algoritmi disponibili, ordinati per nome della fonte e nome dell’algoritmo, insieme ai loro nomi corrispondenti.

Una volta che sai il nome a riga di comando dell’algoritmo, la prossima cosa da fare è determinare la giusta sintassi per eseguirlo. Questo significa sapere quali parametri sono necessari quando si chiama il metodo run().

C’è un metodo per descrivere un algoritmo in dettaglio, che può essere usato per ottenere una lista dei parametri che un algoritmo richiede e gli output che genererà. Per ottenere queste informazioni, puoi usare il metodo algoritmoHelp(id_dell_algoritmo). Usa l’ID dell’algoritmo, non il nome descrittivo completo.

Richiamando il metodo con native:buffer come parametro (qgis:buffer è un alias di native:buffer e funzionerà ugualmente), ottieni la seguente descrizione:

>>> 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

Ora hai tutto il necessario per eseguire qualsiasi algoritmo. Come abbiamo già detto, gli algoritmi possono essere eseguiti usando: run(). La sua sintassi è la seguente:

>>> processing.run(name_of_the_algorithm, parameters)

Dove parameters è un dizionario di parametri che dipendono dall’algoritmo che vuoi eseguire, ed è esattamente la lista che il metodo algorithmHelp() ti dà.

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

Se un parametro è opzionale e non vuoi usarlo, allora non includerlo nel dizionario.

Se un parametro non è specificato, verrà utilizzato il valore predefinito.

A seconda del tipo di parametro, i valori sono inseriti in maniera diversa. Il seguente elenco dà una rapida panoramica di come inserire valori per ogni tipo di parametro in input:

  • Layer Raster, Layer Vettoriale o Tabella. Basta usare una stringa con il nome che identifica il data object da usare (il nome che ha nella Table of Contents di QGIS) o un nome di file (se il layer corrispondente non è aperto, verrà aperto ma non aggiunto alla mappa). Se hai un’istanza di un oggetto QGIS che rappresenta il layer, puoi anche passarlo come parametro.

  • Conteggio. Se un algoritmo ha un parametro di conteggio, il valore di quel parametro dovrebbe essere inserito usando un valore intero. Per conoscere le opzioni disponibili, puoi usare il comando algorithmHelp(), come sopra. Per esempio, l’algoritmo native:buffer ha una numerazione chiamata 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 questo caso, il parametro ha tre opzioni. Da notare che l’ordine è su base zero.

  • Booleano. Usare True o False.

  • Input multipli. Il valore è una stringa con descrittori in input separati da un punto e virgola (;). Come nel caso di layer singoli o tabelle, ogni descrittore in input può essere il nome dell’oggetto o il suo percorso.

  • Campo di una Tabella da XXX. Inserisci una stringa con il nome del campo da usare. Il parametro è sensibile alle lettere maiuscole.

  • Tabella fissa. Inserisci l’elenco di tutti i valori delle tabelle separati da una virgola (,) e racchiusi fra virgolette ("). I valori partono dalla riga in alto e proseguono da sinistra verso destra. Puoi usare un array 2-D per i valori che rappresentano la tabella.

  • SR. Inserisci il codice EPSG del SR desiderato.

  • Estensione. Usa un stringa con valori xmin, xmax, ymin e ymax separati da virgole (,).

Parametri booleani, di file, di stringa e numerici non hanno bisogno di ulteriori spiegazioni.

I parametri di input come stringhe, booleani o valori numerici hanno valori predefiniti. Il valore predefinito viene utilizzato se la voce corrispondente del parametro è mancante.

Per i dati di output, digitare il percorso del file da utilizzare per salvarlo, proprio come si fa dal pannello degli strumenti. Se non viene specificato l’oggetto di output, il risultato viene salvato in un file temporaneo (o omesso se si tratta di un output opzionale). L’estensione del file determina il formato del file. Se si inserisce un’estensione di file non supportata dall’algoritmo, verrà utilizzato il formato di file predefinito per quel tipo di output, e la sua estensione corrispondente verrà aggiunta al percorso indicato.

A differenza di quando un algoritmo viene eseguito dagli strumenti di Processing, gli output non vengono aggiunti alla mappa se si esegue lo stesso algoritmo dalla console Python usando run(), ma runAndLoadResults() lo farà.

Il metodo run() restituisce un dizionario con uno o più nomi in uscita (quelli mostrati nella descrizione dell’algoritmo) come chiavi e i percorsi dei file di tali nomi come valori:

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

Puoi caricare l’output delle funzioni passando i percorsi dei file corrispondenti al metodo load(). Oppure puoi usare runAndLoadResults() invece di run() per caricarli immediatamente.

Se vuoi aprire un dialogo su un algoritmo dalla console puoi usare il metodo createAlgorithmDialog. L’unico parametro obbligatorio è il nome dell’algoritmo, ma puoi anche definire il dizionario dei parametri in modo che il dialogo venga riempito automaticamente:

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

Il metodo execAlgorithmDialog apre immediatamente la finestra di dialogo:

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

24.7.2. Creare script ed eseguirli da Strumenti

Puoi creare i tuoi algoritmi scrivendo codice Python. Gli script di processing hanno una QgsProcessingAlgorithm, quindi devi aggiungere alcune linee di codice extra per implementare le funzioni obbligatorie. Puoi trovare Create new script ( scheda pulita) e Create New Script from Template (template che include il codice per le funzioni obbligatorie di QgsProcessingAlgorithm) sotto il menu a discesa Scripts in cima alla finestra degli strumenti di Processing. Si aprirà l’Editor di script di Processing, ed è lì che dovresti digitare il tuo codice. Salvando lo script da lì nella cartella scripts (la cartella predefinita quando apri la finestra di dialogo di salvataggio del file) con un’estensione .py dovrebbe creare l’algoritmo corrispondente.

Il nome dell’algoritmo (quello che vedrai nella casella degli strumenti) è definito all’interno del codice.

Diamo un’occhiata al seguente codice, che definisce un algoritmo di Processing che esegue un’operazione di buffer con una distanza di buffer definita dall’utente su un layer vettoriale che è specificato dall’utente, dopo aver prima smussato il layer.

 1from qgis.core import (QgsProcessingAlgorithm,
 2       QgsProcessingParameterNumber,
 3       QgsProcessingParameterFeatureSource,
 4       QgsProcessingParameterFeatureSink)
 5
 6from qgis import processing
 7
 8class algTest(QgsProcessingAlgorithm):
 9    INPUT_BUFFERDIST = 'BUFFERDIST'
10    OUTPUT_BUFFER = 'OUTPUT_BUFFER'
11    INPUT_VECTOR = 'INPUT_VECTOR'
12
13    def __init__(self):
14        super().__init__()
15
16    def name(self):
17        return "algTest"
18
19    def displayName(self):
20        return "algTest script"
21
22    def createInstance(self):
23        return type(self)()
24
25    def initAlgorithm(self, config=None):
26        self.addParameter(QgsProcessingParameterFeatureSource(
27            self.INPUT_VECTOR, "Input vector"))
28        self.addParameter(QgsProcessingParameterNumber(
29            self.INPUT_BUFFERDIST, "Buffer distance",
30            QgsProcessingParameterNumber.Double,
31            100.0))
32        self.addParameter(QgsProcessingParameterFeatureSink(
33            self.OUTPUT_BUFFER, "Output buffer"))
34
35    def processAlgorithm(self, parameters, context, feedback):
36        #DO SOMETHING
37        algresult = processing.run("native:smoothgeometry",
38            {'INPUT': parameters[self.INPUT_VECTOR],
39             'ITERATIONS':2,
40             'OFFSET':0.25,
41             'MAX_ANGLE':180,
42             'OUTPUT': 'memory:'},
43            context=context, feedback=feedback, is_child_algorithm=True)
44        smoothed = algresult['OUTPUT']
45        algresult = processing.run('native:buffer',
46            {'INPUT': smoothed,
47            'DISTANCE': parameters[self.INPUT_BUFFERDIST],
48            'SEGMENTS': 5,
49            'END_CAP_STYLE': 0,
50            'JOIN_STYLE': 0,
51            'MITER_LIMIT': 10,
52            'DISSOLVE': True,
53            'OUTPUT': parameters[self.OUTPUT_BUFFER]},
54            context=context, feedback=feedback, is_child_algorithm=True)
55        buffered = algresult['OUTPUT']
56        return {self.OUTPUT_BUFFER: buffered}

Dopo aver fatto le importazioni necessarie, vengono specificate le seguenti funzioni QgsProcessingAlgorithm:

  • name(): L’id dell’algoritmo (minuscolo).

  • displayName(): Un nome interpretabile per l’algoritmo.

  • createInstance(): Crea una nuova istanza nella classe algoritmo.

  • initAlgorithm(): Configura la parameterDefinitions e outputDefinitions.

    Qui descrivi i parametri e l’output dell’algoritmo. In questo caso, una geometria per l’input, una geometria per il risultato e un numero per la distanza del buffer.

  • processAlgorithm(): Esegue.

    Qui eseguiamo prima l’algoritmo moothgeometry per smussare la geometria, e poi eseguiamo l’algoritmo buffer sull’output smussato. Per poter eseguire algoritmi dall’interno di un altro algoritmo dobbiamo impostare lil parametro is_child_algorithm a True`. Puoi vedere come i parametri di input e output sono usati come parametri per gli algoritmi moothgeometry e buffer.

Ci sono diversi tipi di parametri disponibili per l’input e l’output. Di seguito c’è una lista in ordine alfabetico:

Tabella 24.2 Elenco dei tipi di parametri dell’algoritmo in ingresso e in uscita

QgsProcessingParameterAggregate

QgsProcessingParameterAnnotationLayer

QgsProcessingParameterAuthConfig

QgsProcessingParameterBand

QgsProcessingParameterBoolean

QgsProcessingParameterColor

QgsProcessingParameterCoordinateOperation

QgsProcessingParameterCrs

QgsProcessingParameterDatabaseSchema

QgsProcessingParameterDatabaseTable

QgsProcessingParameterDateTime

QgsProcessingParameterDistance

QgsProcessingParameterEnum

QgsProcessingParameterExpression

QgsProcessingParameterExtent

QgsProcessingParameterFeatureSink

QgsProcessingParameterFeatureSource

QgsProcessingParameterField

QgsProcessingParameterFieldMapping

QgsProcessingParameterFile

QgsProcessingParameterFileDestination

QgsProcessingParameterFolderDestination

QgsProcessingParameterGeometry

QgsProcessingParameterLayout

QgsProcessingParameterLayoutItem

QgsProcessingParameterMapLayer

QgsProcessingParameterMapTheme

QgsProcessingParameterMatrix

QgsProcessingParameterMeshLayer

QgsProcessingParameterMultipleLayers

QgsProcessingParameterNumber

QgsProcessingParameterPoint

QgsProcessingParameterPointCloudLayer

QgsProcessingParameterProviderConnection

QgsProcessingParameterRange

QgsProcessingParameterRasterDestination

QgsProcessingParameterRasterLayer

QgsProcessingParameterScale

QgsProcessingParameterString

QgsProcessingParameterVectorDestination

QgsProcessingParameterVectorLayer

QgsProcessingParameterVectorTileWriterLayers

Il primo parametro è il nome del parametro e il secondo è la descrizione del parametro (per l’interfaccia utente). Il resto dei parametri sono specifici del tipo di parametro.

L’input può essere trasformato in classi QGIS usando le funzioni parameterAs di QgsProcessingAlgorithm. Per esempio per ottenere il numero fornito per la distanza del buffer come una doppia:

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

La funzione processAlgorithm dovrebbe restituire un dizionario contenente valori per ogni output definito dall’algoritmo. Questo permette di accedere a questi output da altri algoritmi, compresi altri algoritmi contenuti nello stesso modello.

Gli algoritmi che si comportano bene dovrebbero definire e restituire tanti output quanti hanno importanza. Gli output non relativi alle funzionalità, come numeri e stringhe, sono molto utili quando si esegue l’algoritmo come parte di un modello più grande, poiché questi valori possono essere utilizzati come parametri di input per gli algoritmi successivi all’interno del modello. Si consideri l’aggiunta di output numerici per cose come il numero di elementi processati, il numero di elementi non validi incontrati, il numero di elementi in uscita, ecc. Più output restituite, più utile diventa il vostro algoritmo!

24.7.2.1. Feedback

L’oggetto feedback passato a processAlgorithm() dovrebbe essere usato per il feedback/interazione dell’utente. Puoi usare la funzione setProgress() dell’oggetto feedback per aggiornare la barra di avanzamento (da 0 a 100) per informare l’utente sul avanzamento dell’algoritmo. Questo è molto utile se il tuo algoritmo richiede molto tempo per essere completato.

L’oggetto feedback fornisce un metodo isCanceled() che dovrebbe essere monitorato per consentire la cancellazione dell’algoritmo da parte dell’utente. Il metodo pushInfo() di feedback può essere usato per inviare informazioni all’utente, e reportError() è utile per inviare errori non fatali agli utenti.

Gli algoritmi dovrebbero evitare di usare altre forme per fornire feedback agli utenti, come istruzioni di stampa o di notifica a QgsMessageLog, e dovrebbero invece usare sempre l’oggetto feedback. Questo permette un log dettagliato per l’algoritmo, ed è anche thread-safe (il che è importante, dato che gli algoritmi sono tipicamente eseguiti in un thread in background).

24.7.2.2. Gestire gli errori

Se il tuo algoritmo incontra un errore che ne impedisce l’esecuzione, come valori di input non validi o qualche altra condizione da cui non può o non dovrebbe recuperare, allora dovresti generare una QgsProcessingException. Ad esempio:

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

Cerca di evitare di generare QgsProcessingException per errori non fatali (ad esempio quando una feature ha una geometria nulla), e invece segnala semplicemente questi errori tramite feedback.reportError() e salta la stessa. Questo aiuta a rendere il tuo algoritmo «model-friendly», poiché evita di interrompere l’esecuzione di un intero algoritmo quando si incontra un errore non fatale.

24.7.2.3. Documentare gli script

Come nel caso dei modelli, puoi creare una documentazione aggiuntiva per i tuoi script, per spiegare cosa fanno e come usarli.

QgsProcessingAlgorithm fornisce le funzioni per questo scopo helpString(), shortHelpString() e helpUrl(). Specifica / sovrascrive queste funzioni per fornire più aiuto all’utente.

shortDescription() è usato quando il puntatore del mouse passa sopra l’algoritmo nella casella degli strumenti.

24.7.3. Script agganciati pre e post esecuzione

Gli script possono anche essere usati come controlli pre- e post-esecuzione che vengono eseguiti rispettivamente prima e dopo l’esecuzione di un algoritmo. Questo può essere usato per automatizzare i processi che dovrebbero essere eseguiti ogni volta che un algoritmo viene eseguito.

La sintassi è identica alla sintassi spiegato sopra, ma hai a disposizione anche una variabile globale chiamata alg che rappresenta l’algoritmo che è appena stato (o che sta per essere) eseguito.

Nel gruppo General della finestra di dialogo delle opzioni di processing, troverai due voci chiamate Pre-execution script e Post-execution script dove possono essere inseriti i nomi dei file degli script da eseguire caso per caso.