##実行環境
- 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を使って地図をいじる
import folium
#地図オブジェクト作成。インスタンス化。Layer1つ目
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)
"""
- 変数
my_map
はfolium.Map
のインスタンス。folium.Mapクラスで渡す引数において、locationは初期位置の座標[latitude, longitude]の形式で渡す。latitudeの範囲は-90~90, longtitudeの範囲は-180-180, floatも可能。zoom_start
は地図の拡大倍率。大きいと拡大された地図が表示。最小値は0。tiles
は地図の表示形式。様々な地図があるtiles="Mapbox Bright"
はとてもシンプルな地図が表示される。 -
add_child
メソッドでマーカーを追加できる。地図上のアイコン。folium.Marker([latitude,longitude])
で座標の位置に表示される。マーカーにはCircle
とかCircleMarker
とか様々な種類がある。popup
引数に文字列を指定できる。変数を渡したりすると表示されない場合がある(後述)。icon
引数ではicon=folium.Icon(color="green")
等で色を指定できる。folium.Icon
オブジェクトのヘルプのなかに、指定できる色が規定されている。 -
print(my_map)
ではfolium.folium.Map
オブジェクトであり、メモリの保存場所が返ってくる。 - folium.TileLayer("tile_name")でlayerを作った。つまり別の層を作ること。イメージとしては本の1ページ目の紙うえに、2ページ目にできる別の紙を用意した。
-
add_to(my_map)
でlayerをmy_mapに追加した。2つの紙をホッチキスした感じ。my_mapの部分はfolium.folium.Map
オブジェクトを渡す。 -
folium.LayerControl()
はレイヤーのon,offや切り替えをできるコントローラーのこと。add_to(my_map)
で実際にmy_map
上に追加した。 - レイヤーや要素を追加するには
my_map.add_child(追加したい要素 or layer)
としてもいい。つまりfolium.LayerControl().add_to(my_map)
とmy_map.add_child(folium.LayerControl())
は等価。 -
save
でpythonのコードをhtmlに変換。もちろんこのhtml開ける。たまに真っ白。今回は日本の明石市が初期位置で開く。明石市の理由は特にない。標準時刻やで。 - pythonの組み込み関数で
help
でfolium.map.TileLayer()
を見れば、どんなtileが使えるか見れる。tileは地図の見た目のこと。デフォルトの"OpenStreetMap"は素敵な見た目。
##csvファイルを使って地図上にmarkerを表示する。
普通の地図レイヤーを作る。
その上に世界の火山の座標にアイコンがあるレイヤーを作る。
人口で色分けされたーレイヤーを作る
この3つのレイヤー(層)を重ねる。
3つが重なった地図ができる。
使った火山の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/
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")
- pandasを使って、csvファイルを読み込む。DataFrameオブジェクトを作る。columnのオブジェクト
pandas.core.series.Series
をlist
型へ変換した。 -
folium.FeatureGroup
クラス。こいつで特定の要素を集めてレイヤーを作成する。fgv
はfolium.FeatureGroup
のインスタンス。レイヤーに要素を追加する場合は、前述通りadd_child()
メソッドを使う。今回もMarker
オブジェクトを追加する -
Marker
オブジェクトは前述と変わらない、はずなのだが。引数のpopup
に文字列型以外をつっこむと(この場合は変数name
。火山の名前)地図が真っ白で表示されないoh。原因はpopup部分が最初にrenderされてないからっぽい。で、対策としては、folium.Popup(str, parse_html=True)
クラスのインスタンスを作って、引数popup
に渡す。parse_html=True
は最初にrenderする、の意味。 -
GeoJson
を使って、GeoJson形式のjsonファイルを読み込み、データを取り出すことができる。普通のjsonファイルは読め込めない。GeoJson形式とはざっくりいうと、座標やポリゴンを数字で表記し、地図を表すもの。地図の特定の範囲に情報を追加できる。例えば、中国の範囲を指定して人口情報を追加とか。GeoJson特有の書き方形式はここでは詳しく話さない。引数のstyle_function
を以下の様に指定して色分けをできる。ヘルプから引用。
>>> 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。もうピーチの色違いで我慢しなくていいんだね。