本文最后更新于:2024年5月21日 下午

Folium 是一个基于 Leaflet 的 Python 库,用于将地理数据可视化为地图。本文介绍 Folium 库及其使用方法。

简介

Folium 是一个基于 Leaflet 的 Python 库,用于将地理数据可视化为地图。Leaflet 是一个开源的交互式地图JavaScript库,而 Folium 则提供了一个简单的方式来将这些功能带到 Python 环境中。这对于数据科学家和分析师来说非常有用,因为他们可以在数据分析工作流程中轻松地创建、查看和分享地理空间数据。

folium 建立在 Python 生态系统的数据应用能力和 Leaflet.js 库的映射能力之上,在Python中操作数据,然后通过 folium 在 Leaflet 地图中可视化。folium 相比较于国内百度的 pyecharts 灵活性更强,能够自定义绘制区域,并且展现形式更加多样化。

这个开源库中有许多来自 OpenStreetMap、MapQuest Open、MapQuestOpen Aerial、Mapbox和Stamen 的内建地图元件,而且支持使用 Mapbox 或 Cloudmade 的 API 密钥来定制个性化的地图元件。Folium支持 GeoJSON 和 TopoJSON 两种文件格式的叠加,也可以将数据连接到这两种文件格式的叠加层,最后可使用 color-brewer 配色方案创建分布图。

Folium可以让你用 Python 强大生态系统来处理数据,然后用 Leaflet 地图来展示。Folium内置一些来自 OpenStreetMap、MapQuest Open、MapQuest Open Aerial、Mapbox和Stamen 的地图元件(tilesets),并且支持用 Mapbox 或者 Cloudmade API keys 来自定义地图元件。Folium支持 GeoJSON 和 TopJSON 叠加(overlays),绑定数据来创造一个分级统计图(Choropleth map)。但是,Folium库绘制热点图的时候,需要联网才可显示。

特点

Folium 的主要特点包括:

  1. 简单性:Folium 提供了一个简单易用的接口,使得在 Python 中创建地图变得非常直接。
  2. 功能丰富:通过 Folium,用户可以添加标记、多边形、圆形、热力图等多种地图元素,还可以自定义样式来美化和定制地图。
  3. 可扩展性:由于基于 Leaflet,Folium 能够利用 Leaflet 社区丰富的插件来进一步增强地图的功能。
  4. 集成性:Folium 可以很好地与其他 Python 数据处理库(如 Pandas)集成,方便地从数据集中提取地理信息并将其可视化。
  5. 导出能力:Folium 可以导出为 HTML 文件,使得创建的地图可以在独立的网页中查看,也可以直接在 Jupyter Notebook 中进行预览。

官方文档:https://python-visualization.github.io/folium/latest/user_guide.html

准备工作

安装

1
pip install folium

demo 示例

直接上代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import folium

# 经纬度坐标
latitude = 31.2623051474359
longitude = 121.14525775641026

# 创建一个以给定纬度和经度为中心的地图对象
m = folium.Map(location=[latitude, longitude], zoom_start=18)

for i in range(1, 5):
for j in range(1, 5):
cur_latitude = latitude + 0.0001 * i
cur_longitude = longitude + 0.0001 * j
folium.CircleMarker([cur_latitude, cur_longitude], radius=10, fill_color='red', tooltip=f'test {i} {j}').add_to(m)


# 保存地图
m.save("map-test.html")

效果展示,打开该文件就是这个状态,十分方便友好

使用指南

Map

https://python-visualization.github.io/folium/latest/user_guide/map.html

folium.Map 是 Folium 的基本类,每个地图都需要创建这样一个实例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import folium

min_lon, max_lon = -45, -35
min_lat, max_lat = -25, -15

m = folium.Map(
max_bounds=True,
location=[-20, -40],
zoom_start=6,
min_lat=min_lat,
max_lat=max_lat,
min_lon=min_lon,
max_lon=max_lon,
)

folium.CircleMarker([max_lat, min_lon], tooltip="Upper Left Corner").add_to(m)
folium.CircleMarker([min_lat, min_lon], tooltip="Lower Left Corner").add_to(m)
folium.CircleMarker([min_lat, max_lon], tooltip="Lower Right Corner").add_to(m)
folium.CircleMarker([max_lat, max_lon], tooltip="Upper Right Corner").add_to(m)

m

可以通过参数设置初始位置、放缩倍数,限制区域等属性

LayerControl

可以向当前 map 添加或控制图层

1
2
3
4
5
6
7
8
m = folium.Map(tiles=None)

folium.TileLayer("OpenStreetMap").add_to(m)
folium.TileLayer(show=False).add_to(m)

