オープンストリートマップの道路グラフを利用した経路探索

Image from Gyazo

オープンストリートマップの道路グラフ

オープンストリートマップは,エクスポート機能を利用することで,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 に設定します.

Image from Gyazo

地図を表示するための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)

Image from Gyazo

Foliumを利用して,オンライン地図と重ねて道路グラフを表示することもできます.

# オンライン地図と重ねて道路グラフを表示
ox.plot_graph_folium(graph)

Image from Gyazo

経路探索

取得した道路グラフから,始点と終点となるノードを選び,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)

Image from Gyazo

Foliumを利用して,オンライン地図と重ねて経路を表示しましょう.

# オンライン地図と重ねて経路を表示
ox.plot_route_folium(graph, route)

Image from Gyazo

建物情報のプロット

属性情報の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)

Image from Gyazo

取得した建物情報を表すGeoPandasのデータ形式を可視化します.

# 建物情報(集合住宅)を表示
ox.plot.plot_footprints(residences)

Image from Gyazo

同様に,retailを指定して,建物情報を取得しましょう. 「星ヶ丘三越」や「ヤマダ電機」などの店舗が取得できていることがわかります.

tags = {
    "building": ["retail"]
}

shops = ox.geometries.geometries_from_point((lat, lon), tags=tags, dist=1000)
display(shops)

Image from Gyazo

取得した建物情報を表すGeoPandasのデータ形式を可視化します.

# 建物情報(店舗)を表示
ox.plot.plot_footprints(shops)

Image from Gyazo

取得したデータは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

Image from Gyazo

課題

次の条件に従って経路探索してください.

Google Colaboratoryで作成した chapter5.ipynb を保存し, ノートブック(.ipynb) をダウンロードして提出しなさい. 提出の前に必ず下記の設定を行うこと.

参考書籍

愛知県名古屋市にある椙山女学園大学 文化情報学部 向研究室の公式サイトです. 専門は情報科学であり,人工知能やデータベースなどの技術要素を指導しています. この公式サイトでは,授業で使用している教材を公開すると共に, ベールに包まれた女子大教員のミステリアスな日常を4コマ漫画でお伝えしていきます. サイトに関するご意見やご質問はFacebookまたはTwitterでお問い合わせください.