蜂窝热力地图
视觉通道:颜色、位置、形状
特点
规则六边形网格:将地理区域划分为均匀的六边形单元,避免行政边界干扰。
数据聚合:统计每个单元内的数据密度或汇总值(如事件数量、人口密度)。
可视化效果:通过颜色渐变或蜂窝大小直观展示数据分布。
缺点
- 小区域划分(六边形区域)中数据展现的特性有限
- 不适合地图中分区数据间的比较
应用场景
人口密度分析:展示城市或区域的人口分布情况。
交通流量分析:分析道路或交通网络中的流量分布。
犯罪热力图:展示犯罪事件在城市中的分布。
代码实现:
import matplotlib.pyplot as plt
import numpy as np
# 示例数据
x = np.random.normal(0, 1, 1000)
y = np.random.normal(0, 1, 1000)
# 创建蜂窝热力图
plt.hexbin(x, y, gridsize=30, cmap='viridis')
plt.colorbar()
plt.xlabel('X')
plt.ylabel('Y')
plt.title('Hexbin Map Example')
plt.show()

变形地图
视觉通道:颜色、尺寸
特点
面积变形:地理区域的面积与其代表的数值(如人口、GDP)成比例。
拓扑保留:保持区域相对位置,但形状可能大幅扭曲。
缺点
- 由于区域图形不规则,不适合用于比较相差过小或过大的地区
- 动态地图变化过程中,不适合用于整体的观察和比较
应用场景
人口密度分析:展示城市或区域的人口分布情况。
交通流量分析:分析道路或交通网络中的流量分布。
犯罪热力图:展示犯罪事件在城市中的分布。
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
from matplotlib.patches import Polygon
import matplotlib.colors as mcolors
from matplotlib.lines import Line2D
# 设置中文字体
plt.rcParams["font.family"] = ["SimHei", "WenQuanYi Micro Hei", "Heiti TC"]
class DeformationMap:
def __init__(self):
# 初始化数据
self.years = [2020, 2021, 2022, 2023, 2024, 2025]
self.current_year = 2023
# 地图基本形状(简化的世界地图轮廓)
self.base_map = np.array([
[200, 100], [300, 50], [400, 100], [500, 70], [600, 100],
[650, 200], [600, 300], [550, 280], [400, 350], [300, 400],
[200, 350], [150, 250], [100, 200], [150, 100], [200, 100]
])
# 各年份地图变形数据(简化示例)
self.map_deformations = {
2020: np.array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]),
2021: np.array([0, -5, -10, -5, 0, 5, 10, 5, 0, -5, -10, -5, 0, 0, 0]),
2022: np.array([0, -10, -20, -10, 0, 10, 20, 10, 0, -10, -20, -10, 0, 0, 0]),
2023: np.array([0, -15, -30, -15, 0, 15, 30, 15, 0, -15, -30, -15, 0, 0, 0]),
2024: np.array([0, -20, -40, -20, 0, 20, 40, 20, 0, -20, -40, -20, 0, 0, 0]),
2025: np.array([0, -25, -50, -25, 0, 25, 50, 25, 0, -25, -50, -25, 0, 0, 0])
}
# 标记点数据(位置和大小随年份变化)
self.markers = {
'marker1': {
'base_pos': (300, 150),
'sizes': {2020: 50, 2021: 60, 2022: 75, 2023: 100, 2024: 120, 2025: 150},
'color': '#FF4D4F'
},
'marker2': {
'base_pos': (450, 200),
'sizes': {2020: 70, 2021: 80, 2022: 95, 2023: 150, 2024: 170, 2025: 200},
'color': '#FF7A45'
},
'marker3': {
'base_pos': (350, 250),
'sizes': {2020: 40, 2021: 45, 2022: 50, 2023: 80, 2024: 90, 2025: 100},
'color': '#FFC53D'
},
'marker4': {
'base_pos': (500, 300),
'sizes': {2020: 60, 2021: 55, 2022: 50, 2023: 120, 2024: 110, 2025: 100},
'color': '#52C41A'
}
}
# 创建图形和轴
self.fig, self.ax = plt.subplots(figsize=(10, 6))
self.fig.patch.set_facecolor('#F5F7FA')
self.ax.set_facecolor('#F5F7FA')
# 初始化地图和标记
self.map_polygon = None
self.marker_scatters = {}
self.year_text = None
# 动画控制
self.animation = None
self.is_animating = False
def get_deformed_map(self, year):
"""根据年份获取变形后的地图形状"""
deformation = self.map_deformations[year]
# 对地图的y坐标应用变形
deformed_map = self.base_map.copy()
deformed_map[:, 1] += deformation
return deformed_map
def update_map(self, year):
"""更新地图和标记点以反映指定年份的数据"""
# 更新地图形状
deformed_map = self.get_deformed_map(year)
self.map_polygon.set_xy(deformed_map)
# 更新标记点
for marker_name, marker_data in self.markers.items():
pos = marker_data['base_pos']
size = marker_data['sizes'][year]
color = marker_data['color']
# 如果标记点不存在,创建它
if marker_name not in self.marker_scatters:
scatter = self.ax.scatter(pos[0], pos[1], s=size, color=color,
alpha=0.8, edgecolor='black', linewidth=1, zorder=3)
self.marker_scatters[marker_name] = scatter
else:
# 否则更新大小
self.marker_scatters[marker_name].set_sizes([size])
# 更新年份文本
self.year_text.set_text(f"年份: {year}")
return [self.map_polygon] + list(self.marker_scatters.values()) + [self.year_text]
def animate(self, frame):
"""动画帧更新函数"""
year_idx = frame % len(self.years)
year = self.years[year_idx]
return self.update_map(year)
def toggle_animation(self, event):
"""切换动画状态(播放/暂停)"""
if self.is_animating:
self.animation.pause()
self.animate_button.set_text('播放动画')
else:
self.animation.resume()
self.animate_button.set_text('暂停动画')
self.is_animating = not self.is_animating
def change_year(self, event):
"""响应年份选择"""
if event.inaxes != self.ax:
return
# 获取点击位置对应的年份
x, y = event.xdata, event.ydata
if 100 <= x <= 700 and 450 <= y <= 480:
year_idx = int((x - 100) / 100)
if 0 <= year_idx < len(self.years):
year = self.years[year_idx]
self.update_map(year)
self.fig.canvas.draw_idle()
def create_legend(self):
"""创建图例"""
legend_elements = [
Line2D([0], [0], marker='o', color='w', label='高增长', markerfacecolor='#FF4D4F', markersize=10),
Line2D([0], [0], marker='o', color='w', label='中增长', markerfacecolor='#FF7A45', markersize=10),
Line2D([0], [0], marker='o', color='w', label='低增长', markerfacecolor='#FFC53D', markersize=10),
Line2D([0], [0], marker='o', color='w', label='负增长', markerfacecolor='#52C41A', markersize=10),
]
self.ax.legend(handles=legend_elements, loc='lower right', title='人口变化',
frameon=True, facecolor='white', edgecolor='gray', framealpha=0.8)
def create_year_selector(self):
"""创建年份选择器"""
# 绘制年份选择条
for i, year in enumerate(self.years):
x_pos = 100 + i * 100
rect = plt.Rectangle((x_pos, 450), 80, 30, fill=True,
color='#E6F7FF' if year != self.current_year else '#165DFF',
edgecolor='black', alpha=0.7)
self.ax.add_patch(rect)
text_color = 'black' if year != self.current_year else 'white'
self.ax.text(x_pos + 40, 465, str(year), ha='center', va='center',
fontsize=10, fontweight='bold', color=text_color)
def setup_ui(self):
"""设置用户界面元素"""
# 设置坐标轴范围
self.ax.set_xlim(0, 800)
self.ax.set_ylim(0, 500)
self.ax.axis('off') # 关闭坐标轴
# 添加标题
self.ax.set_title('全球人口变化地图', fontsize=16, fontweight='bold', pad=20)
# 创建初始地图
deformed_map = self.get_deformed_map(self.current_year)
self.map_polygon = Polygon(deformed_map, fill=True, color='#E6F7FF',
edgecolor='#165DFF', linewidth=2, alpha=0.8, zorder=2)
self.ax.add_patch(self.map_polygon)
# 添加初始标记点
for marker_name, marker_data in self.markers.items():
pos = marker_data['base_pos']
size = marker_data['sizes'][self.current_year]
color = marker_data['color']
scatter = self.ax.scatter(pos[0], pos[1], s=size, color=color,
alpha=0.8, edgecolor='black', linewidth=1, zorder=3)
self.marker_scatters[marker_name] = scatter
# 添加年份文本
self.year_text = self.ax.text(400, 420, f"年份: {self.current_year}",
ha='center', va='center', fontsize=14, fontweight='bold')
# 添加图例
self.create_legend()
# 添加年份选择器
self.create_year_selector()
# 添加动画按钮
self.animate_button = plt.Button(plt.axes([0.15, 0.05, 0.1, 0.04]), '播放动画')
self.animate_button.on_clicked(self.toggle_animation)
# 添加数据来源文本
self.ax.text(400, 20, "数据来源: 世界银行", ha='center', va='center',
fontsize=10, color='gray')
# 连接鼠标点击事件
self.fig.canvas.mpl_connect('button_press_event', self.change_year)
def run(self):
"""运行地图可视化"""
self.setup_ui()
# 创建动画
self.animation = FuncAnimation(self.fig, self.animate, frames=len(self.years),
interval=1000, blit=True, repeat=True)
plt.tight_layout()
plt.show()
if __name__ == "__main__":
map_visualization = DeformationMap()
map_visualization.run()

