ArcGIS 10.x|PythonでMXDのデータソースを一括置き換え

ArcGIS Desktop 10.x:arcpy.mappingでMXDのデータソース一括置換(実例つき)

ArcGIS Desktop 10.x:arcpy.mapping で MXD のデータソース一括置換

現場でよくある「レイヤの参照切れ」を、Pythonだけで安全に “上書き修復” する手順とサンプル。今回の実案件(Set_Data 配下)を題材に、再現性のあるスクリプトと運用のコツをまとめました。

今回の事例(要約)

  • 対象ルート:Q:\R06CHIBA\NARITA\TAKO\KYUKEI\Set_Data
  • 上書き保存(相対パス維持)+ 同名を BACKUP に退避(同階層に BACKUP フォルダ作成)
  • レイヤ名とSHP名を厳密に突き合わせ: KTAISEKI_3MKTAISEKI_3M.shp同じフォルダに存在する時だけ差替え(無ければ何もしない)
  • KIDO_100KN も同様。DM系は色崩れ防止のため非表示化・削除はしない(既存の正規パスが生きていれば再接続のみ)
  • 右クリック実行(UTF-8)メニューからワンクリックで動かせる設計

置換ルール(今回案件)

レイヤ名期待ファイル無い場合備考
KTAISEKI_3M./KTAISEKI_3M.shp触らない(残置)ダミー生成・誤接続を禁止
KIDO_100KN./KIDO_100KN.shp触らない(残置)同フォルダにある時のみ差替え
DM/ラスタ既存パス触らない正規の共通ベースから再接続のみ

実運用スクリプト(短縮版・そのまま動作)

ArcGIS Desktop 10.4 / Python 2.7。MXDと同じフォルダに対象SHPがある時だけ置換します。ログはUTF-8、コンソールはASCIIに落として出力します。

# -*- coding: utf-8 -*-
from __future__ import unicode_literals
import os, io, sys, datetime
import arcpy

FS = sys.getfilesystemencoding() or 'mbcs'
def U(x):  # console-safe printable
    try:
        s = x if isinstance(x, unicode) else x.decode(FS, 'replace')
        return s.encode('ascii', 'replace')  # console print safe
    except:
        return '[?]'

ROOT = r"Q:\R06CHIBA\NARITA\TAKO\KYUKEI\Set_Data"
BACKUP = os.path.join(ROOT, "BACKUP")
if not os.path.isdir(BACKUP):
    os.makedirs(BACKUP)

log = io.open(os.path.join(ROOT, "rebuild_set_data.log"), "a", encoding="utf-8")
def writelog(msg):
    log.write(msg + u"\n")
    try:
        print(U(msg))
    except:
        pass

TARGET_RULES = {
    u"KTAISEKI_3M" : "KTAISEKI_3M.shp",
    u"KIDO_100KN"  : "KIDO_100KN.shp",
}

writelog(u"=== 再構築開始: {} ===".format(datetime.datetime.now()))
for root, dirs, files in os.walk(ROOT):
    for f in files:
        if not f.lower().endswith(".mxd"): 
            continue
        mxd_path = os.path.join(root, f)
        writelog(u"[MXD] {}".format(mxd_path))
        try:
            mxd = arcpy.mapping.MapDocument(mxd_path)
        except Exception as e:
            writelog(u"  NG 読込失敗: {}".format(e))
            continue

        changed = 0
        for df in arcpy.mapping.ListDataFrames(mxd):
            for lyr in arcpy.mapping.ListLayers(mxd, "", df):
                if lyr.isGroupLayer: 
                    continue
                rule = TARGET_RULES.get(lyr.name)
                if not rule:
                    continue
                shp_abs = os.path.join(os.path.dirname(mxd_path), rule)
                if arcpy.Exists(shp_abs):
                    try:
                        lyr.replaceDataSource(os.path.dirname(shp_abs),
                                              "SHAPEFILE_WORKSPACE",
                                              os.path.splitext(os.path.basename(shp_abs))[0],
                                              True)
                        changed += 1
                        writelog(u"   OK 置換: {} -> ./{}".format(lyr.name, rule))
                    except Exception as e:
                        writelog(u"   NG 置換失敗: {} :: {}".format(lyr.name, e))
                else:
                    writelog(u"   SKIP: {} は同フォルダに無し".format(lyr.name))

        # バックアップ退避+上書き保存(相対パス維持)
        try:
            bak = os.path.join(BACKUP, f)
            mxd.saveACopy(bak)
            mxd.relativePaths = True
            mxd.save()
            writelog(u"  保存: 上書き完了 changed={}".format(changed))
        except Exception as e:
            writelog(u"  NG 保存失敗: {}".format(e))
        finally:
            del mxd
