Scrivere uno script di elaborazione Python con Qgis 3.0


15

Dopo l'aggiornamento a Qgis 3.0, è diventato molto difficile trovare informazioni relative alla scrittura di script di elaborazione in Qgis 3.0.

@Underdark (vedi qui ) ha fornito una base per lo scheletro. Questo codice sembra essere stato aggiunto anche in Qgis, quando si scrive un nuovo script dal modello (Qgis 3.0.2).

Tuttavia, non sono riuscito a trovare alcun modo per aiutare i neofiti di Python come me a capire come modificare quel codice, specialmente per i livelli di input e output.

Il mio obiettivo è quello di scrivere una sceneggiatura prendendo 2 livelli raster e un doppio come input, producendo due livelli.

Quali sarebbero le modifiche richieste al codice di esempio per consentirlo?

Per Qgis 2.x avrei usato la sintassi seguente:

##Layer1=raster
##Layer2=raster 
##myDouble=Double
##OutLayer1=output raster
##OutLayer2=output raster   

Da quanto ho capito, le modifiche devono essere apportate nella seguente procedura, ma non sono sicuro di cosa mettere in atto.

    def initAlgorithm(self, config=None):
    self.addParameter(QgsProcessingParameterFeatureSource(
        self.INPUT,
        self.tr("Input layer"),
        [QgsProcessing.TypeVectorAnyGeometry]))
    self.addParameter(QgsProcessingParameterFeatureSink(
        self.OUTPUT,
        self.tr("Output layer"),
        QgsProcessing.TypeVectorAnyGeometry))

Il 16 maggio è stata rilasciata la documentazione dell'API python di Qgis . Tuttavia, non è ancora chiaro per me come usarlo qui. (Che potrebbe benissimo essere una mancanza di conoscenza di Python)


1
Potresti fornire un esempio di codice che hai usato per lo stesso scopo su qgis 2.xx La documentazione su qgis 3.x sarà disponibile qui: docs.qgis.org/testing/en/docs/pyqgis_developer_cookbook/… non appena sarà aggiornato. I problemi relativi ai documenti vengono tracciati qui: github.com/qgis/QGIS-Documentation/issues
Nono

Risposta modificata con l'esempio di codice. Grazie per i link, stavo già seguendo il ricettario ma sfortunatamente non ho trovato la mia risposta lì!
Kantan,

Ho letto dei documenti sull'API di Qgis, ma non riesco a collegarmi tra questo e il codice di @Underdark. (vedi modifica per i collegamenti)
Kantan,

Risposte:


26

Con il passaggio da QGIS2.x a QGIS3.x l'intero framework di elaborazione è stato rielaborato e gran parte di esso viene ora eseguito come classi C ++ con cui è possibile interagire utilizzando Python. Sfortunatamente la semplice sintassi dei parametri per i dati / set di dati IO non è più valida. La nuova struttura dei parametri è molto più orientata dopo gli algoritmi di elaborazione integrati (Python-) che trovi preinstallati nella casella degli strumenti.

Come vedo, hai già seguito la descrizione della nuova struttura dell'algoritmo di @underdark. Ma per adattare questa struttura alle tue esigenze (livelli raster, doppio input, ecc.) Devi cambiare il codice in più posizioni nello script. Ho codificato un esempio approssimativo con una breve spiegazione per te (solo uno scheletro algoritmo basato sull'esempio di @underdarks):

from qgis.PyQt.QtCore import QCoreApplication, QVariant
from qgis.core import (QgsProcessing, QgsProcessingAlgorithm, 
QgsProcessingParameterRasterLayer,QgsProcessingParameterNumber, 
QgsProcessingParameterRasterDestination)

