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

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

[复制链接]
- l. l; @, Z& P2 ^, n: W' T I

Folium 简介

1 [0 S/ c- r# U _5 p. [4 y. J

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

$ s2 L# O' Z" L0 s$ J1 e6 e

创建地图

" ], c8 V Y# R: T6 T; N }

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

) ]. N2 }# q* \& U
import folium0 ?" c- b2 G& z# o/ ] %matplotlib inline2 W# k: n c% O- H- z ' [: ~6 ?' O1 P/ c3 q, [9 F* p import webbrowser9 ?1 g' ~! w" ^1 T 4 d; c. s) m- J, I# m$ ^& b print(folium.__version__)1 j8 ]4 |% A/ O. T& }9 N% m; f6 O) H : q/ j/ ^" ~5 Z: g* H( K, G8 Z # define the world map ) m3 t! D) b- W+ ?) A$ A world_map = folium.Map() ( `, H4 _2 j G # display world map9 R$ D& z R/ B world_map9 ~: F/ G4 O/ \! u! j" ]
. \* L# ?/ G; w/ u/ g% _! A5 t
世界地图

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

: h5 _" w7 a' D! }; o( y

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

0 V; l* p, m: X

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

# B% y+ Q, P t m3 f* F+ j

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

$ `& k: d" B: r e' b; f7 F6 k2 i
# latitude and longitude in Singapore city - a0 J# g" X* b0 ?: w coordinate_sentosa = [1.248946, 103.834306]( ^ O k, ~3 B2 h0 ?: G- \ coordinate_orchard_road = [1.304247, 103.833264] $ e* V4 F/ w7 ~( O; R; D coordinate_changi_airport = [1.357557, 103.98847]3 D/ H2 ?9 }5 S4 o6 b [ coordinate_nus = [1.296202,103.776899] % g" g# ?! @% Q coordinate_ntu = [1.34841, 103.682933]- e5 N5 f2 f- S2 C7 v coordinate_zoo = [1.403717, 103.793974] / ^+ w7 i6 V" S$ [8 f- \6 v) ~: k coordinate_ang_mo_kio = [1.37008, 103.849523] _" ~9 q$ {7 a3 m% l4 Y& i coordinate_yi_shun = [1.429384, 103.835028]3 |; c2 R$ J0 v0 f' o2 [ 9 A8 X6 O9 i1 z$ u4 d4 k) l+ Y0 u # icon ! w* b5 X V" L X8 i1 b. @/ F icon_cloud = "cloud" . d8 i& h% j! b" i" j) H% M icon_sign = "info-sign" : u7 e2 i3 K& S# p/ q: P/ Z ( n( S- e0 {( l. x* ^: M # define the city map / J4 ]0 ^5 _3 J# A! x # tiles in {OpenStreetMap, Stamen Terrain, Stamen Toner, Mapbox Bright} - z( a) Z7 _& E6 D city_map = folium.Map(# I& Q$ G% y+ t0 [# i4 V location=coordinate_orchard_road,; O7 Y4 S ?9 |8 Y zoom_start=11, 9 v3 e m9 R" E- y$ n tiles=OpenStreetMap)8 K" z; ~; I" O: W) K ' z9 Y" I; n( G* d+ `% O( M # add marker in the city map 5 f: J6 `( I# @5 n, o% J folium.Marker( 2 T) z% s3 T0 [6 h coordinate_sentosa, # u! a6 X+ O* i: d k icon=folium.Icon(color=blue)% g# Q/ D. \, a: r ).add_to(city_map)( @/ G/ u3 \, ^, i, o( d5 O& d folium.Marker(. E' X! z' I9 V0 H' q1 I coordinate_orchard_road,# o2 c( Y0 `, x! W0 B5 l icon=folium.Icon(color=green, icon=icon_cloud) 1 W* C: Z. n$ P9 m. d' B$ K+ k& U ).add_to(city_map)$ o" r6 J: f( I 7 `% U# w0 e' | r9 Q/ L # add popup 3 A( e g: Q; G folium.Marker(' Q8 {6 t6 z# h2 o/ I coordinate_changi_airport, 2 \# i' K5 L5 w& f0 b L4 n# }/ C7 _ popup=Changi Airport, 3 }! E1 g1 g4 W icon=folium.Icon(color=red, icon=icon_sign) ) s- S; S" I9 H5 {0 m+ m' D ).add_to(city_map)8 ^" k' u' [' d9 X; j& L7 C 9 I6 ^$ _$ d# F) t' s5 ^" G; h. Z # add tooltips and popup. t, w* ~$ i! r- ^ tooltip = "Click me!" ( @. a2 a! p3 m5 j2 Q& ?$ q 2 d3 v% T$ W% O$ P3 E folium.Marker( 4 v$ n4 C3 B, U1 |. G coordinate_nus, : ]: F2 ~ J3 C popup="<i>National University of Singapore</i>", ( @) U/ q% {2 _7 n$ R$ C tooltip=tooltip/ S: ^- c% Q9 y( v ).add_to(city_map)( H3 ?7 W/ t! [6 g" r5 H X4 K v + z# V" E& _3 ~( |1 r( x0 l! N folium.Marker( % c+ M2 E; d$ T& X/ Q ] coordinate_ntu," p+ c/ \; W. n, l9 H3 T$ K popup="<b>Nanyang Technological University</b>"," h9 A! M- p& R1 N2 o. i tooltip=tooltip$ D* \- ^( b" q5 q' g2 E. w. Q ).add_to(city_map) # c# }% Z( D5 [! r, C" d6 f v5 B+ T" y7 i& o: s9 x+ ^* x4 I # display city map i0 x- Y( f' d4 J& E3 `2 ]3 | city_map
" ` v& l. k* v/ v' A7 u
Folium 的经纬度作图(OpenStreetMap)
Folium 的经纬度作图(Stamen Terrain)
Folium 的经纬度作图(Stamen Toner)

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

' ]0 ^! n; m+ A6 G2 U
# define the city map& W. Z/ B) B" g6 B5 _7 E$ \) L0 g city_map = folium.Map(location=coordinate_orchard_road, zoom_start=11) ! c5 G( e- m3 i' B3 p& n. B# x$ m- X3 P8 w( W: U5 f- l6 X: m # 在地图中添加经纬度, add latitude and longitude in the map when click8 u- D! y. K& c: U0 h5 c2 C9 b2 u7 ~- B city_map.add_child(folium.LatLngPopup())0 G8 _( T2 O; r9 @3 \3 ` ; x2 s8 d2 k6 V city_map
$ q9 k0 w: E: {' y( X: k 1 P; l5 A) W) |' c" o1 i0 d% G

几何形状

- ^' V3 o; ~1 R4 a$ {

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

8 B6 Z7 z$ f2 P% ]
# define the city map 4 x# _& j2 q. x. \! u& |3 U city_map = folium.Map(location=coordinate_orchard_road, zoom_start=11)6 o' w4 A9 C6 F6 e+ J $ [% O i9 e% R* S. } } # 在地图中如何添加形状6 Q. z! @0 ?: x4 z, j. v # 多条边( h! X7 w5 Z0 H points_1 = [! K; m: S- d0 L& q0 l9 R coordinate_ntu,; G" f2 E0 h+ ?8 k; y7 [ coordinate_nus, / h9 D1 `/ A0 a/ I1 M coordinate_zoo* Z7 R5 \. j$ b& C) Q$ W0 M, p ]0 W& [, \; @% o! F+ u/ f& ^# L " |; H7 t) p. P# j# \$ n; f # 在 city_map 中添加多条边,第一种添加方式 5 G; b6 W# T9 J3 b6 [4 ]- r# s city_map.add_child(folium.PolyLine(% m6 B% Y% D% U5 l5 k locations=points_1, # 坐标列表) U' G' N( v' a: c weight=3, # 线条宽度& O: d' ^9 O9 a7 t6 A0 @$ p color=gray)) % Y, E% N c; N7 w. a5 m) Q2 t8 i. ?1 k1 }# w # 在 city_map 中添加多条边,第二种添加方式 ( y! O, k" ?; o. q+ A" J% U1 [4 \ folium.PolyLine(9 ?) C3 V- K3 M/ f. F" j locations=points_1, # 坐标列表2 |" u. |0 D% V) \: H( k; ~0 | weight=3, # 线条宽度5 D3 j6 G1 ^- }+ z; {# j. k( Z$ H color=gray).add_to(city_map)! ?% n5 Q1 o; O& J+ k ! c$ U, w5 I7 Z: Z6 c6 R0 E # 多边形/ x+ `8 R U1 d) k( v points_2 = [ . ~# [/ X: A& L% ?6 m0 @ coordinate_orchard_road,+ e) Y: c$ T) |& _( {, q coordinate_sentosa,2 {6 _" S% _. O5 c: V8 {4 W9 P- T coordinate_changi_airport8 n: Q# Y$ k, ]; M ] 3 a: T+ k7 Z0 r, }0 X- m# J) ~% S+ r3 ^( ]! c& o) c city_map.add_child(folium.Polygon(: S5 S$ J; S" x5 [" L D locations=points_2, # 坐标列表2 I6 ~% B4 \2 ? weight=3, # 线条宽度7 U; c0 S: Y+ I& D6 N' X6 A7 e color=yellow)). j3 E6 A8 A) e* T8 c/ }' _ & e' h, S) ~# }6 i: l8 ]. o/ U% F y0 |! A # 矩形" g0 G: R, Y9 O' E bounds = [ ) Z l1 o7 D2 o coordinate_ang_mo_kio,+ i2 l. t8 ?7 L. w; Z# [ coordinate_yi_shun- T% Z+ O; A/ I0 a2 h ]+ C' S6 X2 }* H; h / F R0 k, p) b; } city_map.add_child(folium.Rectangle( 1 i. s/ \8 \7 b4 c bounds=bounds, # 坐标列表, Latitude and Longitude of line (Northing, Easting) ' `' Y" @. I& X$ I0 o weight=2, # 线条宽度 1 p4 d5 {* @, {; v color=blue)) 0 G) j: ^% c( L3 M, ^( l. |$ Z! _ ( o. d! P; q1 z) U # 圆形, circle, radius units meters 9 r0 B8 F# z" S/ T6 o% \% V) m4 Q folium.Circle($ w1 \6 q, w9 [) W radius=1000,' l% M/ J- H0 U6 k location=coordinate_nus,# ]; G/ R! E v; H popup="National University of Singapore",/ }+ _1 c9 t2 R1 O1 c color="crimson",) s! A7 ^5 _0 u& G fill=False,/ @0 e4 Z7 l% `! \" J! G8 C ).add_to(city_map)5 ^* v) `9 S: @2 D 3 v6 d: Y" z2 b# \- g; g2 l2 j- d # 圆形, circle, radius units pixels / J- q/ L. _& [0 ~ folium.CircleMarker( . o0 A: C3 |" [% H- I: o9 l) d location=coordinate_ntu,: o( T. W2 |5 a: {/ f! } radius=30,* P" d, O4 y8 w0 A popup="Nanyang Technological University",. q5 B7 @- C6 @+ l6 @# a5 _/ G color="#3186cc", 9 ?& u- b$ t. p# }# f fill=True,' g7 b" G: Z4 T% j$ g3 W0 K0 d0 I fill_opacity=0.3, # 透明度 + Q2 Z* n( c* P* a6 K0 s fill_color="#3186cc", - J& g; w! C) `. D H, z4 k ).add_to(city_map)* t! c# u. C+ C Y( j+ ~) o , X$ \/ ]% j1 H/ @2 c& c city_map
0 r: H+ p8 \1 N! ]
Folium 中的画出各种形状

