Python(一部手作業)で、ArcMap上に追加されているレイヤをQGISに追加する(またはその逆の)手順を、紹介します。
#Ⅰ. ArcGISからQGISへ
##Ⅰ-1. ArcGISのPythonコンソールでの作業
ArcMapのPythonコンソールに以下を実行します。
#mxdの定義
mxd = arcpy.mapping.MapDocument("CURRENT")
#get layer list
lyr = arcpy.mapping.ListLayers(mxd)
#レイヤの保存先パスをリストに格納
lyrPath =[]
for l in lyr:
if l.isFeatureLayer ==True or l.isRasterLayer ==True:
lyrPath.append(l.dataSource)
print(lyrPath)
実行結果として、追加されているレイヤの保存先パスがリストで取得される。
通常「arcpy.mapping.ListLayers(mxd)」を実行するとレイヤの一覧を取得できるが、下の図のようにレイヤーがグループになっていると、そのグループもリストに加わってしまい、次の処理でそれぞれのレイヤのパスを取得する段階でエラーになってしまう。
そこで、それぞれのレイヤーのタイプを調べて、ベクターレイヤもしくはラスターレイヤだったらlyrPathという別のリストに入れてあげるということをしています。
(ここでは、基盤地図情報から用意したshpと10mDEMがリスト化されています。)
下の画像の赤枠で囲った、実行結果の保存パスが表示されている部分(「[」から、「]」まで)を範囲選択してコピーしてください。
##Ⅰ-2. QGISのPythonコンソールでの作業
今度はQGISのpythonコンソールを立ち上げて、以下のコードの「lyrPath = 」に続いて、先ほどArcGISのPythonコンソールでコピーした内容を貼り付けて実行する。
lyrPath = コピーした内容を貼り付け
続いて、以下を実行する。
lyrPath.reverse()
for i in lyrPath:
if i[len(i)-4:] ==".shp":
iface.addVectorLayer(i,'','ogr')
else:
iface.addRasterLayer(i,"")
iface.addVector(Raster)Layerでそれぞれのデータを追加していますが、そのままリスト順で追加すると、次々にレイヤのトップに追加されて、最終的に、ArcGISでのレイヤの並びとQGISのレイヤの並びが逆になってしまいます。
そこでlyrPath.reverse()でリストの並びを逆にしてあげています。
次のforループではパスの最後4文字が「.shp」ならベクターで追加、そうでないならラスターとして追加という感じです。
(.shpじゃないベクターデータならどうするかということはとりあえず無視しています)
#Ⅱ. QGISからArcGISへ
##Ⅱ-1. QGISのPythonコンソールでの作業
QGISのPythonコンソールに以下を実行。
lyrlist = QgsProject.instance().mapLayers()
lyrPath =[]
for i in lyrlist:
lyrPath.append(lyrlist[i].dataProvider().dataSourceUri())
print(lyrPath)
実行結果として、レイヤーのパスをリストで取得します。
QGISではレイヤ内にグループがあっても、リストには無視してくれます。
しかしこちらで気になるのが、パスを取得すると各レイヤのパスの後ろに「|layerid=0」というのがくっついています。(図中紫枠)
さらにフィルターをかけているレイヤには、後ろに「subset=フィルター式」がはいります(図中青枠)。
これらは、データをロードするときに邪魔になりますが、次の処理で対処するとしてとりあえず気にせず「print(lyrPath)」の実行結果部分(図中赤枠範囲)をコピーします。
##Ⅱ-2. ArcGISのPythonコンソールでの作業
今度はArcGISのpythonコンソールを立ち上げて、以下のコードの「lyrPath = 」に続いて、先ほどQGISのPythonコンソールでコピーしたレイヤのパスの内容を貼り付けて実行する。
lyrPath = コピーした内容を貼り付け
続いて以下を実行。
mxd = arcpy.mapping.MapDocument("CURRENT")
df = arcpy.mapping.ListDataFrames(mxd,"")[0]
for i in lyrPath:
if i.find(".shp") !=-1:
addlayer = arcpy.mapping.Layer(i[0:i.find(".shp") +4])
arcpy.mapping.AddLayer(df, addlayer, "BOTTOM")
else:
addlayer = arcpy.mapping.Layer(i)
arcpy.mapping.AddLayer(df, addlayer, "BOTTOM")
無事追加される。
forループでlyrPath内をひとつずつ追加していくのですが、上で書いたとおり、QGISで取得した保存先パスの後ろに「layerid」とか「subset」とか余計な文字が入っています。
そこで、パス内に「.shp」という文字が入っているかを検索し、あればその.shpまでの文字数文までをレイヤーとして読み込む。
ラスターの時にはそういった余計な文字が入っていないので、「.shp」という文字が入っていなければ(=ラスターの時は)、そのままレイヤとして読み込む。
ということです。
追加の際には"BOTTOM"を指定して、レイヤの最下層に追加するようにしてやれば、QGISでのレイヤの並びと同じになります。
#Ⅲ. 課題
kmlやcsv、xyzタイルなどシェープファイルやラスター以外のデータがレイヤとしてあった場合を対応できてないです。
あと、QGISでレイヤのパスを取得するとフィルター情報も拾えるので、Arcに追加するときにそれも反映できればいいですね。
それはまた追々。