folium 事始め

#記事の目的
Foliumを使うときに同じサイトを見る確率が高い？のでまとめました。

追記：
* タイトルがややこしいので変更
* 指摘いただいたコメントの反映

# 概要
[Leaflet.js](http://leafletjs.com/)をPythonで利用するためのライブラリです。
Pythonで計算・加工したデータをマップ(html形式)へ落とし込むことが可能です。

GitHub:
https://github.com/python-visualization/folium

Document:
http://python-visualization.github.io/folium/docs-v0.5.0/

#インストール方法

## インストール要件
pythonの下記ライブラリが必要です。

**必須**

- branca
- jinja2
- requests
- six


**使用する機能により必要**

- numpy
- pandas
- geopandas
- altair
etc ...

## インストール方法
```
 pip install folium
```

```
 conda install folium -c conda-forge
```

# 基本的な使い方
## 1. 東京駅を中心とした地図を作製
v0.2.0では表示されていましたが、v0.5.0ではデフォルトの出力だとコピーライトが表示されなくなりました。
attrでコピーライトを指定する必要があります。

```py
import folium

copyright_osm = '&copy; <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'

_map = folium.Map(location=[35.681167, 139.767052],
  attr=copyright_osm,
)

_map.save('sample1.html')

```
![001.jpg](https://qiita-image-store.s3.amazonaws.com/0/157364/22938af8-14d9-a042-3b60-0aa99b9a0ab7.jpeg)

Jupyterで憑依する場合は```_map```と変数だけ呼び出せば表示されます。

## 2. 地図タイルの変更
地図タイルは変更可能です。

下記は組込みでタイル指定が可能なものの一覧です。

- “OpenStreetMap”
- “Mapbox Bright” (Limited levels of zoom for free tiles)
- “Mapbox Control Room” (Limited levels of zoom for free tiles)
- “Stamen” (Terrain, Toner, and Watercolor)


下記は組込みでタイル指定が可能なものですが、API Keyが必要です。

* “Cloudmade” (Must pass API key)
* “Mapbox” (Must pass API key)
* “CartoDB” (positron and dark_matter)

**※地図タイルを変更する際はコピーライトも併せて変更する必要があります。**

```py
import folium

#Stamen Tonerのコピーライト
copyright_st = '&copy; ' \
            'Map tiles by <a href="http://stamen.com">Stamen Design</a>,' \
            ' under <a href="http://creativecommons.org/licenses/by/3.0">CC BY 3.0</a>.' \
            'Data by <a href="http://openstreetmap.org">OpenStreetMap</a>,' \
            'under <a href="http://www.openstreetmap.org/copyright">ODbL</a>.'

_map = folium.Map(location=[35.681167, 139.767052],
                  attr=copyright_st,
                  tiles='Stamen Toner')

_map.save('sample2.html')
```
![002.jpg](https://qiita-image-store.s3.amazonaws.com/0/157364/d17729b3-a0fc-54b8-24f2-0011f5a9408d.jpeg)


地図タイルはフォーマットされたURL **[http://{s}.tiles.yourtiles.com/{z}/{x}/{y}.png]**での指定も可能です。

```py
import folium

#Stamen Tonerのコピーライト
copyright_st = '&copy; ' \
            'Map tiles by <a href="http://stamen.com">Stamen Design</a>,' \
            ' under <a href="http://creativecommons.org/licenses/by/3.0">CC BY 3.0</a>.' \
            'Data by <a href="http://openstreetmap.org">OpenStreetMap</a>,' \
            'under <a href="http://www.openstreetmap.org/copyright">ODbL</a>.'

_map = folium.Map(location=[35.681167, 139.767052],
                  attr=copyright_st,
                  tiles='https://stamen-tiles-{s}.a.ssl.fastly.net/toner-lite/{z}/{x}/{y}.png')

_map.save('sample3.html')
```
![003.jpg](https://qiita-image-store.s3.amazonaws.com/0/157364/67383e61-aaf7-5074-e08e-4106b0846b6e.jpeg)



## 3. Markerの設置
```py
import folium

#Stamen Tonerのコピーライト
copyright_st = '&copy; ' \
            'Map tiles by <a href="http://stamen.com">Stamen Design</a>,' \
            ' under <a href="http://creativecommons.org/licenses/by/3.0">CC BY 3.0</a>.' \
            'Data by <a href="http://openstreetmap.org">OpenStreetMap</a>,' \
            'under <a href="http://www.openstreetmap.org/copyright">ODbL</a>.'

_map = folium.Map(location=[35.681167, 139.767052],
                  attr=copyright_st,
                  tiles='https://stamen-tiles-{s}.a.ssl.fastly.net/toner-lite/{z}/{x}/{y}.png')

#MarkerをMapping
folium.Marker([35.681167, 139.767052], popup='<i>東京駅</i>').add_to(_map)
folium.Marker([35.697914, 139.413741], popup='<b>立川駅</b>').add_to(_map)

_map.save('sample4.html')
```
![004.jpg](https://qiita-image-store.s3.amazonaws.com/0/157364/ec87715e-bf45-55fd-c7e1-cee6e9a5d7a0.jpeg)


## 4. レイヤの設定
レイヤを設定することでタイルの変更が可能になります。

```py
import folium
from folium.plugins import FastMarkerCluster

copyright_osm = '&copy; <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'

_map = folium.Map(location=[35.681167, 139.767052],
                  attr=copyright_osm)

# Stamen Tonerのコピーライト
copyright_st = '&copy; ' \
               'Map tiles by <a href="http://stamen.com">Stamen Design</a>,' \
               ' under <a href="http://creativecommons.org/licenses/by/3.0">CC BY 3.0</a>.' \
               'Data by <a href="http://openstreetmap.org">OpenStreetMap</a>,' \
               'under <a href="http://www.openstreetmap.org/copyright">ODbL</a>.'

# レイヤを追加
_map.add_tile_layer(tiles='https://stamen-tiles-{s}.a.ssl.fastly.net/toner-lite/{z}/{x}/{y}.png',
                    name="Stamen Toner",
                    attr=copyright_st)

# レイヤコントロールを追加
folium.LayerControl().add_to(_map)

_map.save('sample5.html')
```

![005.jpg](https://qiita-image-store.s3.amazonaws.com/0/157364/c39d2dde-0070-37ac-d6ae-a760cc974132.jpeg)

## 5. GeoJson/TopoJsonの読み込み
いつもお世話になっている都道府県のGeoJsonを参照します。  
https://github.com/dataofjapan/land

### GeoJsonとTopoJson
GeoJsonの仕様:  
https://tools.ietf.org/html/rfc7946

TopoJsonの仕様:
https://github.com/topojson/topojson

GeoJsonは地理情報を記述するためのフォーマットです。
構造はJson形式をとっています。

TopoJsonはGeoJsonの拡張版です。GeoJsonの冗長性(重複するような線)を単一化し、
データを効率的に記述している、そうです。

### TopoJsonの場合

```python
import folium

#Stamen Tonerのコピーライト
copyright_st = '&copy; ' \
            'Map tiles by <a href="http://stamen.com">Stamen Design</a>,' \
            ' under <a href="http://creativecommons.org/licenses/by/3.0">CC BY 3.0</a>.' \
            'Data by <a href="http://openstreetmap.org">OpenStreetMap</a>,' \
            'under <a href="http://www.openstreetmap.org/copyright">ODbL</a>.'

_map = folium.Map(location=[35.681167, 139.767052],
                  attr=copyright_st,
                  zoom_start=9,
                  tiles='Stamen Toner')

#データ
data_path = './japan.topojson'

#TopoJson読み込み
#object_pathはTopoJson内の読み込み先を指定すること
folium.TopoJson(
    data=open(data_path, encoding='utf-8'),
    object_path='objects.japan',
    name="topojson"
).add_to(_map)

folium.LayerControl().add_to(_map)

_map.save('sample6.html')
```
![006.jpg](https://qiita-image-store.s3.amazonaws.com/0/157364/f3990990-cf89-836f-e00b-44f1e1a3ca26.jpeg)


### GeoJsonとの相違点
先に記述した通り、データ容量ではGeoJson>TopoJsonとなります。
htmlへ出力する場合、TopoJsonを利用したほうがデータ容量を削減することが可能です。



## 6.HeatMap
国土数値情報ダウンロードサービスから東京都の公園の情報をダウンロードしてサンプルとして使います。
[こちら](https://qiita.com/cieloazul310/items/9d0e3f67f60d791726dc#shp%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E3%82%92geojson%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E3%81%AB%E5%A4%89%E6%8F%9B)を参考にしてShapeファイルかGeoJsonへ変換します。

```python
import folium
from folium.plugins import HeatMap
import json

copyright_st = '&copy; ' \
            'Map tiles by <a href="http://stamen.com">Stamen Design</a>,' \
            ' under <a href="http://creativecommons.org/licenses/by/3.0">CC BY 3.0</a>.' \
            'Data by <a href="http://openstreetmap.org">OpenStreetMap</a>,' \
            'under <a href="http://www.openstreetmap.org/copyright">ODbL</a>.'

_map = folium.Map(location=[35.699551, 139.485604],
                  attr=copyright_st,
                  zoom_start=9,
                  tiles='Stamen Toner')
 

with open('./tokyo-park.json', 'r', encoding='utf-8') as fp:
    park_data = json.load(fp)

#緯度経度の並びの修正
data = list()
for d in park_data['features']:
    point = d['geometry']['coordinates']
    location = point[1], point[0]
    data.append(location)

HeatMap(data, radius=15).add_to(_map)

_map.save('Heatmap.html')

```
<img width="965" alt="001.jpg" src="https://qiita-image-store.s3.amazonaws.com/0/157364/0b4608e9-6c02-a913-5d74-8fb07d51d205.jpeg">


## 7.MarkerCluster

HeatMapと同データを利用してMarkerClusterを表示します。
MarkerClusterは多くのPointを表示する際に描画が早くて助かります(かわりにサイズが重くなりますが・・・)

```python
import folium
from folium.plugins import MarkerCluster

import json

copyright_st = '&copy; ' \
            'Map tiles by <a href="http://stamen.com">Stamen Design</a>,' \
            ' under <a href="http://creativecommons.org/licenses/by/3.0">CC BY 3.0</a>.' \
            'Data by <a href="http://openstreetmap.org">OpenStreetMap</a>,' \
            'under <a href="http://www.openstreetmap.org/copyright">ODbL</a>.'

_map = folium.Map(location=[35.699551, 139.485604],
                  attr=copyright_st,
                  zoom_start=11,
                  tiles='Stamen Toner')
 

with open('./tokyo-park.json', 'r', encoding='utf-8') as fp:
    park_data = json.load(fp)


marker_cluster = MarkerCluster(
    name='tokyo park',
    overlay=True,
    control=False,
    icon_create_function=None
)

for d in park_data['features']:
    point = d['geometry']['coordinates']
    location = point[1], point[0]
    marker = folium.Marker(location=location)
    popup = 'lon:{}<br>lat:{}'.format(location[1], location[0])
    folium.Popup(popup).add_to(marker)
    marker_cluster.add_child(marker)

marker_cluster.add_to(_map)

_map.save('MarkerCluster.html')

```

<img width="966" alt="002.jpg" src="https://qiita-image-store.s3.amazonaws.com/0/157364/370c645d-4b9b-9e89-f84a-ac5d552556b9.jpeg">

## 8.
また今度。。。

- コロプレス図