オープンストリートマップの道路グラフを利用した経路探索
オープンストリートマップの道路グラフ
オープンストリートマップは,エクスポート機能を利用することで,OSMという専用のファイル形式でデータをダウンロードすることができます (ライセンスはOpen Database License (ODbL)). OSMはマークアップ言語のXML(Extensible Markup Language)で記述されており,道路グラフのノードを表す node や,属性を表す tag などの要素で構成されています. 例えば椙山女学園大学の文化情報学部を表すノードは次のように記述されています. これらのデータを利用することで,地図上の2点間の経路を探索することができます. ここでは,PythonライブラリのOSMnxを利用して,椙山女学園大学の周辺の道路グラフを取得し,任意の2点間の経路探索に挑戦します.
<node id="1423989393" visible="true" version="2" changeset="100839679" timestamp="2021-03-11T11:46:43Z" user="Psjk2106" uid="6909898" lat="35.1587968" lon="136.9874163">
<tag k="amenity" v="university"/>
<tag k="name" v="椙山女学園大学(文化情報学部)"/>
<tag k="note" v="National-Land Numerical Information (Public Facility) 2006, MLIT Japan"/>
<tag k="note:ja" v="国土数値情報(公共施設データ)平成19年 国土交通省"/>
<tag k="source" v="KSJ2"/>
<tag k="source_ref" v="http://nlftp.mlit.go.jp/ksj/jpgis/datalist/KsjTmplt-P02-v2_0.html"/>
</node>
道路グラフのプロット
それでは,Google Colaboratoryを利用して,オープンストリートマップの道路グラフを取得してみましょう.
ノートブックの作成
まずは,ノートブックを作成します. ノートブックの名前は chapter5.ipynb に設定します.
地図を表示するためのfolium,オープンストリートマップのデータを取得するためのOSMnx,さらに経路探索に必要なscikit-learnをインストールします.
!pip install folium
!pip install osmnx
!pip install scikit-learn # インポートに失敗する場合は削除
import folium
import geopandas as gpd
import pandas as pd
import osmnx as ox
import numpy as np
from sklearn import *
道路グラフの取得
ジオコーディング を利用して,椙山女学園大学の緯度・経度を取得します. ジオコーディングとは,住所や地名から対応する緯度・経度に変換することを意味します.
# ジオコーディングで緯度・経度を取得(星ヶ丘キャンパス)
lat, lon = ox.geocoder.geocode("椙山女学園大学")
print(f"lat={lat} lon={lon}")
lat=35.160005549999994 lon=136.9875383967455
取得した緯度・経度を利用して,周辺の道路グラフを取得します.
取得するデータの範囲はdist
で指定します.
ここでは,dist=1000
を指定し,中心座標から1,000メートルのデータを取得しています.
取得したデータはノード数(交差点)が800,エッジ数(道路)が2203で構成されていることがわかります.
また,MultiDiGraph は多重有向グラフを表し,2点のノード間に複数のエッジが存在する可能性があること(多重辺),また,エッジには向きがあること(有向辺)を意味しています
(MultiDiGraphはNetwrokXのクラス).
# 道路グラフの取得
graph = ox.graph.graph_from_point((lat, lon), dist=1000)
print(graph)
MultiDiGraph with 800 nodes and 2203 edges
それでは,取得した道路グラフを可視化してみましょう.
# 道路グラフを表示
ox.plot_graph(graph)
Foliumを利用して,オンライン地図と重ねて道路グラフを表示することもできます.
# オンライン地図と重ねて道路グラフを表示
ox.plot_graph_folium(graph)
経路探索
取得した道路グラフから,始点と終点となるノードを選び,2点間の経路探索をしてみましょう.
始点は椙山女学園大学に最も近いノードとします.
任意の緯度・経度から最も近いノードのIDを検索するにはnearest_nodes()
を利用します.
始点のノードIDとして1906955364
が選択されました.
# 始点(星ヶ丘キャンパス)
start_lat, start_lon = ox.geocoder.geocode("椙山女学園大学")
start_id = ox.distance.nearest_nodes(graph, start_lon, start_lat)
print(start_id)
print(graph.nodes[start_id])
1906955364
1906955364
{'y': 35.1599814, 'x': 136.9873455, 'street_count': 3}
同様に終点は星ヶ丘駅に最も近いノードとします.
終点のノードIDとして648692862
が選択されました.
# 終点(星ヶ丘駅)
goal_lat, goal_lon = ox.geocoder.geocode("星ヶ丘駅")
goal_id = ox.distance.nearest_nodes(graph, goal_lon, goal_lat)
print(goal_id)
print(graph.nodes[goal_id])
648692862
{'y': 35.1627781, 'x': 136.9858763, 'highway': 'traffic_signals', 'street_count': 4}
上記の始点と終点で経路探索します. 経路はノードIDのリストで与えられます.
# 経路探索
route = ox.distance.shortest_path(graph, start_id, goal_id)
print(route)
[1906955364, 648692839, 2748834444, 5715309843, 5715309842, 7985515453, 5750754052, 7985515458, 648692837, 648692852, 648692853, 602231740, 648692862]
それでは,探索された経路を可視化しましょう.
# 道路グラフと経路を表示
ox.plot_graph_route(graph, route)
Foliumを利用して,オンライン地図と重ねて経路を表示しましょう.
# オンライン地図と重ねて経路を表示
ox.plot_route_folium(graph, route)
建物情報のプロット
属性情報のtag
を利用して,建物情報をGeoPandasのデータ形式で取得することができます.
建物はbuilding
キーで表され,その建物の用途を表すバリューで区別されます(詳細はWikiを参照すること).
例えば,apartments
は集合住宅(アパートやマンション),retail
は物品販売を目的とした店舗を表します(例,<tag k="building v="apartments">
).
それでは,apartments
を指定して,建物情報を取得しましょう.
「アーバンラフレ星ヶ丘」や,「サンハウス西山」などの集合住宅が取得できていることがわかります.
tags = {
"building": ["apartments"]
}
residences = ox.geometries.geometries_from_point((lat, lon), tags=tags, dist=1000)
display(residences)
取得した建物情報を表すGeoPandasのデータ形式を可視化します.
# 建物情報(集合住宅)を表示
ox.plot.plot_footprints(residences)
同様に,retail
を指定して,建物情報を取得しましょう.
「星ヶ丘三越」や「ヤマダ電機」などの店舗が取得できていることがわかります.
tags = {
"building": ["retail"]
}
shops = ox.geometries.geometries_from_point((lat, lon), tags=tags, dist=1000)
display(shops)
取得した建物情報を表すGeoPandasのデータ形式を可視化します.
# 建物情報(店舗)を表示
ox.plot.plot_footprints(shops)
取得したデータはGeoPandasのデータ形式であるため,Foliumにそのままデータを渡して,オンライン地図を表示することもできます.
map = folium.Map(location=[lat, lon], zoom_start=15)
# データフレームをGeoJSON形式に変換して地図に追加
folium.GeoJson(residences).add_to(map)
folium.GeoJson(shops).add_to(map)
map
課題
次の条件に従って経路探索してください.
- 京都駅から2000メートルの範囲の道路グラフを取得
- 京都駅から清水寺までの経路を探索
plot_route_folium()
を利用して経路を可視化
Google Colaboratoryで作成した chapter5.ipynb を保存し, ノートブック(.ipynb) をダウンロードして提出しなさい. 提出の前に必ず下記の設定を行うこと.
- ノートブックの設定で「セルの出力を除外する」のチェックを外す
- ノートブックの変更内容を保存して固定