Folium: Pythonでデータを地図上に可視化

[Folium](https://github.com/python-visualization/folium)はデータを地図上に可視化するライブラリです。

JavaScriptの[Leaflet](http://leafletjs.com/)という
対話的な地図への処理をサポートするライブラリがあり
Foliumはこのライブラリをパースし、Pythonで使えるようにしたものといえます。

## 環境構築

[公式ページ](http://python-visualization.github.io/folium/installing.html)で対応バージョンなどがつかめませんでしたが
[pypi](https://pypi.python.org/pypi/folium)でカテゴリを見た感じだと、2系でも3系でも動きそうです。

ある程度新しいPythonの環境で以下のコマンドを実行。'Easiest'です。

```bash:foliumのインストール
$ pip install folium
```

環境を汚したくない場合はvenvなどで事前に分離してください。
私は使い捨てのコンテナを立てました。

```Dockerfile
FROM python:3.5.2-alpine

RUN pip install folium
```

```bash:コンテナの起動
# カレントディレクトリのDockerfileでfoliumイメージを作成
docker build -t folium . 

# foliumイメージからコンテナを起動
docker run -it -v /home/nanakenashi/workspace:/workspace folium /bin/sh
```

Foliumから吐き出すhtmlファイルを参照するため
カレントディレクトリ（workspace）をコンテナ内にマウントしています。

## 試してみる

[QuickStart](http://python-visualization.github.io/folium/quickstart.html)にお世話になります。
まずはPythonの対話シェルを起動し、foliumを読み込みます。

```bash:下準備
$ python
Python 3.5.2 (default, Nov 17 2016, 22:46:45)
[GCC 5.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>>
>>> import folium
```

### 地図を作ってみる

座標とズームレベルを片手に`Map`オブジェクトを作成し、名前を付けて保存します。
ズームレベルは数値が大きいほどアップになっていきます。

```python:地図の作成と保存
>>> map1 = folium.Map(location=[-30.159215, 138.955078], zoom_start=4)
>>> map1.save('/workspace/map1.html')
```

保存したhtmlファイルをブラウザで開いてみます。

![map_html.png](https://qiita-image-store.s3.amazonaws.com/0/43116/125640d3-6242-e979-abf5-dbc88eea3f61.png "map_html.png")

`location`に指定した座標は中心じゃなかったんだろうかと
中心からズレたオーストラリアを見て思いましたが、先へ進みます。

### マーカーを置いてみる

```python:マーカーの追加
>>> map2 = folium.Map(location=[-30.159215, 138.955078], zoom_start=4)
>>> folium.Marker([-31.253218, 146.921099], popup='New South Wales').add_to(map2)
<folium.map.Marker object at 0x7fc1c73bd048>
>>> map2.save('/workspace/map2.html')
```

保存したmap2.htmlを開いてみます。

![map2_html.png](https://qiita-image-store.s3.amazonaws.com/0/43116/57f5ae8f-15f8-d5cd-4444-05ec45bd7d3b.png "map2_html.png")

マーカーが出現しました。
ちなみにクリックすると`popup`で指定した文字列が表示されます。

![marker.png](https://qiita-image-store.s3.amazonaws.com/0/43116/6234574e-04bd-70e0-a828-0215954d3d6f.png "marker.png")


### 可視化っぽいことをしてみる

Quickstartの中だけでも様々な可視化オプションが使用されていますが
今回は円形のマーカーに着目して何かを出してみます。
まずは試しに。

```python:円形のマーカーを表示
>>> map3 = folium.Map(location=[-30.159215, 138.955078], zoom_start=4)                                                                             
>>> folium.CircleMarker([-31.253218, 146.921099],
...                     radius=100000,
...                     popup='New South Wales',
...                     color='#3186cc',
...                     fill_color='#3186cc',
...                    ).add_to(map3)
<folium.features.CircleMarker object at 0x7fc1c7408a20>
>>> map3.save('/workspace/map3.html')
```

map3をブラウザで開きます。

![map3_html.png](https://qiita-image-store.s3.amazonaws.com/0/43116/4ec577dd-7d63-5cd1-d441-8fb011f9ba91.png "map3_html.png")

`radius`で数量を表せそうなので、何らかの数値を都市ごとに反映してみます。
ここまで来るとインタラクティブな必要もないのでスクリプトを書きます。

```python:都市ごとにマーカーを配置
import folium

map4 = folium.Map(location=[-30.159215, 138.955078], zoom_start=4)

# 各都市のデータを格納（本来はDBやcsvファイルから取得）
states = (
    {'lat': -35.473468, 'lon': 149.012368, 'value': 1, 'name': 'Australian Capital Territory'},
    {'lat': -31.253218, 'lon': 146.921099, 'value': 2, 'name': 'New South Wales'},
    {'lat': -19.491411, 'lon': 132.550960, 'value': 3, 'name': 'Northern Territory'},
    {'lat': -20.917574, 'lon': 142.702796, 'value': 4, 'name': 'Queensland'},
    {'lat': -30.000232, 'lon': 136.209155, 'value': 5, 'name': 'South Australia'},
    {'lat': -41.454520, 'lon': 145.970665, 'value': 6, 'name': 'Tasmania'},
    {'lat': -37.471308, 'lon': 144.785153, 'value': 7, 'name': 'Victoria'},
    {'lat': -27.672817, 'lon': 121.628310, 'value': 8, 'name': 'Western Australia'}
)

# 円の大きさをわかりやすくするための重み
WEIGHT = 100000

# 都市ごとにマーカーを追加（数が増えると辛いため、一括追加が今後の課題）
for state in states:
    folium.CircleMarker(
            [state['lat'], state['lon']],
            radius=state['value'] * WEIGHT,
            popup=state['name'],
            color='#3186cc',
            fill_color='#3186cc',
    ).add_to(map4)

map4.save('/workspace/map4.html')
```

上記のスクリプトを実行後、map4.htmlをブラウザで表示します。

![map4_html.png](https://qiita-image-store.s3.amazonaws.com/0/43116/be358449-a77b-2a20-c963-20d18343e852.png "map4_html.png")

QuickStartの内容だけでも、なんとなくそれっぽい感じになりました。
もっとがっつり使うのであれば、Foliumのドキュメントに
元となった[Leafletのドキュメント](http://leafletjs.com/reference-1.0.2.html)も合わせてチェックするのが良さそうです。

## まとめ

サービスで提供する場合はGoogleMapsを使うことが多いと思いますが
調査や内部の提供であればこのようなライブラリも便利です。
記事中ではマーカーを置くまでの表層的な可視化に留まりましたが
地図自体の編集やポリゴンの配置など、様々な表現ができます。

Jupyter Notebookを使えばもっと対話的に分析ができるようなので
使ったことのある方は是非試してみてください。