22.8. 新たなプロセシングアルゴリズムをPythonスクリプトで作成する¶
Pythonを使ってプロセシングアルゴリズムを書くためには、ふたつの選択肢があります。
QGIS内では、 プロセシングツールボックス の上部にある スクリプト メニューの 新しいスクリプトを作成 を使用して、自分のコードを書ける プロセシングスクリプトエディタ を開いて作成できます。タスクを簡素化するには、同じメニューの テンプレートから新しいスクリプトを作成する を使用して、スクリプトテンプレートから開始できます。これにより QgsProcessingAlgorithm
を拡張するテンプレートが開きます。
スクリプトを scripts
フォルダ(デフォルトの場所) にwith a .py
という拡張子で保存するとアルゴリズムは Processing Toolbox で利用可能になります.
22.8.1. QgsProcessingAlgorithmを拡張する¶
以下のコードの内容です
ベクタレイヤを入力に指定します
地物の数を数えます
バッファの操作を行います
バッファ操作の結果を使ってラスタレイヤを作ります
バッファレイヤ,ラスタレイヤと地物の数を返します
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 | from qgis.PyQt.QtCore import QCoreApplication
from qgis.core import (QgsProcessing,
QgsProcessingAlgorithm,
QgsProcessingException,
QgsProcessingOutputNumber,
QgsProcessingParameterDistance,
QgsProcessingParameterFeatureSource,
QgsProcessingParameterVectorDestination,
QgsProcessingParameterRasterDestination)
from qgis 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}
|
プロセシングアルゴリズムの標準関数:
- createInstance (必須)
あなたのアルゴリズムの新しいコピーを返さなければいけません。もしあなたがクラスの名前を変更した場合はここで返す値が合致しているかどうか気を付けて下さい!
- name (必須)
アルゴリズムのユニークな名前を返します,アルゴリズムの識別に使います.
- displayName (必須)
変換されたアルゴリズム名を返します.
- group
このアルゴリズムが所属しているグループ名を返します.
- groupId
このアルゴリズムが所属しているグループのユニークIDを返します.
- shortHelpString
このアルゴリズムの翻訳された短縮ヘルプ文字列を返します.
- initAlgorithm (必須)
ここでアルゴリズムの入力と出力を定義します.
INPUT
とOUTPUT
はそれぞれメインの入力と出力パラメータ用の推奨名称です.もしパラメータが他のパラメータに依存する場合,
parentParameterName
がこの関係を示します (フィールド/レイヤのバンドまたはレイヤの距離単位は利用できません).
- processAlgorithm (必須)
ここで処理が実行されます.
パラメータはインスタンスによって
parameterAsSource
やparameterAsDouble
のような特別な用途の関数を使って取得されます.processing.run
を使うとプロセシングアルゴリズムから他のアルゴリズムを実行できます. 最初のパラメータはアルゴリズムの名前です, 2つめのパラメータはそのアルゴリズム用のパラメータの辞書です. 他のアルゴリズム内で実行される場合is_child_algorithm
は通常True
に設定します.context
とfeedback
は実行環境とユーザとのやりとりチャンネルについてアルゴリズムに伝えます (キャンセルリクエストのキャッチ, 実行状況のレポート, テキストによるフィードバックの提供). (親) アルゴリズムのパラメータが "子" アルゴリズムのパラメータとして利用される場合オリジナルの値を利用する必要があります(例.parameters['OUTPUT']
).可能な限りキャンセルのためにフィードバックオブジェクトをチェックすることをお勧めします!そうすることで、不要な処理が発生するまでユーザーを待たせる代わりに、レスポンシブなキャンセルが可能になります。
アルゴリズムは、辞書として定義したすべての出力パラメータの値を返す必要があります。この場合、それはバッファとラスタライズされた出力レイヤ、および処理された地物数です。辞書キーは、元のパラメータ/出力名と一致する必要があります。
22.8.2. @alg デコレータ¶
@algデコレータを使ってPythonコードを書き,適切な処理アルゴリズムにするための追加情報を提供する数行を追加することでであなた独自のアルゴリズムをつくることができます.この手法はアルゴリズムの作成を簡素にして、また入力と出力の定義ができます.
アルゴリズム作成にデコレータを使う手法には一つの重要な制約があります.それは作成されたアルゴリズムが常にユーザープロセシングスクリプトプロバイダーに追加されることです--アルゴリズムを(たとえばプラグイン内で使う)カスタムプロバイダーに追加することはできません.
以下のコードは @alg デコレータを使って次の機能を実装してます
ベクタレイヤを入力として利用します
地物の数を数えます
バッファ操作を実行します
バッファ操作の結果を使ってラスタレイヤを作ります
バッファレイヤ,ラスタレイヤと地物の数を返します
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 | from qgis import processing
from qgis.processing import alg
from qgis.core import QgsProject
@alg(name='bufferrasteralg', label='Buffer and export to raster (alg)',
group='examplescripts', group_label='Example scripts')
# 'INPUT' is the recommended name for the main input parameter
@alg.input(type=alg.SOURCE, name='INPUT', label='Input vector layer')
# 'OUTPUT' is the recommended name for the main output parameter
@alg.input(type=alg.RASTER_LAYER_DEST, name='OUTPUT',
label='Raster output')
@alg.input(type=alg.VECTOR_LAYER_DEST, name='BUFFER_OUTPUT',
label='Buffer output')
@alg.input(type=alg.DISTANCE, name='BUFFERDIST', label='BUFFER DISTANCE',
default=1.0)
@alg.input(type=alg.DISTANCE, name='CELLSIZE', label='RASTER CELL SIZE',
default=10.0)
@alg.output(type=alg.NUMBER, name='NUMBEROFFEATURES',
label='Number of features processed')
def bufferrasteralg(instance, parameters, context, feedback, inputs):
"""
Description of the algorithm.
(If there is no comment here, you will get an error)
"""
input_featuresource = instance.parameterAsSource(parameters,
'INPUT', context)
numfeatures = input_featuresource.featureCount()
bufferdist = instance.parameterAsDouble(parameters, 'BUFFERDIST',
context)
rastercellsize = instance.parameterAsDouble(parameters, 'CELLSIZE',
context)
if feedback.isCanceled():
return {}
buffer_result = processing.run('native:buffer',
{'INPUT': parameters['INPUT'],
'OUTPUT': parameters['BUFFER_OUTPUT'],
'DISTANCE': bufferdist,
'SEGMENTS': 10,
'DISSOLVE': True,
'END_CAP_STYLE': 0,
'JOIN_STYLE': 0,
'MITER_LIMIT': 10
},
is_child_algorithm=True,
context=context,
feedback=feedback)
if feedback.isCanceled():
return {}
rasterized_result = processing.run('qgis:rasterize',
{'LAYER': buffer_result['OUTPUT'],
'EXTENT': buffer_result['OUTPUT'],
'MAP_UNITS_PER_PIXEL': rastercellsize,
'OUTPUT': parameters['OUTPUT']
},
is_child_algorithm=True, context=context,
feedback=feedback)
if feedback.isCanceled():
return {}
return {'OUTPUT': rasterized_result['OUTPUT'],
'BUFFER_OUTPUT': buffer_result['OUTPUT'],
'NUMBEROFFEATURES': numfeatures}
|
ご覧の通りこのコードには2つのアルゴリズム('native:buffer' と 'qgis:rasterize')が含まれています. 後の物 ('qgis:rasterize') は最初のもの ('native:buffer') が作成したバッファレイヤを利用してラスタレイヤを作成します.
この処理を行うコードの一部分はあなたが前の章を読んでいてば理解するのはむつかしくないです.ただし最初の行には追加の説明が必要です.これらはあなたのコードをアルゴリズムに変換するために必要な情報を提供しています,それによってコードはツールボックスやグラフィカルモデラーのようなGUIコンポーネントから実行できます.
これらの行は @alg
デコレータ関数を呼び出しています.その結果アルゴリズムを簡単にコーディングできます.
@alg デコレータはツールボックス内でのアルゴリズムの名前と場所を定義するのに利用されます.
@alg.input デコレータはアルゴリズムの入力を定義するのにつかわれます.
@alg.output デコレータはアルゴリズムの出力を定義するのにつかわれます.
22.8.3. プロセシングアルゴリズムのための入力と出力の型¶
プロセシングの algデコレータ定数でサポートされている入力と出力タイプのリストです (algfactory.py
にはalg定数の完全なリストが含まれます). クラス名でソートされています.
22.8.3.1. 入力タイプ¶
クラス |
Alg定数 |
説明 |
---|---|---|
|
ユーザに利用可能な認証構成を選択させるか新しい認証構成を作成させます |
|
|
ラスタレイヤのバンド |
|
|
ブール値 |
|
|
色 |
|
|
座標参照系 |
|
|
距離の値用の倍精度数値パラメータ |
|
|
事前定義された複数の値からの選択を許す列挙 |
|
|
式 |
|
|
xmin, xmax, ymin, ymaxで定義された空間領域 |
|
|
ベクタレイヤ属性テーブルのフィールド |
|
|
既存ファイルのファイル名 |
|
|
新たに作成された出力ファイルのファイル名 |
|
|
フォルダ |
|
|
整数 |
|
|
レイアウト |
|
|
レイアウトアイテム |
|
|
マップレイヤ |
|
|
配列 |
|
|
メッシュレイヤ |
|
|
レイヤのセット |
|
|
数値 |
|
|
点 |
|
|
数値の範囲 |
|
|
ラスターレイヤー |
|
|
ラスターレイヤー |
|
|
地図の縮尺 |
|
|
地物シンク |
|
|
地物ソース |
|
地図の縮尺 |
||
|
テキストストリング |
|
|
ベクターレイヤー |
|
|
ベクターレイヤー |
22.8.3.2. 出力タイプ¶
クラス |
Alg定数 |
説明 |
---|---|---|
|
ブール値 |
|
|
距離の値用の倍精度数値パラメータ |
|
|
既存ファイルのファイル名 |
|
|
フォルダ |
|
|
HTML |
|
|
整数 |
|
|
レイヤ定義 |
|
|
マップレイヤ |
|
|
レイヤのセット |
|
|
数値 |
|
|
ラスターレイヤー |
|
|
テキストストリング |
|
|
ベクターレイヤー |
22.8.4. アルゴリズムの出力を渡す¶
出力としてレイヤ(ラスタまたはベクタ)を指定すると、アルゴリズムは終了後にそれをQGISに追加しようとします。
ラスタレイヤ出力: QgsProcessingParameterRasterDestination / alg.RASTER_LAYER_DEST.
ベクタレイヤ出力: QgsProcessingParameterVectorDestination / alg.VECTOR_LAYER_DEST.
したがって processing.run()
メソッドが作成したレイヤをユーザの現在のプロジェクトに読み込まない場合でも2つの出力レイヤ (バッファとラスタバッファ)がロードされます. will be loaded,これらはユーザが入力した保存先 (またはユーザが保存先を指定しない場合は一時的な保存先)に保存されるからです.
レイヤがアルゴリズムの出力として作成される場合、そのように宣言する必要があります。そうしないと、宣言されたものがアルゴリズムが実際に作成するものと一致しないため、モデラーでアルゴリズムを適切に使用できません。
結果の辞書で文字列、数値などを指定することで返すことができます(「NUMBEROFFEATURES」で示したとおり)が、それらは常にアルゴリズムからの出力として明示的に定義する必要があります。アルゴリズムがモデルの一部として使用される場合、これらのアルゴリズムは後のアルゴリズムで使用するのに役立つ可能性があるため、アルゴリズムではできるだけ多くの有用な値を出力することをを推奨します。
22.8.5. ユーザーとやりとりする¶
あなたのアルゴリズムが処理に長い時間を必要とする場合ユーザに進捗状況を知らせるといいと思います. feedback
(QgsProcessingFeedback
) を利用するとそれを実現できます.
処理状況テキストとプログレスバーは2つのメソッドを使って更新できます: setProgressText(text)
と setProgress(percent)
です.
次のメソッドを使うとさらに多くの情報を提供できます pushCommandInfo(text)
, pushDebugInfo(text)
, pushInfo(text)
と reportError(text)
.
スクリプトに問題がある場合、それを処理する正しい方法は QgsProcessingException
を発生させることです。メッセージを引数として例外のコンストラクタに渡すことができます。プロセシングでは、アルゴリズムの実行元(ツールボックス、モデラー、Pythonコンソールなど)に応じてプロセシングとユーザーとの通信を処理します。
22.8.6. スクリプトのドキュメントを作成する¶
以下のものをオーバーロードするとあなたのスクリプトのドキュメントを作れます helpString()
と helpUrl()
methods of QgsProcessingAlgorithm
.
22.8.7. フラグ¶
QgsProcessingAlgorithm
の flags
メソッドをオーバーライドして、アルゴリズムについてQGISに通知できます。たとえば、スクリプトをモデラーから非表示にすること、キャンセルできること、スレッドセーフではないことなどをQGISに伝えることができます。
ちなみに
デフォルトでは、処理タスクの実行中にQGISの応答性を維持するために、Processingはアルゴリズムを別のスレッドで実行します。アルゴリズムが定期的にクラッシュする場合は、おそらくバックグラウンドスレッドで安全に実行できないAPI呼び出しを使用している可能性があります。アルゴリズムのflags() メソッドからQgsProcessingAlgorithm.FlagNoThreadingフラグを返して、代わりにメインスレッドでアルゴリズムを実行するように強制します。
22.8.8. スクリプトアルゴリズムを書くためのベストプラクティス¶
スクリプトアルゴリズムを作成する際、特に他のQGISユーザーと共有したい場合に考慮すべきアイデアの簡単な概要を以下に示します。これらの単純な規則に従うことで、ツールボックス、モデラー、バッチ処理インターフェースなどのさまざまな処理要素間で一貫性が確保されます。
結果のレイヤはロードしないでください。結果はプロセッシングに処理させ、必要であればレイヤをロードしてください。
あなたのアルゴリズム作成する出力について常に宣言して下さい.
メッセージボックスを表示したり、スクリプトのGUI要素を使用したりしないでください。ユーザーと通信する場合は、フィードバックオブジェクトのメソッド(
QgsProcessingFeedback
)を使用するか、QgsProcessingException
をスローします。
QGISで利用できる多くのプロセッシングアルゴリズムがすでに存在します. https://github.com/qgis/QGIS/blob/release-3_10/python/plugins/processing/algs/qgis でソースコードを参照することができます.