folium.LayerControl().add_to(m)

m

手动展示标记

1
2
3
4
5
6
7
8
m = folium.Map()

fg = folium.FeatureGroup(name="Icon collection", show=False).add_to(m)
folium.Marker(location=(0, 0)).add_to(fg)

folium.LayerControl().add_to(m)

m

Popups

可以向地图上的标记添加弹出介绍

Simple popups

弹出文字信息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
import folium


m = folium.Map([45, 0], zoom_start=4)

folium.Marker([45, -30], popup="inline implicit popup").add_to(m)

folium.CircleMarker(
location=[45, -10],
radius=25,
fill=True,
popup=folium.Popup("inline explicit Popup"),
).add_to(m)

ls = folium.PolyLine(
locations=[[43, 7], [43, 13], [47, 13], [47, 7], [43, 7]], color="red"
)

ls.add_child(folium.Popup("outline Popup on Polyline"))
ls.add_to(m)

gj = folium.GeoJson(
data={"type": "Polygon", "coordinates": [[[27, 43], [33, 43], [33, 47], [27, 47]]]}
)

gj.add_child(folium.Popup("outline Popup on GeoJSON"))
gj.add_to(m)

m

HTML in popup

可以在弹出提示中加入 HTML 元素

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
mport branca

m = folium.Map([43, -100], zoom_start=4)

html = """
<h1> This is a big popup</h1><br>
With a few lines of code...
<p>
<code>
from numpy import *<br>
exp(-2*pi)
</code>
</p>
"""


folium.Marker([30, -100], popup=html).add_to(m)

m

Iframe in popup

也可以将 Iframe 添加进去

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# Let's create a Figure, with a map inside.
f = branca.element.Figure()
folium.Map([-25, 150], zoom_start=3).add_to(f)

# Let's put the figure into an IFrame.
iframe = branca.element.IFrame(width=500, height=300)
f.add_to(iframe)

# Let's put the IFrame in a Popup
popup = folium.Popup(iframe, max_width=2650)

# Let's create another map.
m = folium.Map([43, -100], zoom_start=4)

# Let's put the Popup on a marker, in the second map.
folium.Marker([30, -100], popup=popup).add_to(m)

# We get a map in a Popup. Not really useful, but powerful.
m

Vega chart in popup

还可以加入 Vega 图表

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import json

import numpy as np
import vincent

multi_iter2 = {
"x": np.random.uniform(size=(100,)),
"y": np.random.uniform(size=(100,)),
}
scatter = vincent.Scatter(multi_iter2, iter_idx="x", height=100, width=200)
data = json.loads(scatter.to_json())

m = folium.Map([0, 0], zoom_start=1)
marker = folium.Marker([0, 0]).add_to(m)
popup = folium.Popup("Hello").add_to(marker)
folium.Vega(data, width="100%", height="100%").add_to(popup)

m

Vega-Lite chart in popup

更高级的 Vega 图表

Vector Layers

Circle and CircleMarker

CircleMarker 以像素指定半径,而 Circle 以米指定。这意味着当你缩放时,CircleMarker 不会改变你屏幕上的大小,而 Circle 在地图上有一个固定的位置。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
import folium

m = folium.Map(location=[-27.5717, -48.6256], zoom_start=9)

radius = 50
folium.CircleMarker(
location=[-27.55, -48.8],
radius=radius,
color="cornflowerblue",
stroke=False,
fill=True,
fill_opacity=0.6,
opacity=1,
popup="{} pixels".format(radius),
tooltip="I am in pixels",
).add_to(m)

radius = 25
folium.CircleMarker(
location=[-27.35, -48.8],
radius=radius,
color="black",
weight=3,
fill=False,
fill_opacity=0.6,
opacity=1,
).add_to(m)

radius = 10000
folium.Circle(
location=[-27.551667, -48.478889],
radius=radius,
color="black",
weight=1,
fill_opacity=0.6,
opacity=1,
fill_color="green",
fill=False, # gets overridden by fill_color
popup="{} meters".format(radius),
tooltip="I am in meters",
).add_to(m)

m

PolyLine
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
# Coordinates are 15 points on the great circle from Boston to San Francisco.
coordinates = [
[42.3581, -71.0636],
[42.82995815, -74.78991444],
[43.17929819, -78.56603306],
[43.40320216, -82.37774519],
[43.49975489, -86.20965845],
[43.46811941, -90.04569087],
[43.30857071, -93.86961818],
[43.02248456, -97.66563267],
[42.61228259, -101.41886832],
[42.08133868, -105.11585198],
[41.4338549, -108.74485069],
[40.67471747, -112.29609954],
[39.8093434, -115.76190821],
[38.84352776, -119.13665678],
[37.7833, -122.4167],
]

