Написание скрипта обработки Python с Qgis 3.0

15

После обновления до Qgis 3.0 стало очень трудно найти какую-либо информацию, касающуюся написания сценариев обработки в Qgis 3.0.

@Underdark (см. Здесь ) послужил основой для скелета. Этот код также, кажется, был добавлен в Qgis при написании нового скрипта из шаблона (Qgis 3.0.2).

Однако я не мог найти способ помочь новичкам в Python, таким как я, понять, как изменить этот код, особенно для входного и выходного слоев.

Моя цель состоит в том, чтобы написать скрипт, принимающий 2 растровых слоя и двойной в качестве входных данных, выводящий два слоя.

Какие изменения потребуются в коде примера, чтобы это сделать?

Для Qgis 2.x я бы использовал следующий синтаксис:

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

Из того, что я понимаю, изменения должны быть сделаны в следующей процедуре, но я не уверен, что поставить на место.

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

16 мая была выпущена документация по API Qgis python . Однако мне все еще неясно, как использовать это здесь. (Что вполне может быть недостаток знаний Python)

Kantan
источник
1
Не могли бы вы предоставить пример кода, который вы использовали для той же цели в qgis 2.xx? Документация по qgis 3.x будет доступна здесь: docs.qgis.org/testing/en/docs/pyqgis_developer_cookbook/…, как только это будет обновлено. Проблемы с документами отслеживаются здесь: github.com/qgis/QGIS-Documentation/issues
Nono
Ответ отредактирован на примере кода. Спасибо за ссылки, я уже следил за кулинарной книгой, но, к сожалению, я не смог найти там свой ответ!
Кантан
Я читал о документации по API Qgis, но я не могу связать это с кодом @Underdark. (см. правку для ссылок)
Кантан

Ответы:

26

С переходом с QGIS2.x на QGIS3.x вся инфраструктура обработки была переработана, и большая ее часть теперь работает как классы C ++, с которыми вы можете взаимодействовать с помощью Python. К сожалению, простой синтаксис параметров для ввода-вывода данных / набора данных больше не действителен. Новая структура параметров гораздо более ориентирована после встроенных (Python-) алгоритмов обработки, которые вы найдете предварительно установленными в наборе инструментов.

Как я вижу, вы уже следовали описанию новой структуры алгоритма @underdark. Но чтобы настроить эту структуру в соответствии с вашими требованиями (растровые слои, двойной ввод и т. Д.), Вам необходимо изменить код в нескольких местах в сценарии. Я написал грубый пример с кратким объяснением для вас (просто скелет алгоритма, основанный на примере @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

Какие шаги сделаны?

  1. Импортируйте все необходимые классы.
  2. Определите алгоритм как класс, наследующий от QgsProcessingAlgorithm.
  3. Сначала вы должны объявить имена входных и выходных параметров как строковые переменные (имена параметров) класса алгоритма (т. Е. INPUT_RASTER_A = 'INPUT_RASTER_A'), Чтобы связать ваш алгоритм с параметрами, предоставленными платформой обработки.
  4. Добавьте методы, которые связывают ваш алгоритм с графическим интерфейсом панели инструментов обработки, предоставляя строки помощи и т. Д.
  5. Затем вы добавляете параметры структуры обработки. Они определяются как дочерние классы QgsProcessingParameterType- в случае вашего алгоритма: QgsProcessingParameterRasterLayer, QgsProcessingParameterNumberи так далее. Вы можете обратиться к записям API (т. Е. QgsProcessingParameterRasterLayer), Чтобы передать правильные аргументы и построить объекты параметров.
  6. Пропускают параметры наряду contextи feedbackобъекты к processAlgorithm()способу , где вы получение входных наборов данных из параметров во время выполнения (в данном случае QgsRasterLayer объектов, используя parameterAsRasterLayer()метод и т.д.).
  7. Сделай свой расчет.
  8. Добавьте выходные данные в словарь результатов и верните их как результат вызова processAlgorithm().

Я надеюсь, что смогу дать вам некоторое представление о том, как разрабатывать ваши алгоритмы Python в QGIS3. Всякий раз, когда вы застряли, всегда полезно посмотреть, как существующие алгоритмы инфраструктуры обработки обрабатывают параметры. Вы можете посмотреть их здесь .

root676
источник
1
Хорошая рецензия! Не возражаете, если я добавлю его в github.com/qgis/QGIS/blob/master/doc/porting_processing.dox ?
ndawson
Я был бы рад, если бы вы добавили его в документацию qgis. Пожалуйста, сделай так! Есть ли какие-либо предпосылки для предоставления дополнительной документации по Python для qgis3? Я думаю, что это важно для более широкой пользовательской базы с точки зрения сценаристов и программистов.
root676
1
Никаких предпосылок. На самом деле это довольно легко добавить в официальную кулинарную книгу Python с помощью запросов на получение GitHub (все изменения могут быть сделаны даже на сайте GitHub: github.com/qgis/QGIS-Documentation/tree/master/source/docs/… ). Добавление новых примеров в официальные документы также приветствуется!
ndawson
1
Спасибо за Ваш ответ! Я был сегодня занят, но завтра попробую покопаться. Это выглядит действительно многообещающе.
Кантан
2
Это, безусловно, отличный ответ, спасибо за детали и ссылки. Ссылка на скрипты на gitHub - настоящая золотая жила! Сначала объявление QVariant дало мне ошибку, но когда я снова набрал его в редакторе и использовал автоматическое завершение, ошибка исчезла. Сейчас действительно требуется большой шаг, чтобы погрузиться в скриптинг, я надеюсь, что это не отпугнет новых программистов. Однако, по мере того, как будет доступно больше документации, я надеюсь, что она станет более понятной!
Кантан