writelog(u"=== 再構築終了 ===")
log.close()
ポイント
  • 検索は「MXDと同じフォルダ」だけ。だから 誤って別区画のSHPへ接続しない
  • 存在しない場合は何もしない(ダミー生成・隣のフォルダ探索もしない)。
  • 保存は相対パスを維持。既存MXDはBACKUPにコピー。

右クリック実行(UTF-8)メニュー(任意)

レジストリに1回登録すれば、右クリックArcGIS 10.4 で実行(UTF-8) から起動できます。

@echo off
reg add "HKCU\Software\Classes\SystemFileAssociations\.py\shell\RunWithArcGIS104" /ve /d "ArcGIS 10.4 で実行(UTF-8)" /f
reg add "HKCU\Software\Classes\SystemFileAssociations\.py\shell\RunWithArcGIS104\command" /ve ^
 /d "cmd.exe /d /k chcp 65001 <nul ^& set PYTHONIOENCODING=utf-8 ^& "C:\Python27\ArcGIS10.4\python.exe" "%1" ^& pause" /f
echo 追加しました。

トラブルシュート実例

  • コンソールで文字化け / Illegal byte sequenceprintはASCIIに落として出力、ログはUTF-8で書く(上の U() 参照)。
  • 一部だけリンク復旧しない:今回のロジックは「MXDと同じフォルダにある時だけ置換」。別階層にしかデータが無いレイヤは 仕様どおりスキップ
  • DM系が全部リンク切れ:DMやラスタは「既存パスの再接続のみ・無ければ放置」。必要に応じて LAYER_RULES を追加し、正規の共通ベースへ差し替える。

実務でよく使う編集・自動化 20例(超コンパクト)

1. データソース置換mapping
lyr.replaceDataSource()
2. 相対パス化mapping
mxd.relativePaths=True; mxd.save()
3. レイヤ非表示/凡例除外
lyr.visible=False; lyr.showInLegend=False
4. 0件レイヤの処置
arcpy.GetCount_management(lyr)→削除/非表示
5. グループ整理
arcpy.mapping.AddLayer() / Remove
6. ラベルON/OFF
lyr.showLabels=True
7. 定義クエリ設定
lyr.definitionQuery="TYPE='A'"
8. フィールド可視/順序
arcpy.mapping.ListFields+更新
9. シンボル読み替え
レイヤファイル(.lyr)で UpdateLayer
10. レイアウト要素の文字更新
ListLayoutElements(...,"TEXT_ELEMENT")
11. 図郭の自動回転/縮尺
df.rotation, df.scale
12. 出図の一括PDF化
arcpy.mapping.ExportToPDF()
13. 画像出力(PNG/TIFF)
ExportToPNG/TIFF
14. ブックマーク巡回
ListBookmarks→中心移動→出力
15. レイヤ存在チェック
名前→辞書化して差異検出
16. マップシリーズもどき
グリッドIDをクエリに流して連番出図
17. 文字スタイル一括変更
テキスト要素→フォント/サイズ更新
18. 複数MXDの監査
データソース一覧をCSV出力
19. 破損対策バックアップ
saveACopy() で世代管理
20. 10.0–10.8互換の安全運転
使える引数を最小に、例外は握りつぶさずログ化

なぜ「できた図葉 / できない図葉」が出る?

  • 本稿のサンプルは「MXDと同じフォルダにデータがある時だけ置換」=誤接続を防ぐため。
  • 別階層にしかないデータはあえてスキップ。必要なら探索ルール(親・兄弟フォルダを順に探す等)を足してください。

おわりに

「何があってもダミー生成しない/むやみに探しに行かない」ポリシーに徹すると、事故は激減します。必要最小限から始めて、現場の規約に合わせて探索ルールを段階的に拡張していくのがコツです。

© Your Team — ArcGIS Desktop 10.x / Python 2.7 実務メモ

コメント

このブログの人気の投稿

石川県:土砂災害(特別)警戒区域+CS立体図

日本でよく使う EPSG コード 一覧

設計定数を求めるための代表N値について