关联地图
视觉通道:位置、颜色
特点
使用不同颜色填充不同的地理区域,以表示区域内的数值大小。
适合展示分类或分级的数据,如疾病发病率、环境监测数据等。
可以直观地展示地理区域之间的差异。
缺点:
- 存在失真的情况
- 一般不显示定量数据
应用场景
选举结果:展示不同地区的选举结果,如各州或县的投票倾向。
环境监测:展示不同地区的空气质量、水质等环境指标。
代码实现
from pyecharts import options as opts
from pyecharts.charts import Geo # 地理坐标系绘制方法
from pyecharts.globals import GeoType, ThemeType, SymbolType # Geo图的类型 主题 图形符号
import os
data = [("广州", "8302"), ("河源", "10006"), ("东莞", "9559"), ("汕头", "6860"), ("珠海", "11169")]
geo = (
Geo(init_opts=opts.InitOpts(width="600px", height="500px", theme=ThemeType.WHITE)) # 设置画板
.add_schema(maptype="广东", # 生成广东省的地图
emphasis_itemstyle_opts=opts.ItemStyleOpts(color="#31708f"), # 高亮颜色
)
.add("", # 读入数据,生成几个城市的点
data,
type_=GeoType.EFFECT_SCATTER,
symbol_size=6
)
.add("", # 建立联系
[("广州", "河源"), ("广州", "东莞"), ("广州", "汕头"), ("广东", "珠海")],
type_=GeoType.LINES,
effect_opts=opts.EffectOpts(symbol=SymbolType.ARROW, symbol_size=6, color='#5f99bb'),
linestyle_opts=opts.LineStyleOpts(curve=0.2, color="#B0E2FF"))
.set_series_opts(label_opts=opts.LabelOpts(is_show=False))
.set_global_opts(
title_opts=opts.TitleOpts(title="广州出发的航班", pos_right="center", pos_top="5%"))
.render('linked.html'))
os.system('linked.html')

