python foliumメモ

##実行環境

* MacBook Air (11-inch, Mid 2012)
* JupyterLab (from Anaconda)
* Python 3.6.4


##参考元
教材元
https://www.udemy.com/the-python-mega-course/learn/v4/content

folium.LayerControl(): tilesetの詳細
https://deparkes.co.uk/2016/06/10/folium-map-tiles/

GeoJsonとは
http://blog.qaramell.com/hunzy/8191

utf-8 bomの見分け方
http://uxmilk.jp/48923

utf-8 bomを開く
https://qiita.com/showmurai/items/60d32006d13512ffeaff

##まえがき
foliumライブラリーを使って地図を作ろう。
ブラウザはhtml, css, javascriptしか読めないらしい？ゆえにpythonのcodeをhtml,css, javascriptのいずれかに変換する必要がある。



##foliumを使って地図をいじる


```py
import folium

#地図オブジェクト作成。インスタンス化。Layer１つ目
my_map = folium.Map(location=[34.39, 135.0], zoom_start=10, tiles="Mapbox Bright")

#地図上に要素を作成
my_map.add_child(folium.Marker([34.6441550, 135.0175760], popup="This is Akashi-shi", icon=folium.Icon(color="green")))

"""
>>> #メモリー上の保存場所が返される?
>>> print(my_map)
<folium.folium.Map object at 0x114351c50>
"""

#別のLayerを作成
folium.TileLayer('openstreetmap').add_to(my_map)

#Layerをmy_mapへ追加
folium.LayerControl().add_to(my_map)
#my_map.add_child(folium.LayerControl())とも記述可能。

#folium.folium.Map objectをhtmlに変換
my_map.save("Map.html")

"""
>>> #tiles
>>> help(folium.map.TileLayer())
Map tileset to use. Can choose from this list of built-in tiles:
        - "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)
        - "Cloudmade" (Must pass API key)
        - "Mapbox" (Must pass API key)
        - "CartoDB" (positron and dark_matter)
"""
```

1.  変数`my_map`は`folium.Map`のインスタンス。folium.Mapクラスで渡す引数において、locationは初期位置の座標[latitude, longitude]の形式で渡す。latitudeの範囲は-90~90, longtitudeの範囲は-180-180, floatも可能。`zoom_start`は地図の拡大倍率。大きいと拡大された地図が表示。最小値は0。`tiles`は地図の表示形式。様々な地図がある`tiles="Mapbox Bright"`はとてもシンプルな地図が表示される。
2.  `add_child`メソッドでマーカーを追加できる。地図上のアイコン。`folium.Marker([latitude,longitude])`で座標の位置に表示される。マーカーには`Circle`とか`CircleMarker`とか様々な種類がある。`popup`引数に文字列を指定できる。変数を渡したりすると表示されない場合がある(後述)。`icon`引数では`icon=folium.Icon(color="green")`等で色を指定できる。`folium.Icon`オブジェクトのヘルプのなかに、指定できる色が規定されている。
3.  `print(my_map)`では`folium.folium.Map`オブジェクトであり、メモリの保存場所が返ってくる。
4.  folium.TileLayer("tile_name")でlayerを作った。つまり別の層を作ること。イメージとしては本の1ページ目の紙うえに、2ページ目にできる別の紙を用意した。
5.  `add_to(my_map)`でlayerをmy_mapに追加した。2つの紙をホッチキスした感じ。my_mapの部分は`folium.folium.Map`オブジェクトを渡す。
6.  `folium.LayerControl()`はレイヤーのon,offや切り替えをできるコントローラーのこと。`add_to(my_map)`で実際に`my_map`上に追加した。
7.  レイヤーや要素を追加するには`my_map.add_child(追加したい要素　or　layer)`としてもいい。つまり`folium.LayerControl().add_to(my_map)`と`my_map.add_child(folium.LayerControl())`は等価。
8.  `save`でpythonのコードをhtmlに変換。もちろんこのhtml開ける。たまに真っ白。今回は日本の明石市が初期位置で開く。明石市の理由は特にない。標準時刻やで。
9.  pythonの組み込み関数で`help`で`folium.map.TileLayer()`を見れば、どんなtileが使えるか見れる。tileは地図の見た目のこと。デフォルトの"OpenStreetMap"は素敵な見た目。



##csvファイルを使って地図上にmarkerを表示する。
普通の地図レイヤーを作る。
その上に世界の火山の座標にアイコンがあるレイヤーを作る。
人口で色分けされたーレイヤーを作る
この３つのレイヤー(層)を重ねる。
３つが重なった地図ができる。