class RasterAlg(QgsProcessingAlgorithm):
    INPUT_RASTER_A = 'INPUT_RASTER_A'
    INPUT_RASTER_B = 'INPUT_RASTER_B'
    INPUT_DOUBLE = 'INPUT_DOUBLE'
    OUTPUT_RASTER_A = 'OUTPUT_RASTER_A'
    OUTPUT_RASTER_B = 'OUTPUT_RASTER_B'

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

    def name(self):
        return "RasterAlg"

    def tr(self, text):
        return QCoreApplication.translate("RasterAlg", text)

    def displayName(self):
        return self.tr("RasterAlg script")

    def group(self):
        return self.tr("RasterAlgs")

    def groupId(self):
        return "RasterAlgs"

    def shortHelpString(self):
        return self.tr("RasterAlg script without logic")

    def helpUrl(self):
        return "https://qgis.org"

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

    def initAlgorithm(self, config=None):
        self.addParameter(QgsProcessingParameterRasterLayer(
            self.INPUT_RASTER_A,
            self.tr("Input Raster A"), None, False))
        self.addParameter(QgsProcessingParameterRasterLayer(
            self.INPUT_RASTER_B,
            self.tr("Input Raster B"), None, False))
        self.addParameter(QgsProcessingParameterNumber(
            self.INPUT_DOUBLE, 
            self.tr("Input Double"), 
            QgsProcessingParameterNumber.Double,
            QVariant(1.0)))
        self.addParameter(QgsProcessingParameterRasterDestination(
            self.OUTPUT_RASTER_A,
            self.tr("Output Raster A"),
            None, False))
        self.addParameter(QgsProcessingParameterRasterDestination(
            self.OUTPUT_RASTER_B,
            self.tr("Output Raster B"),
            None, False))

    def processAlgorithm(self, parameters, context, feedback):
        raster_a = self.parameterAsRasterLayer(parameters, self.INPUT_RASTER_A, context)
        raster_b = self.parameterAsRasterLayer(parameters, self.INPUT_RASTER_B, context)
        double_val = self.parameterAsDouble(parameters, self.INPUT_DOUBLE,context)
        output_path_raster_a = self.parameterAsOutputLayer(parameters, self.OUTPUT_RASTER_A, context)
        output_path_raster_b = self.parameterAsOutputLayer(parameters, self.OUTPUT_RASTER_B, context)

        #DO SOME CALCULATION

        results = {}
        results[self.OUTPUT_RASTER_A] = output_path_raster_a
        results[self.OUTPUT_RASTER_B] = output_path_raster_b
        return results

Quali passaggi vengono eseguiti?

  1. Importa tutte le classi necessarie.
  2. Definire l'algoritmo come una classe che eredita da QgsProcessingAlgorithm.
  3. Per prima cosa devi dichiarare i nomi dei parametri di input e output come variabili stringa (nomi dei parametri) della classe dell'algoritmo (es. INPUT_RASTER_A = 'INPUT_RASTER_A') Per fare riferimento al tuo algoritmo con i parametri forniti dal framework di elaborazione.
  4. Aggiungi i metodi che collegano il tuo algoritmo alla GUI della toolbox di elaborazione e forniscono stringhe di aiuto, ecc.
  5. Quindi aggiungi i parametri del framework di elaborazione. Coloro che sono definiti come classi figlio di QgsProcessingParameterType- nel caso del vostro algoritmo: QgsProcessingParameterRasterLayer, QgsProcessingParameterNumber, e così via. È possibile consultare le voci API (es. QgsProcessingParameterRasterLayer) Per passare gli argomenti giusti e costruire gli oggetti parametro.
  6. Passare i parametri a fianco contexte gli feedbackoggetti al processAlgorithm()metodo in cui si ottengono i set di dati di input dai parametri in fase di esecuzione (in questo caso oggetti QgsRasterLayer utilizzando il parameterAsRasterLayer()metodo, ecc.).
  7. Fai il tuo calcolo.
  8. Aggiungi gli output al dizionario dei risultati e restituiscili come risultato della chiamata processAlgorithm().

Spero di poterti dare alcune informazioni su come progettare i tuoi algoritmi Python in QGIS3. Ogni volta che sei bloccato, è sempre utile guardare come gli algoritmi esistenti del framework di elaborazione gestiscono i parametri. Puoi dare un'occhiata qui .


1
Buona scrittura! Ti dispiace se lo aggiungo a github.com/qgis/QGIS/blob/master/doc/porting_processing.dox ?
ndawson,

Sarei onorato se lo aggiungessi alla documentazione di qgis. Per favore fallo! Ci sono dei prerequisiti per contribuire con più documentazione su Python per qgis3? Penso che questo sia essenziale per una base di utenti più ampia in termini di programmatori e programmatori.
root676,

1
Nessun prerequisito In realtà è abbastanza facile da aggiungere al ricettario ufficiale di Python tramite le richieste pull di GitHub (tutte le modifiche possono anche essere fatte sul sito GitHub: github.com/qgis/QGIS-Documentation/tree/master/source/docs/… ). Anche aggiungere altri esempi ai documenti ufficiali sarebbe molto gradito!
ndawson,

1
Grazie per la tua risposta! Ero occupato oggi, ma proverò a scavare domani. Sembra davvero promettente.
Kantan,

2
È sicuramente un'ottima risposta, grazie per i dettagli e i riferimenti. Il link agli script su gitHub è una vera miniera d'oro! Inizialmente la dichiarazione QVariant mi ha dato un errore, ma quando l'ho riscritto nell'editor e ho usato il completamento automatico, l'errore è scomparso. Adesso ci vuole davvero un grande passo per immergersi negli script, spero che non scoraggi i nuovi programmatori. Poiché è disponibile più documentazione, spero che diventi più chiara!
Kantan,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.