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

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

[复制链接]
- p4 Z& G3 t9 q' n, k. b1 B

Folium 简介

/ N2 x& ~( z; P: m

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

0 \! B1 s( H: j7 [) M

创建地图

+ j% v8 A5 |1 ]4 M

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

" T* L7 Y; r- V# E( U. u
import folium 7 i4 q5 x/ o: k* i$ o% c/ s %matplotlib inline 6 H4 `4 _) y2 D$ l% r$ P7 o ) c3 }; F2 k7 Q& \# [ f( O0 \# l import webbrowser 1 z0 Y) o# J% r5 h8 B; _2 A% `7 ] print(folium.__version__) ^$ x7 c; l, L- x 5 N3 _6 ?9 r! N7 o1 F' A # define the world map ; l7 _3 q9 R7 o1 W0 M world_map = folium.Map()) x7 m# l0 b; W: R # display world map 6 s E$ d( h) h7 N$ J3 u/ d world_map ! _" r; ^$ A! D0 c8 u: h8 L) {
1 l5 F# w! u6 }& i$ `, w
世界地图

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

7 V0 n) D- B( t, Q6 [! a, m

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

3 i8 m6 r" @' r2 q' x }

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

0 J0 Y5 t# ?5 e

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

1 `- X, A$ e5 i. }
# latitude and longitude in Singapore city9 {& ~; X4 k0 b; {+ K9 F coordinate_sentosa = [1.248946, 103.834306] u: [( r& L3 j& W9 r6 W% { coordinate_orchard_road = [1.304247, 103.833264] " `, q6 n4 h$ E2 f' V9 Z) ^ coordinate_changi_airport = [1.357557, 103.98847]1 Y( M8 Q* ?6 [- J6 }0 i+ E coordinate_nus = [1.296202,103.776899] % p# k9 d$ l% ], o. w; p8 l coordinate_ntu = [1.34841, 103.682933] & D4 e5 `/ M: u* B# A: x i% w+ s coordinate_zoo = [1.403717, 103.793974]# U! q9 R1 Y9 k5 `$ W; c coordinate_ang_mo_kio = [1.37008, 103.849523] # s& A/ D: i' O* J5 ]* I9 P! f coordinate_yi_shun = [1.429384, 103.835028]- V J% d4 u) J m% o* g " q' [& u1 m/ d # icon) B! w4 A z4 R icon_cloud = "cloud"+ d4 }& f( ?3 d$ K+ C: s- N icon_sign = "info-sign"2 I \9 T9 b5 g1 l8 {4 u ) b. L0 ~7 R, k: s8 U # define the city map . B# {! x0 i' e+ v) | # tiles in {OpenStreetMap, Stamen Terrain, Stamen Toner, Mapbox Bright} / w& d2 C, j& { city_map = folium.Map( # e5 _5 b+ I# U$ B location=coordinate_orchard_road, 2 k9 A5 r# m. b3 ?5 _$ p zoom_start=11,) x3 K2 |2 C2 G. s9 V tiles=OpenStreetMap) ; w7 g- h6 n, Q3 I5 @ # ]; @& |' l3 Z6 J0 r# f # add marker in the city map! f% D8 C- l* D B ~: M4 n folium.Marker(* ~7 v7 F) K, C3 s: Y' Y/ J coordinate_sentosa,2 z6 I; o6 g' F6 d) n8 N' w icon=folium.Icon(color=blue) : G4 K, e& m. {+ {7 f5 C- l ).add_to(city_map)) }2 d. x _2 P+ j5 u3 Z1 s2 F folium.Marker( 9 e/ z8 m5 F W& U- r% T$ C coordinate_orchard_road,8 h: H( H2 G1 c1 ` icon=folium.Icon(color=green, icon=icon_cloud) 8 H0 e1 ]; w0 a ).add_to(city_map)# @5 |2 N4 L: ~7 X! h8 T 2 @. {6 p; v u9 O # add popup" c# j" G5 ~- }# H( S folium.Marker(& H/ K( w) v" l& h' r coordinate_changi_airport,, i: f' u8 `: T3 M popup=Changi Airport, 8 D; h; ~. J& ^ icon=folium.Icon(color=red, icon=icon_sign)! n* W5 b0 w7 \! v ).add_to(city_map)3 u# E# a @" c 9 I2 h* D# ?+ J x7 U( f # add tooltips and popup H u$ J% ^# h% L tooltip = "Click me!"! X: X! q8 ~+ B: {# ~# J! v ' ^2 E- [8 e* u+ U folium.Marker( 7 x$ t4 p$ b" i# F9 Q: f coordinate_nus,' l( j+ H$ p) X8 R popup="<i>National University of Singapore</i>", 8 i# D" x. B: ~" e- l tooltip=tooltip & e3 t) l9 ]* z% S; i y ).add_to(city_map) 0 k7 Q0 {1 N' C# O! A / E8 L! c6 Y! V) w: d folium.Marker(2 n! W; |9 y% Q0 i5 j4 q [ coordinate_ntu, 7 x! \2 p/ _/ I: v popup="<b>Nanyang Technological University</b>", : _0 v7 o' g: s$ s2 w4 y( k tooltip=tooltip 5 L' J* \$ j; i2 F ).add_to(city_map) # f0 o; H, C2 h4 i1 z* v $ ]+ d) |6 `5 v% O$ H # display city map 3 }; o: R, }$ @& F9 J city_map
9 X" `2 V( ^( r
Folium 的经纬度作图(OpenStreetMap)
Folium 的经纬度作图(Stamen Terrain)
Folium 的经纬度作图(Stamen Toner)

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

