ArcGIS の Python でのマルチプロセス処理 - ジオプロセシングツールへの組み込み例

469
0
4 weeks ago
Labels (1)

ArcGIS の Python でのマルチプロセス処理 - ジオプロセシングツールへの組み込み例

はじめに

過去に本ブログで、「ArcGIS の Python でのマルチプロセス処理 」、「ArcGIS の Python でのマルチプロセス処理-実装例 」として、ArcPy と Python でのマルチプロセス処理をとりあげ、ベスト プラクティスや、コーディング パターンをサンプルを交えながら紹介させて頂きました。
今回は、Python 3.3 以上でのコーディング パターンとしてアップデートするとともに、ArcGIS Pro のジオプロセシング ツールへの組み込み例を加えた解説記事になります。

なお、本記事で解説しているコードは、すでに「Farmland polygon conversion tools」として、すぐに利用可能な Python ツールボックス のサンプルとして公開したものを基にしております。併せてご参照ください。

 

コーディングパターン

前回の記事では、コーティング パターンのポイントとしてあげていたのは以下の3つです。

1) ワーカー関数:batch_convert

2) ワーカー関数のラッパー:multi_run_batch_convert ※今回は不要

3) マルチプロセスの処理:exec_batch_convert

しかしながら、Python 3.3 からmultiprocessing モジュールのPool クラスに複数引数での呼出が可能な starmap が追加されました。そのため、現在のArcGIS Pro の環境で利用する際には、ワーカー関数のラッパーは不要になり、コーディングもよりシンプルにすることが可能です。

それでは、サンプルをもとに、コーティングする際のポイントを中心に解説していきます。

 

サンプルコード(GeoJSON形式の農地筆ポリゴンの変換)

 変換対象のデータは、前回までの記事と同様、農林水産省が公開している「農地の区画情報(筆ポリゴン)」のデータを例にしています。

※筆ポリゴンの仕様は、前回までの記事時点とは異なるため、本ブログで取り上げているサンプルは、最新の筆ポリゴン(GeoJSON形式)を変換するコードをもとにした紹介記事としています。
今回のサンプル(MP_Farmland_JsonToFeatureClass.py)は、筆ポリゴンのZIP 解凍後の1つの「都道府県フォルダー」を処理するものです。

解凍した状態では、次のように「都道府県フォルダー」下に「各市区町村のGeoJSONファイル(ファイルの拡張子はjson)」が複数入っています。

入力フォルダー: 市区町村別のGeoJSONファイルが入った都道府県フォルダー

例)
    |-2024_02
        |-2024_022012.json # 市区町村別のGeoJSON
        |-2024_022021.json
        |-2024_022039.json
        .....

今回のサンプルプログラムでは、この都道府県フォルダーを入力フォルダーとして、次のような処理を行います。

1.各市区町村のファイル ジオデータベース(FGDB) を作成し、農地の筆界ポリゴンをフィーチャクラスへ変換(※この処理をマルチプロセスで実行)
2.都道府県ファイル ジオデータベース(FGDB) を作成し、1.の各市区町村のフィーチャクラスを、都道府県のフィーチャクラスとして統合
3.各市区町村のファイル ジオデータベース(FGDB) を削除
結果として、最終的には都道府県ファイル ジオデータベース(FGDB) に、農地の筆界ポリゴン(フィーチャクラス)として、統合されたFarmland フィーチャクラスだけが残ります(下図参照)。

出力フォルダー: 統合された都道府県ファイル ジオデータベース の作成先

例)
    |-2024_02_filegdb
        |-2024_022012.gdb # 市区町村別のFGDBは都道府県にマージ後に削除される
            |   c_2024_022012
        |-2024_022021.gdb
            |   c_2024_022021
            ・・・・・
        |-2024_02_filegdb.gdb # 市区町村別のフィーチャクラスをマージしたフィーチャクラスを格納する都道府県のファイルジオデータベース
            |   Farmland # フィーチャクラス名(コード内で固定)

 

それでは、マルチプロセスに関連したコーディング パターンの実装ポイントを中心に解説します。

1)ワーカー関数 : batch_convert

コーディング パターンとして、まずはワーカー関数を通常の ArcPyでの処理と同様に記述します。このときに注意するべきなのは、ベストプラクティスで取り上げたように、このワーカー関数での処理が1プロセスでの処理に相当するため、複数プロセス(複数のワーカー関数)から書込み先としてアクセスする必要がある場合、エンタープライズ ジオデータベースを利用するか、同じファイル ジオデータベースを使用しないようにすることです。