气泡地图
视觉通道:位置、颜色
特点
在地图上的特定位置绘制气泡,气泡的大小通常与数据值成比例。
适合展示点数据,如城市人口、商店数量等。
可以直观地展示特定地点的数据量。
缺点
- 气泡大小的度量尺度不能超过5个
- 不能显示地理上的连接关系
应用场景
城市人口分布:在地图上用气泡表示不同城市的人口规模。
商店分布:在地图上用气泡表示不同地区的商店数量。
import plotly.express as px
import folium
import pandas as pd
import numpy as np
# 模拟城市数据
cities = pd.DataFrame({
"City": ["New York", "London", "Tokyo", "Beijing", "Sydney"],
"Lat": [40.7, 51.5, 35.7, 39.9, -33.9],
"Lon": [-74.0, -0.1, 139.7, 116.4, 151.2],
"GDP": [1800, 900, 1600, 1400, 500], # 十亿美元
"Growth": [2.1, 1.8, 0.9, 6.1, 2.3] # 增长率%
})
fig = px.scatter_geo(cities,
lat="Lat",
lon="Lon",
size="GDP",
color="Growth",
hover_name="City",
projection="natural earth",
size_max=30,
color_continuous_scale=px.colors.sequential.Plasma,
title="全球主要城市GDP与增长率")
fig.show()