( f2 Y' c& o" v1 G& u1 a
# define the city map4 g# K R7 C) q city_map = folium.Map(location=coordinate_orchard_road, zoom_start=11): O G7 _2 M2 E8 j% S3 W y. b4 a' E6 Q+ `% W+ T # 在地图中添加经纬度, add latitude and longitude in the map when click + S" R( h0 @& ^4 I7 w: l; ^ city_map.add_child(folium.LatLngPopup()) 3 _5 A; p2 V4 r/ C8 ~0 {0 a# S q: U city_map
6 t# T' f/ o+ A0 b9 q6 P/ J 6 O" M. o) l9 D

几何形状

+ o: D& v$ G8 H

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

' a" d' J: E- r% y4 E0 q1 I
# define the city map ' v, d2 W% g1 U+ }' [ city_map = folium.Map(location=coordinate_orchard_road, zoom_start=11) 6 E5 [. q3 ~" D- i5 d5 r& c0 l6 i' F1 o% {( V# X # 在地图中如何添加形状 + ~) @* `. G3 [+ B # 多条边4 O. z1 ^- R2 ~- W9 _$ t2 {4 m points_1 = [ + C& _8 t% n. W. w8 m. }6 K coordinate_ntu, / ~$ t# O* j+ h) X coordinate_nus,: n5 @+ u. |/ v. S& ~ coordinate_zoo$ U; z2 E5 V$ P( C2 x9 S& v! d ] 6 r2 i- K8 \6 O 2 W H5 q8 S( ~6 s # 在 city_map 中添加多条边,第一种添加方式 9 G+ {5 J/ M" b- P0 V2 b- ] city_map.add_child(folium.PolyLine(1 L. [' ^8 S; y# Q- m locations=points_1, # 坐标列表6 ~- j3 p" g p8 A weight=3, # 线条宽度 V3 m$ j( X! a. S* a5 |3 | color=gray)) % c( Y( W; o" P! P5 l( I" V1 o' w- s0 T, Q # 在 city_map 中添加多条边,第二种添加方式 % V/ H5 O0 G9 A3 J folium.PolyLine( 7 o+ e) K. |* Y, Y4 U8 t2 h6 p4 Q3 \ locations=points_1, # 坐标列表$ N D/ k" S, ?" p8 t1 b" U2 C weight=3, # 线条宽度 ) p' z% N3 L. B color=gray).add_to(city_map) h/ R4 y( [: Q2 q' e, b2 U, Q+ @" z9 \( U3 k # 多边形) k0 l& h1 r: v points_2 = [. M2 b; a- b) h! d/ t coordinate_orchard_road,5 S, c( P( C7 U i* V: W$ j coordinate_sentosa, ' Z# Y/ \5 l0 F6 Q3 Y. G coordinate_changi_airport) L5 J b- W8 d2 Q/ q0 i% s ]6 \2 x6 P) T* b4 Z 2 b; S/ R. [2 w city_map.add_child(folium.Polygon( , }; B7 k4 l0 D( g locations=points_2, # 坐标列表 4 B0 ~1 x F7 ]& a! o weight=3, # 线条宽度! h8 g4 @7 h7 @- O color=yellow)) ( T" n* z$ V& U/ P+ }3 U0 U7 h) a6 E0 ?! ~% {' ]8 ] # 矩形2 U( W8 w! q& x- q, u bounds = [ , C+ @3 q; q7 `' M% | coordinate_ang_mo_kio,, Y& _0 g+ {+ p E: L2 R+ l9 N coordinate_yi_shun: E! @1 o) K' a+ M1 n+ M ]5 M6 K7 x u$ Z7 b6 ]* d 9 r/ d2 h+ t, {# A6 w. Y city_map.add_child(folium.Rectangle(0 Q% U4 Z$ K; U$ F bounds=bounds, # 坐标列表, Latitude and Longitude of line (Northing, Easting) . b4 A0 Y, s0 W! b. j+ O! U weight=2, # 线条宽度 * v" y, u$ `4 ?; ^; H color=blue))8 i; C1 x" ]' H- a5 j, T * t+ s$ _" E- p* q( }. E- a+ ~& M6 Y # 圆形, circle, radius units meters 5 q/ a! v: o3 F' O/ B- j folium.Circle(( {5 r8 N1 |, L radius=1000,! A# G' S3 \ a: ^, J3 k location=coordinate_nus,9 j* C1 t# o& C$ ?5 d( w4 V# Z popup="National University of Singapore",7 }0 A& V3 m6 w$ x. g P7 M: r color="crimson",& ]0 G- x- a- d6 E/ C6 V fill=False,8 E; f3 ?: p4 E2 }' F9 W ).add_to(city_map)! }2 H6 E1 \; q- g1 ` q' Q1 y 3 R' {( L: S; F9 f8 z& R0 J # 圆形, circle, radius units pixels; r) d( X) P; ?' }- n- o folium.CircleMarker( ; q0 n+ A4 t, u* x/ G location=coordinate_ntu,1 \ V M- k6 l% S* ^: \ radius=30, K9 a: c, a" m# y' j9 K popup="Nanyang Technological University", ! M( R& X$ D3 s! h" l0 _ color="#3186cc",# ]" L0 l# I, v- b! D8 H+ ~ fill=True, 6 y9 F) Q- }9 p$ F# w fill_opacity=0.3, # 透明度 % o2 }; w8 U& K) U" M( i, z fill_color="#3186cc",) ^0 W9 E1 v3 _, o3 M. O ).add_to(city_map) # m" M* }' l1 P* Q! c7 b* L9 o* Q : n9 T" W) C3 v city_map
; o1 S) A# {" J; ^7 s
Folium 中的画出各种形状

