Escrevendo um script de processamento python com o Qgis 3.0


14

Após a atualização para o Qgis 3.0, tornou-se muito difícil encontrar informações sobre a gravação de scripts de processamento no Qgis 3.0.

@Underdark (veja aqui ) forneceu uma base para o esqueleto. Este código também parece ter sido adicionado no Qgis, ao escrever um novo script a partir do modelo (Qgis 3.0.2).

No entanto, não consegui encontrar nenhuma maneira de ajudar iniciantes em python como eu a entender como alterar esse código, especialmente para as camadas de entrada e saída.

Meu objetivo é escrever um script com duas camadas raster e um duplo como entrada, produzindo duas camadas.

Quais seriam as alterações necessárias no código de exemplo para permitir isso?

Para o Qgis 2.x, eu teria usado a seguinte sintaxe:

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

Pelo que entendi, as alterações devem ser feitas no procedimento a seguir, mas não tenho certeza do que colocar em prática.

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

Em 16 de maio, a documentação da API pyg do Qgis foi lançada. No entanto, ainda não está claro para mim como usá-lo aqui. (O que pode muito bem ser uma falta de conhecimento de python)


1
Você poderia fornecer uma amostra do código usado para o mesmo objetivo no qgis 2.xx A documentação no qgis 3.x estará disponível aqui: docs.qgis.org/testing/en/docs/pyqgis_developer_cookbook/… assim que for Atualizada. Os problemas do documento são rastreados aqui: github.com/qgis/QGIS-Documentation/issues
Nono

Resposta editada com o exemplo de código. Obrigado pelos links, eu já estava seguindo o livro de receitas, mas infelizmente não consegui encontrar minha resposta lá!
Kantan

Eu li sobre os documentos da API do Qgis, mas não consigo me relacionar com isso e o código do @Underdark. (veja a edição para os links)
Kantan

Respostas:


26

Com a transição do QGIS2.x para o QGIS3.x, toda a estrutura de processamento foi reformulada e grande parte dela é executada agora como classes C ++ com as quais você pode interagir usando o Python. Infelizmente, a sintaxe simples dos parâmetros para IO de dados / conjunto de dados não é mais válida. A nova estrutura de parâmetros é muito mais orientada após os algoritmos de processamento interno (Python-) que você encontra pré-instalados na caixa de ferramentas.

A meu ver, você já seguiu a descrição da nova estrutura de algoritmos do @underdark. Mas, para ajustar essa estrutura aos seus requisitos (camadas raster, entrada dupla, etc.), é necessário alterar o código em vários locais do script. Eu codifiquei um exemplo aproximado com uma breve explicação para você (apenas um esqueleto de algoritmo baseado no exemplo @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

Quais etapas foram feitas?

  1. Importe todas as classes necessárias.
  2. Defina o algoritmo como uma classe herdada de QgsProcessingAlgorithm.
  3. Primeiro, você deve declarar os nomes dos parâmetros de entrada e saída como variáveis ​​de string (nomes de parâmetros) da classe de algoritmos (ou seja, INPUT_RASTER_A = 'INPUT_RASTER_A') para fazer referência ao seu algoritmo com os parâmetros fornecidos pela estrutura de processamento.
  4. Adicione os métodos que conectam seu algoritmo à GUI da caixa de ferramentas de processamento e forneça instruções, etc.
  5. Em seguida, você adiciona os parâmetros da estrutura de processamento. Aqueles são definidos como classes filhas de QgsProcessingParameterType- no caso do seu algoritmo: QgsProcessingParameterRasterLayer, QgsProcessingParameterNumbere assim por diante. Você pode consultar as entradas da API (ou seja, QgsProcessingParameterRasterLayer) para passar os argumentos corretos e construir os objetos de parâmetro.
  6. Passe os parâmetros ao lado de contexte feedbackobjetos para o processAlgorithm()método em que você obtém os conjuntos de dados de entrada dos parâmetros em tempo de execução (nesse caso, objetos QgsRasterLayer usando o parameterAsRasterLayer()método etc.).
  7. Faça o seu cálculo.
  8. Adicione as saídas ao dicionário de resultados e retorne-as como resultado da chamada processAlgorithm().

Espero poder fornecer algumas idéias sobre como projetar seus algoritmos python no QGIS3. Sempre que você está parado, é sempre útil observar como os algoritmos existentes da estrutura de processamento lidam com os parâmetros. Você pode dar uma olhada neles aqui .


1
Boa redação! Se importa se eu o adicionar ao github.com/qgis/QGIS/blob/master/doc/porting_processing.dox ?
Ndawson 28/05

Ficaria honrado se você o adicionar à documentação do qgis. Por favor, faça isso! Existem pré-requisitos para contribuir com mais documentação python para o qgis3? Eu acho que isso é essencial para uma base de usuários mais ampla em termos de scripts e programadores.
root676

1
Sem pré-requisitos. Na verdade, é muito fácil adicionar ao livro de receitas oficial do python por meio de solicitações pull do GitHub (todas as edições podem ser feitas no site do GitHub: github.com/qgis/QGIS-Documentation/tree/master/source/docs/… ). Adicionar mais exemplos aos documentos oficiais também seria muito bem-vindo!
Ndawson 29/05

1
Obrigado pela sua resposta! Eu estava ocupado hoje, mas vou tentar cavar amanhã. Parece realmente promissor.
Kantan

2
Essa é definitivamente uma ótima resposta, obrigado pelos detalhes e referências. O link para os scripts no gitHub é uma verdadeira mina de ouro! No início, a declaração QVariant me deu um erro, mas quando eu a redigitei no editor e usei a conclusão automática, o erro desapareceu. Agora é realmente necessário um grande passo para mergulhar nos scripts, espero que não desanime novos programadores. Quanto mais documentação estiver disponível, espero que esteja ficando mais clara!
Kantan
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.