使った火山のcsvファイル元：
https://data.humdata.org/dataset/volcano-population-exposure-index-gvm/resource/e3b1ecf0-ec47-49f7-9011-6bbb7403ef6d

GeoJsonファイル：
https://github.com/pipinstallbadapple330/file

GeoJsonファイルをweb上で作れるサービス：使ってない
http://geojson.io/


```py
import folium
import pandas

#csv読み込み
df = pandas.read_csv("Volcano.csv")
latitude = list(df["Latitude"])
longitude = list(df["Longitude"])
risk = list(df["risk"])
name = list(df["V_Name"])

#folium.Mapオブジェクト作成
my_map = folium.Map(location=[34.39, 135.0], zoom_start=10, tiles="Mapbox Bright")

#危険度で色分け
def color(risk):
    if risk >= 3:
        return "red"
    if risk >= 2:
        return "orange"
    if risk >= 1:
        return "pink"
    return "green"

#feature group volcanoes layerの作成
fgv = folium.FeatureGroup(name="Volcanoes")
print(type(fgv))
>>>folium.map.FeatureGroup

for lt, lo, name, risk in zip(latitude, longitude, name, risk):
    fgv.add_child(folium.Marker(location=[round(lt, 4), round(lo, 4)], popup=folium.Popup("Mt. "+name, parse_html=True), icon=folium.Icon(color=color(risk))))

#GeoJson object layerの作成
fgp = folium.FeatureGroup(name = "Population")
fgp.add_child(folium.GeoJson(data=open('world.json', 'r', encoding='utf-8-sig').read(),\
style_function=lambda x:{'fillColor':"green" if x['properties']['POP2005'] < 10000000 else\
'orange' if 10000000 <= x['properties']['POP2005'] < 50000000 else 'red'}))

#add layer
my_map.add_child(fgv)
my_mao.add_child(fgp)
#layer controller
my_map.add_child(folium.LayerControl())

#save
my_map.save("Mapr.html")

```
1. pandasを使って、csvファイルを読み込む。DataFrameオブジェクトを作る。columnのオブジェクト`pandas.core.series.Series`を`list`型へ変換した。
2. `folium.FeatureGroup`クラス。こいつで特定の要素を集めてレイヤーを作成する。`fgv`は`folium.FeatureGroup`のインスタンス。レイヤーに要素を追加する場合は、前述通り`add_child()`メソッドを使う。今回も`Marker`オブジェクトを追加する
3. `Marker`オブジェクトは前述と変わらない、はずなのだが。引数の`popup`に文字列型以外をつっこむと(この場合は変数`name`。火山の名前)地図が真っ白で表示されないoh。原因はpopup部分が最初にrenderされてないからっぽい。で、対策としては、`folium.Popup(str, parse_html=True)`クラスのインスタンスを作って、引数`popup`に渡す。`parse_html=True`は最初にrenderする、の意味。
4. `GeoJson`を使って、GeoJson形式のjsonファイルを読み込み、データを取り出すことができる。普通のjsonファイルは読め込めない。GeoJson形式とはざっくりいうと、座標やポリゴンを数字で表記し、地図を表すもの。地図の特定の範囲に情報を追加できる。例えば、中国の範囲を指定して人口情報を追加とか。GeoJson特有の書き方形式はここでは詳しく話さない。引数の`style_function`を以下の様に指定して色分けをできる。ヘルプから引用。

```py
>>> style_function = lambda x: {'fillColor': '#0000ff' if
...                             x['properties']['name']=='Alabama' else
...                             '#00ff00'}
```

5.`utf-8`には`Byte order mark`通称`BOM`と呼ばれる3バイトのデータがファイルの先頭にくっついてる場合がある。これはUnicodeで符号化したテキストの先頭に付与される数バイトのデータのこと。windowのメモ帳とかで保存すると自動的につくらしい。これを扱うために、`read()`関数において、`encoding='utf-8-sig'`を追加すればいい。じゃないとエラーでた。ファイル行数がながすぎます〜的な感じの。

6.`add_child`でさっき作った`fgv`と`fgp`レイヤーを元のレイヤー`my_map`に追加。`folium.LayerControl`クラスのコントローラーも追加。これでレイヤーのon,offを可能になる。

7.`save`でhtmlに。俺のmacだとくっそ重い。全世界の火山の位置が表示される地図が作成できた。マーカーの色も危険度順に場合分けした。危険；赤→オレンジ→ピンク→緑:安全。国も人口別に色分けされてある。


##あとがき
Geojsonのことを普通のjsonファイルだと思って読もうとするとちんぷんかんなのありますねぇ。
大乱闘にデイジー参戦ktkr。もうピーチの色違いで我慢しなくていいんだね。