Pythonスクリプトとして新しい処理アルゴリズムを書く

QGIS 3.4では、Pythonを使用して処理アルゴリズムを記述する唯一の方法は、 QgsProcessingAlgorithm クラスを拡張することです。

QGIS内では、 プロセシングツールボックス の上部にある スクリプト メニューの 新しいスクリプトを作成 を使用して、自分のコードを書ける プロセシングスクリプトエディタ を開いて作成できます。タスクを簡素化するには、同じメニューの テンプレートから新しいスクリプトを作成する を使用して、スクリプトテンプレートから開始できます。これにより QgsProcessingAlgorithm を拡張するテンプレートが開きます。

If you save the script in the scripts folder (the default location) with a .py extension, the algorithm will become available in the Processing Toolbox.

Extending QgsProcessingAlgorithm

The following code

  1. takes a vector layer as input

  2. counts the number of features

  3. does a buffer operation

  4. creates a raster layer from the result of the buffer operation

  5. returns the buffer layer, raster layer and number of features

from qgis.PyQt.QtCore import QCoreApplication
from qgis.core import (QgsProcessing,
                       QgsProcessingAlgorithm,
                       QgsProcessingException,
                       QgsProcessingOutputNumber,
                       QgsProcessingParameterDistance,
                       QgsProcessingParameterFeatureSource,
                       QgsProcessingParameterVectorDestination,
                       QgsProcessingParameterRasterDestination)
import processing


class ExampleProcessingAlgorithm(QgsProcessingAlgorithm):
    """
    This is an example algorithm that takes a vector layer,
    creates some new layers and returns some results.
    """

    def tr(self, string):
        """
        Returns a translatable string with the self.tr() function.
        """
        return QCoreApplication.translate('Processing', string)

    def createInstance(self):
        # Must return a new copy of your algorithm.
        return ExampleProcessingAlgorithm()

    def name(self):
        """
        Returns the unique algorithm name.
        """
        return 'bufferrasterextend'

    def displayName(self):
        """
        Returns the translated algorithm name.
        """
        return self.tr('Buffer and export to raster (extend)')

    def group(self):
        """
        Returns the name of the group this algorithm belongs to.
        """
        return self.tr('Example scripts')

    def groupId(self):
        """
        Returns the unique ID of the group this algorithm belongs
        to.
        """
        return 'examplescripts'

    def shortHelpString(self):
        """
        Returns a localised short help string for the algorithm.
        """
        return self.tr('Example algorithm short description')

    def initAlgorithm(self, config=None):
        """
        Here we define the inputs and outputs of the algorithm.
        """
        # 'INPUT' is the recommended name for the main input
        # parameter.
        self.addParameter(
            QgsProcessingParameterFeatureSource(
                'INPUT',
                self.tr('Input vector layer'),
                types=[QgsProcessing.TypeVectorAnyGeometry]
            )
        )
        self.addParameter(
            QgsProcessingParameterVectorDestination(
                'BUFFER_OUTPUT',
                self.tr('Buffer output'),
            )
        )
        # 'OUTPUT' is the recommended name for the main output
        # parameter.
        self.addParameter(
            QgsProcessingParameterRasterDestination(
                'OUTPUT',
                self.tr('Raster output')
            )
        )
        self.addParameter(
            QgsProcessingParameterDistance(
                'BUFFERDIST',
                self.tr('BUFFERDIST'),
                defaultValue = 1.0,
                # Make distance units match the INPUT layer units:
                parentParameterName='INPUT'
            )
        )
        self.addParameter(
            QgsProcessingParameterDistance(
                'CELLSIZE',
                self.tr('CELLSIZE'),
                defaultValue = 10.0,
                parentParameterName='INPUT'
            )
        )
        self.addOutput(
            QgsProcessingOutputNumber(
                'NUMBEROFFEATURES',
                self.tr('Number of features processed')
            )
        )

    def processAlgorithm(self, parameters, context, feedback):
        """
        Here is where the processing itself takes place.
        """
        # First, we get the count of features from the INPUT layer.
        # This layer is defined as a QgsProcessingParameterFeatureSource
        # parameter, so it is retrieved by calling
        # self.parameterAsSource.
        input_featuresource = self.parameterAsSource(parameters,
                                                     'INPUT',
                                                     context)
        numfeatures = input_featuresource.featureCount()

        # Retrieve the buffer distance and raster cell size numeric
        # values. Since these are numeric values, they are retrieved
        # using self.parameterAsDouble.
        bufferdist = self.parameterAsDouble(parameters, 'BUFFERDIST',
                                            context)
        rastercellsize = self.parameterAsDouble(parameters, 'CELLSIZE',
                                                context)
        if feedback.isCanceled():
            return {}
        buffer_result = processing.run(
            'native:buffer',
            {
                # Here we pass on the original parameter values of INPUT
                # and BUFFER_OUTPUT to the buffer algorithm.
                'INPUT': parameters['INPUT'],
                'OUTPUT': parameters['BUFFER_OUTPUT'],
                'DISTANCE': bufferdist,
                'SEGMENTS': 10,
                'DISSOLVE': True,
                'END_CAP_STYLE': 0,
                'JOIN_STYLE': 0,
                'MITER_LIMIT': 10
            },
            # Because the buffer algorithm is being run as a step in
            # another larger algorithm, the is_child_algorithm option
            # should be set to True
            is_child_algorithm=True,
            #
            # It's important to pass on the context and feedback objects to
            # child algorithms, so that they can properly give feedback to
            # users and handle cancelation requests.
            context=context,
            feedback=feedback)

        # Check for cancelation
        if feedback.isCanceled():
            return {}

        # Run the separate rasterization algorithm using the buffer result
        # as an input.
        rasterized_result = processing.run(
            'qgis:rasterize',
            {
                # Here we pass the 'OUTPUT' value from the buffer's result
                # dictionary off to the rasterize child algorithm.
                'LAYER': buffer_result['OUTPUT'],
                'EXTENT': buffer_result['OUTPUT'],
                'MAP_UNITS_PER_PIXEL': rastercellsize,
                # Use the original parameter value.
                'OUTPUT': parameters['OUTPUT']
            },
            is_child_algorithm=True,
            context=context,
            feedback=feedback)

        if feedback.isCanceled():
            return {}

        # Return the results
        return {'OUTPUT': rasterized_result['OUTPUT'],
                'BUFFER_OUTPUT': buffer_result['OUTPUT'],
                'NUMBEROFFEATURES': numfeatures}

