鐵人賽2019 Day10 地圖互動folium

  1. 1. 基本操作
  2. 2. 加入向量資料
  3. 3. 做個時序地圖
  4. 4. 參考資料
  5. 5. 後記

folium是基於leaflet.js的python地圖套件,讓使用者可以很快速的使用python產生一些可互動的地圖。
我們可以很方便把加工後的GIS資料丟進去,並完成一個網頁地圖。

leaflet: [Day 13] WebGIS中的向量資料-在Leaflet實作 - iT 邦幫忙::一起幫忙解決難題,拯救 IT 人的一天

以下我們就快速來試一試

基本操作

安裝 folium
conda install -c conda-forge folium

初始化地圖
初始化地圖要指定地圖中心的經緯度坐標,跟比例尺(zomm_start)
例如:

1
2
3
import folium
m = folium.Map((25.0133904,121.52245),zoom_start=14)
m

https://ithelp.ithome.com.tw/upload/images/20181025/20107816JJuymkhfJt.png

folium內建一些基本的WMTS,使用tiles,我們把它換成使用Cartodb Positron

1
2
m = folium.Map((25.0133904,121.52245), tiles="Cartodb Positron",zoom_start=14)
m

https://ithelp.ithome.com.tw/upload/images/20181025/201078160s7ArzQK5C.png

當然,還有很多其他選擇,有需要的人可以自行參考

加入向量資料

folium的操作沒有很複雜,如果要加入向量資料,操作起來跟leaflet很像。

例如我們增加一個marker然後設定style及popup

1
2
3
4
5
6
7
8
9
10
m = folium.Map((25.0133904,121.52245),zoom_start=14)
folium.CircleMarker(
location=[25.0133904,121.52245],
radius=20,
popup='永和',
color='#3186cc',
fill=True,
fill_color='#3186cc'
).add_to(m)
m

https://ithelp.ithome.com.tw/upload/images/20181025/20107816fEhqTioBMW.png

若要丟整份資料,folium使用的格式是geojson,如果是Geopandas處理的資料,可以使用to_json()這個方法將資料餵進去。

再次以新北的村里界資料為範例
先把資料準備好並轉好坐標系統為epsg4326

1
2
3
4
5
6
7
import geopandas as gpd
village=gpd.read_file('data/village/village.shp',encoding='utf-8')
village=village[village.is_valid]
village=village[village['ADMIT']=='永和區']
village.crs = {'init' :'epsg:3826'} # 避免資料沒設,這邊再重新給一次
village=village.to_crs(epsg=4326)
village=village.reset_index()

處理好的資料是GeoDataFrame丟進去,可以用to_json轉為geojson
並直接丟進去folium

1
2
3
4
5
6
m = folium.Map((25.0133904,121.52245),zoom_start=14)
folium.GeoJson(
village.to_json(),
name='geojson'
).add_to(m)
m

https://ithelp.ithome.com.tw/upload/images/20181025/20107816HG0BOrqSk6.png

如果要增加圖層開關,讓瀏覽的時候比較方便,可以加入LayerControl(用法跟leaflet差不多)

1
folium.LayerControl().add_to(m)

https://ithelp.ithome.com.tw/upload/images/20181025/20107816vvcy7RYzNX.png

做個時序地圖

folium有一個滿好用的套件TimeSliderChoropleth
可以快速做一個時間序列的資料展示
他的基本操作如下:

1
2
3
4
g = TimeSliderChoropleth(
village.to_json(),
styledict = styledict,
).add_to(m)

其中,styledict定義的是時序資料的值
餵進去的資料需要按照要求
為了演示,我們針對village隨機產生時序資料

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import pandas as pd
import numpy as np
n_periods = 24
n_sample = 12
assert n_sample < n_periods
dt_index = pd.date_range('2012-1-1', periods = n_periods, freq='M').strftime('%s')
styledata = { }

for item in village.index:
df = pd.DataFrame({'color': np.random.normal(size=n_periods),
'opacity': np.random.normal(size=n_periods)},
index = dt_index)
df = df.cumsum()
df.sample(n_sample, replace=False).sort_index()
styledata[item] = df

styledict = {str(country): data.to_dict(orient='index') for
country, data in styledata.items()}

產生的資料結構是長這樣
https://ithelp.ithome.com.tw/upload/images/20181025/20107816epB85W0rAc.png

我們把向量圖丟進去,
並把上面產生的styledict也放進去

1
2
3
4
5
6
7
8
9
from folium.plugins import TimeSliderChoropleth
m = folium.Map((25.0133904,121.52245), tiles="Cartodb Positron",zoom_start=14)
g = TimeSliderChoropleth(
village.to_json(),
styledict = styledict,

).add_to(m)

m

https://ithelp.ithome.com.tw/upload/images/20181025/201078164mrDypE8Q3.png

參考資料

folium

後記

folium還很很多功能,可以講個好幾天,之後幾天有機會再多看看吧!

今天的練習請參考github