地図のWikipedia！OpenStreetMapのデータをPythonで簡単にダウンロードできるPyrosmとleafmapを使ってみよう！

## OpenStreetMapって？

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/203944/8d04f5da-832e-36bb-bfc2-a30995572b95.png)

OpenStreetMap（以下、OSM）とは、誰でも自由に利用でき、なおかつ自分で編集することも可能な地図のWikipediaとも呼ばれるサービス・プロジェクトです。

OSMは例えば、自社サイトで本社の位置を示す時の背景地図として利用したり、検索機能を使って近隣のコンビニの位置を取得したり、登録された道路のデータを使って（めちゃくちゃ頑張れば）カーナビが作れたりするかもしれない、そういったプロジェクトになります。

印刷してプロジェクトの報告書の挿絵に使ったりもできます。
（GoogleMapは基本有料。）

細かい説明は検索すればいくらでも出てきますので、そちらの記事に任せるとして…そんなOSMのデータをPythonで直接ダウンロードし、GeoPandasのGeoDataFrameに変換してくれる便利なツール、「Pyrosm」を見つけたので紹介しつつleafmapで可視化していきます。

leafmapの説明などはこちら！
[Pythonのコードを1行書くだけで誰でも手軽にインタラクティブな地図アプリを作れるLeafmapを使ってみよう](https://qiita.com/nokonoko_1203/items/a287b1d48e91c23bb0c5)

## Pyrosmのダウンロード

公式サイトはこちらになります。
[Pyrosm](https://pyrosm.readthedocs.io/en/latest/index.html)

OSMでは`*.osm.pbf`という形式のバイナリファイルに全ての情報を格納しています。
*の部分にはasiaやjapanといった地域名が入るのですが、全て合わせると30Gをゆうに超えます。

データには道路網、建物、POI（Points of Interest）、土地利用、自然要素、行政境界など様々な要素が含まれており、Pyrosmではこのデータをダウンロードおよびフィルタリングなどの処理を（既存のツールに比べて遥かに）簡単に行うことのできます。

と、説明していても何が便利なのかさっぱりわからないと思うので、実際にインストールして使っていきましょう。

jupyterでPythonを利用していきますが、この記事では深く説明しませんが、基本的なセットアップは以下の記事を見ればできると思います！

- [MacでGISデータ分析を始めるためにサクッとAnacondaとjupyter labをインストールしてみる](https://qiita.com/nokonoko_1203/items/3b5ceb911af6b22a449f)
- [jupyter labで最低限これだけは入れとけっていう拡張機能の紹介！](https://qiita.com/nokonoko_1203/items/edd010616a74468ea531)
- [Pythonで地理空間情報（GIS）やるために必要なパッケージ全部入りの「geospatial」が便利すぎた](https://qiita.com/nokonoko_1203/items/55faf4455f7986080e59)
- [Pythonのコードを1行書くだけで誰でも手軽にインタラクティブな地図アプリを作れるLeafmapを使ってみよう](https://qiita.com/nokonoko_1203/items/a287b1d48e91c23bb0c5)

Pyrosmのインストールはこんな感じで行います。

```bash
conda install -c conda-forge pyrosm
```

## ダウンロード可能な地域を確認する

早速インポートしてデータをダウンロードしていきましょう。
と言いたいところですが、OSMのデータを初めて触る場合は、どんな地域のデータが存在しているのか知らないですよね。

Pyrosmからこのように確認できます。

```python
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`など大陸レベルでデータが分かれているようですね。
もっと細かい区分けはないんでしょうか？
どんどん深ぼっていきましょう。

```python
# もっと詳細を見る
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が格納されていますね。こちらのデータをダウンロードしていきましょう。

```python
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`を指定することで、ファイルを更新できます。

```python
from pyrosm import OSM, get_data

file_path = get_data("kanto", directory="./")

file_path = get_data("kanto", update=True)
```

実行すると、`kanto-latest.osm.pbf`がダウンロードされるほか、戻り値としてファイルパスが返ります。

このファイルパスをOSMクラスのイニシャライザに格納してインスタンスを作りましょう。

```python
osm = OSM("kanto-latest.osm.pbf")
```

このインスタンスの`get_buildings`メソッドなどを利用することで、関東全域の建物データを取得することができますが、それなりに大きなサイズになってしまうので、行政界のポリゴンを利用して領域を絞っていきましょう！

## 東京都の行政界をダウンロードして中身を確認する

各府省の統計情報を統合し公開している[e-Stat](https://www.e-stat.go.jp/)というサイトがあります。
詳しくはこちら。

- [政府統計の総合窓口「e-Stat」のAPIを使って市区町村の境界データと目的の統計データをマージするツールを公開！](https://qiita.com/nokonoko_1203/items/a6a37c943e90a57227c2)

このe-Statでは東京都の行政界をshapefileで公開していますので、そちらを利用していきましょう。
以下のようにダウンロードすることができます。

```python
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を使ってどんなデータか見てみましょう。
データ量を減らしたいので、`恵比寿一丁目`のポリゴンだけにフィルタリングしていきます。

```python
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を利用して可視化してみましょう！

```python
%%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
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/203944/134035dd-3698-710e-aae6-3593ebd4ee3c.png)

ちゃんと出てきましたね！

## 渋谷区全体のポリゴンを作成する

`渋谷区`でフィルタリングをしてみると、〇〇丁目のようなレコードがたくさん見つかり、80レコードほどヒットします。

```python
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になります。

```python
shibuya = gdf[gdf["CITY_NAME"] == "渋谷区"]["geometry"].unary_union
type(shibuya)
# shapely.geometry.polygon.Polygon
```

## OSMのデータをフィルタリング

このポリゴンを使ってフィルタリングしていきましょう。
フィルタリングする際にはbounding_boxにポリゴンを格納します。
結果、28000件超の建物が取得できました。

```python
# リーダーを再定義
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	Ｔ．ＦＬＡＴ表参道	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のデータを可視化

```python
map = leafmap.Map(zoom=18)
map.add_gdf(shibuya_convenience, style=style, hover_style=hover_style)
map
```

![スクリーンショット 2022-06-30 22.14.37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/203944/c0ba9bfd-ccff-2b67-999c-e93ecb2710bd.png)

できましたね！！！

## 終わりに

jupyter/Pyrosm/leafmapの組み合わせを使うことで手軽にOSMをダウンロード・編集・可視化を行うことができます！
めちゃ便利なのでみなさん使ってみてくださいね！