waigani's diary

QGISを中心にFOSS4Gをいじくる

QGIS プロセッシング Scriptsで一括処理したい その2

若干捕捉

QGIS プロセッシング Scriptsで一括処理したい その1 - waigani's diaryの続きを少々。

multiple vector

入力にfolderを指定しているのですが、本当はファイルを複数指定したいところです。

##input=multiple vector

という指定方法もあるのですが、これだとQGISに読み込み済みのレイヤしか対象に出来なかったりします。

processing.getObject()

前回の記事とは関係ないのですが、processingの仕様もバージョンによって少し変わっています。ファイル名を受け取りレイヤインスタンスを返してくれたメソッドが、以前のバージョンですと、

processing.getobject()

と書いていたところが、QGIS 2.4では

processing.getObject()

となっていたりします。ご注意ください。

複数のベクトルファイルを1つにする

QGISのメニューに【ベクタ】→【データマネジメントツール】→【複数のシェープファイルを1つに結合する】という機能があります。processingで対応するのは'qgis:mergevectorlayers'になるようです。ただしprocessingで実行すると、2つのファイルを指定して1つにする機能になっているようです。
複数のベクトルファイルを指定して1つにマージする機能が、processingのアルゴリズムの中になさそうなので、自作してみましょう。
入力は、

  • 基準とするベクトルファイル指定
  • マージするベクトルファイルの入っているフォルダを指定
  • 出力ファイル名指定

とします。
処理の内容としては、

  • 基準のベクトルファイルを出力ベクトルファイルにコピー
  • 入力先フォルダから拡張子.shpのファイル名を取得
  • 基準のベクトルファイルと違う図形タイプのファイルは対象外
  • 基準のベクトルファイルと違う属性定義(名称と型だけ確認している)のファイルは対象外
  • 対象のファイルについては、出力ベクトルファイルに図形をコピー

としています。

##[My Scripts]=group
##source=vector
##target_folder=folder
##output_file=output vector

from processing.core.VectorWriter import VectorWriter
from processing.core.ProcessingLog import ProcessingLog
import os
import glob 

def isSameFields(f1, f2) :
    if f1.count() != f2.count() :
        return False
    for i in range(0, f1.count()) :
        if f1.at(i).name() != f2.at(i).name() :
            return False
        if f1.at(i).type() != f2.at(i).type() :
            return False

ProcessingLog().addToLog(ProcessingLog.LOG_INFO, "source vector file :" + source)
ProcessingLog().addToLog(ProcessingLog.LOG_INFO, "target folder :" + target_folder)
ProcessingLog().addToLog(ProcessingLog.LOG_INFO, "output vector file :" + output_file)

sourceLayer = processing.getObject(source)
provider = sourceLayer.dataProvider()

writer = VectorWriter(output_file, provider.encoding(), provider.fields(), provider.geometryType(), sourceLayer.crs())
features = sourceLayer.getFeatures()
for feature in features:
    writer.addFeature(feature)
  
files = glob.glob(os.path.join(target_folder, r'*.shp'))
for file in files:
    if os.path.normpath(file) == os.path.normpath(sourceLayer.source()) :
        continue
    layer = processing.getObject(file)
    if provider.geometryType ()  != layer.dataProvider().geometryType () :
        ProcessingLog().addToLog(ProcessingLog.LOG_INFO, "different geometry type :" + file)
        continue
    if isSameFields(provider.fields(), layer.dataProvider().fields()) :
        ProcessingLog().addToLog(ProcessingLog.LOG_INFO, "different fields :" + file)
        continue
    features = layer.getFeatures()
    for feature in features:
        writer.addFeature(feature)

del writer

適当な名前にして、

 ユーザのホームディレクトリ\.qgis2\processing\scripts

に置いておきます。qgisを再起動して、プロセッシングツールボックスから追加されたスクリプトを探して実行しましょう。

出力ベクトルファイルに対して、同一のスクリプト内もしくはモデラーで繋げて処理を行うことで、

  • ファイルをマージ
  • マージしたファイルに対して解析処理

の流れを作ってあげることが出来ます。