【零代码秘籍】Folium交互式地图可视化:10分钟从菜鸟到大师的完全指南
1. 引言:地图可视化的利器
在数据可视化领域,地图作为一种直观的空间信息表达方式,具有无可替代的优势。而当地图从静态走向交互式,其表达力更是呈指数级提升。Folium库作为Python生态中最受欢迎的交互式地图可视化工具,以其简洁的语法和强大的功能,让数据分析师和开发者能够轻松创建专业级的Web地图应用。
本文将带你全面掌握Folium的使用技巧,从基础地图创建到高级功能应用,帮助你快速实现各类地理数据的可视化需求,无需编写一行JavaScript代码。
2. Folium基础:理解与安装
2.1 Folium是什么?
Folium是Python的一个强大库,它将Python的数据处理能力与Leaflet.js的交互式地图可视化能力完美结合。使用Folium,你可以:
- 在Python中创建交互式Web地图
- 利用各种底图服务(OpenStreetMap, Mapbox等)
- 添加标记、弹出窗口、线条、多边形等地图元素
- 集成地理数据(GeoJSON, TopoJSON等)
- 创建分级统计图(Choropleth Maps)
- 生成热力图、聚类图等高级可视化
- 导出为独立的HTML文件,可在任何浏览器中查看
2.2 安装与环境配置
# 使用pip安装Folium
pip install folium
# 如果需要高级功能,安装扩展包
pip install folium branca geojson numpy pandas
# 导入基础库
import folium
import pandas as pd
import numpy as np
3. 创建你的第一个交互式地图
3.1 基础地图创建
# 创建一个地图对象,指定中心点和缩放级别
m = folium.Map(location=[30.5928, 114.3055], zoom_start=12) # 武汉市中心
# 保存为HTML文件
m.save('my_first_map.html')
3.2 切换底图样式
Folium提供多种底图样式选择:
# 常用的底图样式
tiles = {
'默认OpenStreetMap': 'OpenStreetMap',
'卫星图': 'Stamen Terrain',
'黑白底图': 'CartoDB positron',
'暗黑模式': 'CartoDB dark_matter',
'水彩风格': 'Stamen Watercolor'
}
# 创建包含多种样式的地图
for name, tile in tiles.items():
m = folium.Map(location=[30.5928, 114.3055], zoom_start=12, tiles=tile)
m.save(f'map_{tile.replace(" ", "_")}.html')
3.3 添加简单标记
# 创建基础地图
m = folium.Map(location=[30.5928, 114.3055], zoom_start=12)
# 添加标记
folium.Marker(
location=[30.5928, 114.3055],
popup='武汉市中心',
tooltip='点击查看详情',
icon=folium.Icon(color='red', icon='info-sign')
).add_to(m)
# 保存地图
m.save('map_with_marker.html')
4. 基础地图元素
4.1 标记与图标
# 创建地图
m = folium.Map(location=[30.5928, 114.3055], zoom_start=12)
# 自定义图标
custom_icon = folium.Icon(
color='green', # 图标颜色
icon_color='white', # 图标中符号的颜色
icon='university', # Font Awesome图标名称
prefix='fa' # 图标库前缀
)
# 添加带自定义图标的标记
folium.Marker(
location=[30.5928, 114.3055],
popup='<b>武汉大学</b><br>中国顶尖高校',
tooltip='武汉大学',
icon=custom_icon
).add_to(m)
# 使用圆形标记
folium.CircleMarker(
location=[30.5830, 114.2830],
radius=50, # 半径(像素)
popup='华中科技大学',
color='#3186cc', # 边框颜色
fill=True,
fill_color='#3186cc', # 填充颜色
fill_opacity=0.2
).add_to(m)
m.save('markers_and_icons.html')
4.2 弹出窗口与工具提示
# 创建地图
m = folium.Map(location=[30.5928, 114.3055], zoom_start=12)
# 添加带HTML格式弹出窗口的标记
folium.Marker(
location=[30.5928, 114.3055],
popup=folium.Popup(
'<h3>武汉大学</h3>'
'<img src="https://example.com/whu.jpg" width="200px"><br>'
'<p>始建于1893年,是中国著名的综合性大学。</p>'
'<a href="https://www.whu.edu.cn" target="_blank">官网链接</a>',
max_width=300
),
tooltip='点击查看详情',
icon=folium.Icon(color='red', icon='graduation-cap', prefix='fa')
).add_to(m)
# 添加IFrame弹出窗口
iframe = folium.IFrame(html='<h3>华中科技大学</h3>', width=200, height=100)
popup = folium.Popup(iframe, max_width=300)
folium.Marker(
location=[30.5830, 114.2830],
popup=popup,
tooltip='华中科技大学',
icon=folium.Icon(color='blue', icon='book', prefix='fa')
).add_to(m)
m.save('markers_with_popups.html')
4.3 线条与路径
# 创建地图
m = folium.Map(location=[30.5928, 114.3055], zoom_start=12)
# 添加一条线段
folium.PolyLine(
locations=[
[30.5928, 114.3055], # 武汉大学
[30.5830, 114.2830], # 华中科技大学
[30.5223, 114.3559] # 华中师范大学
],
color='blue',
weight=5, # 线宽
opacity=0.8,
popup='武汉高校连线'
).add_to(m)
# 添加带箭头的线段
folium.plugins.AntPath(
locations=[
[30.5928, 114.3055], # 起点
[30.6100, 114.3600] # 终点
],
color='red',
weight=5,
opacity=0.8,
popup='路线A',
tooltip='带动画效果的路径'
).add_to(m)
m.save('lines_and_paths.html')
4.4 多边形区域
# 创建地图
m = folium.Map(location=[30.5928, 114.3055], zoom_start=12)
# 创建多边形
folium.Polygon(
locations=[
[30.6000, 114.3000],
[30.6000, 114.3200],
[30.5800, 114.3200],
[30.5800, 114.3000]
],
color='purple',
fill=True,
fill_color='purple',
fill_opacity=0.4,
popup='武昌区域范围'
).add_to(m)
# 添加圆形区域
folium.Circle(
location=[30.5928, 114.3055],
radius=2000, # 半径(米)
color='green',
fill=True,
fill_color='green',
fill_opacity=0.2,
popup='2公里覆盖范围'
).add_to(m)
m.save('polygons_and_areas.html')
5. 高级地图功能
5.1 分级统计图 (Choropleth Maps)
# 加载示例数据
import pandas as pd
data = pd.DataFrame({
'district': ['东湖高新区', '江岸区', '江汉区', '硚口区', '汉阳区', '武昌区', '洪山区'],
'population': [10000, 85000, 75000, 65000, 70000, 90000, 80000]
})
# 加载区域GeoJSON数据(假设已有武汉市区域GeoJSON文件)
import json
with open('wuhan_districts.geojson', 'r', encoding='utf-8') as f:
wuhan_geo = json.load(f)
# 创建地图
m = folium.Map(location=[30.5928, 114.3055], zoom_start=11)
# 添加分级统计图
folium.Choropleth(
geo_data=wuhan_geo,
name='人口分布',
data=data,
columns=['district', 'population'],
key_on='feature.properties.name', # GeoJSON中的属性名
fill_color='YlOrRd', # 色阶
fill_opacity=0.7,
line_opacity=0.2,
legend_name='人口数量'
).add_to(m)
# 添加图层控制
folium.LayerControl().add_to(m)
m.save('choropleth_map.html')
5.2 热力图 (Heatmap)
# 加载示例点数据
import numpy as np
np.random.seed(42)
data = pd.DataFrame({
'lat': np.random.normal(30.58, 0.05, 500),
'lon': np.random.normal(114.30, 0.05, 500),
'value': np.random.uniform(1, 10, 500) # 权重值
})
# 创建地图
m = folium.Map(location=[30.5928, 114.3055], zoom_start=12)
# 添加热力图
from folium.plugins import HeatMap
HeatMap(
data=data[['lat', 'lon', 'value']].values.tolist(),
radius=15, # 热点半径
gradient={0.4: 'blue', 0.65: 'lime', 1: 'red'}, # 自定义色阶
min_opacity=0.2,
max_opacity=0.8,
blur=10
).add_to(m)
m.save('heatmap.html')
5.3 标记聚类 (Marker Cluster)
# 创建地图
m = folium.Map(location=[30.5928, 114.3055], zoom_start=12)
# 创建聚类标记组
from folium.plugins import MarkerCluster
marker_cluster = MarkerCluster().add_to(m)
# 生成随机点
np.random.seed(42)
for i in range(100):
lat = np.random.uniform(30.55, 30.65)
lon = np.random.uniform(114.25, 114.35)
folium.Marker(
location=[lat, lon],
popup=f'标记 #{i+1}',
icon=folium.Icon(color='green', icon='info-sign')
).add_to(marker_cluster)
m.save('marker_cluster.html')
5.4 自定义图层控制
# 创建地图
m = folium.Map(location=[30.5928, 114.3055], zoom_start=12)
# 创建不同的特征组
universities = folium.FeatureGroup(name='高校')
hospitals = folium.FeatureGroup(name='医院')
parks = folium.FeatureGroup(name='公园')
# 添加高校标记
universities_data = [
{'name': '武汉大学', 'location': [30.5928, 114.3055]},
{'name': '华中科技大学', 'location': [30.5830, 114.2830]},
{'name': '华中师范大学', 'location': [30.5223, 114.3559]}
]
for uni in universities_data:
folium.Marker(
location=uni['location'],
popup=uni['name'],
icon=folium.Icon(color='blue', icon='graduation-cap', prefix='fa')
).add_to(universities)
# 添加医院标记
hospitals_data = [
{'name': '武汉协和医院', 'location': [30.5800, 114.3000]},
{'name': '湖北省人民医院', 'location': [30.6000, 114.2800]}
]
for hospital in hospitals_data:
folium.Marker(
location=hospital['location'],
popup=hospital['name'],
icon=folium.Icon(color='red', icon='plus', prefix='fa')
).add_to(hospitals)
# 添加公园区域
parks_data = [
{'name': '东湖', 'polygon': [
[30.5800, 114.3600],
[30.5800, 114.3900],
[30.5500, 114.3900],
[30.5500, 114.3600]
]}
]
for park in parks_data:
folium.Polygon(
locations=park['polygon'],
popup=park['name'],
color='green',
fill=True,
fill_color='green',
fill_opacity=0.4
).add_to(parks)
# 将所有特征组添加到地图
universities.add_to(m)
hospitals.add_to(m)
parks.add_to(m)
# 添加图层控制
folium.LayerControl().add_to(m)
m.save('custom_layer_control.html')
6. 实用案例与扩展功能
6.1 房地产选址分析地图
# 创建地图
m = folium.Map(location=[30.5928, 114.3055], zoom_start=12)
# 添加房产标记
properties = [
{'name': '项目A', 'location': [30.5900, 114.3100], 'price': 15000, 'area': 120},
{'name': '项目B', 'location': [30.6000, 114.3200], 'price': 18000, 'area': 90},
{'name': '项目C', 'location': [30.5800, 114.3000], 'price': 12000, 'area': 150},
{'name': '项目D', 'location': [30.6100, 114.3300], 'price': 20000, 'area': 85}
]
# 创建设施标记图层
facilities = folium.FeatureGroup(name='周边设施')
# 添加学校、商场等设施
facilities_data = [
{'name': '学校A', 'location': [30.5920, 114.3080], 'type': 'school'},
{'name': '商场B', 'location': [30.5950, 114.3150], 'type': 'shopping'},
{'name': '医院C', 'location': [30.6050, 114.3250], 'type': 'hospital'},
{'name': '地铁站D', 'location': [30.5880, 114.3020], 'type': 'subway'}
]
icon_map = {
'school': {'color': 'blue', 'icon': 'graduation-cap'},
'shopping': {'color': 'green', 'icon': 'shopping-cart'},
'hospital': {'color': 'red', 'icon': 'plus'},
'subway': {'color': 'purple', 'icon': 'subway'}
}
for facility in facilities_data:
icon_info = icon_map.get(facility['type'], {'color': 'gray', 'icon': 'info'})
folium.Marker(
location=facility['location'],
popup=facility['name'],
icon=folium.Icon(color=icon_info['color'], icon=icon_info['icon'], prefix='fa')
).add_to(facilities)
# 创建房产标记图层
property_group = folium.FeatureGroup(name='房产项目')
for prop in properties:
# 创建自定义HTML弹出窗口
html = f"""
<h3>{prop['name']}</h3>
<table style="width:100%">
<tr>
<td>均价:</td>
<td>{prop['price']}元/㎡</td>
</tr>
<tr>
<td>面积:</td>
<td>{prop['area']}㎡</td>
</tr>
<tr>
<td>总价:</td>
<td>{prop['price'] * prop['area'] / 10000:.2f}万元</td>
</tr>
</table>
"""
iframe = folium.IFrame(html=html, width=200, height=150)
popup = folium.Popup(iframe)
# 圆形标记,大小与价格相关
folium.CircleMarker(
location=prop['location'],
radius=prop['price']/1000, # 价格越高,圆越大
popup=popup,
color='red',
fill=True,
fill_color='red',
fill_opacity=0.6,
tooltip=f"{prop['name']} - {prop['price']}元/㎡"
).add_to(property_group)
# 添加1公里和3公里半径圈(以市中心为原点)
travel_distance = folium.FeatureGroup(name='出行距离')
folium.Circle(
location=[30.5928, 114.3055],
radius=1000, # 1公里
color='blue',
fill=True,
fill_opacity=0.1,
popup='1公里范围'
).add_to(travel_distance)
folium.Circle(
location=[30.5928, 114.3055],
radius=3000, # 3公里
color='green',
fill=True,
fill_opacity=0.1,
popup='3公里范围'
).add_to(travel_distance)
# 将图层添加到地图
facilities.add_to(m)
property_group.add_to(m)
travel_distance.add_to(m)
# 添加图层控制
folium.LayerControl().add_to(m)
# 添加迷你地图
from folium.plugins import MiniMap
MiniMap().add_to(m)
m.save('real_estate_analysis.html')
6.2 交通路线规划与分析
# 创建地图
m = folium.Map(location=[30.5928, 114.3055], zoom_start=12)
# 添加起点和终点标记
start_point = [30.5928, 114.3055] # 武汉大学
end_point = [30.5830, 114.2830] # 华中科技大学
folium.Marker(
location=start_point,
popup='起点:武汉大学',
icon=folium.Icon(color='green', icon='play', prefix='fa')
).add_to(m)
folium.Marker(
location=end_point,
popup='终点:华中科技大学',
icon=folium.Icon(color='red', icon='stop', prefix='fa')
).add_to(m)
# 定义多条路线
routes = [
{
'name': '路线1 (最短)',
'path': [
start_point,
[30.5900, 114.2950],
[30.5850, 114.2900],
end_point
],
'color': 'blue',
'time': '25分钟',
'distance': '5.2公里'
},
{
'name': '路线2 (最快)',
'path': [
start_point,
[30.6000, 114.3000],
[30.5950, 114.2850],
end_point
],
'color': 'red',
'time': '20分钟',
'distance': '6.5公里'
},
{
'name': '路线3 (风景好)',
'path': [
start_point,
[30.5800, 114.3100],
[30.5750, 114.3000],
[30.5800, 114.2900],
end_point
],
'color': 'green',
'time': '30分钟',
'distance': '7.0公里'
}
]
# 创建路线图层
for route in routes:
# 创建路线弹出信息
html = f"""
<h3>{route['name']}</h3>
<p>行程时间: {route['time']}</p>
<p>距离: {route['distance']}</p>
"""
# 添加路线
folium.PolyLine(
locations=route['path'],
color=route['color'],
weight=5,
opacity=0.7,
popup=folium.Popup(html, max_width=300)
).add_to(m)
# 添加交通拥堵点
congestion_points = [
{'location': [30.5880, 114.2930], 'level': 'high', 'time': '08:00-09:00'},
{'location': [30.5950, 114.2980], 'level': 'medium', 'time': '17:00-19:00'}
]
for point in congestion_points:
color = 'red' if point['level'] == 'high' else 'orange'
folium.CircleMarker(
location=point['location'],
radius=10,
color=color,
fill=True,
fill_opacity=0.7,
popup=f"拥堵等级: {point['level']}<br>时段: {point['time']}"
).add_to(m)
# 添加交通信息图层控制
folium.LayerControl().add_to(m)
m.save('route_planning.html')
6.3 位置搜索与地理编码功能
# 创建地图
m = folium.Map(location=[30.5928, 114.3055], zoom_start=12)
# 添加搜索功能
from folium.plugins import Search
# 假设我们有POI数据
poi_data = {
'type': 'FeatureCollection',
'features': [
{
'type': 'Feature',
'properties': {'name': '武汉大学', 'type': '教育'},
'geometry': {'type': 'Point', 'coordinates': [114.3055, 30.5928]}
},
{
'type': 'Feature',
'properties': {'name': '华中科技大学', 'type': '教育'},
'geometry': {'type': 'Point', 'coordinates': [114.2830, 30.5830]}
},
{
'type': 'Feature',
'properties': {'name': '武汉协和医院', 'type': '医疗'},
'geometry': {'type': 'Point', 'coordinates': [114.3000, 30.5800]}
}
]
}
# 创建GeoJSON图层
poi_layer = folium.GeoJson(
poi_data,
name='兴趣点',
popup=folium.GeoJsonPopup(fields=['name', 'type'])
)
poi_layer.add_to(m)
# 添加搜索控件
search = Search(
layer=poi_layer,
geom_type='Point',
placeholder='搜索地点...',
collapsed=False,
search_label='name'
)
m.add_child(search)
# 添加地理定位控件
from folium.plugins import LocateControl
LocateControl().add_to(m)
m.save('location_search.html')
6.4 时间序列数据可视化
# 创建地图
m = folium.Map(location=[30.5928, 114.3055], zoom_start=12)
# 准备时间序列数据(模拟一周内的交通流量)
time_data = []
days = ['周一', '周二', '周三', '周四', '周五', '周六', '周日']
np.random.seed(42)
for i, day in enumerate(days):
# 模拟交通路口在不同时间的流量
flow = np.random.normal(100, 30, 24) # 24小时
# 模拟高峰时段
flow[7:9] += 100 # 早高峰
flow[17:19] += 150 # 晚高峰
# 周末模式不同
if i >= 5:
flow = flow * 0.7 # 周末交通量较低
flow[10:14] += 80 # 午间购物高峰
for hour in range(24):
time_data.append({
'day': day,
'hour': hour,
'flow': int(max(0, flow[hour])),
'location': [30.5928, 114.3055]
})
# 使用TimestampedGeoJson插件可视化时间序列数据
from folium.plugins import TimestampedGeoJson
# 准备GeoJSON格式数据
features = []
for entry in time_data:
features.append({
'type': 'Feature',
'geometry': {
'type': 'Point',
'coordinates': [entry['location'][1], entry['location'][0]]
},
'properties': {
'time': f"{entry['day']} {entry['hour']:02d}:00",
'icon': 'circle',
'iconstyle': {
'fillColor': f"{'green' if entry['flow'] < 100 else 'yellow' if entry['flow'] < 200 else 'red'}",
'fillOpacity': 0.8,
'stroke': True,
'radius': entry['flow'] / 20
},
'popup': f"{entry['day']} {entry['hour']:02d}:00<br>流量: {entry['flow']}"
}
})
# 添加时间序列图层
time_layer = TimestampedGeoJson(
{
'type': 'FeatureCollection',
'features': features
},
period='PT1H', # 1小时间隔
duration='PT1H', # 每个时间点显示1小时
transition_time=200, # 过渡动画时间
auto_play=True, # 自动播放
loop=True # 循环播放
)
time_layer.add_to(m)
m.save('time_series_visualization.html')
7. 与其他Python库集成
7.1 与Pandas集成
# 从Pandas DataFrame创建地图
# 假设我们有一个包含城市数据的DataFrame
cities_data = pd.DataFrame({
'city': ['武汉', '北京', '上海', '广州', '深圳'],
'lat': [30.5928, 39.9042, 31.2304, 23.1291, 22.5431],
'lon': [114.3055, 116.4074, 121.4737, 113.2644, 114.0579],
'population': [11.21, 21.54, 24.28, 15.31, 17.56], # 单位:百万
'gdp': [1.77, 3.61, 3.87, 2.39, 2.69] # 单位:万亿元
})
# 创建地图
m = folium.Map(location=[35, 105], zoom_start=5)
# 添加城市标记,大小表示人口,颜色表示GDP
for _, city in cities_data.iterrows():
# GDP决定颜色深浅
gdp_normalized = (city['gdp'] - cities_data['gdp'].min()) / (cities_data['gdp'].max() - cities_data['gdp'].min())
color = f'#{int(255 * (1 - gdp_normalized)):02x}0000' # 从浅红到深红
# 创建HTML信息窗口
html = f"""
<h3>{city['city']}</h3>
<table>
<tr><td>人口:</td><td>{city['population']}百万</td></tr>
<tr><td>GDP:</td><td>{city['gdp']}万亿元</td></tr>
</table>
"""
iframe = folium.IFrame(html=html, width=200, height=100)
popup = folium.Popup(iframe)
# 创建圆形标记,人口决定大小
folium.CircleMarker(
location=[city['lat'], city['lon']],
radius=city['population']/2, # 人口越多,圆越大
popup=popup,
color=color,
fill=True,
fill_color=color,
fill_opacity=0.6,
tooltip=city['city']
).add_to(m)
m.save('pandas_integration.html')
7.2 与GeoPandas集成
# 安装GeoPandas
# pip install geopandas
import geopandas as gpd
# 加载中国省级行政区划数据
china = gpd.read_file('china_provinces.geojson')
# 创建一些示例数据
china['value'] = np.random.randint(100, 1000, size=len(china))
# 创建地图
m = folium.Map(location=[35, 105], zoom_start=4)
# 添加区域多边形
folium.GeoJson(
china,
name='中国省份',
style_function=lambda feature: {
'fillColor': '#ffff00' if feature['properties']['value'] < 500 else '#ff0000',
'color': 'black',
'weight': 1,
'fillOpacity': 0.5
},
tooltip=folium.GeoJsonTooltip(
fields=['name', 'value'],
aliases=['省份:', '数值:'],
localize=True
),
popup=folium.GeoJsonPopup(
fields=['name', 'value'],
aliases=['省份:', '数值:'],
localize=True
)
).add_to(m)
# 添加分级统计图
folium.Choropleth(
geo_data=china,
name='分级统计图',
data=china,
columns=['name', 'value'],
key_on='feature.properties.name',
fill_color='YlOrRd',
fill_opacity=0.7,
line_opacity=0.2,
legend_name='指标值'
).add_to(m)
# 添加图层控制
folium.LayerControl().add_to(m)
m.save('geopandas_integration.html')
7.3 与Matplotlib集成
# 在Folium地图中嵌入Matplotlib图表
import matplotlib.pyplot as plt
import io
import base64
from PIL import Image
# 创建地图
m = folium.Map(location=[30.5928, 114.3055], zoom_start=12)
# 创建Matplotlib图表
def create_chart(city_name, data):
fig, ax = plt.subplots(figsize=(6, 4))
categories = ['教育', '医疗', '交通', '环境', '文化']
ax.bar(categories, data, color='skyblue')
ax.set_ylim(0, 100)
ax.set_title(f'{city_name}城市评分')
ax.set_ylabel('得分')
# 保存图表为内存中的图像
img_bytes = io.BytesIO()
plt.savefig(img_bytes, format='png', bbox_inches='tight')
plt.close()
img_bytes.seek(0)
# 转换为base64编码
encoded = base64.b64encode(img_bytes.read()).decode('utf-8')
return encoded
# 城市数据
cities = [
{'name': '武汉', 'location': [30.5928, 114.3055], 'scores': [85, 78, 82, 75, 88]},
{'name': '上海', 'location': [31.2304, 121.4737], 'scores': [92, 90, 95, 80, 93]},
{'name': '北京', 'location': [39.9042, 116.4074], 'scores': [90, 85, 88, 70, 95]}
]
# 为每个城市添加包含图表的标记
for city in cities:
chart_img = create_chart(city['name'], city['scores'])
# 创建包含图表的HTML
html = f"""
<h3>{city['name']}城市评分</h3>
<img src="data:image/png;base64,{chart_img}" width="300">
"""
iframe = folium.IFrame(html=html, width=320, height=280)
popup = folium.Popup(iframe)
folium.Marker(
location=city['location'],
popup=popup,
tooltip=f"{city['name']}城市评分",
icon=folium.Icon(color='blue', icon='info-sign')
).add_to(m)
m.save('matplotlib_integration.html')
8. 高级定制与性能优化
8.1 自定义样式与主题
# 创建自定义样式的地图
from branca.element import Template, MacroElement
# 创建基础地图
m = folium.Map(location=[30.5928, 114.3055], zoom_start=12, tiles='CartoDB dark_matter')
# 添加自定义CSS样式
custom_css = """
<style>
.leaflet-popup-content-wrapper {
background-color: rgba(0, 0, 0, 0.8);
color: white;
border-radius: 0px;
padding: 0px;
}
.leaflet-popup-content {
margin: 15px;
}
.leaflet-popup-tip {
background-color: rgba(0, 0, 0, 0.8);
}
.leaflet-container a.leaflet-popup-close-button {
color: white;
}
.leaflet-control-layers {
background-color: rgba(0, 0, 0, 0.7);
color: white;
border-radius: 0px;
}
.leaflet-control-layers-expanded {
padding: 10px;
}
.legend {
background-color: rgba(0, 0, 0, 0.7);
color: white;
padding: 10px;
border-radius: 0px;
}
</style>
"""
# 创建自定义CSS元素
class CustomCSS(MacroElement):
def __init__(self, css):
super(CustomCSS, self).__init__()
self._css = css
def render(self, **kwargs):
self._parent.header.add_child(Template(self._css))
# 添加自定义CSS到地图
m.get_root().add_child(CustomCSS(custom_css))
# 添加一些标记和弹出窗口
locations = [
{'name': '地点A', 'location': [30.5928, 114.3055], 'info': '这是地点A的详细信息'},
{'name': '地点B', 'location': [30.6000, 114.3100], 'info': '这是地点B的详细信息'},
{'name': '地点C', 'location': [30.5850, 114.2950], 'info': '这是地点C的详细信息'}
]
for loc in locations:
html = f"""
<div style="font-family: 'Arial', sans-serif;">
<h3 style="margin-top: 0;">{loc['name']}</h3>
<p>{loc['info']}</p>
</div>
"""
folium.Marker(
location=loc['location'],
popup=folium.Popup(html),
tooltip=loc['name'],
icon=folium.Icon(color='white', icon_color='#1a1a1a', icon='info')
).add_to(m)
# 添加自定义图例
legend_html = """
<div class='legend'>
<h4 style="margin-top: 0;">图例</h4>
<div><i class="fa fa-circle" style="color:white"></i> 兴趣点</div>
</div>
"""
# 添加图例
m.get_root().html.add_child(folium.Element(legend_html))
m.save('custom_styled_map.html')
8.2 性能优化与大数据处理
# 处理大量数据点的策略
# 创建地图
m = folium.Map(location=[30.5928, 114.3055], zoom_start=12)
# 方法1: 使用聚类减少标记数量
from folium.plugins import MarkerCluster
# 生成大量标记点
np.random.seed(42)
n_points = 10000 # 一万个点
# 创建聚类
marker_cluster = MarkerCluster(
name='聚类标记',
overlay=True,
control=True,
icon_create_function=None
).add_to(m)
# 添加部分点到聚类中
for i in range(min(1000, n_points)): # 限制初始加载点数
lat = np.random.normal(30.59, 0.05)
lon = np.random.normal(114.30, 0.05)
folium.Marker(
location=[lat, lon],
popup=f'点 {i+1}'
).add_to(marker_cluster)
# 方法2: 使用热力图代替大量单独标记
from folium.plugins import HeatMap
# 生成热力图数据
heat_data = []
for i in range(n_points):
lat = np.random.normal(30.59, 0.05)
lon = np.random.normal(114.30, 0.05)
intensity = np.random.uniform(0.1, 1.0) # 随机强度
heat_data.append([lat, lon, intensity])
# 添加热力图
HeatMap(
heat_data,
name='热力图',
radius=10,
blur=15,
gradient={0.4: 'blue', 0.65: 'lime', 1: 'red'}
).add_to(m)
# 方法3: 使用WebGL点图层
from folium.plugins import FastMarkerCluster
# 准备数据
callback = """
function (row) {
var icon = L.divIcon({
html: '<div style="background-color: #3186cc; border-radius: 50%; width: 5px; height: 5px;"></div>',
className: 'dummy'
});
return L.marker(new L.LatLng(row[0], row[1]), {icon: icon});
};
"""
fast_markers = np.random.normal(
loc=[30.59, 114.30],
scale=[0.05, 0.05],
size=(n_points, 2)
).tolist()
# 添加快速标记聚类
FastMarkerCluster(
data=fast_markers,
name='快速点图层',
callback=callback
).add_to(m)
# 添加图层控制
folium.LayerControl().add_to(m)
m.save('performance_optimized_map.html')
8.3 移动端优化
# 为移动设备优化地图
m = folium.Map(
location=[30.5928, 114.3055],
zoom_start=12,
preferCanvas=True # 使用Canvas渲染,提高移动端性能
)
# 添加定位控件
from folium.plugins import LocateControl
LocateControl(
position='topleft',
strings={'title': '定位'},
locateOptions={
'enableHighAccuracy': True, # 高精度定位
'watch': True, # 持续追踪位置
'setView': True, # 定位后自动将视图移动到当前位置
'maxZoom': 16, # 最大缩放级别
'timeout': 10000 # 定位超时时间(毫秒)
}
).add_to(m)
# 添加移动友好的图层控制
from folium.plugins import GroupedLayerControl
# 创建不同组的图层
poi_group = folium.FeatureGroup(name='兴趣点')
poi_markers = [
{'name': '餐厅A', 'location': [30.5928, 114.3055], 'type': 'restaurant'},
{'name': '商店B', 'location': [30.5950, 114.3100], 'type': 'shopping'},
{'name': '景点C', 'location': [30.5900, 114.3000], 'type': 'attraction'}
]
for poi in poi_markers:
folium.Marker(
location=poi['location'],
popup=poi['name'],
tooltip=poi['name'],
icon=folium.Icon(
icon='cutlery' if poi['type'] == 'restaurant' else
'shopping-cart' if poi['type'] == 'shopping' else
'camera',
prefix='fa'
)
).add_to(poi_group)
# 添加交通图层
transport_group = folium.FeatureGroup(name='交通')
bus_stops = [
{'name': '公交站A', 'location': [30.5920, 114.3050]},
{'name': '公交站B', 'location': [30.5940, 114.3070]},
{'name': '地铁站C', 'location': [30.5910, 114.3030]}
]
for stop in bus_stops:
folium.CircleMarker(
location=stop['location'],
radius=5,
color='blue',
fill=True,
popup=stop['name']
).add_to(transport_group)
# 将图层添加到地图
poi_group.add_to(m)
transport_group.add_to(m)
# 添加移动友好的图层控制
folium.LayerControl(collapsed=True).add_to(m) # 默认折叠图层控制面板
# 添加全屏控件
from folium.plugins import Fullscreen
Fullscreen(
position='topleft',
title='全屏',
title_cancel='退出全屏',
force_separate_button=True
).add_to(m)
# 添加响应式设计的元标签
meta_html = """
<meta name="viewport" content="width=device-width,
initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
"""
m.get_root().header.add_child(folium.Element(meta_html))
# 添加触摸事件优化的CSS
touch_css = """
<style>
.leaflet-touch .leaflet-control-layers,
.leaflet-touch .leaflet-bar {
border: 2px solid rgba(0,0,0,0.2);
background-clip: padding-box;
}
.leaflet-control-layers-toggle {
width: 36px !important;
height: 36px !important;
}
.leaflet-control-zoom-in,
.leaflet-control-zoom-out {
width: 36px !important;
height: 36px !important;
line-height: 36px !important;
font-size: 18px !important;
}
</style>
"""
m.get_root().header.add_child(folium.Element(touch_css))
m.save('mobile_optimized_map.html')
9. 实战项目案例
9.1 城市数据分析面板
# 创建综合城市数据分析面板
m = folium.Map(
location=[30.5928, 114.3055],
zoom_start=12,
tiles='CartoDB positron'
)
# 添加城市行政区划
admin_data = {
'type': 'FeatureCollection',
'features': [
{
'type': 'Feature',
'properties': {
'name': '武昌区',
'population': 1200000,
'gdp': 125,
'area': 82.4
},
'geometry': {
'type': 'Polygon',
'coordinates': [[[114.32, 30.57], [114.35, 30.57], [114.35, 30.60], [114.32, 30.60], [114.32, 30.57]]]
}
},
{
'type': 'Feature',
'properties': {
'name': '洪山区',
'population': 1650000,
'gdp': 145,
'area': 123.1
},
'geometry': {
'type': 'Polygon',
'coordinates': [[[114.35, 30.57], [114.38, 30.57], [114.38, 30.60], [114.35, 30.60], [114.35, 30.57]]]
}
},
{
'type': 'Feature',
'properties': {
'name': '江汉区',
'population': 950000,
'gdp': 110,
'area': 33.2
},
'geometry': {
'type': 'Polygon',
'coordinates': [[[114.29, 30.60], [114.32, 30.60], [114.32, 30.63], [114.29, 30.63], [114.29, 30.60]]]
}
}
]
}
# 添加分级统计图 - 人口密度
folium.Choropleth(
geo_data=admin_data,
name='人口密度',
data=pd.DataFrame([
{'name': '武昌区', 'density': 1200000/82.4},
{'name': '洪山区', 'density': 1650000/123.1},
{'name': '江汉区', 'density': 950000/33.2}
]),
columns=['name', 'density'],
key_on='feature.properties.name',
fill_color='YlOrRd',
fill_opacity=0.7,
line_opacity=0.2,
legend_name='人口密度 (人/平方公里)'
).add_to(m)
# 添加详细信息弹出窗口
style_function = lambda x: {'fillColor': '#ffffff', 'color': '#000000', 'fillOpacity': 0.1, 'weight': 0.5}
highlight_function = lambda x: {'fillColor': '#000000', 'color': '#000000', 'fillOpacity': 0.5, 'weight': 1}
admin_info = folium.features.GeoJson(
admin_data,
name='行政区信息',
style_function=style_function,
highlight_function=highlight_function,
tooltip=folium.features.GeoJsonTooltip(
fields=['name', 'population', 'gdp', 'area'],
aliases=['区名:', '人口:', 'GDP (亿元):', '面积 (平方公里):'],
localize=True
),
popup=folium.features.GeoJsonPopup(
fields=['name', 'population', 'gdp', 'area'],
aliases=['区名:', '人口:', 'GDP (亿元):', '面积 (平方公里):'],
localize=True
)
)
m.add_child(admin_info)
# 添加交通设施图层
transport_layer = folium.FeatureGroup(name='交通设施')
# 地铁站
subway_stations = [
{'name': '洪山广场站', 'location': [30.5928, 114.3055], 'lines': [2, 4]},
{'name': '中南路站', 'location': [30.5380, 114.3330], 'lines': [2, 8]},
{'name': '街道口站', 'location': [30.5280, 114.3520], 'lines': [2]}
]
for station in subway_stations:
# 创建HTML格式的弹出窗口
lines_str = ', '.join([f'{line}号线' for line in station['lines']])
html = f"""
<div style="width:200px">
<h4 style="margin-bottom:5px">{station['name']}</h4>
<p><b>线路:</b> {lines_str}</p>
<p><b>换乘数:</b> {len(station['lines'])}</p>
</div>
"""
# 创建地铁站标记
folium.Marker(
location=station['location'],
icon=folium.Icon(icon='subway', prefix='fa', color='blue'),
popup=folium.Popup(html),
tooltip=f"{station['name']} ({lines_str})"
).add_to(transport_layer)
# 公交站
bus_stops = [
{'name': '中南医院站', 'location': [30.5830, 114.3130], 'lines': [12, 542, 806]},
{'name': '武汉大学站', 'location': [30.5928, 114.3070], 'lines': [592, 519, 552]}
]
for stop in bus_stops:
lines_str = ', '.join([f'{line}路' for line in stop['lines']])
folium.Marker(
location=stop['location'],
icon=folium.Icon(icon='bus', prefix='fa', color='green'),
popup=f"{stop['name']}<br>线路: {lines_str}",
tooltip=stop['name']
).add_to(transport_layer)
# 添加交通设施图层到地图
transport_layer.add_to(m)
# 添加热门地点图层
poi_layer = folium.FeatureGroup(name='热门地点')
# 添加热门地点
pois = [
{'name': '武汉大学', 'location': [30.5928, 114.3055], 'type': 'education', 'rating': 5.0},
{'name': '东湖风景区', 'location': [30.5800, 114.3600], 'type': 'scenic', 'rating': 4.8},
{'name': '黄鹤楼', 'location': [30.5433, 114.3025], 'type': 'landmark', 'rating': 4.9},
{'name': '武汉天地', 'location': [30.5867, 114.2819], 'type': 'shopping', 'rating': 4.6}
]
# 为不同类型选择不同图标
icon_map = {
'education': {'icon': 'graduation-cap', 'color': 'blue'},
'scenic': {'icon': 'tree', 'color': 'green'},
'landmark': {'icon': 'monument', 'color': 'red'},
'shopping': {'icon': 'shopping-cart', 'color': 'purple'}
}
for poi in pois:
icon_info = icon_map.get(poi['type'], {'icon': 'info', 'color': 'gray'})
html = f"""
<div style="width:200px">
<h4 style="margin-bottom:5px">{poi['name']}</h4>
<p>类型: {poi['type']}</p>
<p>评分: {"★" * int(poi['rating']) + "☆" * (5 - int(poi['rating']))}</p>
</div>
"""
folium.Marker(
location=poi['location'],
popup=folium.Popup(html),
tooltip=poi['name'],
icon=folium.Icon(icon=icon_info['icon'], prefix='fa', color=icon_info['color'])
).add_to(poi_layer)
# 添加热门地点图层到地图
poi_layer.add_to(m)
# 添加房价热力图 (模拟数据)
np.random.seed(42)
n_points = 500
housing_prices = []
# 生成以市中心为中心的房价分布(越靠近中心越贵)
center = np.array([30.5928, 114.3055]) # 市中心坐标
for _ in range(n_points):
# 生成随机位置
offset = np.random.normal(0, 0.03, 2) # 标准差控制分布范围
location = center + offset
# 计算到中心的距离
distance = np.sqrt(np.sum(offset**2))
# 基于距离计算房价(距离越远价格越低)
price = 30000 * np.exp(-5 * distance) + np.random.normal(0, 2000)
housing_prices.append([location[0], location[1], max(8000, price)])
# 添加房价热力图
heat_layer = folium.FeatureGroup(name='房价热力图')
HeatMap(
housing_prices,
name='房价分布',
radius=15,
gradient={0.4: 'blue', 0.65: 'lime', 1: 'red'},
min_opacity=0.5
).add_to(heat_layer)
heat_layer.add_to(m)
# 添加迷你地图和图层控制
from folium.plugins import MiniMap, Draw
minimap = MiniMap()
m.add_child(minimap)
folium.LayerControl(collapsed=False).add_to(m)
# 添加绘图工具
draw = Draw(
export=True,
position='topleft',
draw_options={
'polyline': True,
'rectangle': True,
'circle': True,
'marker': True,
'circlemarker': False
}
)
m.add_child(draw)
# 添加地图标题
title_html = '''
<div style="position: fixed;
top: 10px; left: 50%; transform: translateX(-50%);
z-index: 9999; background-color: white;
padding: 10px; border-radius: 5px; box-shadow: 0 0 5px rgba(0,0,0,0.3);">
<h3 style="margin:0;">武汉市城市数据分析面板</h3>
</div>
'''
m.get_root().html.add_child(folium.Element(title_html))
m.save('wuhan_city_analysis.html')
9.2 环境监测与灾害管理系统
# 创建环境监测与灾害管理系统
m = folium.Map(
location=[30.5928, 114.3055],
zoom_start=11,
tiles='CartoDB positron'
)
# 添加多种底图
folium.TileLayer('CartoDB dark_matter', name='暗色底图').add_to(m)
folium.TileLayer('Stamen Terrain', name='地形图').add_to(m)
folium.TileLayer('Stamen Watercolor', name='水彩风格').add_to(m)
# 模拟空气质量监测站点数据
air_quality_stations = [
{'name': '监测站A', 'location': [30.5928, 114.3055], 'aqi': 75, 'pm25': 35, 'pm10': 65, 'status': 'good'},
{'name': '监测站B', 'location': [30.6100, 114.2800], 'aqi': 110, 'pm25': 58, 'pm10': 95, 'status': 'moderate'},
{'name': '监测站C', 'location': [30.5600, 114.3300], 'aqi': 145, 'pm25': 85, 'pm10': 120, 'status': 'unhealthy'},
{'name': '监测站D', 'location': [30.5300, 114.2700], 'aqi': 55, 'pm25': 22, 'pm10': 48, 'status': 'good'},
{'name': '监测站E', 'location': [30.6300, 114.3400], 'aqi': 165, 'pm25': 105, 'pm10': 145, 'status': 'very_unhealthy'}
]
# 创建空气质量图层
air_quality_layer = folium.FeatureGroup(name='空气质量监测站')
# 为不同空气质量状态定义颜色
status_colors = {
'good': 'green',
'moderate': 'yellow',
'unhealthy': 'orange',
'very_unhealthy': 'red',
'hazardous': 'purple'
}
# 添加监测站点
for station in air_quality_stations:
color = status_colors.get(station['status'], 'gray')
html = f"""
<div style="width:200px">
<h4 style="margin-bottom:5px">{station['name']}</h4>
<table style="width:100%">
<tr><td>AQI:</td><td>{station['aqi']}</td></tr>
<tr><td>PM2.5:</td><td>{station['pm25']} μg/m³</td></tr>
<tr><td>PM10:</td><td>{station['pm10']} μg/m³</td></tr>
<tr><td>状态:</td><td style="color:{color};font-weight:bold">{station['status'].replace('_', ' ').title()}</td></tr>
</table>
</div>
"""
folium.CircleMarker(
location=station['location'],
radius=10,
color=color,
fill=True,
fill_color=color,
fill_opacity=0.7,
popup=folium.Popup(html, max_width=200),
tooltip=f"{station['name']} - AQI: {station['aqi']}"
).add_to(air_quality_layer)
# 添加空气质量图层到地图
air_quality_layer.add_to(m)
# 模拟洪水风险区域
flood_zones = {
'high_risk': {
'polygon': [
[30.56, 114.30],
[30.56, 114.33],
[30.54, 114.33],
[30.54, 114.30]
],
'color': 'red',
'name': '高风险区'
},
'medium_risk': {
'polygon': [
[30.60, 114.26],
[30.60, 114.29],
[30.58, 114.29],
[30.58, 114.26]
],
'color': 'orange',
'name': '中风险区'
},
'low_risk': {
'polygon': [
[30.63, 114.31],
[30.63, 114.34],
[30.61, 114.34],
[30.61, 114.31]
],
'color': 'yellow',
'name': '低风险区'
}
}
# 创建洪水风险图层
flood_risk_layer = folium.FeatureGroup(name='洪水风险区域')
# 添加风险区域多边形
for risk_id, risk_data in flood_zones.items():
folium.Polygon(
locations=risk_data['polygon'],
color=risk_data['color'],
fill=True,
fill_color=risk_data['color'],
fill_opacity=0.4,
weight=2,
popup=risk_data['name']
).add_to(flood_risk_layer)
# 添加洪水风险图层到地图
flood_risk_layer.add_to(m)
# 添加避险场所
shelters = [
{'name': '避险场所A', 'location': [30.5700, 114.3100], 'capacity': 2000, 'supplies': True},
{'name': '避险场所B', 'location': [30.5950, 114.2850], 'capacity': 1500, 'supplies': True},
{'name': '避险场所C', 'location': [30.6150, 114.3250], 'capacity': 3000, 'supplies': False}
]
# 创建避险场所图层
shelter_layer = folium.FeatureGroup(name='避险场所')
# 添加避险场所标记
for shelter in shelters:
html = f"""
<div style="width:200px">
<h4 style="margin-bottom:5px">{shelter['name']}</h4>
<table style="width:100%">
<tr><td>容纳人数:</td><td>{shelter['capacity']}人</td></tr>
<tr><td>应急物资:</td><td>{'充足' if shelter['supplies'] else '不足'}</td></tr>
</table>
</div>
"""
folium.Marker(
location=shelter['location'],
popup=folium.Popup(html, max_width=200),
tooltip=shelter['name'],
icon=folium.Icon(color='green', icon='home', prefix='fa')
).add_to(shelter_layer)
# 添加避险场所图层到地图
shelter_layer.add_to(m)
# 添加实时降雨量热力图
np.random.seed(42)
rain_data = []
center = np.array([30.5928, 114.3055]) # 降雨中心
# 模拟降雨分布(从中心向外递减)
for _ in range(500):
offset = np.random.normal(0, 0.05, 2) # 标准差控制分布范围
location = center + offset
# 计算到中心的距离
distance = np.sqrt(np.sum(offset**2))
# 基于距离计算降雨量(越靠近中心降雨越大)
intensity = 10 * np.exp(-5 * distance) + np.random.normal(0, 0.5)
intensity = max(0, intensity)
rain_data.append([location[0], location[1], intensity])
# 创建降雨量图层
rain_layer = folium.FeatureGroup(name='实时降雨量')
# 添加降雨热力图
HeatMap(
rain_data,
name='降雨分布',
radius=12,
gradient={0.4: '#a6cee3', 0.65: '#1f78b4', 1: '#081d58'},
min_opacity=0.3
).add_to(rain_layer)
# 添加降雨图层到地图
rain_layer.add_to(m)
# 添加图层控制
folium.LayerControl(collapsed=False).add_to(m)
# 添加全屏控件
from folium.plugins import Fullscreen
Fullscreen().add_to(m)
# 添加测量工具
from folium.plugins import MeasureControl
m.add_child(MeasureControl(position='bottomleft', primary_length_unit='kilometers'))
# 添加比例尺
folium.plugins.FloatImage('https://upload.wikimedia.org/wikipedia/commons/thumb/b/b0/North_arrow_01.svg/1200px-North_arrow_01.svg.png',
bottom=2, left=1, width='40px').add_to(m)
# 添加图例
legend_html = '''
<div style="position: fixed;
bottom: 50px; right: 50px; z-index: 1000; background-color: white;
padding: 10px; border-radius: 5px; box-shadow: 0 0 5px rgba(0,0,0,0.3);">
<p><strong>空气质量</strong></p>
<p><i class="fa fa-circle" style="color:green"></i> 良好</p>
<p><i class="fa fa-circle" style="color:yellow"></i> 中等</p>
<p><i class="fa fa-circle" style="color:orange"></i> 不健康</p>
<p><i class="fa fa-circle" style="color:red"></i> 很不健康</p>
<p><i class="fa fa-circle" style="color:purple"></i> 危险</p>
<p><strong>洪水风险区域</strong></p>
<p><i class="fa fa-square" style="color:red"></i> 高风险</p>
<p><i class="fa fa-square" style="color:orange"></i> 中风险</p>
<p><i class="fa fa-square" style="color:yellow"></i> 低风险</p>
</div>
'''
m.get_root().html.add_child(folium.Element(legend_html))
# 添加标题
title_html = '''
<div style="position: fixed;
top: 10px; left: 50%; transform: translateX(-50%);
z-index:9999; background-color: white;
padding: 10px; border-radius: 5px; box-shadow: 0 0 5px rgba(0,0,0,0.3);">
<h3 style="margin:0;">环境监测与灾害管理系统</h3>
</div>
'''
m.get_root().html.add_child(folium.Element(title_html))
m.save('disaster_management_system.html')
10. 总结与进阶资源
10.1 学习路径推荐
Folium是一个功能强大的Python地图可视化库,掌握它可以帮助你创建专业级的交互式地图应用。以下是推荐的学习路径:
-
基础入门:
- 掌握基本地图创建
- 学习添加标记、线条和多边形
- 了解弹出窗口和工具提示的使用
-
中级应用:
- 掌握分级统计图(Choropleth)的创建
- 学习热力图和标记聚类的应用
- 了解图层控制和自定义图标
-
高级功能:
- 掌握插件的使用(热力图、聚类、时间序列等)
- 学习与其他库(Pandas、GeoPandas、Matplotlib)的集成
- 了解性能优化和大数据处理技巧
-
实战应用:
- 完成综合项目,如城市分析面板、环境监测系统等
- 将地图嵌入到Web应用中
- 创建交互式地图仪表板
10.2 常见问题与解决方案
-
地图无法显示:
- 检查Folium版本是否最新
- 确认所有依赖库是否正确安装
- 检查HTML文件是否在支持JavaScript的环境中运行
-
自定义图标不显示:
- 确认图标名称是否正确
- 检查图标前缀(prefix)是否正确设置
- 尝试使用不同的图标库(‘fa’, 'glyphicon’等)
-
GeoJSON数据加载问题:
- 确保GeoJSON格式正确
- 检查坐标系统是否一致
- 尝试使用更简化的GeoJSON数据
-
性能问题:
- 使用聚类或热力图代替大量单独标记
- 减少不必要的弹出窗口内容
- 考虑使用
prefer_canvas=True
选项提高渲染性能
-
移动设备兼容性:
- 添加适当的元标签和CSS样式
- 使用更大的按钮和控件
- 测试不同设备上的显示效果
10.3 进阶资源推荐
-
官方文档:
- Folium 官方文档
- Leaflet.js 文档(了解底层库)
-
教程和示例:
-
相关库:
- GeoPandas:用于地理数据处理
- Branca:Folium的依赖库,用于颜色映射
- ipyleaflet:另一个基于Leaflet的交互式地图库
-
书籍:
- 《Python地理空间分析指南》
- 《交互式数据可视化:用D3.js和Leaflet创建地图》
10.4 结语
Folium为Python开发者提供了一个强大的工具,让我们能够在不深入学习JavaScript的情况下创建精美的交互式地图。通过本文介绍的各种功能和技巧,你已经掌握了使用Folium进行地理数据可视化的核心能力。
从简单的点标记到复杂的分级统计图,从基础地图到综合的城市数据分析面板,Folium的灵活性和易用性使它成为地理数据可视化的首选工具之一。随着智慧城市、位置服务和空间分析的不断发展,这些技能将变得越来越重要。
希望本教程能帮助你开启地理数据可视化的探索之旅,创建出更多精彩的交互式地图应用!