オンラインマップを利用したGeoJSONデータのプロット
GeoJSON
これまでcsv形式のオープンデータを利用してきました,よりウェブに相性が良いデータ形式があります. それが,JSON形式(.json) です. JSONは,「じぇいそん」と読み,ブラウザで動作するプログラミング言語の JavaScript で用いられるデータ形式ですが, 現在はPythonを始めとした様々なプログラミング言語でサポートされています(Pythonでは辞書に対応する).
下記のCSV形式のデータを例に考えてみましょう.
町名,男,女,総数,世帯数
赤池町,1693,1647,3340,1315
浅田町,2593,2431,5024,2086
上記のデータをJSON形式に変換すると下記になります. JSON形式では,データは string(文字列) と value(値) の組で表現されます. 例えば,“町名"という文字列と,“赤池町"という値が組になっていることがわかります. また,[ ] は配列を表しており,0番目の要素に赤池町のデータ,1番目の要素に浅田町のデータが格納されます. 要素は「,」で区切られますが,最後の要素には必要ありません.
json = [
{
"町名": "赤池町",
"男": 1693,
"女": 1647,
"総数": 3340,
"世帯数": 1315
},
{
"町名": "浅田町",
"男": 2593,
"女": 2431,
"総数": 5042,
"世帯数": 2086
}
]
print(json[0])
print(json[1])
{'町名': '赤池町', '男': 1693, '女': 1647, '総数': 3340, '世帯数': 1315}
{'町名': '浅田町', '男': 2593, '女': 2431, '総数': 5042, '世帯数': 2086}
このJSON形式を基本として,点,線,多角形などの空間データを表現するために用いられるのが GeoJSON 形式です. GeoJSONは,「じおじぇいそん」と読み, Leefletを始めとした様々な地図サービスで利用可能です. geojson.ioというサービスで,オリジナルのGeoJSON形式のデータを作成・共有することも可能です.
下記のCSV形式のデータを例に考えてみましょう. 緯度・経度の情報が含まれており,オンライン地図では点として扱われます.
名称,緯度,経度,説明
休日急病診療所,35.132795,137.042009,日進市中央福祉センター内にある休日急病診療所です.
西部福祉会館,35.12599221,137.0147748,乳幼児室,学習室があります.
上記のCSV形式のデータをGeoJSON形式に変換すると下記になります. 少し複雑に見えますが,JSON形式に従っていることを確認してください. ここでは,空間データの種類を表す type に Point(点) を設定しています. Pointの他にも, LineString(線) , Polygon(多角形) などを指定することもできます. また,座標は coordinates で指定していますが,経度・緯度の順番であることに注意してください. その他,名称,説明などの情報は, properties に記載します.
geojson = {
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"geometry":
{
"type": "Point",
"coordinates": [137.042009,35.132795]
},
"properties":
{
"名称": "休日急病診療所",
"説明": "日進市中央福祉センター内にある休日急病診療所です."
}
},
{
"type": "Feature",
"geometry":
{
"type": "Point",
"coordinates": [137.0147748,35.12599221]
},
"properties":
{
"名称": "西部福祉会館",
"説明": "日進市中央福祉センター内にある休日急病診療所です."
}
}
]
}
print(geojson["features"][0])
print(geojson["features"][1])
{'type': 'Feature', 'geometry': {'type': 'Point', 'coordinates': [137.042009, 35.132795]}, 'properties': {'名称': '休日急病診療所', '説明': '日進市中央福祉センター内にある休日急病診療所です.'}}
{'type': 'Feature', 'geometry': {'type': 'Point', 'coordinates': [137.0147748, 35.12599221]}, 'properties': {'名称': '西部福祉会館', '説明': '日進市中央福祉センター内にある休日急病診療所です.'}}
今回はGeoJSON形式に変換したオープンデータとオープンストリートマップを組み合わせ, 前回と同様のオンライン地図を作成する方法について学習していきましょう.
GeoJSONの可視化
それでは,Google Colaboratoryを利用して,GeoJSON形式のデータを可視化してみましょう.
ノートブックの作成
まずは,ノートブックを作成します. ノートブックの名前は chapter4.ipynb に設定します.
前回利用したfoliumと,GeoJSONデータの取り込みが可能なGeoPandas,タイル地図の表示が可能なcontextilyをインストールします.
!pip install folium
!pip install geopandas
!pip install contextily
import folium
import geopandas as gpd
import contextily as cx
GeoJSON形式のデータの作成
geojson.ioを利用して,GeoJSON形式のデータを生成しましょう. 「日進市役所」をキーワードとして検索して,日進市の地図を表示してください. 画面右側にPoint(点),LineString(線),Polygon(多角形)を挿入するためのボタンがあります. このボタンを利用して,日進市役所を中心に,自由に空間オブジェクトを配置してみましょう.
下図は日進市役所の周辺にPoint(点),LineString(線),Polygon(多角形)が配置されています.
配置した空間オブジェクトを表すGeoJSON形式のデータは次のようになります.
変数geojson
にデータを追加していることに注意してください.
名称や説明などの情報をproperties
に追加することも可能です.
geojson = {
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"properties": {},
"geometry": {
"coordinates": [
137.03411692069665,
35.137951224356854
],
"type": "Point"
}
},
{
"type": "Feature",
"properties": {},
"geometry": {
"coordinates": [
[
137.04240293087713,
35.139557898285005
],
[
137.05239739676426,
35.13382961145339
]
],
"type": "LineString"
}
},
{
"type": "Feature",
"properties": {},
"geometry": {
"coordinates": [
[
[
137.0341974720302,
35.13038180316762
],
[
137.03936555054537,
35.128984539737644
],
[
137.0376998062303,
35.13101056388973
],
[
137.0341974720302,
35.13038180316762
]
]
],
"type": "Polygon"
}
}
]
}
オープンストリートマップの表示
表示する地図の中心を日進市役所の緯度・経度に設定します.
緯度は35.134
,軽度は137.040
に設定します.
また,スケール(倍率)は15
に設定します.
# 日進市役所の緯度・経度
lat = 35.134
lon = 137.040
# 地図の表示
map = folium.Map(location=[lat, lon], zoom_start=15)
map
上記で生成したGeoJSON形式のデータを,folium.Geojson()
を利用して地図に追加します.
地図に作成した点や線などのデータが追加されていることを確認してください.
# 日進市役所の緯度・経度
lat = 35.134
lon = 137.040
# 地図の表示
map = folium.Map(location=[lat, lon], zoom_start=15)
# GeoJSON形式のデータを地図に追加
folium.GeoJson(geojson).add_to(map)
map
日進市のバス停の可視化
次に日進市のバス停のオープンデータを地図上に表示してみましょう.
データフレーム(GeoPandas)
GeoPandasを利用して,GeoJSON形式のオープンデータbus_stops.geojsonを読み込みます. これは,日進市が公開しているCSV形式のバス停のオープンデータを,GeoJSON形式に変換したファイルです.
# bus_stops.geojson
url = "https://mukai-lab.info/classes/seminar_fundamental_areas/csv/bus_stops.geojson"
# GeoJSON用のデータフレームの生成
df = gpd.read_file(url)
# HTMLで表示(=display(df)))
df
オープンストリートマップの表示
表示する地図の中心を,全てのバス停の緯度・経度の平均に設定します.
データフレームから,geometryの列を取得し,経度x
と緯度y
の平均を求めます.
緯度は35.1372
,経度は137.0465
になりました.
center_lat = df["geometry"].y.mean()
center_lon = df["geometry"].x.mean()
print(f"center_lat={center_lat} center_lon={center_lon}")
center_lat=35.1372590495031 center_lon=137.04657202546582
先に計算した緯度・経度を中心として地図を表示します.
スケール(倍率)は15
に設定します.
map = folium.Map(location=[center_lat, center_lon], zoom_start=15)
map
GeoJSON形式のデータを表示するには,上述と同様にfolium.GeoJson()
を用い,
引数にはGeoPandasのデータフレームを指定します.
この結果,バス停がマーカーとして表示されていることを確認できます.
map = folium.Map(location=[center_lat, center_lon], zoom_start=15)
# データフレームをGeoJSON形式に変換して地図に追加
folium.GeoJson(df).add_to(map)
map
さらに,GeoJsonTooltip()
を利用して,バス停の名前をツールチップとして表示します.
GeoJSON形式のpropertiesに含まれるname
プロパティを,バス停の名前として参照するよう設定します.
マーカーをマウスでホバーすると,バス停の名前が表示されることがわかります.
map = folium.Map(location=[center_lat, center_lon], zoom_start=15)
tooltip = folium.features.GeoJsonTooltip(fields=["name"], labels=False)
folium.GeoJson(df, tooltip=tooltip).add_to(map)
map
GeoPandasの活用
GeoJSON形式を読み込んだGeoPandasのデータフレームを活用すると,地理情報に関する様々な処理が可能です.
距離の算出
データフレームの各レコードから,特定の緯度・経度までの距離(単位:メートル)を算出することが可能です. ここでは,データフレームから市役所のバス停のレコードを抽出し,各バス停から市役所のバス停までの距離を算出します.
from shapely.geometry import Point
df = df.to_crs(6675) # 直交座標系に変換
siyakusyo = df[df["name"]=="市役所"] # 市役所のレコードを抽出
point = Point(siyakusyo.geometry.x, siyakusyo.geometry.y)
df.distance(point) # 市役所までの距離を算出(単位:メートル)
データのプロット
データフレームの緯度・経度で表された点データをグラフをして表示するには,plot()
を実行するだけです.
グラフの横軸が経度,縦軸が緯度になっていることが確認できます.
df = df.to_crs(4326) # 世界測地系に変換
df.plot(figsize=(10, 10))
グラフの背景として,オープンストリートマップを表示させることができます.
データフレームの座標系をWebメルカトル(EPSG:3856)に変換してから,plot()
でグラフを作成します.
このグラフに対し,add_basemap()
でオープンストリートマップを背景に設定しています.
df = df.to_crs(epsg=3857) # Webメルカトルに変換
ax = df.plot(figsize=(10, 10))
cx.add_basemap(ax, source="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png")
課題
Google Colaboratoryで作成した chapter4.ipynb を保存し, ノートブック(.ipynb) をダウンロードして提出しなさい. 提出の前に必ず下記の設定を行うこと.
- ノートブックの設定で「セルの出力を除外する」のチェックを外す
- ノートブックの変更内容を保存して固定