Einführung
In einem früheren Blogbeitrag mit dem Titel „Mehrfachverarbeitung in Python für ArcGIS“ und „Mehrfachverarbeitung in Python für ArcGIS – Implementierungsbeispiel“ haben wir die Mehrfachverarbeitung mit ArcPy und Python vorgestellt, einschließlich Best-Practice-Methoden und Codebeispielen.Dieses Mal fügen wir eine Erklärung hinzu, wie man unter Python 3.3 oder höher als Codierungsmuster ein Update durchführt und ein Beispiel zur Integration in die Geoprocessing-Tools von ArcGIS Pro.
Hinweis: Der im Artikel erklärte Code basiert bereits auf dem als „Farmland polygon conversion tools“ veröffentlichten, sofort nutzbaren Python Toolboxes. Bitte beziehen Sie sich darauf.
Codierungsmuster
Im vorherigen Artikel wurden drei Punkte als Codierungsmuster vorgestellt.1) Worker-Funktion: batch_convert
2) Wrapper-Funktion für Worker: multi_run_batch_convert
※ Diesmal nicht benötigt3) Verarbeitung der Mehrfachverarbeitung: exec_batch_convert
Allerdings wurde ab Python 3.3 die starmap-Methode der Pool-Klasse des multiprocessing-Moduls hinzugefügt, die Aufrufe mit mehreren Argumenten ermöglicht. Daher ist es in der aktuellen ArcGIS Pro-Umgebung möglich, auf die Wrapper-Funktion zu verzichten und den Code einfacher zu gestalten.
Im Folgenden wird anhand eines Beispiels erläutert, wie man den Fokus auf die Punkte bei der Codierung legt.
Beispielcode (Konvertierung von landwirtschaftlichen Polygonen im GeoJSON-Format)
Die zu konvertierenden Daten basieren wie im vorherigen Artikel auf den vom Landwirtschaftsministerium veröffentlichten Daten „Landwirtschaftliche Flächendaten (Polygon)“.※ Da sich das Format der Polygone gegenüber dem vorherigen Artikel geändert hat, basiert das Beispiel im Blog auf einem aktualisierten Code, der die neuesten Polygon-Daten (im GeoJSON-Format) konvertiert.
Aktuelles Beispiel (MP_Farmland_JsonToFeatureClass.py) verarbeitet nach dem Entpacken der ZIP-Datei der Polygone eine einzelne "Präfekturordner".Nach dem Entpacken befinden sich unter dem Ordner "Präfekturordner" mehrere GeoJSON-Dateien für Städte, Bezirke, Gemeinden usw. (Dateierweiterung json).
Eingabeordner: Präfekturordner mit GeoJSON-Dateien für Städte, Bezirke und Gemeinden
Beispiel)
|-2024_02
|-2024_022012.json # GeoJSON-Datei für Städte, Bezirke und Gemeinden
|-2024_022021.json
|-2024_022039.json
.....
Im aktuellen Beispielprogramm wird dieser Präfekturordner als Eingabeordner verwendet und folgendermaßen verarbeitet:
1. Erstellen einer File-Geodatabase (FGDB) für jede Stadt, jeden Bezirk und jede Gemeinde und Konvertierung der landwirtschaftlichen Polygon-Daten in Feature-Classes (dieser Schritt wird mit Mehrfachverarbeitung ausgeführt). 2. Erstellen einer FGDB für den Präfekturordner und Zusammenführung der einzelnen FGDBs aus Schritt 1 als Gesamt-FGDB des Präfekturordners. 3. Löschen der einzelnen FGDBs aus Schritt 1. Als Ergebnis bleibt nur die zusammengeführte Farmland-Feature-Class in der FGDB des Präfekturordners übrig (siehe Abbildung unten).
Ausgabeordner: Speicherort der zusammengeführten FGDB des Präfekturordners
Beispiel)
|-2024_02_filegdb
|-2024_022012.gdb # Die FGDB für Städte, Bezirke und Gemeinden wird nach dem Merge gelöscht.
| c_2024_022012
|-2024_022021.gdb
| c_2024_022021
.....
|-2024_02_filegdb.gdb # Die FGDB des Präfekturordners enthält die gemergten Feature-Classes der einzelnen Städte, Bezirke und Gemeinden.
| Farmland # Name der Feature-Class (festgelegt im Code)
Im Folgenden wird anhand dieses Beispiels das Codierungsmuster erläutert.
1) Worker-Funktion: batch_convert
Als Codierungsmuster wird zunächst die Worker-Funktion beschrieben, die ähnlich wie eine normale ArcPy-Verarbeitung geschrieben ist. Dabei ist zu beachten, dass die Verarbeitung so gestaltet sein muss, dass sie mit einer einzigen Prozessinstanz kompatibel ist, wie sie bei ArcGIS Pro verwendet wird.
def batch_convert(in_jsonfile :str, outws :str) -> str:
'''
Verarbeitung in einem Prozess:
1) Schreiben in FGDB ist so gestaltet, dass es nicht mit mehreren Prozessen gleichzeitig geschieht.
Jede GeoJSON-Datei einer Stadt/Bezirk/Gemeinde wird mit einer eigenen FarmlandGeojsonToFeaturesEx-Klasse in eine Feature-Class innerhalb einer GDB konvertiert.
in_jsonfile : Pfad zur GeoJSON-Datei einer Stadt/Bezirk/Gemeinde
outws : Ausgabegdb-Pfad
'''
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) # Dateiname beginnt nicht mit Zahl; daher Präfix c_.
convGeojson = FarmlandGeojsonToFeaturesEx()
convGeojson.geojson_to_features(in_jsonfile, os.path.join(outws, newfc))
return u" Konvertierung abgeschlossen: {0}".format(outws)
2) Wrapper-Funktion für Worker (multi_run_batch_convert) Wird hier nicht definiert, da sie in der aktuellen ArcGIS Pro Umgebung nicht benötigt wird.
3) Verarbeitung der Mehrfachverarbeitung: exec_batch_convert
'Übergabe von Pfaden zu pythonw.exe für jeden Prozess mittels multiprocessing.set_executable(), Übergabe von zwei Argumenten (in_jsonfile, outws) als Liste params an die Worker-Funktion.' 'Erstellen eines Pools mit multiprocessing.Pool(cpu_cnt)' 'Aufruf von pool.starmap(batch_convert, params), wobei Funktionsname (batch_convert) und Parameter params angegeben werden.' また、各ワーカー関数での処理が終了したら、
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]))
ジオプロセシングツールへの組み込み
Die Umwandlungsverarbeitung von Agrarflächen-Polygonen im GeoJSON-Format endet mit dem oben aufgeführten Code, daher folgt nunPython Toolbox eine Erklärung des Aufrufs aus der definierten Geoprocessing-Toolbox in Python.
In der Python Toolbox wird, wie in der Hilfe zu „Was ist eine Python Toolbox?“ beschrieben, die Geoprocessing Toolbox und das Geoprocessing Tool als Klassen definiert.
1) Definition der Toolbox und Hinzufügen der Tools
Zwei Geoprocessing-Tools, class AgrilandJsonConvTool und class AgrilandShpConvTool, werden bei der Initialisierung der class Toolbox hinzugefügt als
self.tools = [AgrilandJsonConvTool, AgrilandShpConvTool]
.
# Import des Moduls für die Multi-Prozess-Unterstützung
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
# Definition der Python Toolbox
class Toolbox:
def __init__(self):
self.label = "Agrarflächen-Polygon Umwandlung Sample Toolbox"
self.alias = ""
self.tools = [AgrilandJsonConvTool, AgrilandShpConvTool]
# Definition der einzelnen Geoprocessing Tools
class AgrilandJsonConvTool:
# ~ Auslassung ~
class AgrilandShpConvTool:
# ~ Auslassung ~
2) Definition der Tools
Jedes Geoprocessing Tool muss mindestens __init__, getParameterInfo und execute implementieren, damit es als Geoprocessing Tool in ArcGIS Pro funktioniert.
Der Punkt hier ist, dass im execute nur die Funktion exec_batch_convert aus MP_Farmland_JsonToFeatureClass.py aufgerufen wird (da es auch eine gleichnamige Funktion für Shapefile gibt, wird sie beim Import mit as exec_batch_json_convert umbenannt).
class AgrilandJsonConvTool:
def __init__(self):
self.label = "01_MultiProcessSample_Agrarflächen-Polygon (GeoJSON Format) Umwandlungstool"
self.description = ""
def getParameterInfo(self):
param0 = arcpy.Parameter(
displayName="Eingabeordner (Ordner nach Entpackung)",
name="input_folder",
datatype="DEFolder",
parameterType="Required",
direction="Input")
# ~ Auslassung ~
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) Benutzeroberfläche zur Ausführung
Dies ist die Benutzeroberfläche zur Ausführung des „Farmland polygon conversion tools“.
Beispiel (Umwandlung von GeoJSON-Dateien)
Um GeoJSON-Dateien in ArcGIS Pro umzuwandeln, wird üblicherweise „JSON → Features (JSON To Features)“ verwendet. Aufgrund folgender Einschränkungen wird hier jedoch eine eigene Klasse (class FarmlandGeojsonToFeaturesEx) verwendet.
- Das Geometrieobjekt wird als PolygonZ definiert.
- Der Dateityp wird automatisch bestimmt, was später eine Typumwandlung erforderlich machen kann.
- Das Tool unterstützt nicht die Definition des CRS-Codes für das Geometrieobjekt des Agrarflächen-Polygons.
Zusammenfassung
Basierend auf früheren Blogbeiträgen über Multi-Prozess-Verarbeitung mit ArcPy und Python wurde hier ein Update mit Codebeispielen für Python 3.3 oder höher vorgenommen.