热力图

! T9 c3 f+ g9 Y

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

! r6 m3 f6 F( @% ^/ }0 Y
import numpy as np5 ^9 |1 ~) r& o3 }" F from folium.plugins import HeatMap : _3 i1 G, R+ s4 F. g ! {# Z8 O1 P/ m$ N # define the city map % ?" g* d# O6 T% [ city_map = folium.Map(location=coordinate_orchard_road, zoom_start=11)" b0 N6 E' A1 X3 g0 `( o i; m9 k. Q; n7 v # 构建随机数据 " |) q D# I- N, @ data = ( 5 a& j$ B; s$ T$ n np.random.normal(0 D" f9 b) p0 N3 y2 Y size=(10, 3)) * 0.03 * np.array([[1, 1, 1]]) + : A3 s) }! i3 m2 j3 | np.array([[coordinate_orchard_road[0], coordinate_orchard_road[1], 1]]) " e9 N; b$ `6 v, H: {5 D2 C [ ).tolist()! y" y$ S3 N3 x4 R5 s' \ 4 ~0 n( P6 A5 c1 s6 q. i+ P city_map.add_child(HeatMap(data=data))3 d5 n1 G l# m' B* c city_map
' Q3 k% s( g$ q
* | o- {7 F H1 p& q! V5 u

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

3 X1 P i$ p6 R; U$ ^4 ~" A
import numpy as np1 b" x( B: r* L4 C7 | from folium.plugins import HeatMapWithTime" G3 v, `' W8 y# e s' s 1 n+ H9 u$ V' k* _0 ^+ D4 n" h # define the city map+ G8 i0 l3 w9 V; ] city_map = folium.Map(location=coordinate_orchard_road, zoom_start=11): N z2 R, b8 D4 T/ h! m. @7 p: l1 J % R$ P! l/ u* ?0 |6 I2 V& \# ? # 使用 numpy 建立初始数据7 D; G; m s) X' F initial_data = (np.random.normal(size=(200, 2)) *+ p% }- \- `* D. h% O2 _ np.array([[0.02, 0.02]]) + 5 W; O' t# N. E+ S+ I6 I" e+ Z np.array([coordinate_orchard_road]))3 ]& `; I" P: H2 b* q * M+ n8 w5 \& U+ ? # 建立连续的数据 4 Z. l9 i- |6 D4 ^ data = [initial_data.tolist()]7 I, L4 i, ]; o% x for i in range(20): 3 {: g& V# Z4 G. l data.append((data[i] + np.random.normal(size=(200, 2)) * 0.001).tolist())! d5 S0 c1 e: E Y4 \0 R9 k ! N# `4 S1 K5 B) b$ A # 显示连续的热力图 , b. o9 t! m; p' g# \5 n% p3 k V city_map.add_child(HeatMapWithTime(data)), @* r3 \' q0 u. w8 O1 ]; _ city_map
0 J1 V& L/ |$ A2 Q* N* \6 m 2 F. Q% V) |; j* [$ V: H* c

经纬度点的聚类

+ m$ z8 b& p6 Z" f) E3 G( f

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

- k, u- F: ~9 `/ {. ^& n
from folium.plugins import MarkerCluster # Q& G0 L" F6 l3 y/ i! G% q% e! ~9 r8 A9 q8 c, f4 ~. p # define the city map $ a. U1 k" w7 T- O city_map = folium.Map(location=coordinate_orchard_road, zoom_start=11) ) N) Z& A% D3 h8 b, v ' F; m s& Q5 B6 f. H3 B # 经纬度的聚类, z: K8 Z) e* K" e- \ # 在 NUS 的经纬度附近随机生成 100 个点;. Z, Z( f' o! f data = (# O e6 z% D# f. I7 \8 L1 W1 y) i/ O+ S) U np.random.normal(size=(100, 2))8 g1 |0 ~$ L9 j3 w( a: D * np.array([[0.001, 0.001]]) +' y+ | \) D( L( Z8 o! d" j np.array([coordinate_nus]))+ B5 G) z$ g. d# [" R 5 o) P2 Y- J/ G% J1 o1 c7 j' r # create a mark cluster object ; m0 m) w8 b* d% X0 n7 E# c marker_cluster = MarkerCluster().add_to(city_map) i% _8 R% h0 P* p& |- ^/ B 5 Q* C7 k1 |- d) J# c9 x, S% M # 将这些经纬度数据加入聚类 2 u- ?- O% t! {6 Q for element in data: 6 P1 S/ ~% K& k folium.Marker(location=[element[0], element[1]],icon=None).add_to(marker_cluster)4 X# c! Z4 r" B& n% @3 t1 d) s4 H* [ 3 Q# Y/ Y6 C2 a' S # add marker_cluster to map# [0 k8 H5 g( f/ {( {1 l8 U city_map.add_child(marker_cluster) / S8 {1 v6 [* u. |( w. l0 y* M9 }: b # 作图 # }, ~/ q) p% q% S: | city_map
2 s: g9 @ {' n& y) `' R. }2 _7 m1 l 2 n V9 A. m+ ?0 X$ M$ X

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

; I! |0 p1 f! j4 {0 ^

参考文献

0 o" c( z. V2 U; a

Folium 官方文档:Folium - Folium 0.12.1 documentation

& u+ u3 B$ o3 `3 n n' R( h ! {0 U2 G8 O0 K3 |+ C1 a : Z, w) a4 O0 ~; a! ] 3 @5 ~- `0 Z, [$ `9 C/ r1 k. ~' E* `% {; C% |7 H
回复

举报 使用道具

相关帖子

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