Écrire un script de traitement python avec Qgis 3.0

15

Suite à la mise à jour de Qgis 3.0, il est devenu très difficile de trouver des informations concernant l'écriture de scripts de traitement dans Qgis 3.0.

@Underdark (voir ici ) a fourni une base pour le squelette. Ce code semble également avoir été ajouté dans Qgis, lors de l'écriture d'un nouveau script à partir d'un modèle (Qgis 3.0.2).

Cependant, je n'ai trouvé aucun moyen d'aider les débutants en python comme moi à comprendre comment changer ce code, en particulier pour les couches d'entrée et de sortie.

Mon objectif est d'écrire un script prenant 2 couches raster et un double en entrée, produisant deux couches.

Quelles seraient les modifications nécessaires à l'exemple de code pour permettre cela?

Pour Qgis 2.x, j'aurais utilisé la syntaxe suivante:

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

D'après ce que je comprends, les modifications doivent être apportées dans la procédure suivante, mais je ne sais pas quoi mettre en place.

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

Le 16 mai, la documentation de l' API python Qgis a été publiée. Cependant, je ne sais toujours pas comment l'utiliser ici. (Ce qui pourrait très bien être un manque de connaissances en python)

Kantan
la source
1
Pourriez-vous fournir un exemple de code que vous avez utilisé dans le même but sur qgis 2.xx La documentation sur qgis 3.x sera disponible ici: docs.qgis.org/testing/en/docs/pyqgis_developer_cookbook/… dès qu'elle sera mis à jour. Les problèmes de documentation sont suivis ici: github.com/qgis/QGIS-Documentation/issues
Nono
Réponse modifiée avec l'exemple de code. Merci pour les liens, je suivais déjà le livre de cuisine mais malheureusement je n'y ai pas trouvé ma réponse!
Kantan
J'ai lu sur les documents de l'API Qgis, mais je ne peux pas faire de lien entre cela et le code de @Underdark. (voir modification pour les liens)
Kantan

Réponses:

26

Avec la transition de QGIS2.x à QGIS3.x, l'ensemble de l'infrastructure de traitement a été retravaillé et de grandes parties de celui-ci s'exécutent maintenant en tant que classes C ++ avec lesquelles vous pouvez interagir avec Python. Malheureusement, la simple syntaxe des paramètres pour les données / jeux de données IO n'est plus valide. La nouvelle structure de paramètres est beaucoup plus orientée après les algorithmes de traitement intégrés (Python-) que vous trouvez préinstallés dans la boîte à outils.

Comme je le vois, vous avez déjà suivi la description de la nouvelle structure d'algorithme par @underdark. Mais pour ajuster cette structure à vos besoins (couches raster, double entrée, etc.), vous devez modifier le code à plusieurs endroits dans le script. J'ai codé un exemple approximatif avec une courte explication pour vous (juste un squelette d'algorithme basé sur l'exemple @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

Quelles étapes sont effectuées?

  1. Importez toutes les classes nécessaires.
  2. Définissez l'algorithme comme une classe héritant de QgsProcessingAlgorithm.
  3. Vous devez d'abord déclarer les noms des paramètres d'entrée et de sortie en tant que variables de chaîne (noms de paramètres) de la classe d'algorithme (c.-à-d. INPUT_RASTER_A = 'INPUT_RASTER_A') Afin de référencer votre algorithme avec les paramètres fournis par le cadre de traitement.
  4. Ajoutez les méthodes qui câblent votre algorithme à l'interface graphique de la boîte à outils de traitement et fournissez des chaînes d'aide, etc.
  5. Ensuite, vous ajoutez les paramètres du cadre de traitement. Ceux -ci sont définis comme des classes d'enfants de QgsProcessingParameterType- dans le cas de votre algorithme: QgsProcessingParameterRasterLayer, QgsProcessingParameterNumberet ainsi de suite. Vous pouvez consulter les entrées API (ie. QgsProcessingParameterRasterLayer) Afin de passer les bons arguments et construire les objets paramètres.
  6. Passez les paramètres à côté contextet les feedbackobjets à la processAlgorithm()méthode où vous obtenez les jeux de données d'entrée à partir des paramètres lors de l'exécution (dans ce cas, les objets QgsRasterLayer à l'aide de la parameterAsRasterLayer()méthode, etc.).
  7. Faites votre calcul.
  8. Ajoutez les sorties au dictionnaire de résultats et renvoyez-les suite à l'appel processAlgorithm().

J'espère que je pourrais vous donner quelques informations sur la façon de concevoir vos algorithmes python dans QGIS3. Chaque fois que vous êtes bloqué, il est toujours utile de voir comment les algorithmes existants du cadre de traitement gèrent les paramètres. Vous pouvez les consulter ici .

root676
la source
1
Bon résumé! Cela vous dérange si je l'ajoute à github.com/qgis/QGIS/blob/master/doc/porting_processing.dox ?
ndawson
Je serais honoré si vous l'ajoutiez à la documentation qgis. S'il-vous-plaît faites ainsi! Existe-t-il des conditions préalables pour contribuer à la documentation de python pour qgis3? Je pense que cela est essentiel pour une base d'utilisateurs plus large en termes de scripteurs et de programmeurs.
root676
1
Aucun prérequis. Il est en fait assez facile à ajouter au livre de recettes python officiel via les demandes d'extraction GitHub (toutes les modifications peuvent même être effectuées sur le site GitHub: github.com/qgis/QGIS-Documentation/tree/master/source/docs/… ). Ajouter plus d'exemples aux documents officiels serait également le bienvenu!
ndawson
1
Merci pour votre réponse! J'étais occupé aujourd'hui, mais je vais essayer de creuser demain. Cela semble vraiment prometteur.
Kantan
2
C'est certainement une excellente réponse, merci pour les détails et les références. Le lien vers les scripts sur gitHub est une véritable mine d'or! Au début, la déclaration QVariant m'a donné une erreur, mais quand je l'ai retapée dans l'éditeur et utilisé la complétion automatique, l'erreur a disparu. Il faut maintenant vraiment un grand pas pour plonger dans les scripts, j'espère que cela ne décourage pas les nouveaux programmeurs. Comme plus de documentation est disponible, cependant, j'espère que cela devient plus clair!
Kantan