AlteryxでTopoJSON形式に変換する方法をご紹介します
Alteryx ACEのAkimasaKajitaniです。PowerBIではTopoJSON形式のデータを読み込んで色分けマップとして表示することが可能ですが、そもそもTopoJSONのデータは一般的にはあまり配布などされておらず、ShapeやGeoJSON形式のデータを変換して利用する必要があります。ちなみに、LookerでもTopoJSONが使われます。
今回は、AlteryxでTopoJSON形式のデータを出力する方法をご紹介します。
TopoJSONとは?
そもそもTopoJSONとは何なのでしょうか?
TopoJSONは、GeoJSONの境界データが重なっている部分を省略することでデータの圧縮を大きく行うことができた形式です。d3.jsの作者の方が作られたGeoJSONを拡張した地理情報データを格納するファイルのフォーマットです。
一般的には、CLIのツールかWEBのサービスを使ってShapeファイルやGeoJSONファイルから変換する方法が主流のようです。
ちなみに、少しどのように違うのか中身を覗いてみたいと思います。3点からなるポリゴン2つからなるデータをそれぞれの形式に変換してみました。
GeoJSON:
{ "type": "FeatureCollection",
"features": [
{ "type": "Feature",
"geometry": {"type":"Polygon", "coordinates":[[[139.756222,35.691322], [139.748325,35.689509], [139.748669,35.694807], [139.756222,35.691322]]]},
"properties": {"Label":1}
},
{ "type": "Feature",
"geometry": {"type":"Polygon", "coordinates":[[[139.756393,35.690346], [139.755192,35.684769], [139.748154,35.688394], [139.756393,35.690346]]]},
"properties": {"Label":2}
}
]
}
topoJSON
{"type": "Topology", "objects": {"object_name": {"type": "GeometryCollection", "geometries": [{"type": "Polygon", "arcs": [[0]], "properties": {"Label": 1}}, {"type": "Polygon", "arcs": [[1]], "properties": {"Label": 2}}]}}, "arcs": [[[979244, 652819], [-958489, -180614], [41753, 527794], [916736, -347180]], [[999999, 555588], [-145770, -555588], [-854229, 361127], [999999, 194461]]], "bbox": [139.748154, 35.684769, 139.756393, 35.694807], "transform": {"scale": [8.239008239011455e-09, 1.003801003800448e-08], "translate": [139.748154, 35.684769]}}
だいぶんGeoJSONとは構造的には異なりますね・・・。正直ぱっと見ですぐに理解できるような構造にはなっていないようです。
Alteryxでどのように対応するか
AlteryxでTopoJSONを扱うにはいくつかの選択肢があります。
- CLIツールを使って変換する
- Pythonツールにモジュールをインストールして変換する
CLIツールの場合は、いずれもJavaScriptベースのツールとなります。Alteryxでは「コマンド実行」ツールを使います。
今回は、Pythonで進めたいと思います。Pythonではパッケージが2つあるようです。
- pytopojson
- topojson
pyTopoJSONは依存関係がNumPyだけのように見えるので、依存関係で苦労することはあまりなさそうです。topojsonの場合は、NumPyだけではなく、shapely、packagingと依存関係があります。
Pythonツールにデータを渡すところまで
Pythonツールに渡す際に、GeoJSON形式にする必要があります。いずれのパッケージもGeoJSONをそのまま読み込み変換することができるため、あらかじめGeoJSONにしておく方が楽です。そうしない場合は、GeoPandasを使って結局GeoJSONに変換する必要があります。
ただ、Alteryxには通常のデータストリーム(テーブル形式のデータ)からGeoJSONに直接変換するようなツールはありません。そのため、今回は、コミュニティに掲載されているJSONCreateというツールを使っていきたいと思います。このV2バージョンを使うとGeoJSONに直接変換することができます。
これは以下のコミュニティのブログを参照しています。
Alteryx: Spatial Data Output (GeoJSON)
このパッケージに含まれている「JSONCreateV2.yxmc」というマクロを使うことで、GeoJSON形式に変換することができます。これ、2013年に作られたものですが全然動きますね(他の記事でバージョン1のマクロがありますが、そちらはGeoJSONの変換ができないので要注意です)。
ワークフローの全景としては、以下のようになります。
それでは、Pythonツールのコードを書いていきましょう。
pytopojson
パッケージは、pandas、json、pytopojsonを使います。パッケージのインストールについては、管理者権限でDesignerを起動し、ワークフローを実行する必要があります。pandasは元々入っているため、pytopojsonをインストールすればオッケーです。
from ayx import Package
Package.installPackages(['pytopojson'])
パッケージインストール後の本番部分です。ファイルとして保存するようにしているのと、データをそのままストリーミングでAlteryxワークフローに流すようにもしています。ファイルが巨大になるような場合はエラーになる可能性があるので気をつけてください。
from ayx import Alteryx
import os
import pandas as pd
import json
from pytopojson import topology
# Data読み込み
rd = Alteryx.read("#1")
geojson_data = json.loads(rd.loc[0,'JSON'])
outputfile = rd.loc[0,'FilePath']
#相対パスならWF直下を起点とする
if not os.path.isabs(outputfile):
outputfile = os.path.join(Alteryx.getWorkflowConstant("Engine.WorkflowDirectory"),outputfile)
# TopoJSONへの変換
topology_ = topology.Topology()
topojson = topology_({"object_name": geojson_data},quantization=1e6)
# TopoJSONデータをファイルに書き込み
with open(outputfile, 'w') as output_file:
json.dump(topojson, output_file)
# TopoJSONデータをAlteryxのDataStreamに出力
try: # 1cell 2Gまでという制限に気をつけること。
df = pd.DataFrame({'JSON_FilePath':outputfile,'GeoJSON':[json.dumps(topojson)]})
except Exception as e:
print("Error occured at writing memory", e)
df = pd.DataFrame({'JSON_FilePath':outputfile,'GeoJSON':None})
#WFへ出力
Alteryx.write(df,1)
topojson
パッケージは、pandas、json、topojsonを使います。パッケージのインストールについては、管理者権限でDesignerを起動し、ワークフローを実行する必要があります。pandasは元々入っているため、pytopojsonをインストールすればオッケーです。
from ayx import Package
Package.installPackages(['topojson'])
パッケージインストール後の本番部分です。ファイルとして保存するようにしているのと、データをそのままストリーミングでAlteryxワークフローに流すようにもしています。ファイルが巨大になるような場合はエラーになる可能性があるので気をつけてください。
from ayx import Alteryx
import os
import json
import pandas as pd
import topojson as tp
# Data読み込み
rd = Alteryx.read("#1")
geojson_data = json.loads(rd.loc[0,'JSON'])
outputfile = rd.loc[0,'FilePath']
#相対パスならWF直下を起点とする
if not os.path.isabs(outputfile):
outputfile = os.path.join(Alteryx.getWorkflowConstant("Engine.WorkflowDirectory"),outputfile)
# TopoJSONへの変換と保存
topojson = tp.Topology(geojson_data, prequantize=False).to_json(outputfile)
# TopoJSONデータをAlteryxのDataStreamに出力
try: # 1cell 2Gまでという制限に気をつけること。
df = pd.DataFrame({'JSON_FilePath':outputfile,'GeoJSON':[tp.Topology(geojson_data, prequantize=False).to_json()]})
except Exception as e:
print("Error occured at writing memory", e)
#WFへ出力
Alteryx.write(df,1)
ちなみに、こちらのパッケージは神奈川県のポリゴンデータだと全然終わらなかったので、サイズが大きかったり複雑なポリゴンだとNGかもしれません(簡単なポリゴンだと問題ありませんでした)。
まとめ
- AlteryxのPythonツールを使ってTopoJSONへの変換を行いました
- Pythonのモジュールとして2つありますが、おすすめはpytopojsonとしたいと思います
- TopoJSON形式への変換ができれば、PowerBIにて自由に自作ポリゴンを使った表現ができるようになります
サンプルワークフローダウンロード
参考URL
JSON Create macroが配布されているブログです(若干公開時期は古いですが問題なく動作することを確認しています)
※Alteryx バージョン2023.2.1.89 パッチ: 2 時点での内容となります