# Create the map and add the line
m = folium.Map(location=[41.9, -97.3], zoom_start=4)

folium.PolyLine(
locations=coordinates,
color="#FF0000",
weight=5,
tooltip="From Boston to San Francisco",
).add_to(m)

m

平滑

1
2
3
4
5
6
7
8
9
10
11
m = folium.Map(location=[41.9, -97.3], zoom_start=4)

folium.PolyLine(
smooth_factor=50,
locations=coordinates,
color="grey",
tooltip="Too much smoothing?",
weight=5,
).add_to(m)

m

多条线

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
lat = +38.89399
lon = -77.03659
zoom_start = 17

m = folium.Map(location=[lat, lon], zoom_start=zoom_start)

kw = {"color": "red", "fill": True, "radius": 20}

folium.CircleMarker([38.89415, -77.03738], **kw).add_to(m)
folium.CircleMarker([38.89415, -77.03578], **kw).add_to(m)


locations = [
[
(38.893596444352134, -77.03814983367920),
(38.893379333722040, -77.03792452812195),
],
[
(38.893379333722040, -77.03792452812195),
(38.893162222428310, -77.03761339187622),
],
[
(38.893162222428310, -77.03761339187622),
(38.893028615148424, -77.03731298446655),
],
[
(38.893028615148424, -77.03731298446655),
(38.892920059048464, -77.03691601753235),
],
[
(38.892920059048464, -77.03691601753235),
(38.892903358095296, -77.03637957572937),
],
[
(38.892903358095296, -77.03637957572937),
(38.893011914220770, -77.03592896461487),
],
[
(38.893011914220770, -77.03592896461487),
(38.893162222428310, -77.03549981117249),
],
[
(38.893162222428310, -77.03549981117249),
(38.893404384982480, -77.03514575958252),
],
[
(38.893404384982480, -77.03514575958252),
(38.893596444352134, -77.03496336936950),
],
]

folium.PolyLine(
locations=locations,
color="orange",
weight=8,
opacity=1,
smooth_factor=0,
).add_to(m)

m

Rectangle
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
m = folium.Map(location=[35.685, 139.76], zoom_start=15)

kw = {
"color": "blue",
"line_cap": "round",
"fill": True,
"fill_color": "red",
"weight": 5,
"popup": "Tokyo, Japan",
"tooltip": "<strong>Click me!</strong>",
}

folium.Rectangle(
bounds=[[35.681, 139.766], [35.691, 139.776]],
line_join="round",
dash_array="5, 5",
**kw,
).add_to(m)

dx = 0.012
folium.Rectangle(
bounds=[[35.681, 139.766 - dx], [35.691, 139.776 - dx]],
line_join="mitter",
dash_array="5, 10",
**kw,
).add_to(m)

folium.Rectangle(
bounds=[[35.681, 139.766 - 2 * dx], [35.691, 139.7762 - 2 * dx]],
line_join="bevel",
dash_array="15, 10, 5, 10, 15",
**kw,
).add_to(m)

m

Polygon
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
m = folium.Map(location=[35.67, 139.78], zoom_start=13)

locations = [
[35.6762, 139.7795],
[35.6718, 139.7831],
[35.6767, 139.7868],
[35.6795, 139.7824],
[35.6787, 139.7791],
]

folium.Polygon(
locations=locations,
color="blue",
weight=6,
fill_color="red",
fill_opacity=0.5,
fill=True,
popup="Tokyo, Japan",
tooltip="Click me!",
).add_to(m)

m

ColorLine
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import numpy as np

x = np.linspace(0, 2 * np.pi, 300)

lats = 20 * np.cos(x)
lons = 20 * np.sin(x)
colors = np.sin(5 * x)
import folium

m = folium.Map([0, 0], zoom_start=3)

color_line = folium.ColorLine(
positions=list(zip(lats, lons)),
colors=colors,
colormap=["y", "orange", "r"],
weight=10,
).add_to(m)

m

更多功能参考:https://python-visualization.github.io/folium/latest/user_guide.html

参考资料



文章链接:
https://www.zywvvd.com/notes/coding/python/folium/folium/


“觉得不错的话,给点打赏吧 ୧(๑•̀⌄•́๑)૭”

微信二维码

微信支付

支付宝二维码

支付宝支付

Python 地图可视化 Folium
https://www.zywvvd.com/notes/coding/python/folium/folium/
作者
Yiwei Zhang
发布于
2024年5月21日
许可协议