热力图

) y I% g* O6 |9 {8 ?! ^0 }

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

4 h4 [; V) U$ h& c
import numpy as np / g) Y+ S5 U0 n9 C from folium.plugins import HeatMap% ~. |3 Y! |& Y 9 u1 i7 R4 c! O1 ^% E3 F3 m6 M# D # define the city map 0 k0 d1 \4 x1 ?" M) b! @8 X( U( V1 _ city_map = folium.Map(location=coordinate_orchard_road, zoom_start=11) 6 B" l' c* W& A7 ^5 R* v9 k! m( F [( s+ u # 构建随机数据- }# }& L8 l; ~7 n data = ( ! J. o- o+ {& b' `+ |6 a( d) h np.random.normal(0 F6 `! h: N0 {! K5 s( R" A" a5 Y size=(10, 3)) * 0.03 * np.array([[1, 1, 1]]) + # ]8 Y: U( f/ `; X. P4 L9 d: ~ np.array([[coordinate_orchard_road[0], coordinate_orchard_road[1], 1]])6 Z a! X1 b8 ^# |% X ).tolist() + ?5 X9 e9 U$ u3 t" B 4 j0 w# d8 E0 {1 Z+ z4 s city_map.add_child(HeatMap(data=data))% ^; f0 W- i# A' y1 M ] city_map
% d% ~, ~. W3 I# B. J# h. {8 K
, v4 }4 h% ^% C! ?

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

