收藏本站 劰载中...网站公告 | 吾爱海洋论坛交流QQ群:835383472

如何用 PYTHON 绘制漂亮的地图?— FOLIUM 作图工具介绍

[复制链接]
4 Y: |/ I4 w* A

Folium 简介

! x1 |# h, x% Q

作为 Python 的一个可视化工具包 Folium,它通过 Leaflet 的地图服务,可以在 Jupyter Notebook 上实现可视化的地理位置作图,制作各种各样精美的地图信息。它不仅可以针对某个经纬度进行地理位置的可视化操作,还能够根据实时的人群地理位置信息来构建静态与动态热力图,甚至还能够针对经纬度的数量来进行必要的聚类可视化。本文将会基于新加坡的地图,对 Folium 的一些功能做简要的介绍,对此工具有兴趣的读者可以参阅 Folium 的官方文档。

& ]2 i/ O6 d/ u }- T, b4 h

创建地图

1 T5 W$ ^' q# |7 F/ w

通过 Folium 工具,可以直接作出一张世界地图,其代码也十分地简洁明了。

& g b6 O) R# q8 D% j0 o( [) g
import folium. J+ H, _' e1 X& X+ F8 f% _ %matplotlib inline9 g; I; J6 W3 p5 F. t ; A- y) v3 X0 Q+ T3 k import webbrowser . _7 s9 s; ~5 `3 m& q- J5 q $ r% ]/ _% n9 T: v+ H# P7 ?8 y print(folium.__version__)% L( n2 {. a1 {9 _/ |- @; x : b+ q, Q c! T T5 L # define the world map5 x- G3 Y- E6 l& N( q; @- p world_map = folium.Map()$ J6 q+ B' _% Y # display world map" J6 R) U6 h/ `0 { world_map 2 m; q1 T0 Y- b5 v$ }7 H
3 q4 s/ j6 C4 p3 u9 y( i7 q# e
世界地图

除了能够作出一张完整的世界地图之外,通常程序员最常见的需求是针对某个或者某一些经纬度,来作出一张局部地图。地图中不仅需要包括经纬度信息,也需要有街道信息等必要的内容,甚至需要对经纬度的标记做一些必要的定制化工作。

3 M7 o f. E: {& N% a4 [

在初始化一张地图的时候,需要指定它的经纬度信息,也就是 location 的位置。也需要根据需要放大的尺寸来指定相应的 zoom_start 值。另外,tiles 是 str 型,用于控制绘图调用的地图样式,默认为OpenStreetMap,也有一些其他的内建地图样式,如Stamen Terrain,Stamen Toner。

7 r& I' c C5 X) U

有的时候需要在地图上标识出相应的经纬度,此时需要使用 folium.Marker 函数。其使用方法就是直接输入相应的经纬度信息,以及 icon 的形状(例如 cloud, info-sign 等);除此之外,还可以对其颜色进行标记,一般是对参数 color 进行调整即可。

$ @$ r' G- u' B4 z7 P

另外,在某些经纬度上,还可以使用“点击-弹出“的控件 tooltip 和 popup,一旦鼠标指向该位置,就会呈现出相应的弹出信息。

; h( A: }3 J- B& V& X
# latitude and longitude in Singapore city8 {* \' W1 ~" o7 t4 o coordinate_sentosa = [1.248946, 103.834306] / S' j/ Q. @+ o/ V4 g/ E coordinate_orchard_road = [1.304247, 103.833264]2 }2 i1 z; [2 U coordinate_changi_airport = [1.357557, 103.98847]. z4 \- R$ x8 x coordinate_nus = [1.296202,103.776899] 9 V9 H9 @ P2 M. b4 Y4 g) w coordinate_ntu = [1.34841, 103.682933] ) K& v+ Q: o% Z coordinate_zoo = [1.403717, 103.793974]3 y- J. t' F& S coordinate_ang_mo_kio = [1.37008, 103.849523] 8 z4 z7 O N, j; O ]% C coordinate_yi_shun = [1.429384, 103.835028]' w: N8 K1 ?: Y# U* m ! M" b0 \; O, `: z& `) M+ d # icon { p- \: K' |9 O- w icon_cloud = "cloud", i: l2 O9 z- ?# q- i icon_sign = "info-sign" ( L4 }$ y$ J4 f9 ~( q. u 2 b0 z) n' c6 j; W A% \ # define the city map6 s" {; ]1 e) C # tiles in {OpenStreetMap, Stamen Terrain, Stamen Toner, Mapbox Bright}. o- \" w! U7 w' u city_map = folium.Map(" t& a9 a( N6 w0 `4 P location=coordinate_orchard_road,3 e* S: P; z2 d' ?% C zoom_start=11,5 e+ j7 k9 y" U/ x tiles=OpenStreetMap) . b9 H a$ y2 A9 w ' t7 h3 K/ X3 J' R% V6 e* X5 _ # add marker in the city map ; O) y; }1 D/ B9 c7 a7 g folium.Marker(4 r" r! |2 i1 X- r coordinate_sentosa,3 f; _5 Y5 E- r* u( E icon=folium.Icon(color=blue) 4 {0 I) {8 K9 ]. F& W' d ).add_to(city_map) , l8 f% g* t7 \( @' ?5 `! F folium.Marker(3 z7 ^% K- Q2 Z" b5 }, Y coordinate_orchard_road, 7 a0 y3 W- ^8 K" f1 A9 L icon=folium.Icon(color=green, icon=icon_cloud) 4 I. O4 }4 z! H2 C; _/ Y ~ ).add_to(city_map): K0 b. R9 A2 @7 z" y7 D; l" N$ A 6 c" ~" {( s7 y # add popup. f2 m- I7 K, [) F folium.Marker( 4 f( Y7 x9 T! E% ?$ F# K coordinate_changi_airport,* F( m" s: q) i) f popup=Changi Airport, {9 G1 p& z, n; D3 t9 [$ e7 m icon=folium.Icon(color=red, icon=icon_sign) + Z1 z7 E- }7 A- x2 d2 ` ).add_to(city_map)7 V. H" M# o8 E+ w0 k$ j ; t6 r ?1 E! {9 X+ J/ N # add tooltips and popup# y M2 R6 v0 l4 e/ c/ r! T tooltip = "Click me!" 2 X- X& L8 o7 v% n 5 S7 U. g! P) N6 K. J folium.Marker( 7 C" I( I, n3 T coordinate_nus,, k6 H" q& {" ?9 ]5 d popup="<i>National University of Singapore</i>",$ u. s( r( s, M) C) e tooltip=tooltip1 k8 ^0 ]" a9 g; ` ).add_to(city_map)4 [; Z" u0 T/ I, A6 j' U ' k% G; O$ t3 M+ M* k( W folium.Marker( : ~9 u: y8 `' f: d, E0 D coordinate_ntu,) h# N7 d% L7 [ c8 V popup="<b>Nanyang Technological University</b>", - V5 ?' y1 j, l/ [' Q. [% D! h9 r* A tooltip=tooltip ( M8 E: Q9 N4 i! O9 r" G$ M0 C+ J ).add_to(city_map) ) p- Y2 R7 T+ I3 [ . Q- k1 Y# O8 v' |4 ]9 j # display city map ; a5 I; p) _( w% F. H0 [ city_map
3 w1 E& A5 q7 x0 |2 v
Folium 的经纬度作图(OpenStreetMap)
Folium 的经纬度作图(Stamen Terrain)
Folium 的经纬度作图(Stamen Toner)

有的时候,我们只知道某个地点,但是并不知道相应的经纬度数据,此时,只需要使用 folium.LatLngPopup() 就可以在鼠标指向位置上呈现相应的经纬度值,可以方便的查阅和使用。

' J. n3 V* k/ w4 i$ y+ {$ T: ]
# define the city map : l6 m# E5 y, m: V" H7 y city_map = folium.Map(location=coordinate_orchard_road, zoom_start=11)- J' m/ D7 {. v) i& h r: t3 T 0 ?5 F9 j9 A4 v% | # 在地图中添加经纬度, add latitude and longitude in the map when click / c+ Y( Z/ |- W5 W. e5 J t city_map.add_child(folium.LatLngPopup()) ( q2 n$ U- a& i- ^8 q$ \2 h0 W+ F9 k3 h$ _: \, r% T4 Y2 } city_map
" y: a$ r7 f+ N/ t 5 ?- g# l G; x5 Z P

几何形状

3 w" e% X W. V) r+ o

在作出关键的经纬度点之后,有的时候我们需要作出相应的几何图形将其显示得更加清楚。Folium 提供线段相连,多边形,圆形,矩形等诸多图形,只需要使用相应的函数即可。

5 t$ H, a0 q& C( O9 K% n0 s7 y
# define the city map ) ^: [' O. v% H6 I( Y$ o& d city_map = folium.Map(location=coordinate_orchard_road, zoom_start=11) 0 ^& v; T' E8 u0 n% @" z( ~. ~) W1 @3 R # 在地图中如何添加形状. n8 e# F' V; G8 R/ k, z& K9 V # 多条边 8 h; C+ r3 P% g. b3 A- U6 p points_1 = [ . }) Y% }% @' @; B: M1 h coordinate_ntu, 7 Q6 p/ `: e" O coordinate_nus, / W" P' K2 P! c) T5 d, F' f- N coordinate_zoo ; M. G0 x* K. l3 N0 N ]5 R% N4 |. H. B. `- s6 d 1 B: t2 ?. ]0 F' p3 z # 在 city_map 中添加多条边,第一种添加方式 - P8 ]! {# o$ r& M city_map.add_child(folium.PolyLine( 2 r) z; K+ T0 J* N4 G9 S locations=points_1, # 坐标列表 9 v3 F# I# D8 M% z/ Y weight=3, # 线条宽度 6 S/ I9 q( U j color=gray)), V2 t- x+ }. t# i- d# f9 F4 ~ l $ m' U! `# M+ n2 U, z # 在 city_map 中添加多条边,第二种添加方式 / e( ~" r- \' b0 j* d7 @; r+ Q9 F! \/ W folium.PolyLine(. Y6 H' Z2 o2 D, Y0 | ^5 Q w locations=points_1, # 坐标列表 : @) c A0 D1 O/ d8 _: p" E weight=3, # 线条宽度! M. A7 M/ l9 K) b: ]# k( @ color=gray).add_to(city_map) # ~) C( x2 U' G2 V3 t' V+ E9 P2 p6 e: X! S1 V+ Z8 @) n, J" h& g # 多边形 & X6 R: s# q. O* U/ j points_2 = [ 3 [" ^6 ~3 F6 D! K G3 _1 | coordinate_orchard_road, / s' X: D1 N# v4 ]# m coordinate_sentosa, + o4 i- O1 P) D5 c$ U. \6 k coordinate_changi_airport 8 u: j# Q1 W/ v7 e$ K- W2 K/ k; A ] 3 D( h$ V3 J: X5 J( p * A& s4 Q% j3 k& [ city_map.add_child(folium.Polygon( $ J) H' ?( t8 {- \6 E2 |$ u6 Z locations=points_2, # 坐标列表+ \4 ^4 Y- U* t1 A, O# I weight=3, # 线条宽度' X! @8 `( J1 x+ g color=yellow))$ Y' @' \* D3 z4 o; o + t2 ?. l- S* L0 T: R # 矩形 1 @* ~( }2 f9 T$ E* ?: [9 u0 ~ bounds = [& D/ T m& [* ?6 ^ _9 y coordinate_ang_mo_kio, / N: n8 P6 u7 k# C coordinate_yi_shun % ^( g+ r+ ~# } ] - P# M2 a( d T1 T! Z3 L3 [ . v6 F, w- t# C% G3 g city_map.add_child(folium.Rectangle( . v9 d/ a0 t u( x W; x h6 N9 P3 z bounds=bounds, # 坐标列表, Latitude and Longitude of line (Northing, Easting)2 G5 R! b$ S4 _+ _: T weight=2, # 线条宽度 # [2 q/ Q0 i2 e$ g6 Q8 M: Z color=blue))2 X" y8 G4 [- U / P# C! O/ h* I6 I7 L! D5 A2 F9 \ # 圆形, circle, radius units meters - y4 r8 ~* ~; f$ w folium.Circle(& @1 P, T& J" ~, B X* O* z x radius=1000, 9 m- N/ J8 \. J' H location=coordinate_nus,3 j) P' t" A) K popup="National University of Singapore", " m+ a1 a2 Y& D1 Z: ]* S color="crimson",7 r& W, Z2 Y5 U; q* y fill=False, o6 G9 {. U1 C# O! d ).add_to(city_map); r! a# @0 `; ]7 I " u) A" W8 {) z5 L6 M6 b # 圆形, circle, radius units pixels2 K3 r$ c$ @/ | Q6 [ folium.CircleMarker( * ^4 T3 z- A% F location=coordinate_ntu,0 b- ^# U3 d5 i; G6 W9 X3 _ radius=30, H8 i* ~' C, W; Q& H0 J; a popup="Nanyang Technological University",) J0 U, z+ ~( w" G+ ?; A color="#3186cc", . B+ F# U/ ?4 f9 V fill=True,# l9 Y' G8 r$ h* y4 t fill_opacity=0.3, # 透明度 ' s! g0 \( d+ ]7 L& z fill_color="#3186cc", 8 j* D7 u3 `) Z/ {7 V ).add_to(city_map) ' u! d* ^ B7 D9 n, \% v: E/ m' Q, G2 z4 k+ \7 d' X P- T city_map
+ N& F6 [; e( q$ P
Folium 中的画出各种形状

热力图

/ {6 ]" g, A1 _. w* ^

在实际使用经纬度信息的时候,通常来说会针对某个 APP 或者多款 APP 的实时经纬度信息来获取路况的拥挤程度,景区的人流量等信息,在这种情况下,就可以做出热力图。通过实时的热力图信息,我们可以获得相应的人流量信息进行必要的数据分析工作。

, g/ a! g- o6 D# h5 o
import numpy as np* j- L* }$ I6 q9 g' G$ L from folium.plugins import HeatMap9 a: H: j* V0 s I: c2 ~$ I , {+ @2 ]( n( `* M& v( ]" Y # define the city map/ _# z+ ^) O4 C city_map = folium.Map(location=coordinate_orchard_road, zoom_start=11) " A) H+ |2 g4 Y: [ " E5 a8 t$ G' ?2 P, v3 f # 构建随机数据5 x1 _, ~/ M, m2 V data = ( 2 M# M6 h% l. e0 [. ?8 R: z np.random.normal(9 m: T3 O* L) Y size=(10, 3)) * 0.03 * np.array([[1, 1, 1]]) + * n/ Z4 F: L z, F np.array([[coordinate_orchard_road[0], coordinate_orchard_road[1], 1]])' V+ I6 \) K* C8 j) Q ).tolist() 1 _( X/ R6 q. T/ Z& Q1 U0 `2 I 7 G8 v: a& E, p2 z" m1 U city_map.add_child(HeatMap(data=data)) ! S q* ?/ j# a2 G city_map
6 W5 K& A$ w$ f$ X; U$ V
; i; M& D8 c, h$ V0 M& @

除了单张图的热力图之外,Folium 还能够计算一段时间的连续热力图信息。

- s7 @4 i X3 P+ m: A; l1 U
import numpy as np 0 d' J5 [% S0 n. i* V from folium.plugins import HeatMapWithTime 5 g+ N5 r& U- _( h $ ?& u; F2 f7 w3 C/ K # define the city map 1 V2 S4 }/ t( ]( o1 p7 q! c city_map = folium.Map(location=coordinate_orchard_road, zoom_start=11) I$ i( a- F7 I- g" }. z3 r8 @! i & [' q/ A% \/ b5 t* \+ \ n* o # 使用 numpy 建立初始数据 9 O- x* F# u$ m- k# o3 U initial_data = (np.random.normal(size=(200, 2)) *, h& o1 T) b% z, D0 b/ S. V8 W3 C np.array([[0.02, 0.02]]) + 3 Q' C2 t/ I7 c0 @ np.array([coordinate_orchard_road]))' c6 S8 _+ D5 @0 ^ k. Q9 M 1 x* v+ d- L3 P # 建立连续的数据 / _/ ?- p: b0 j) Z( F9 I data = [initial_data.tolist()]. J' ]& L! h# n6 r. H for i in range(20):1 e( r! m% y6 o z9 \0 S data.append((data[i] + np.random.normal(size=(200, 2)) * 0.001).tolist()) # y. I* n! @. s* Q# K: I- }8 V& l+ m: E( |) o- r; _ # 显示连续的热力图 ( L% {: s/ x' g& P( W city_map.add_child(HeatMapWithTime(data)) 2 z& H- K) n+ X city_map
2 e P5 @* o% ]6 s; I* h, W/ | ; K7 Q1 E) }/ y6 y- i

经纬度点的聚类

9 S/ b& G i% g# @! V2 t

除了热力图能反映人流量的信息,基于地理位置的聚类算法同样能够反映一个地区的拥挤程度,Folium 的 MarkerCluster() 函数可以对一个区域中的点来做聚类,在地图中可以放大和缩小,从而知道局部最拥挤的点在哪里了,最稀疏的区域是哪里。

" ?; D; k4 i& h3 x! Q
from folium.plugins import MarkerCluster# l( ^: H e6 P2 h & q2 V* Y# ^# h2 ] f& `% v # define the city map* c. F/ y1 I% s' K5 `6 y city_map = folium.Map(location=coordinate_orchard_road, zoom_start=11)+ ^; d$ j0 d5 J" T! T2 e) A 7 M, q7 g3 }- w& l# `6 U. _# F: E # 经纬度的聚类/ B) \' v# s0 q # 在 NUS 的经纬度附近随机生成 100 个点;7 R, s$ S& G1 ~& @2 V/ _2 _ data = (* K0 }8 I8 x* S2 z9 D0 ~1 { np.random.normal(size=(100, 2))7 F2 @% {8 L! z1 k * np.array([[0.001, 0.001]]) +7 N* G! C* ^2 I0 h7 R np.array([coordinate_nus]))% J" \3 {* m! z( C" Z 1 b" N/ o) E7 q% O4 Q. U # create a mark cluster object ; Q2 Y! S: E% q2 ]% s# v6 W marker_cluster = MarkerCluster().add_to(city_map)6 M7 ?5 _% n) [4 s 3 z) m' C: }' O# V1 a* h# s: M* D # 将这些经纬度数据加入聚类 $ m, R3 L7 P+ R for element in data:1 {, M: m J3 b3 @6 [ folium.Marker(location=[element[0], element[1]],icon=None).add_to(marker_cluster) 8 T+ D7 U7 s" O# m+ K& G8 H$ v* |3 z' D: E- T/ H' I # add marker_cluster to map 2 X, S2 f9 U% F9 f! r4 X/ Z city_map.add_child(marker_cluster) " A2 J+ I+ p& @7 \$ S * v5 u0 z8 E1 k5 ~ # 作图 ) }. J/ d/ b: J" r3 d9 t! |1 v# x city_map
& v6 I* }0 a% x2 `: V& E; U/ z * L5 y q6 V! _, ]8 U& K

以上就是关于 Folium 的基础内容,有兴趣的读者可以自行参阅 Folium 的官方文档。

( \# K3 A! Q- A4 x' t

参考文献

2 X7 H( Q! b6 m1 y9 W# f6 u

Folium 官方文档:Folium - Folium 0.12.1 documentation

4 S9 l' z$ i( P4 z7 ]- ` l 0 _5 V. o' t. {8 W. q 7 P( n$ b1 V, e: l6 x) R/ z) r8 U4 E6 {2 P 0 N1 Q8 O! @( z, s; N. d: Q2 h
回复

举报 使用道具

相关帖子

全部回帖
暂无回帖,快来参与回复吧
懒得打字?点击右侧快捷回复 【吾爱海洋论坛发文有奖】
您需要登录后才可以回帖 登录 | 立即注册
冰死铁
活跃在3 天前
快速回复 返回顶部 返回列表