Escribir un script de procesamiento de Python con Qgis 3.0

15

Después de la actualización de Qgis 3.0, se ha vuelto muy difícil encontrar información sobre la escritura de scripts de procesamiento en Qgis 3.0.

@Underdark (ver aquí ) ha proporcionado una base para el esqueleto. Este código también parece haberse agregado en Qgis, al escribir un nuevo script desde la plantilla (Qgis 3.0.2).

Sin embargo, no pude encontrar ninguna manera de ayudar a los novatos de Python como yo a comprender cómo cambiar ese código, especialmente para las capas de entrada y salida.

Mi objetivo es escribir un script que tome 2 capas ráster y un doble como entrada, produciendo dos capas.

¿Cuáles serían los cambios necesarios en el código de ejemplo para permitir eso?

Para Qgis 2.x hubiera usado la siguiente sintaxis:

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

Por lo que entiendo, los cambios deben hacerse en el siguiente procedimiento, pero no estoy seguro de qué poner en práctica.

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

El 16 de mayo, se lanzó la documentación de Qgis python API . Sin embargo, todavía no está claro para mí cómo usarlo aquí. (Lo que bien podría ser una falta de conocimiento de Python)

Kantan
fuente
1
¿Podría proporcionar una muestra de código que utilizó para el mismo propósito en qgis 2.xx? La documentación sobre qgis 3.x estará disponible aquí: docs.qgis.org/testing/en/docs/pyqgis_developer_cookbook/… tan pronto como esté disponible. actualizado. Los problemas de documentos se rastrean aquí: github.com/qgis/QGIS-Documentation/issues
Nono
Respuesta editada con el código de ejemplo. Gracias por los enlaces, ya estaba siguiendo el libro de cocina, pero desafortunadamente no pude encontrar mi respuesta allí.
Kantan
Leí sobre los documentos de la API de Qgis, pero no puedo relacionarme entre eso y el código de @Underdark. (ver edición de los enlaces)
Kantan

Respuestas:

26

Con la transición de QGIS2.x a QGIS3.x, todo el marco de procesamiento se ha modificado y gran parte de él se ejecuta ahora como clases de C ++ con las que puede interactuar utilizando Python. Desafortunadamente, la sintaxis simple de parámetros para datos / conjunto de datos IO ya no es válida. La nueva estructura de parámetros está mucho más orientada después de los algoritmos de procesamiento incorporados (Python) que se encuentran preinstalados en la caja de herramientas.

Como veo, ya has seguido la descripción de la nueva estructura del algoritmo por @underdark. Pero para ajustar esta estructura a sus requisitos (capas ráster, doble entrada, etc.) debe cambiar el código en varias ubicaciones en el script. He codificado un ejemplo aproximado con una breve explicación para usted (solo un esqueleto de algoritmo basado en el ejemplo @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

¿Qué pasos se hacen?

  1. Importa todas las clases necesarias.
  2. Defina el algoritmo como una clase heredada de QgsProcessingAlgorithm.
  3. Primero debe declarar los nombres de los parámetros de entrada y salida como variables de cadena (nombres de parámetros) de la clase de algoritmo (es decir INPUT_RASTER_A = 'INPUT_RASTER_A') para poder hacer referencia a su algoritmo con los parámetros proporcionados por el marco de procesamiento.
  4. Agregue los métodos que conectan su algoritmo a la interfaz gráfica de usuario de la caja de herramientas de procesamiento y proporcione cadenas de ayuda, etc.
  5. Luego agrega los parámetros del marco de procesamiento. Los que se definen como clases hijas de QgsProcessingParameterType- en el caso de que su algoritmo: QgsProcessingParameterRasterLayer, QgsProcessingParameterNumbery así sucesivamente. Puede consultar las entradas de la API (es decir QgsProcessingParameterRasterLayer) para pasar los argumentos correctos y construir los objetos de parámetros.
  6. Pasar los parámetros junto contexty feedbackobjetos para el processAlgorithm()método en el que se obtiene los conjuntos de datos de entrada de los parámetros en tiempo de ejecución (en este caso QgsRasterLayer objetos mediante el parameterAsRasterLayer()método, etc.).
  7. Haz tu cálculo.
  8. Agregue las salidas al diccionario de resultados y devuélvalas como resultado de la llamada processAlgorithm().

Espero poder darle algunas ideas sobre cómo diseñar sus algoritmos de Python en QGIS3. Siempre que esté atascado, siempre es útil observar cómo los algoritmos existentes del marco de procesamiento manejan los parámetros. Puedes echarles un vistazo aquí .

root676
fuente
1
Buena redacción! ¿Te importa si lo agrego a github.com/qgis/QGIS/blob/master/doc/porting_processing.dox ?
ndawson
Me sentiría honrado si lo agrega a la documentación de qgis. ¡Por favor, hazlo! ¿Hay algún requisito previo para contribuir con más documentación de Python para qgis3? Creo que esto es esencial para una base de usuarios más amplia en términos de scripters y programadores.
root676
1
No hay requisitos previos. En realidad, es bastante fácil agregar al libro de cocina oficial de Python a través de solicitudes de extracción de GitHub (todas las ediciones se pueden hacer incluso en el sitio de GitHub: github.com/qgis/QGIS-Documentation/tree/master/source/docs/… ). ¡Agregar más ejemplos a los documentos oficiales también sería muy bienvenido!
ndawson
1
¡Gracias por tu respuesta! Estuve ocupado hoy, pero intentaré cavar mañana. Se ve muy prometedor.
Kantan
2
Definitivamente es una gran respuesta, gracias por los detalles y referencias. ¡El enlace a los scripts en gitHub es una verdadera mina de oro! Al principio, la declaración QVariant me dio un error, pero cuando lo volví a escribir en el editor y usé la finalización automática, el error desapareció. Ahora realmente toma un gran paso sumergirse en las secuencias de comandos, espero que no desanime a los nuevos programadores. Sin embargo, a medida que haya más documentación disponible, ¡espero que se vuelva más clara!
Kantan