; p" ] \5 \3 z6 N1 U" H; w% {
import numpy as np' [5 E8 P P. D: I- x# ? from folium.plugins import HeatMapWithTime + p% N- k2 N$ V( C z8 v ) t" H7 d' T- G, T5 `9 E5 \ # define the city map( t6 U: g3 f- Y% G1 a city_map = folium.Map(location=coordinate_orchard_road, zoom_start=11). s- m6 P/ {% Y0 p0 G; R0 I) i ( t: P' O4 `" Z8 U! ~ # 使用 numpy 建立初始数据5 o4 \: v$ o7 g; P' p* [1 ]; o initial_data = (np.random.normal(size=(200, 2)) * 8 e4 s8 |/ h+ }) K' h np.array([[0.02, 0.02]]) + + l' ]' c; s. ^6 A& h2 C" l# l np.array([coordinate_orchard_road])) 3 J E! R% G1 V) f - g3 t# o% v. R9 D # 建立连续的数据0 n/ G8 q* B/ P0 o! E7 z data = [initial_data.tolist()] % P" i) R* k9 H- c1 S- g s for i in range(20): ; j; G2 d& ~9 e data.append((data[i] + np.random.normal(size=(200, 2)) * 0.001).tolist()) 3 J( g" \0 U. Y1 f: \ * w. J* w3 b* H' J # 显示连续的热力图 6 {- e" W3 D, n0 Q' E city_map.add_child(HeatMapWithTime(data))# a' T6 ^+ U/ X F" A& u city_map
4 e& x# B, c/ f* K , B* `5 I7 g- @" Y! Q

经纬度点的聚类

# Y9 ]2 W N W3 V. W9 j* F

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

/ ]9 r! h' Q" I p: Y
from folium.plugins import MarkerCluster b4 E, T& D: T7 O4 O- S2 E( i; W) e6 s8 y2 } # define the city map ' `) C+ h: O! ^) E0 E& Y1 D city_map = folium.Map(location=coordinate_orchard_road, zoom_start=11)+ {! q; L, l7 E7 m 7 N2 T$ R c8 _6 v7 { # 经纬度的聚类 ; q' K1 O& M7 ^+ o" ? # 在 NUS 的经纬度附近随机生成 100 个点;3 N) S5 o- q2 z data = ( 9 p; t" r5 K0 u! e) W" } np.random.normal(size=(100, 2))5 l" F* j0 f) [ * np.array([[0.001, 0.001]]) +9 q b( z. p' Q0 I np.array([coordinate_nus])) , ^$ [# y3 x6 C5 G+ `3 ^8 F8 H . q3 v+ T7 f, Y; Z- n7 E/ F! o$ O # create a mark cluster object1 {- ]! \% h1 Y0 r6 ]. h0 r8 n marker_cluster = MarkerCluster().add_to(city_map)- J7 S" f0 Q- ` / u* q' `; a% z) O& h7 E k # 将这些经纬度数据加入聚类1 g) f9 t7 K4 E: v for element in data: ! M1 O) A9 p4 z folium.Marker(location=[element[0], element[1]],icon=None).add_to(marker_cluster) 8 {1 @6 C( `6 q3 U: x) C* i; P # add marker_cluster to map4 y3 Z; r0 P2 q, n( i& e5 q; c2 ` city_map.add_child(marker_cluster) . F2 e! l7 i7 L+ m1 V + L- @0 w2 J+ J# r # 作图 % ?& v+ l$ l1 Z$ v7 E. j( c* j city_map
! t) w7 {/ M- `3 W- {. m$ u 8 H: V9 _& ^% I3 M0 \4 K, j

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

4 K# D! S0 }4 ~# z! f6 ~

参考文献

9 H1 ^. Q" V4 \& l; @4 g' N

Folium 官方文档:Folium - Folium 0.12.1 documentation

- T5 v" I- s, c( t2 F9 H . [ `* S. ]# M R! x 3 U+ W2 R" L0 F9 Y6 d; o6 ^! T/ k5 p0 D; `* Z . @! r. _; ^1 g& P! E
回复

举报 使用道具

相关帖子

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