Introduction
Dans un article précédent du blog, nous avons présenté le traitement multi-processus avec Python dans ArcGIS sous les titres Traitement multi-processus avec Python dans ArcGIS et Traitement multi-processus avec Python dans ArcGIS - Exemple d'implémentation, en expliquant le traitement multi-processus avec ArcPy et Python, en présentant des exemples simples d'utilisation de processus et de modèles de codage.Cette fois-ci, nous ajoutons un exemple d'intégration dans un outil de géoprocessing d'ArcGIS Pro, tout en mettant à jour le code pour Python 3.3 et plus.
Notez que le code expliqué dans cet article est basé sur un échantillon déjà publié sous le nom Farmland polygon conversion tools, un package Python disponible immédiatement. Veuillez vous y référer.
Modèle de codage
Dans l'article précédent, les points clés du modèle de codage étaient les trois suivants.1) Fonction worker : batch_convert
2) Wrapper de la fonction worker : multi_run_batch_convert
※ Cette fois-ci, elle n'est pas nécessaire3) Traitement multi-processus : exec_batch_convert
Cependant, depuis Python 3.3, la méthode starmap permettant d'appeler une fonction Pool du module multiprocessing avec plusieurs arguments a été ajoutée. Par conséquent, dans l'environnement actuel d'ArcGIS Pro, il n'est pas nécessaire d'utiliser un wrapper pour la fonction worker, ce qui simplifie aussi le code.
Nous allons donc expliquer ici le point central du traitement par lot en se basant sur un exemple simple centré sur les points clés du codage.
Exemple de code (conversion de polygones agricoles au format GeoJSON)
Les données à convertir sont, comme dans l'article précédent, basées sur les données "Informations sur la délimitation des terres agricoles (polygones)" publiées par le Ministère de l'Agriculture, des Forêts et de la Pêche.
※ La structure des polygones diffère de celle présentée précédemment. L'échantillon utilisé ici est basé sur un code convertissant les derniers polygones agricoles (au format GeoJSON) récupérés dans ce blog.L'échantillon actuel (MP_Farmland_JsonToFeatureClass.py) traite un "dossier préfecture" parmi les fichiers ZIP décompressés des polygones agricoles.
Après décompression, plusieurs fichiers GeoJSON par ville/district/village sont contenus sous le dossier "dossier préfecture".
Dossier d'entrée : dossier préfecture contenant des fichiers GeoJSON par ville/district/village
Exemple)
|-2024_02
|-2024_022012.json # GeoJSON par ville/district/village
|-2024_022021.json
|-2024_022039.json
.....
Dans ce programme d'exemple, ce dossier préfecture est défini comme dossier d'entrée et traité comme suit.
1. Création d'une géodatabase fichier (FGDB) pour chaque fichier GeoJSON par ville/district/village et conversion des polygones agricoles en classes d'entités (ce traitement est effectué par le multi-processus)
2. Création d'une géodatabase fichier (FGDB) pour la préfecture et fusion des classes d'entités créées en 1.
3. Suppression des classes d'entités par ville/district/village
En résultat final, seule la classe d'entités Farmland fusionnée reste dans la FGDB préfecture (voir schéma ci-dessous).
Dossier de sortie : emplacement de création de la géodatabase fichier fusionnée préfecture
Exemple)
|-2024_02_filegdb
|-2024_022012.gdb # Les FGDB par ville/district/village sont supprimées après fusion dans la préfecture
| c_2024_022012
|-2024_022021.gdb
| c_2024_022021
.....
|-2024_02_filegdb.gdb # FGDB préfecture contenant les classes fusionnées des classes par ville/district/village
| Farmland # Nom fixe de la classe (fixé dans le code)
Nous allons maintenant expliquer le point central du modèle de codage lié au multi-processus.
1) Fonction worker : batch_convert
En tant que modèle de codage, nous décrivons d'abord la fonction worker similaire au traitement habituel avec ArcPy. Ce dont il faut faire attention ici est que, pour que ce traitement corresponde au traitement dans 1 processus, si l'on doit accéder à partir de plusieurs processus (plusieurs fonctions worker), il faut utiliser une géodatabase entreprise ou éviter d'utiliser la même géodatabase fichier.
def batch_convert(in_jsonfile :str, outws :str) -> str:
'"'
'Traitement exécuté en 1 processus :',' 1) Écriture vers FGDB impossible en écriture multiple simultanée',' car chaque fichier GeoJSON par ville/district/village est converti individuellement en classe d'entités dans une gdb distincte.'"'
'in_jsonfile : chemin vers le fichier GeoJSON par ville/district/village','outws : gdb de sortie'"'
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) # Le nom du fichier commençant par un chiffre ne peut pas être changé tel quel, donc on ajoute le préfixe c_.
convGeojson = FarmlandGeojsonToFeaturesEx()
convGeojson.geojson_to_features(in_jsonfile, os.path.join(outws, newfc))
del convGeojson
return u" Conversion terminée : {0}".format(outws)
2) Wrapper de la fonction worker
Comme indiqué ci-dessus, il n'est pas nécessaire de définir cette fonction dans l'environnement actuel d'ArcGIS Pro.
3) Traitement multi-processus : exec_batch_convert
Le chemin vers pythonw.exe pour chaque processus pythonw.exe est défini via multiprocessing.set_executable(), puis deux arguments (in_jsonfile, outws) sont passés à la fonction worker sous forme de liste params.Ensuite, on crée un pool avec multiprocessing.Pool(cpu_cnt).'results = pool.starmap(batch_convert, params)' appelle la fonction nommée batch_convert avec les paramètres params.
'pool.close()'
'pool.join()'
'sont appelés après que tous les traitements des fonctions worker soient terminés.
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]))
ジオプロセシングツールへの組み込み
Le traitement de conversion des polygones agricoles au format GeoJSON se termine avec le code ci-dessus, donc ensuite,Boîte à outils Python nous expliquons la partie d'appel depuis la boîte à outils géoprocessing définie en Python.
Dans la boîte à outils Python, comme indiqué dans l'aide "Qu'est-ce qu'une boîte à outils Python ?", les boîtes à outils de géoprocessing sont définies en tant que classes.
1) Définition et ajout des outils dans la boîte à outils
Deux outils de géoprocessing définis comme classes AgrilandJsonConvTool et AgrilandShpConvTool sont ajoutés lors de l'initialisation de la classe Toolbox,
self.tools = [AgrilandJsonConvTool, AgrilandShpConvTool]
est ajouté ainsi.
# Importation des modules pour le traitement multi-processus
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
# Définition de la boîte à outils Python
class Toolbox:
def __init__(self):
self.label = "Boîte à outils de conversion des polygones agricoles - exemple"
self.alias = ""
self.tools = [AgrilandJsonConvTool, AgrilandShpConvTool]
# Définition de chaque outil de géoprocessing
class AgrilandJsonConvTool:
# ~omission~
class AgrilandShpConvTool:
# ~omission~
2) Définition des outils
Chaque outil de géoprocessing doit au minimum définir __init__, getParameterInfo et execute pour fonctionner dans ArcGIS Pro en tant qu'outil de géoprocessing.
Le point principal ici est que dans execute, seule la fonction exec_batch_convert définie dans le fichier MP_Farmland_JsonToFeatureClass.py est appelée (une fonction du même nom pour le format shapefile est aussi importée sous un alias exec_batch_shp_convert).
class AgrilandJsonConvTool:
def __init__(self):
self.label = "01_MultiProcess_Sample_PolygoneAgricole (format GeoJSON)_OutilConversion"
self.description = ""
def getParameterInfo(self):
param0 = arcpy.Parameter(
displayName="Dossier d'entrée (dossier pré-décodé par préfecture)",
name="input_folder",
datatype="DEFolder",
parameterType="Required",
direction="Input")
# ~omission~
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) Interface d'exécution
Voici l'interface d'exécution réelle de "Farmland polygon conversion tools".
Exemple (conversion de fichier GeoJSON)
Pour convertir un fichier GeoJSON dans ArcGIS Pro, il est courant d'utiliser "JSON → Features (JSON To Features)", mais en raison des limitations suivantes, cette fois nous utilisons notre propre classe (class FarmlandGeojsonToFeaturesEx).
- Le géométrie est définie comme PolygonZ.
- Le type de fichier est automatiquement déterminé, ce qui peut nécessiter une conversion ultérieure du type.
- L'outil ne prend pas en charge la définition du code CRS des géométries des polygones agricoles.
Résumé
En s'appuyant sur les traitements multi-processus avec ArcPy et Python déjà publiés sur des blogs auparavant,
- mise à jour du code pour Python 3.3 ou supérieur,
- ajout d'un exemple d'intégration dans une boîte à outils de géoprocessing ArcGIS Pro,