* U0 X. ^' j( H. u4 w Folium 简介
" P$ E Q0 u1 y9 _5 n+ M 作为 Python 的一个可视化工具包 Folium,它通过 Leaflet 的地图服务,可以在 Jupyter Notebook 上实现可视化的地理位置作图,制作各种各样精美的地图信息。它不仅可以针对某个经纬度进行地理位置的可视化操作,还能够根据实时的人群地理位置信息来构建静态与动态热力图,甚至还能够针对经纬度的数量来进行必要的聚类可视化。本文将会基于新加坡的地图,对 Folium 的一些功能做简要的介绍,对此工具有兴趣的读者可以参阅 Folium 的官方文档。
8 d/ Y' N5 R" B4 C 创建地图
$ m/ [* p, s0 `9 O. ~* ` 通过 Folium 工具,可以直接作出一张世界地图,其代码也十分地简洁明了。 ; Y/ k( Y+ S4 E# m: v
import folium
2 Y* r* s# }+ M& C% |9 n0 R7 j b %matplotlib inline1 H3 Q6 {6 ]9 x# K& Z
' Y+ O0 z3 A3 U" i( Q0 k import webbrowser& \. ?" q% I# A* c8 O' ~' o# p9 R
: E1 g$ n: x" @9 ~0 e7 F print(folium.__version__)
" O7 X8 \! N; {* ]# J3 H
+ |5 |8 {6 W0 H# \" {! O # define the world map8 p5 \7 Z( Q6 R6 y* |- ?
world_map = folium.Map()
! W9 P7 l! X, l" i# h1 q # display world map
1 T" W. F2 q: V( Q* [ world_map% l4 ]8 B3 O( [
- m' r7 v) B! Z4 f6 o7 G 世界地图除了能够作出一张完整的世界地图之外,通常程序员最常见的需求是针对某个或者某一些经纬度,来作出一张局部地图。地图中不仅需要包括经纬度信息,也需要有街道信息等必要的内容,甚至需要对经纬度的标记做一些必要的定制化工作。 ! M& A- q. ~: n4 k7 X
在初始化一张地图的时候,需要指定它的经纬度信息,也就是 location 的位置。也需要根据需要放大的尺寸来指定相应的 zoom_start 值。另外,tiles 是 str 型,用于控制绘图调用的地图样式,默认为OpenStreetMap,也有一些其他的内建地图样式,如Stamen Terrain,Stamen Toner。 - {% R) N4 m: @' h9 W
有的时候需要在地图上标识出相应的经纬度,此时需要使用 folium.Marker 函数。其使用方法就是直接输入相应的经纬度信息,以及 icon 的形状(例如 cloud, info-sign 等);除此之外,还可以对其颜色进行标记,一般是对参数 color 进行调整即可。 & e! x& A- [. @% J$ v: Y& F Q) X
另外,在某些经纬度上,还可以使用“点击-弹出“的控件 tooltip 和 popup,一旦鼠标指向该位置,就会呈现出相应的弹出信息。 8 }, V" C4 q y! f0 s% _$ A
# latitude and longitude in Singapore city) f4 G) \( t1 @! m( I5 j
coordinate_sentosa = [1.248946, 103.834306]
! f! l$ {. m. a+ Y" ]) l coordinate_orchard_road = [1.304247, 103.833264]
* O+ F, e8 f$ A- e coordinate_changi_airport = [1.357557, 103.98847]
5 G6 J1 i; |" x# l& m- p coordinate_nus = [1.296202,103.776899]4 S# d( Q! M: ~, N' }
coordinate_ntu = [1.34841, 103.682933]
- k E# c* h& H coordinate_zoo = [1.403717, 103.793974]
& M" v6 S' v2 ]0 G8 P coordinate_ang_mo_kio = [1.37008, 103.849523]1 {. }2 R6 ?; f8 }3 k- T. D2 p
coordinate_yi_shun = [1.429384, 103.835028]5 n) A8 {3 ?9 i6 o! V
& A6 Q# B [" J; ^- G1 ?* \2 g2 p # icon
' ?. ]( X q( @3 o$ v( m& S0 s icon_cloud = "cloud"
8 r9 ~+ @! U$ f% {5 X* A icon_sign = "info-sign"$ L- b6 W E p# N- d2 Y
. S0 y: K2 H8 Z. q' u # define the city map2 b+ I! y* Q! t5 S" R, `
# tiles in {OpenStreetMap, Stamen Terrain, Stamen Toner, Mapbox Bright}
% S: q3 b- d/ U2 { city_map = folium.Map(7 {9 t8 v1 X/ z4 b6 O9 A, I
location=coordinate_orchard_road,$ S+ r+ Z( k4 J) V! V9 L6 i
zoom_start=11,
$ G4 i* b1 [8 C, A tiles=OpenStreetMap); b5 B& x6 p6 m; W
9 F7 v- q1 z; W$ w e8 E # add marker in the city map, y& P+ |7 |( j1 C' E/ V
folium.Marker(# y3 \. P/ v9 C- S: s
coordinate_sentosa,& M( {3 R" ~% c2 @& @. e- w1 ~) ^
icon=folium.Icon(color=blue)
5 |8 W$ W m- c/ z& ` ).add_to(city_map)5 i2 p! m; m' I* a
folium.Marker(
, |7 u# g8 ?. K' M# y% [1 y coordinate_orchard_road,
" @4 G; i6 P0 J& c* o% z, b0 r icon=folium.Icon(color=green, icon=icon_cloud)) w3 S. \( g( _" |; [
).add_to(city_map)
& ?3 q/ Z5 c) D+ o8 u" u% v
5 E6 V2 q: a. u: q1 [ # add popup( g! C( d3 j* S" v k
folium.Marker(' H0 d6 V8 E$ D/ N
coordinate_changi_airport,: D8 m4 T" m1 k H2 T7 S/ ^0 x% l2 O
popup=Changi Airport,/ A& O7 I; F m6 C/ C& [
icon=folium.Icon(color=red, icon=icon_sign)3 |8 c h" R. |& d
).add_to(city_map)* X6 a" Y- ]& t% H. e+ ?
3 A s: J1 l2 q' S
# add tooltips and popup
9 f" e+ T2 F2 g/ S7 f4 j+ g tooltip = "Click me!"# w9 ]6 `! }9 a( I6 j( g' t
* Y% ~- u3 n7 W
folium.Marker(
6 X( j0 J. [. Y8 V coordinate_nus,1 Y5 `3 r5 Q a
popup="<i>National University of Singapore</i>",2 N( g* |! g& b) v: K
tooltip=tooltip& K0 v( \ {) f9 L; i# I8 s
).add_to(city_map)
- B' \6 b$ k9 e$ x9 R/ L. N8 }( X; g
folium.Marker(# f2 \" L" O; |+ L: N
coordinate_ntu,* O& o, s) t5 D+ K- ?6 o5 B. X
popup="<b>Nanyang Technological University</b>",: j4 J$ Z0 F9 l. D1 T: Q
tooltip=tooltip* S; d1 o0 l9 J0 _+ \
).add_to(city_map)
: O I' ?6 J( l; j2 _4 l6 r4 |% D: S6 n
# display city map
/ V4 t4 @2 j" h& W# G9 H city_map . X- E' Z' b2 Q* g! w6 o* k
Folium 的经纬度作图(OpenStreetMap)Folium 的经纬度作图(Stamen Terrain)Folium 的经纬度作图(Stamen Toner)有的时候,我们只知道某个地点,但是并不知道相应的经纬度数据,此时,只需要使用 folium.LatLngPopup() 就可以在鼠标指向位置上呈现相应的经纬度值,可以方便的查阅和使用。
' r/ n" Z* p3 w* {3 |1 D7 j # define the city map' u& X- g0 Q2 Y7 C
city_map = folium.Map(location=coordinate_orchard_road, zoom_start=11)( Z7 y- M& ? t4 |
w( ~/ w+ i2 G% j2 h
# 在地图中添加经纬度, add latitude and longitude in the map when click
, F' X9 n, Y9 s6 q" M city_map.add_child(folium.LatLngPopup()); O9 o! ~' p# l/ P
9 B* j, [: i% G: g$ v9 K city_map , R: I j# k1 B1 z( z4 x
: z! \( b( ]$ u% O3 ~, u5 }8 S8 _ 几何形状
7 P$ Z2 r S; V 在作出关键的经纬度点之后,有的时候我们需要作出相应的几何图形将其显示得更加清楚。Folium 提供线段相连,多边形,圆形,矩形等诸多图形,只需要使用相应的函数即可。 # F" t! z( `. ~' z5 t
# define the city map6 u6 i* D0 q* B+ p: b6 Y& V t
city_map = folium.Map(location=coordinate_orchard_road, zoom_start=11); V. @3 y, [. c5 N$ u
1 i/ a: U3 b3 ?
# 在地图中如何添加形状- A/ L3 H: Q. o3 F/ [
# 多条边3 u7 S) k5 F4 J3 m, b! z: x5 d
points_1 = [
! t' h% u* Z" a) f) o coordinate_ntu,
7 G2 A8 k2 J R# E coordinate_nus,/ g6 v$ ^- t2 D! q1 _- d
coordinate_zoo* W8 C. x+ z% G" k5 R- [
]
1 w$ Q J. x, f3 o5 u* F! V0 P3 \; [5 h$ ?
# 在 city_map 中添加多条边,第一种添加方式" y5 [8 W I) K
city_map.add_child(folium.PolyLine(
( C7 l6 C3 J+ R( S0 W0 d locations=points_1, # 坐标列表
4 i8 ^, t3 c- n4 V# h weight=3, # 线条宽度4 Y- V9 I: c, ], h' S: }
color=gray))8 ?: j- j6 y2 x
3 ?9 c* }7 i7 t8 |; A # 在 city_map 中添加多条边,第二种添加方式+ N( n* | N7 U; ]: m& D
folium.PolyLine(
9 Q/ B0 x4 v" C I% n" [ locations=points_1, # 坐标列表2 L; D# j# @6 Z- A7 X
weight=3, # 线条宽度! \! L, H' ^, |; V
color=gray).add_to(city_map); E: j$ f( X0 S- n5 _1 x" {
4 U) q4 a* n0 U9 V
# 多边形
- }% H. i$ l2 _/ b0 u points_2 = [
4 V3 @% o3 W# J, ?4 x coordinate_orchard_road,
+ N2 n" ]0 X/ @' z) y+ J ?! e- J coordinate_sentosa,
( x# {1 j! ^, Q G7 a coordinate_changi_airport
" z, F! f! o9 g2 }0 o ]
, d2 m, d( U: Z2 K
+ q/ n4 H+ }" V city_map.add_child(folium.Polygon(
* `. F; I( Q4 y& n+ p$ @8 [ locations=points_2, # 坐标列表
1 |4 `6 ]3 m# u2 |. [5 r8 ^: ~# { weight=3, # 线条宽度
: _, Z1 P8 ]( x" p color=yellow))
$ O% Q/ q3 [8 J$ S1 c
' |) t% f8 D+ Z # 矩形) Q" }3 ~2 _# w- l: O4 t; m
bounds = [
9 c7 i; w+ M% ~# Q# B$ V! I0 [ coordinate_ang_mo_kio,
% ^$ l0 p: _! v8 \9 O0 q coordinate_yi_shun, N/ P0 I, i% R( q0 U
]
1 b, x) o# w2 `# @/ S) B' U& ]9 ?7 }0 k7 e! S
city_map.add_child(folium.Rectangle(
: s8 h$ ~6 H8 ~" h& S# V. g bounds=bounds, # 坐标列表, Latitude and Longitude of line (Northing, Easting)1 l- ~& X& Y4 T& P$ q
weight=2, # 线条宽度$ Y; k- I% m: Z: i) `6 J" h% u. ^
color=blue))
9 i8 P, R3 x% {% r1 w y( D* n+ d0 y
# 圆形, circle, radius units meters& K$ w4 X. {! s1 [
folium.Circle(
+ _0 _' s/ X1 D4 D$ @ radius=1000,
. K* p: ?& B1 g$ ]9 U5 L location=coordinate_nus,
+ n; |9 K# U; H. F8 l' h% N popup="National University of Singapore",
( _+ W+ t% [) M, H% F color="crimson",
; P& A# o, c6 `% B fill=False,
/ d/ {; V- s8 Y' x l ).add_to(city_map)
, }- K/ I T3 Z( d+ F0 ]* u0 K# s) Y$ W. L3 {) G
# 圆形, circle, radius units pixels
, }5 Y9 V. ^( m! _& \! U folium.CircleMarker(
# V, K3 k# b2 t+ a R location=coordinate_ntu,0 p0 t+ o: i/ N3 B( z) G
radius=30,
* S$ u3 z. c" B+ y8 i popup="Nanyang Technological University",
3 D; \5 V5 D; K: B# d ^ {' q3 [ color="#3186cc",
' }1 D/ s# J+ f5 f+ g. T fill=True,
* X- M9 L/ ]. Q) E3 z fill_opacity=0.3, # 透明度
% s( w1 s) q2 T. Q7 V7 u2 \ fill_color="#3186cc",) V" N; D5 O8 W
).add_to(city_map)2 T( ^0 S: F6 `8 Y% {
4 _7 m. k) ?0 r
city_map
, u) B3 v& e/ a+ R: x1 l& R Folium 中的画出各种形状热力图
g4 F6 i0 j( B8 M 在实际使用经纬度信息的时候,通常来说会针对某个 APP 或者多款 APP 的实时经纬度信息来获取路况的拥挤程度,景区的人流量等信息,在这种情况下,就可以做出热力图。通过实时的热力图信息,我们可以获得相应的人流量信息进行必要的数据分析工作。 . F" O5 v- T7 s- e
import numpy as np
7 ^; h8 E' @3 @) ~7 m" v% I+ C7 m from folium.plugins import HeatMap# k1 u. V5 v, Z- b
0 k' ^! J$ o/ ]. i5 k/ U! Z
# define the city map* C; l: G* u7 q2 O! y& F' N: a. q
city_map = folium.Map(location=coordinate_orchard_road, zoom_start=11)
+ I) a1 ?4 i# B( n' w5 B6 j# t* ~" K W
# 构建随机数据
: K7 w% A' i! L data = (
3 H* e! Q9 ]9 b' ^# t- S np.random.normal(' }! B. N) J; I2 W) I! K6 n
size=(10, 3)) * 0.03 * np.array([[1, 1, 1]]) +, M+ N1 ?9 {; u9 {
np.array([[coordinate_orchard_road[0], coordinate_orchard_road[1], 1]]): |/ B' b; I# T, Y% O
).tolist()
9 H1 A0 [6 k6 \ Y7 K7 D& F5 _' I- C
+ s; f% C5 T# @* k/ b) H$ | Y4 I8 G city_map.add_child(HeatMap(data=data))1 m% W5 Q7 J# |; w8 l7 y# x
city_map ; {: [' v/ N: J4 B% e% G4 ]1 e
( J/ p/ `& y/ O4 }
除了单张图的热力图之外,Folium 还能够计算一段时间的连续热力图信息。
7 F. Y0 I4 {! c. {2 G import numpy as np
6 F$ ?( u) u% P- f0 E! ~$ f from folium.plugins import HeatMapWithTime
' k" U$ J# U6 D# b0 u9 s) M$ ?4 l0 e' K
# define the city map
( n6 ?, `; }6 @' D- b! M city_map = folium.Map(location=coordinate_orchard_road, zoom_start=11)* `+ r- e+ v; O7 W0 m4 W9 i
2 Z. {9 q* f4 v/ }" J9 H' O/ X # 使用 numpy 建立初始数据! c+ |5 S8 I: C2 u3 o2 Z! p
initial_data = (np.random.normal(size=(200, 2)) *0 |% T5 b; b' _, h6 K) y4 I/ h
np.array([[0.02, 0.02]]) +: L; T8 V- P! h7 C" K1 N$ {8 I
np.array([coordinate_orchard_road]))& ~+ H9 t- `. d" W$ U+ P8 r$ @( h
( w0 [9 H8 r2 D' X! ]( U. U
# 建立连续的数据
* A$ p. R7 d1 `% k+ R data = [initial_data.tolist()]
: _: h9 [! y$ G' U for i in range(20):
5 `6 {( t, W( Z1 h5 c2 M data.append((data[i] + np.random.normal(size=(200, 2)) * 0.001).tolist())
C& N* r/ @" A" Q6 n/ B- r' U i O8 ]4 d6 a; L& }! z
# 显示连续的热力图
z- `' q9 n0 \' o city_map.add_child(HeatMapWithTime(data))' A# I( `- s* h }0 G. j
city_map
7 c/ [, s% i# D 5 ^- h5 v0 @ L) U' k
经纬度点的聚类8 D# ?8 I0 U$ u$ p" p
除了热力图能反映人流量的信息,基于地理位置的聚类算法同样能够反映一个地区的拥挤程度,Folium 的 MarkerCluster() 函数可以对一个区域中的点来做聚类,在地图中可以放大和缩小,从而知道局部最拥挤的点在哪里了,最稀疏的区域是哪里。
! J9 _2 M' e! J& Y( F3 R, r from folium.plugins import MarkerCluster
% N$ B4 ], L6 f* s+ g
$ M8 Q+ p. u7 P: d9 |1 P # define the city map
! _1 [& X; y' d city_map = folium.Map(location=coordinate_orchard_road, zoom_start=11)7 U2 {4 h3 b+ ]% T
5 Z/ f. D3 w; h* U# [7 X
# 经纬度的聚类
: U$ B6 l9 V* }5 X! ^ # 在 NUS 的经纬度附近随机生成 100 个点;5 Z" B# l5 J8 [( ] n# U
data = (
7 S- x( Y4 h9 |- \6 n% d: }: k np.random.normal(size=(100, 2))
6 \. k3 m4 j- M& z0 D * np.array([[0.001, 0.001]]) +& y0 A- G( p/ e0 K, v
np.array([coordinate_nus]))/ e$ j0 Z2 }8 t9 L
0 C* R/ [4 F* O% }+ F # create a mark cluster object, X" C3 W+ c# }. a
marker_cluster = MarkerCluster().add_to(city_map)
6 \( S* t' }! S/ t" t& {7 F2 X/ o+ ~- f. s5 c9 p w% V; [
# 将这些经纬度数据加入聚类
+ V6 s0 K: n6 f9 _$ u2 n for element in data:2 a+ |2 Q$ J3 |/ }/ o7 r
folium.Marker(location=[element[0], element[1]],icon=None).add_to(marker_cluster)5 I8 [' Z; U2 H; o o8 {
) t C s4 z8 k+ ]5 }7 a
# add marker_cluster to map
( ~! W# r" C( U, C! X city_map.add_child(marker_cluster)
) s4 g+ L4 M# e: A* R
: a& [: [; m; W& F& S # 作图; d) @7 w+ h% F" ?
city_map
# Y( o2 i" C3 B7 M! x5 F4 X " o9 @4 Z7 Y. c% o6 Z8 _
以上就是关于 Folium 的基础内容,有兴趣的读者可以自行参阅 Folium 的官方文档。
4 V2 y+ |) S$ _0 Z 参考文献
0 o& l N/ \! X Folium 官方文档:Folium - Folium 0.12.1 documentation - n4 T7 }0 j# U
. Z" M) w, i' N$ K
, ~& d$ p( |& | [7 Q) [: k+ Q; x/ p- f( O7 h e' A
# e& j4 i; l1 i |