.lyrx は開けます（ArcGIS の CIM の話）

**対象読者** ArcGIS Pro 利用者

**実行環境** Windows10, ArcGIS Pro 2.8.2 (python 3.7.10, arcpy 2.8)

## はじめに

紛らわしいので、まず最初にお伝えします。

ここで取り上げる CIM は Construction Information Modeling ではありません。

これから説明する **CIM** は **Esri Cartographic Information Model** になります。

国交省の BIM/CIM とは別物です。

この後者の CIM を最近知ったのですが、「使える」と思ったのでご紹介します。

## CIM を使ったオブジェクト操作

先述の通り CIM は [Esri Cartographic Information Model](https://pro.arcgis.com/ja/pro-app/latest/arcpy/mapping/python-cim-access.htm) の略で、直訳すると「Esri地図製作情報モデル」でしょうか。

ArcGIS 関連ソフトで採用されているオブジェクトモデルになります。

[Arcpy](https://pro.arcgis.com/ja/pro-app/latest/arcpy/get-started/what-is-arcpy-.htm) には [Mapping](https://pro.arcgis.com/ja/pro-app/latest/arcpy/mapping/introduction-to-arcpy-mp.htm) というモジュール (Arcpy.mp モジュール) があって、マップに関するオブジェクトにアクセスできるようになっていますが、**CIM を使うと arcpy.mp モジュールよりも詳細な設定が可能になります。**

マップ、レイアウト、レイヤは、それぞれ .mapx .pagx .lyrx という拡張子のファイルとしてエクスポートできますが、これらが CIM に準拠しています。

これらのファイルはテキストエディタで読むことができて、中身はJSON形式で書かれています。
（拡張子を .json に変えて、対応エディタで開くと読みやすくなります。）

:::note warn
ということで、この中身をエディタで直接書き換えてインポートするという使い方ができるのですが、残念ながらこの方法は非推奨、というか禁止とされています。
理由は、エディタで編集すると、通常ではありえない設定をしてしまう恐れがあるためで、それをしてしまうと、アプリケーションやプロジェクトファイルに悪影響を与えることになります。
:::

では、どうするのかというと CIM 用の API を通じてオブジェクトにアクセスするようにします。

流れとしてはこんな感じです。

**1. オブジェクトの取得
2. getDefinition() メソッドでオブジェクト定義の読込
3. オブジェクト定義を API で変更
4. setDefinition() メソッドでオブジェクトにプッシュ**

難点は、どこをどう変えればいいのかはちょっとググるくらいでは分からないところです。

[GitHub リポジトリ](https://github.com/esri/cim-spec)にリファレンスもありますが、項目が多すぎて逆に分かりにくいです。

変更項目を特定する正攻法としては、公式ページでおすすめしている通り、変更前後のJSONファイルを比較する方法になります。

あとは、提供されている[サンプルスクリプト](https://www.arcgis.com/home/item.html?id=8772f61319584882bb697ba003030636)を参考にするのも良いと思います。

## CIM を使ったレイヤのソースの変更

レイヤ操作の簡単な具体例です。

東京都の行政区域ポリゴンを、神奈川県の行政区域ポリゴンに置き換えます。

データは[国土数値情報の行政区域ポリゴン](https://nlftp.mlit.go.jp/ksj/gml/datalist/KsjTmplt-N03-v3_0.html)を使っています。

設定項目の変更は指定の文字列で置換する方法をとっています。

なお、本コードはフィーチャレイヤを想定したもので、ラスタ等のレイヤについてはエラーが出ます。

ファイルの階層
`C:\data`
├─`N03-20210101_13_GML`
│　　　N03-21_13_210101.shp　< 東京都の行政区域ポリゴン
└─`N03-20210101_14_GML`
　　　　N03-21_14_210101.shp　< 神奈川県の行政区域ポリゴン


```py:実行コード
import arcpy

# マップ名
map_name = 'マップ'
# 置換用文字列 レイヤ名とファイル名に使用
name_old = 'N03-21_13_210101'
name_new = 'N03-21_14_210101'
# 置換用文字列 ソースパスに使用
path_old = 'N03-20210101_13_GML'
path_new = 'N03-20210101_14_GML'

# ArcGIS Pro で現在開いているプロジェクトを取得
aprx = arcpy.mp.ArcGISProject("CURRENT")
# マップを取得
m = aprx.listMaps(map_name)[0]
# レイヤリストを取得
lyrs = m.listLayers()

for lyr in lyrs:
	# CIM定義を取得
	lyrCIM = lyr.getDefinition('V2')
	# CIM定義からdataConectionを取得
	dc = lyrCIM.featureTable.dataConnection
	# レイヤ名を置換
	lyrCIM.name = lyrCIM.name.replace(name_old, name_new)
	# ファイル名を置換
	dc.dataset = dc.dataset.replace(name_old, name_new)
	# ソースパスを置換
	dc.workspaceConnectionString = dc.workspaceConnectionString.replace(path_old, path_new)
	# CIM定義の変更を適用
	lyr.setDefinition(lyrCIM)
```
結果（東京都島しょ部はフレームアウトさせています）
![ソースの変更結果.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1409923/4b85184c-bad0-6239-676e-facfecaa5796.png)


シンボル表示はそのままで、ファイルソースとレイヤ名が変更されました。

ソースのフォルダパスやレイヤ名を変更することは arcpy.ma モジュールだけでもできるのですが、参照ファイル名の変更は CIM で初めて実現できました。

## 最後に

CIM の紹介をしました。

複数のレイヤのシンボル情報や結合しているテーブルの情報のようなディープな階層の設定も CIM を使えば実現できると思うので、arcpy.ma モジュールと使い分けながらCIM を使っていきたいと思います。

Python CIM access (Esri 公式ページ)
https://pro.arcgis.com/ja/pro-app/latest/arcpy/mapping/python-cim-access.htm

GitHub リポジトリ
https://github.com/esri/cim-spec

サンプルスクリプト
https://www.arcgis.com/home/item.html?id=8772f61319584882bb697ba003030636