※今回は後者の同じファイル ジオデータベースを使用しないようにするため、ワーカー関数内で新規の市区町村ファイル ジオデータベースを作成し、そのファイル ジオデータベース内で変換処理を行うようにしています。

def batch_convert(in_jsonfile :str, outws :str) -> str:
    '''
    1プロセスで実行する処理:
      1) FGDBへの書込みは仕様で複数プロセスで書込みできないため
           1市区町村のGeoJSONファイルを 独自のFarmlandGeojsonToFeaturesEx クラスで1市区町村.gdb内のフィーチャクラスに変換
    
    in_jsonfile : 市区町村のGeoJSONファイルへのパス
    outws       : 出力するgdb
    '''
    if not arcpy.Exists(outws):
        outfolder = u"{0}".format(os.path.dirname(outws))
        foldername= u"{0}".format(os.path.basename(outws))
        arcpy.management.CreateFileGDB(outfolder, foldername, "CURRENT")
    filename = os.path.basename(in_jsonfile)
    in_json_file = os.path.splitext(filename)[0]
    newfc = u"c_{0}".format(in_json_file) #数値で始まるファイル名はそのまま変換できないので接頭にc_を入れる
    #独自のFarmlandGeojsonToFeaturesEx クラスで変換
    #arcpy.conversion.JSONToFeatures(in_jsonfile, os.path.join(outws, newfc))
    convGeojson = FarmlandGeojsonToFeaturesEx()
    convGeojson.geojson_to_features(in_jsonfile, os.path.join(outws, newfc))
    del convGeojson
    return u"    変換済:{0}".format(outws)

 

2)ワーカー関数のラッパー

上述のように、現在のArcGIS Pro の環境で利用する際は不要のため、定義していません。

 

3)マルチプロセスの処理 : exec_batch_convert

各プロセス用のpythonw.exe へのパスを、multiprocessing.set_executable() で設定し、ワーカー関数へ渡す2つの引数(in_jsonfile, outws)を params にリスト化して入れます。
その後、
pool = multiprocessing.Pool(cpu_cnt) で確保した pool に
results = pool.starmap(batch_convert, params) で関数名 (batch_convert) と params を指定します。
また、各ワーカー関数での処理が終了したら、

pool.close()

pool.join()

を呼び出します。
def exec_batch_convert(infolder :str, outfolder :str, cpu_cnt :int):
    '''
    マルチプロセスでの処理:
    '''
    try:
        start = datetime.datetime.now()
        arcpy.AddMessage(u"-- Strat: MP_Farmland_JsonToFeatureClass --:{0}".format(start))
        
        #a) 各プロセス用の pythonw.exe を設定
        python_path = sys.exec_prefix
        multiprocessing.set_executable(os.path.join(python_path,'pythonw.exe'))
        #multiprocessing.set_executable(os.path.join(python_path,'python.exe')) #CMDプロンプトの画面が起動するので'pythonw.exe'を使う
        
        #b) 各プロセスに渡すパラメータをリスト化
        arcpy.AddMessage(u"  Convert each GeoJSON files : multiprocessing")
        arcpy.env.workspace = infolder
        infiles = arcpy.ListFiles("*.json")
        params=[]
        for infile in infiles:
            param1 = os.path.join(infolder,infile) #市区町村のGeoJSONファイル
            filename = os.path.basename(infile)
            gdbname = u"{0}.gdb".format(os.path.splitext(filename)[0])
            param2 = os.path.join(outfolder,gdbname) # 出力する市区町村ファイルジオデータベース
            params.append((param1, param2))
        if len(infiles) < cpu_cnt: # 処理ファイル数がCPUコアより少ない場合無駄なプロセスを起動不要
            cpu_cnt = len(infiles)
        pool = multiprocessing.Pool(cpu_cnt) # cpu数分プロセス作成
        results = pool.starmap(batch_convert, params) # 割り当てプロセスで順次実行される(Python3.3で追加されたstarmapは複数の引数に対応)
        pool.close()
        pool.join()
        
        # 各プロセスでの処理結果を出力
        for r in results:
            arcpy.AddMessage(u"{0}".format(r))
        
        #c) 各プロセスで変換されたフィーチャクラスを都道府県のFGDBへマージしたものを作成("Farmland")
        #~省略~
        
        # フィールドエイリアスを設定
        #~省略~
        
        # コード値ドメインを設定
        #~省略~
        
        #d) マージが終わったので後片付け 各市区町村のFGDBを削除
        #~省略~
        
        fin = datetime.datetime.now()
        arcpy.AddMessage(u"-- Finish: MP_Farmland_JsonToFeatureClass --:{0}".format(fin))
        arcpy.AddMessage(u"     Elapsed time:{0}".format(fin-start))
    except:
        arcpy.AddError(u"Exception:{0}".format(sys.exc_info()[2]))

 

