OpenStreetMapって?
OpenStreetMap(以下、OSM)とは、誰でも自由に利用でき、なおかつ自分で編集することも可能な地図のWikipediaとも呼ばれるサービス・プロジェクトです。
OSMは例えば、自社サイトで本社の位置を示す時の背景地図として利用したり、検索機能を使って近隣のコンビニの位置を取得したり、登録された道路のデータを使って(めちゃくちゃ頑張れば)カーナビが作れたりするかもしれない、そういったプロジェクトになります。
印刷してプロジェクトの報告書の挿絵に使ったりもできます。
(GoogleMapは基本有料。)
細かい説明は検索すればいくらでも出てきますので、そちらの記事に任せるとして…そんなOSMのデータをPythonで直接ダウンロードし、GeoPandasのGeoDataFrameに変換してくれる便利なツール、「Pyrosm」を見つけたので紹介しつつleafmapで可視化していきます。
leafmapの説明などはこちら!
Pythonのコードを1行書くだけで誰でも手軽にインタラクティブな地図アプリを作れるLeafmapを使ってみよう
Pyrosmのダウンロード
公式サイトはこちらになります。
Pyrosm
OSMでは*.osm.pbf
という形式のバイナリファイルに全ての情報を格納しています。
*の部分にはasiaやjapanといった地域名が入るのですが、全て合わせると30Gをゆうに超えます。
データには道路網、建物、POI(Points of Interest)、土地利用、自然要素、行政境界など様々な要素が含まれており、Pyrosmではこのデータをダウンロードおよびフィルタリングなどの処理を(既存のツールに比べて遥かに)簡単に行うことのできます。
と、説明していても何が便利なのかさっぱりわからないと思うので、実際にインストールして使っていきましょう。
jupyterでPythonを利用していきますが、この記事では深く説明しませんが、基本的なセットアップは以下の記事を見ればできると思います!
- MacでGISデータ分析を始めるためにサクッとAnacondaとjupyter labをインストールしてみる
- jupyter labで最低限これだけは入れとけっていう拡張機能の紹介!
- Pythonで地理空間情報(GIS)やるために必要なパッケージ全部入りの「geospatial」が便利すぎた
- Pythonのコードを1行書くだけで誰でも手軽にインタラクティブな地図アプリを作れるLeafmapを使ってみよう
Pyrosmのインストールはこんな感じで行います。
conda install -c conda-forge pyrosm
ダウンロード可能な地域を確認する
早速インポートしてデータをダウンロードしていきましょう。
と言いたいところですが、OSMのデータを初めて触る場合は、どんな地域のデータが存在しているのか知らないですよね。
Pyrosmからこのように確認できます。
from pyrosm.data import sources
sources.available.keys()
# dict_keys(['africa', 'antarctica', 'asia', 'australia_oceania', 'central_america', 'europe', 'north_america', 'south_america', 'cities', 'subregions'])
africa
やasia
など大陸レベルでデータが分かれているようですね。
もっと細かい区分けはないんでしょうか?
どんどん深ぼっていきましょう。
# もっと詳細を見る
sources.asia.available
# ['afghanistan',
# 'armenia',
# 'azerbaijan',
# 'bangladesh',
# 'bhutan',
# 'cambodia',
# 'china',
# 'gcc_states',
# 'india',
# 'indonesia',
# 'iran',
# 'iraq',
# 'israel_and_palestine',
# 'japan',
# 'jordan',
# 'kazakhstan',
# 'kyrgyzstan',
# 'laos',
# 'lebanon',
# 'malaysia_singapore_brunei',
# 'maldives',
# 'mongolia',
# 'myanmar',
# 'nepal',
# 'north_korea',
# 'pakistan',
# 'philippines',
# 'south_korea',
# 'sri_lanka',
# 'syria',
# 'taiwan',
# 'tajikistan',
# 'thailand',
# 'turkmenistan',
# 'uzbekistan',
# 'vietnam',
# 'yemen']
# もっともっと詳細を見る
sources.asia.japan.available
# ['chubu',
# 'chugoku',
# 'hokkaido',
# 'kansai',
# 'kanto',
# 'kyushu',
# 'shikoku',
# 'tohoku']
# さらに詳細を取得しようとするとエラー
sources.asia.japan.kanto.available
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
File <timed eval>:2, in <module>
AttributeError: 'dict' object has no attribute 'available'
asia->japan->kantoと深ぼっていき、さらに詳細を取得しようとするとエラーが出てしまいましたね。
ということで日本の領域で一番小さい区分けは関東や四国などの区分けのようです。
kantoを指定すると、ファイル名とURLが格納されていますね。こちらのデータをダウンロードしていきましょう。
sources.asia.japan.kanto
# {'name': 'kanto-latest.osm.pbf',
# 'url': 'http://download.geofabrik.de/asia/japan/kanto-latest.osm.pbf'}
OSMのデータをダウンロードしてみる
データは以下のように、ダウンロードしたい地域をget_data
関数の第一引数に入れて実行することでダウンロードできます。
デフォルトでは/tmp/pyrosm/
以下にダウンロードされてしまうので、ディレクトリを指定して、保存ディレクトリを変更できます。
また、ダウンロードしたファイルは当然再利用可能で、upload=True
を指定することで、ファイルを更新できます。
from pyrosm import OSM, get_data
file_path = get_data("kanto", directory="./")
file_path = get_data("kanto", update=True)
実行すると、kanto-latest.osm.pbf
がダウンロードされるほか、戻り値としてファイルパスが返ります。
このファイルパスをOSMクラスのイニシャライザに格納してインスタンスを作りましょう。
osm = OSM("kanto-latest.osm.pbf")
このインスタンスのget_buildings
メソッドなどを利用することで、関東全域の建物データを取得することができますが、それなりに大きなサイズになってしまうので、行政界のポリゴンを利用して領域を絞っていきましょう!
東京都の行政界をダウンロードして中身を確認する
各府省の統計情報を統合し公開しているe-Statというサイトがあります。
詳しくはこちら。
このe-Statでは東京都の行政界をshapefileで公開していますので、そちらを利用していきましょう。
以下のようにダウンロードすることができます。
import download
download.download(
"https://www.e-stat.go.jp/gis/statmap-search/data?dlserveyId=A002005212020&code=13&coordSys=1&format=shape&downloadType=5&datum=2000",
"tokyo",
kind="zip",
replace=True,
)
こうすると、tokyoディレクトリの中にr2ka13.shp
というファイルが入っているかと思います。
GeoPandasを使ってどんなデータか見てみましょう。
データ量を減らしたいので、恵比寿一丁目
のポリゴンだけにフィルタリングしていきます。
import geopandas
shp_path = "./tokyo/r2ka13.shp"
gdf = geopandas.read_file(shp_path)
ebisu_1 = gdf[gdf["S_NAME"] == "恵比寿一丁目"]
ebisu_1
# KEY_CODE PREF CITY S_AREA PREF_NAME CITY_NAME S_NAME KIGO_E HCODE AREA ... N_KEN N_CITY KIGO_I KBSUM JINKO SETAI X_CODE Y_CODE KCODE1 geometry
# 1686 13113001001 13 113 001001 東京都 渋谷区 恵比寿一丁目 None 8101 152575.858 ... None None None 65 4497 3043 139.713784 35.647161 0010-01 POLYGON ((139.71457 35.64793, 139.71495 35.647...
# 1 rows × 30 columns
このように、都道府県・市区町村・町丁目などのほか面積などの情報も格納されています。
一度leafmapを利用して可視化してみましょう!
%%time
import leafmap
map = leafmap.Map(zoom=17)
# 表示スタイルを定義
style = {
"stroke": True,
"color": "#0000ff",
"weight": 2,
"opacity": 1,
"fill": True,
"fillColor": "#0000ff",
"fillOpacity": 0.1,
}
hover_style = {"fillOpacity": 0.7}
# 恵比寿一丁目のポリゴンを表示してみる
map.add_gdf(ebisu_1, style=style, hover_style=hover_style)
map
ちゃんと出てきましたね!
渋谷区全体のポリゴンを作成する
渋谷区
でフィルタリングをしてみると、〇〇丁目のようなレコードがたくさん見つかり、80レコードほどヒットします。
shibuya = gdf[gdf["CITY_NAME"] == "渋谷区"]
shibuya
# KEY_CODE PREF CITY S_AREA PREF_NAME CITY_NAME S_NAME KIGO_E HCODE AREA ... N_KEN N_CITY KIGO_I KBSUM JINKO SETAI X_CODE Y_CODE KCODE1 geometry
# 1686 13113001001 13 113 001001 東京都 渋谷区 恵比寿一丁目 None 8101 152575.858 ... None None None 65 4497 3043 139.713784 35.647161 0010-01 POLYGON ((139.71457 35.64793, 139.71495 35.647...
# 1687 13113001002 13 113 001002 東京都 渋谷区 恵比寿二丁目 None 8101 174058.395 ... None None None 69 4543 2980 139.720196 35.646523 0010-02 POLYGON ((139.72309 35.64582, 139.72308 35.645...
# 1688 13113001003 13 113 001003 東京都 渋谷区 恵比寿三丁目 None 8101 188298.437 ... None None None 67 5120 3177 139.718265 35.643642 0010-03 POLYGON ((139.71777 35.64544, 139.71903 35.645...
# 1689 13113001004 13 113 001004 東京都 渋谷区 恵比寿四丁目 None 8101 177286.069 ... None None None 44 2802 1853 139.713156 35.644560 0010-04 POLYGON ((139.70967 35.64784, 139.70986 35.647...
# 1690 13113002001 13 113 002001 東京都 渋谷区 広尾一丁目 None 8101 121664.492 ... None None None 43 3224 2168 139.714018 35.649136 0020-01 POLYGON ((139.71473 35.64940, 139.71476 35.649...
# ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ...
# 1761 13113032002 13 113 032002 東京都 渋谷区 神宮前二丁目 None 8101 215165.344 ... None None None 59 3597 2264 139.711661 35.673712 0320-02 POLYGON ((139.71271 35.67492, 139.71270 35.674...
# 1762 13113032003 13 113 032003 東京都 渋谷区 神宮前三丁目 None 8101 216376.383 ... None None None 54 3156 1816 139.711154 35.670717 0320-03 POLYGON ((139.71368 35.67221, 139.71377 35.672...
# 1763 13113032004 13 113 032004 東京都 渋谷区 神宮前四丁目 None 8101 152375.090 ... None None None 35 1152 688 139.709340 35.668263 0320-04 POLYGON ((139.70829 35.66972, 139.70871 35.669...
# 1764 13113032005 13 113 032005 東京都 渋谷区 神宮前五丁目 None 8101 257466.734 ... None None None 58 1947 1021 139.707148 35.664657 0320-05 POLYGON ((139.71068 35.66620, 139.71091 35.666...
# 1765 13113032006 13 113 032006 東京都 渋谷区 神宮前六丁目 None 8101 212207.414 ... None None None 43 869 452 139.703477 35.666629 0320-06 POLYGON ((139.70300 35.66993, 139.70314 35.669...
# 80 rows × 30 columns
これだとOSMデータのフィルタリングに都合が悪いので、80レコード分のポリゴンをマージしてしまいましょう。
マージ後はshapelyのPolygonになります。
shibuya = gdf[gdf["CITY_NAME"] == "渋谷区"]["geometry"].unary_union
type(shibuya)
# shapely.geometry.polygon.Polygon
OSMのデータをフィルタリング
このポリゴンを使ってフィルタリングしていきましょう。
フィルタリングする際にはbounding_boxにポリゴンを格納します。
結果、28000件超の建物が取得できました。
# リーダーを再定義
osm = OSM("kanto-latest.osm.pbf", bounding_box=shibuya)
# 渋谷区の建物を取得
shibuya_convenience = osm.get_buildings()
shibuya_convenience
# addr:city addr:country addr:full addr:housenumber addr:housename addr:postcode addr:street email name opening_hours ... source start_date wikipedia id timestamp version tags osm_type geometry changeset
# 0 None None None None None None None None 住友不動産原宿ビル None ... None None None 28009908 1545055621 4 {"layer":"1","name:en":"Sumitomo Fudosan Haraj... way POLYGON ((139.70757 35.67419, 139.70773 35.673... NaN
# 1 None None None None None None None None 渋谷区立社会教育館 None ... Bing,2007-04 None None 30780468 1600938253 3 None way POLYGON ((139.70642 35.64700, 139.70625 35.646... NaN
# 2 None None None None None None None None None None ... None None None 43837863 1257419751 2 None way POLYGON ((139.68729 35.66161, 139.68723 35.661... NaN
# 3 None None None None None None None None セルリアンタワー None ... None None None 55441040 1641098343 9 {"emergency":"assembly_point:unable_to_move=ye... way POLYGON ((139.69869 35.65635, 139.69886 35.656... NaN
# 4 None None None None None None None None 渋谷クロスタワー None ... None None ja:渋谷クロスタワー 55441047 1630868132 6 {"name:en":"Shibuya Cross Tower","name:es":"Sh... way POLYGON ((139.70507 35.65874, 139.70539 35.658... NaN
# ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ...
# 28467 None NaN NaN None NaN None NaN NaN 新国立劇場 None ... None None None 31425927052 1558531686 2 {"type":"multipolygon"} relation POLYGON ((139.68578 35.68343, 139.68579 35.683... 0.0
# 28468 None NaN NaN None NaN None NaN NaN 国立競技場 None ... None None ja:新国立競技場 13039933871 1625100155 7 {"leisure":"stadium","name:en":"National Stadi... relation POLYGON ((139.71420 35.67917, 139.71407 35.679... 0.0
# 28469 None NaN NaN None NaN None NaN NaN None None ... None None None 32688313477 1584717142 1 {"type":"multipolygon"} relation POLYGON ((139.68560 35.67386, 139.68589 35.673... 0.0
# 28470 None NaN NaN None NaN None NaN NaN AbemaTowers None ... None None None 64455555404 1642860214 2 {"name:ja":"\u30A2\u30D9\u30DE\u30BF\u30EF\u30... relation POLYGON ((139.69662 35.66246, 139.69620 35.662... 0.0
# 28471 渋谷区 NaN NaN 9 NaN 150-0001 NaN NaN T.FLAT表参道 None ... None 2013-08 None 98227791711 1656148608 2 {"addr:block_number":"16","addr:neighbourhood"... relation POLYGON ((139.70619 35.66580, 139.70627 35.665... 0.0
# 28472 rows × 38 columns
leafmapでOSMのデータを可視化
map = leafmap.Map(zoom=18)
map.add_gdf(shibuya_convenience, style=style, hover_style=hover_style)
map
できましたね!!!
終わりに
jupyter/Pyrosm/leafmapの組み合わせを使うことで手軽にOSMをダウンロード・編集・可視化を行うことができます!
めちゃ便利なのでみなさん使ってみてくださいね!