Python
GIS
ArcGIS
Arcpy

arcpyでベクタフォーマット操作&変換

More than 1 year has passed since last update.

Open Source GISしか使ったことなくて、転職して初めてArcGISの洗礼を受けたkochizufanです。
クソ高いらしいけど同じ処理操作しようと思ったらやっぱArcの方が大分速いね!まあ高いだけで取り柄なかったら誰も選ばんだろうから当然だとは思うけど...。

で、ベクタ地図フォーマット(例:Shapeファイル)からデータを読み取って、各属性をいろいろ加工して、他のフォーマット(例:FGDB)に吐き出すような要件があって、それをarcpy(ArcGISのpython環境)でごにょごにょする方法がわかったので、ちょっとノウハウを書いてみます。
※ 本記事では、吐き出し先のスキーマファイルは空ですでに作られているものとして、それへの行追加を想定しています。ゼロからスキーマファイルを作るところは私もまだ調べていません。

なぜ苦労したか

正直、調べるのかなり苦労しました。なんでかって言うと、だいたいのarcpy記事、最初に

import arcpy

# Set the workspace environment to local file geodatabase
arcpy.env.workspace = "C:/data/base.gdb"

とか書いてあって、ここからこの下のスキーマをリストアップしたりできるのだけど、このworkspace属性にDBフォルダを指定する処理を、「DBを開く処理」だと勘違いしちゃって。
それで、「インスタンスも作らずに、開くDB指定するの?複数開いて読んで突っ込んでとかしたい時はどうなるの?」とか思って混乱しちゃって。
実際には記事数はガクンと減るけど、普通にCursorクラスのインスタンスを作るようなインタフェースもありました。
俺だけかもしれないけど、同じ沼にはまる人もいるかもしれないので、はまったところを前もって共有。

開いて突っ込む処理サンプル

で、実際に開いて処理して突っ込むコードのサンプル。

arcpyサンプル
import arcpy
from arcpy import env
import datetime

# 元のShapeファイル
sFClass = "D:/Data/SampleShape/SampleScheme.shp"
# 元ファイルの定義オブジェクトを読み込み
sDesc   = arcpy.Describe(sFClass)
# フィールド定義リストを読み込み
sFields = sDesc.fields
# フィールド定義リストからフィールド名リストを作成
sKeys   = [field.name for field in sFields]
# 自動付番のシステムID的フィールドを削除(Shapeの場合)
sKey.remove('FID')
# ジオメトリフィールドであるShapeフィールドを削除
# (デフォルトのShapeフィールドだと、代表点の点情報しか出ないため)
# ジオメトリをWKBで抜き出すためのフィールドを追加
sKey.remove('Shape')
sKey.append('Shape@WKB')

# 書込み先のFGDBファイル
fFClass = "D:/Data/Sample_FGDB.gdb/SAMPLE_SCHEME"
# 先ファイルの定義オブジェクトを読み込み
fDesc   = arcpy.Describe(fFClass)
# フィールド定義リストを読み込み
fFields = fDesc.fields
# フィールド定義リストからフィールド名リストを作成
fKeys   = [field.name for field in fFields]
# 自動付番のシステムID的フィールドを削除(FGDBの場合)
fKey.remove('OBJECTID')
# ジオメトリフィールドであるShapeフィールドを削除
# (デフォルトのShapeフィールドだと、代表点の点情報しか書き込めないため)
# ジオメトリをWKBで書き込むためのフィールドを追加
fKey.remove('Shape')
fKey.append('Shape@WKB')

# 元ファイルを読み込みでCursor開く(検索結果はsKeysの並びで出てくる)
# なお、arcpy.daはArcGIS 10.1以降かららしいので、それ以前だと動かないらしい...
# 同僚のPCは10.0だったので動かなかった
sCur = arcpy.da.SearchCursor(sFClass, sKeys)
# 先ファイルを追記でCursor開く(書込みはfKeysの並びのリストで行う)
fCur = arcpy.da.InsertCursor(fFClass, fKeys)
# 1行ずつ読み込み
for sRow in sCur:
    # sRow はsKeys並びのリストで来るので、zipして辞書オブジェクトにする
    sDic = dict(zip(sKeys,sRow))
    # 書込みデータを辞書で作成(以下のマッピングは適当)
    fDic = {
        "CODE"          : "ID_" + sDic["ID"],
        "Shape@WKB"     : sDic["Shape@WKB"],
        "CUSTOMER_NAME" : sDic["FIRST_NM"] + " " + sDic["LAST_NM"],
        "Importance"    : sDic["Priority"],
        "Even_Or_Odd"   : sDic["NUMBER"] % 2
    }
    # 書込みデータ辞書をfKeys順のリストに展開(注:この書き方だと全fKeysに対応する値がないとエラー)
    fRow = [fDic[key] for key in fKey]
    # FGDBに値挿入
    fCur.insertRow(fRow)

del fCur
del sCur

こんな感じで、簡単に元ベクタ地図ファイルと異なるスキーマ、異なるフォーマットを持つベクタ地図ファイルを、arcpyで簡単に作ることができます。

ゆるぼ

FOSS4G版誰か書いて