Processing algorithm standard functions:

  • createInstance (mandatory)

    Must return a new copy of your algorithm. If you change the name of the class, make sure you also update the value returned here to match!

  • name (mandatory)

    Returns the unique algorithm name, used for identifying the algorithm.

  • displayName (mandatory)

    Returns the translated algorithm name.

  • group

    Returns the name of the group this algorithm belongs to.

  • groupId

    Returns the unique ID of the group this algorithm belongs to.

  • shortHelpString

    Returns a localised short help string for the algorithm.

  • initAlgorithm (mandatory)

    Here we define the inputs and outputs of the algorithm.

    INPUT and OUTPUT are recommended names for the main input and main output parameters, respectively.

    If a parameter depends on another parameter, parentParameterName is used to specify this relationship (could be the field / band of a layer or the distance units of a layer).

  • processAlgorithm (mandatory)

    This is where the processing takes place.

    Parameters are retrieved using special purpose functions, for instance parameterAsSource and parameterAsDouble.

    processing.run can be used to run other processing algorithms from a processing algorithm. The first parameter is the name of the algorithm, the second is a dictionary of the parameters to the algorithm. is_child_algorithm is normally set to True when running an algorithm from within another algorithm. context and feedback inform the algorithm about the environment to run in and the channel for communicating with the user (catching cancel request, reporting progress, providing textual feedback). When using the (parent) algorithm's parameters as parameters to "child" algorithms, the original parameter values should be used (e.g. parameters['OUTPUT']).

    可能な限りキャンセルのためにフィードバックオブジェクトをチェックすることをお勧めします!そうすることで、不要な処理が発生するまでユーザーを待たせる代わりに、レスポンシブなキャンセルが可能になります。

    アルゴリズムは、辞書として定義したすべての出力パラメータの値を返す必要があります。この場合、それはバッファとラスタライズされた出力レイヤ、および処理された地物数です。辞書キーは、元のパラメータ/出力名と一致する必要があります。

Input and output types for Processing Algorithms

Here is the list of input and output types that are supported in Processing with their corresponding alg decorator constants (algfactory.py contains the complete list of alg constants). Sorted on class name.

Input types

Class

Description

QgsProcessingParameterBand

A band of a raster layer

QgsProcessingParameterBoolean

A boolean value

QgsProcessingParameterCrs

A Coordinate Reference System

QgsProcessingParameterDistance

A double numeric parameter for distance values

QgsProcessingParameterEnum

An enumeration, allowing for selection from a set of predefined values

QgsProcessingParameterExpression

An expression

QgsProcessingParameterExtent

A spatial extent defined by xmin, xmax, ymin, ymax

QgsProcessingParameterFeatureSink

A feature sink

QgsProcessingParameterFeatureSource

A feature source

QgsProcessingParameterField

A field in the attribute table of a vector layer

QgsProcessingParameterFile

A filename of an existing file

QgsProcessingParameterFileDestination

A filename for a newly created output file

QgsProcessingParameterFolderDestination

A folder

QgsProcessingParameterMapLayer

A map layer

QgsProcessingParameterMatrix

A matrix

