LoginSignup
12
12

More than 5 years have passed since last update.

python foliumメモ

Last updated at Posted at 2018-07-14

実行環境

  • 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)
"""
  1. 変数my_mapfolium.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の組み込み関数でhelpfolium.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")

  1. pandasを使って、csvファイルを読み込む。DataFrameオブジェクトを作る。columnのオブジェクトpandas.core.series.Serieslist型へ変換した。
  2. folium.FeatureGroupクラス。こいつで特定の要素を集めてレイヤーを作成する。fgvfolium.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を以下の様に指定して色分けをできる。ヘルプから引用。
>>> 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でさっき作ったfgvfgpレイヤーを元のレイヤーmy_mapに追加。folium.LayerControlクラスのコントローラーも追加。これでレイヤーのon,offを可能になる。

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

あとがき

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

12
12
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
12
12