ジオプロセシングツールへの組み込み

GeoJSON形式の農地筆ポリゴンの変換処理は、上記までのコードで終わっているので、後は、Python ツールボックス に定義した、ジオプロセシングツールからの呼出し部分を中心に解説します。

Python ツールボックスでは、「What is a Python toolbox?」のヘルプに記載されているように、ジオプロセシング ツールボックスとジオプロセシング ツールは、クラスとして定義されます。

1) ツールボックスの定義とツールの追加

class AgrilandJsonConvTool、class AgrilandShpConvTool として定義した2つのジオプロセシングツールを、class Toolbox の初期化時に、

self.tools = [AgrilandJsonConvTool, AgrilandShpConvTool]

として追加しています。

#マルチプロセス対応のモジュールをインポート
from MP_Farmland_JsonToFeatureClass import exec_batch_convert as exec_batch_json_convert
from MP_Farmland_ShapefileToFeatureClass import exec_batch_convert as exec_batch_shp_convert

#Pythonツールボックスの定義
class Toolbox:
    def __init__(self):
    self.label = "農地筆ポリゴン変換 サンプルツールボックス"
    self.alias = ""
    self.tools = [AgrilandJsonConvTool, AgrilandShpConvTool]

#各ジオプロツールの定義
class AgrilandJsonConvTool:
    #~省略~
class AgrilandShpConvTool:
    #~省略~

 

2) ツールの定義

各ジオプロセシングツールは、最低限、初期化の__init__、getParameterInfo、execute を書けばジオプロセシングツールとしてArcGIS Pro 上で動作します。

今回のポイントは、execute で、MP_Farmland_JsonToFeatureClass.py のファイル内に定義されている、exec_batch_convert を呼び出している箇所だけです(シェープファイル形式の同名の関数も追加しているため、import 時に as exec_batch_json_convert と別名を付与しています)。

class AgrilandJsonConvTool:
    def __init__(self):
        self.label = "01_マルチプロセスサンプル_農地筆ポリゴン(GeoJSON形式)_変換ツール"
        self.description = ""
        
    def getParameterInfo(self):
		    param0 = arcpy.Parameter(
		        displayName="入力フォルダー(解凍後の都道府県フォルダー)", 
		        name="input_folder", 
		        datatype="DEFolder", 
		        parameterType="Required",
		        direction="Input")
		    #~省略~
        params = [param0, param1, param2]
        return params
        
		def execute(self, parameters, messages):
        infolder = parameters[0].valueAsText
        outfolder = parameters[1].valueAsText
        cpu_cnt = int(parameters[2].valueAsText)
        exec_batch_json_convert(infolder, outfolder, cpu_cnt)
        return

 

3) 実行画面

実際の「Farmland polygon conversion tools」の実行画面です。

2025-04-07_16h43_19.png

2025-04-07_16h49_39.png2025-04-07_16h50_11.png

 

おまけ(GeoJSONファイルの変換)

ArcGIS Pro でGeoJSONファイルを変換するには、「JSON → フィーチャ (JSON To Features)」で変換するのが一般的ですが、次のような制限があるため、今回は自前のクラス(class FarmlandGeojsonToFeaturesEx)で対応しています。

  • ジオメトリがPolygonZ として定義される
  • フィールド型が自動的に決まり、後から型の再変換が必要となる場合が生じる
  • 農地筆ポリゴンのジオメトリのCRSコードの定義にツールが未対応

 

まとめ

過去にブログでとりあげた、ArcPy と Python でのマルチプロセス処理 を題材に、

  • Python 3.3 以上でのコーディング パターンでアップデート
  • ArcGIS Pro のジオプロセシング ツールへの組み込み例を追加

した「Farmland polygon conversion tools」のサンプルをもとに、コーティングする際のポイントを中心に解説させていただきました。

データの処理の上で、必ずしもマルチプロセスで行う必要はないかもしれませんが、必要に応じて、本記事のベスト プラクティスやコーディング パターンを参考にしていただければと思います。

 

関連リンク

ArcGIS の Python でのマルチプロセス処理

ArcGIS の Python でのマルチプロセス処理-実装例

Labels (1)
Tags (2)
Version history
Last update:
4 weeks ago
Updated by:
Contributors