QgsProcessingParameterMultipleLayers

A set of layers

QgsProcessingParameterNumber

A numerical value

QgsProcessingParameterPoint

A point

QgsProcessingParameterRange

A number range

QgsProcessingParameterRasterLayer

A raster layer

QgsProcessingParameterRasterDestination

A raster layer

QgsProcessingParameterString

A text string

QgsProcessingParameterVectorLayer

A vector layer

QgsProcessingParameterVectorDestination

A vector layer


Output types

Class

Description

QgsProcessingOutputFile

A filename of an existing file

QgsProcessingOutputFolder

A folder

QgsProcessingOutputHtml

HTML

QgsProcessingOutputLayerDefinition

A layer definition

QgsProcessingOutputMapLayer

A map layer

QgsProcessingOutputMultipleLayers

A set of layers

QgsProcessingOutputNumber

A numerical value

QgsProcessingOutputRasterLayer

A raster layer

QgsProcessingOutputString

A text string

QgsProcessingOutputVectorLayer

A vector layer

Handing algorithm output

レイヤ(ラスタまたはベクタ)を表す出力を宣言すると、アルゴリズムは終了後にQGISに追加しようとします。

  • Raster layer output: QgsProcessingParameterRasterDestination.

  • Vector layer output: QgsProcessingParameterVectorDestination.

したがって、 processing.run() メソッドが作成したレイヤをユーザの現在のプロジェクトに追加しなくても、2つの出力レイヤ(バッファとラスタバッファ)は読み込まれます。それらはユーザが入力した宛先(または、ユーザが宛先を指定しない場合は一時的な宛先)に保存されているからです。

レイヤがアルゴリズムの出力として作成される場合、そのように宣言する必要があります。そうしないと、宣言されたものがアルゴリズムが実際に作成するものと一致しないため、モデラーでアルゴリズムを適切に使用できません。

結果の辞書で文字列、数値などを指定することで返すことができます(「NUMBEROFFEATURES」で示したとおり)が、それらは常にアルゴリズムからの出力として明示的に定義する必要があります。アルゴリズムがモデルの一部として使用される場合、これらのアルゴリズムは後のアルゴリズムで使用するのに役立つ可能性があるため、アルゴリズムではできるだけ多くの有用な値を出力することをを推奨します。

ユーザーとやりとりする

If your algorithm takes a long time to process, it is a good idea to inform the user about the progress. You can use feedback (QgsProcessingFeedback) for this.

The progress text and progressbar can be updated using two methods: setProgressText(text) and setProgress(percent).

You can provide more information to the user using pushCommandInfo(text), pushDebugInfo(text), pushInfo(text) and reportError(text).

スクリプトに問題がある場合、それを処理する正しい方法は QgsProcessingException を発生させることです。メッセージを引数として例外のコンストラクタに渡すことができます。プロセシングでは、アルゴリズムの実行元(ツールボックス、モデラー、Pythonコンソールなど)に応じてプロセシングとユーザーとの通信を処理します。

スクリプトの文書を作成する

You can document your scripts by overloading the helpString() and helpUrl() methods of QgsProcessingAlgorithm.

Flags

QgsProcessingAlgorithmflags メソッドをオーバーライドして、アルゴリズムについてQGISに通知できます。たとえば、スクリプトをモデラーから非表示にすること、キャンセルできること、スレッドセーフではないことなどをQGISに伝えることができます。

ちなみに

デフォルトでは、処理タスクの実行中にQGISの応答性を維持するために、Processingはアルゴリズムを別のスレッドで実行します。アルゴリズムが定期的にクラッシュする場合は、おそらくバックグラウンドスレッドで安全に実行できないAPI呼び出しを使用している可能性があります。アルゴリズムのflags() メソッドからQgsProcessingAlgorithm.FlagNoThreadingフラグを返して、代わりにメインスレッドでアルゴリズムを実行するように強制します。

スクリプトアルゴリズムを書くためのベストプラクティス

スクリプトアルゴリズムを作成する際、特に他のQGISユーザーと共有したい場合に考慮すべきアイデアの簡単な概要を以下に示します。これらの単純な規則に従うことで、ツールボックス、モデラー、バッチ処理インターフェースなどのさまざまな処理要素間で一貫性が確保されます。

  • 結果のレイヤーはロードしないでください。処理に結果を処理させ、必要であれば、レイヤーをロードしてください。

  • Always declare the outputs your algorithm creates.

  • メッセージボックスを表示したり、スクリプトのGUI要素を使用したりしないでください。ユーザーと通信する場合は、フィードバックオブジェクトのメソッド( QgsProcessingFeedback )を使用するか、 QgsProcessingException をスローします。

There are already many processing algorithms available in QGIS. You can find code on https://github.com/qgis/QGIS/blob/release-3_4/python/plugins/processing/algs/qgis.