点地图
视觉通道:位置、颜色、大小
特点
在地图上直接标记数据点的位置,每个点代表一个具体的地理位置。
适合展示具体的地理位置信息,如旅游景点、事故现场等。
可以直观地展示地理位置的分布情况。
缺点
- 在地图上标记过多的点可能导致视觉混乱,使得单个点的信息难以辨识。
- 点地图可能不直观地展示点与点之间的空间关系,如接近度或分布模式。
应用场景
事件分布:展示特定事件(如交通事故、犯罪事件)在城市中的分布。
设施位置:标记商店、医院、学校等公共设施的位置。
人口分布:在地图上标记人口密集区域。
旅游热点:展示旅游景点或酒店的位置。
环境监测:标记污染源、自然保护区等环境相关地点。
代码实现
import plotly.express as px
import numpy as np
# 模拟大数据(1000个随机点)
np.random.seed(42)
n_points = 1000
lons = np.random.uniform(-180, 180, n_points)
lats = np.random.uniform(-90, 90, n_points)
values = np.random.randint(1, 100, n_points)
fig = px.scatter_geo(
lat=lats,
lon=lons,
size=values,
color=values,
hover_name=[f"点{i}" for i in range(n_points)],
projection="natural earth",
title="全球数据点分布(动态聚类)",
size_max=20,
color_continuous_scale=px.colors.sequential.Plasma
)
fig.update_traces(
marker=dict(line=dict(width=0, color='white')),
selector=dict(mode='markers')
)
fig.update_layout(
geo=dict(
showland=True,
landcolor="rgb(250, 250, 250)",
subunitcolor="rgb(217, 217, 217)"
),
margin={"r":0,"t":40,"l":0,"b":0}
)
fig.show()

分级地图
视觉通道:颜色
特点
颜色编码:使用颜色梯度来表示数值的大小,通常颜色越深表示数值越大。
地理区域划分:适用于展示按地理区域(如国家、州、县等)划分的数据。
直观比较:可以直观地比较不同区域之间的数值差异。
数据类型:通常用于展示定量数据,也可以用于定序数据。
应用场景
人口分布:展示不同地区的人口密度。
经济分析:比较不同地区的GDP或人均收入。
公共健康:展示疾病发病率或疫苗接种率的地理分布。
政治选举:显示选举结果,如各选区的支持率。
代码实现
from pyecharts import options as opts
from pyecharts.charts import Map
import os
# 创建基础数据
value = [95.1, 23.2, 43.3, 66.4, 88.5]
attr = ["China", "Canada", "Brazil", "Russia", "United States"]
data = []
for index in range(len(attr)):
city_ionfo = [attr[index], value[index]] # 逐个将国家名和数据搭配
data.append(city_ionfo) # 将数据导为一个字典
c = (
Map()
.add("世界地图", data, "world")
.set_series_opts(label_opts=opts.LabelOpts(is_show=False))
.set_global_opts(
title_opts=opts.TitleOpts(title="世界地图示例"), # 设置标题
visualmap_opts=opts.VisualMapOpts(max_=200), # 设置图形大小
)
.render('density.html')
)
# 打开html
os.system("density.html")

| 可视化类型 | 视觉通道 | 数据适用性 | 优点 | 缺点 | 典型应用场景 |
|---|---|---|---|---|---|
| 蜂窝热力地图 | 颜色、位置、形状 | 连续/离散点数据 | 避免行政边界干扰 数据聚合直观 | 小区域特性展现有限 不适合跨区比较 | 犯罪热点分析 共享单车分布 |
| 变形地图 | 颜色、尺寸 | 区域统计值 | 突出数据权重 保持拓扑关系 | 形状失真严重 需安装C扩展库 | 人口/GDP对比 选举结果 |
| 关联地图 | 位置、颜色 | 网络关系数据 | 直观展示连接关系 支持动态交互 | 连接线交叉混乱 大数据性能差 | 航班航线 社交网络 |
| 气泡地图 | 位置、颜色、大小 | 点数值数据 | 多维度映射(大小+颜色) 直观对比 | 气泡重叠 建议≤5个尺寸等级 | 城市经济指标 疫情分布 |
| 点地图 | 位置、颜色、大小 | 精确地理位置 | 精准标记位置 支持10万+数据点 | 点过多时混乱 需聚类算法辅助 | 地震定位 POI分布 |
| 分级地图 | 颜色 | 区域分级数据 | 区域对比清晰 兼容行政边界数据 | 受区域面积影响 需数据标准化 | 选举地图 环境监测 |
544



被折叠的 条评论
为什么被折叠?



