查看全课大纲(第 34 / 45 节)
- 1.课程简介
- 2.环境搭建
- 3.预备知识
- 4.pyecharts初体验
- 5.数据可视化概述
- 6.数据可视化的目标和作用
- 7.数据可视化工具对比分析
- 8.数据可视化基本流程
- 9.数据可视化设计原则
- 10.pyecharts简介
- 11.官方图表样例
- 12.常用图表的基本结构
- 13.数据格式
- 14.图表的分类
- 15.柱状图与条形图
- 16.其他对比图表
- 17.常用配置项(一)
- 18.常用配置项(二)
- 19.折线图 面积图
- 20.K线图
- 21.其他时间图表
- 22.常用配置项
- 23.散点图 气泡图
- 24.热力图
- 25.其他相关性图表
- 26.饼图
- 27.矩形树图
- 28.其他成分比例图表
- 29.箱型图与直方图
- 30.3D柱状图与折线图
- 31.其他统计图表
- 32.地图 Map
- 33.地理坐标系Geo
- 34.3D 地图
- 35.网络关系图
- 36.主题河流图
- 37.词云图
- 38.组合图表组件
- 39.仪表盘相关图表
- 40.项目介绍
- 41.数据准备
- 42.子图制作(一)
- 43.子图制作(二)
- 44.数据大屏制作
- 45.项目总结
3D 地图
3D 地图:从地球仪到三维柱状图
小象实战讲义 · ECharts 数据可视化
在掌握了基础地图和地理坐标系(Geo)的可视化后,我们将进入更具沉浸感和表现力的空间数据可视化领域——3D地图。本节将带你学习如何利用 pyecharts 绘制两种主流的3D地图:一种是用于展示全球数据的“地球仪”式地图,另一种是在平面地图上叠加三维柱状图,以直观对比不同区域的数据高低。这不仅是数据分析结果的华丽呈现,更是构建交互式数据大屏的核心技能。
💡 核心导读
- 两种3D地图场景:理解“地球仪”式全球数据展示与“地图+三维柱状图”的区域数据对比两种核心应用。
- 数据格式是关键:掌握为不同3D地图准备特定数据结构的方法,包括全球人口数据列表和包含经纬度、数值的三元组列表。
- 视觉映射(VisualMap)的精确控制:学习如何根据数据动态范围设置颜色映射,使图表颜色准确反映数据大小。
- 进阶标签格式化:使用
JsCode编写 JavaScript 函数,灵活定制3D柱状图上的标签显示内容,解决默认显示异常问题。 - 交互式探索:生成的3D地图支持旋转、缩放、拖拽,是构建可探索式数据大屏的理想组件。
一、 地球数据可视化:绘制可交互的地球仪
当我们需要展示全球范围的数据分布时,一个可以手动旋转、缩放的地球仪视图是最直观的选择。pyecharts 的 MapGlobe 图表专门用于此场景。
1. 准备全球人口数据
pyecharts 2.1.0 的 faker 模块不再提供旧示例中的 POPULATION。下面直接使用一组固定的国家人口样本,保证代码可复现,也避免依赖版本已移除的属性。
from pyecharts import options as opts
from pyecharts.charts import MapGlobe
# 固定样本:国家名使用 world.js 中的标准英文名称
population_data = [
("China", 1433783686),
("India", 1366417754),
("United States", 329064917),
("Indonesia", 270625568),
("Pakistan", 216565318),
("Brazil", 211049527),
("Nigeria", 200963599),
("Bangladesh", 163046161),
("Russia", 145872256),
("Japan", 126529100),
]
population_values = [value for _, value in population_data]
low_value = min(population_values)
high_value = max(population_values)
globe_chart = (
MapGlobe()
.add_schema()
.add(
maptype="world",
series_name="2019年人口数量",
data_pair=population_data,
is_map_symbol_show=False,
label_opts=opts.LabelOpts(is_show=False),
)
.set_global_opts(
visualmap_opts=opts.VisualMapOpts(
min_=low_value,
max_=high_value,
range_color=["lightskyblue", "yellow", "orangered"],
)
)
)
globe_chart.render("global_population_globe.html")
print(f"人口最小值: {low_value:,}")
print(f"人口最大值: {high_value:,}")
print(f"地球仪图表已生成,图表类型: {type(globe_chart).__name__}")
print(f"数据系列名称: '2019年人口数量',包含 {len(population_data)} 个国家样本")人口最小值: 126,529,100
人口最大值: 1,433,783,686
地球仪图表已生成,图表类型: MapGlobe
数据系列名称: '2019年人口数量',包含 10 个国家样本结果解读:运行后,将生成一个可交互的 HTML 文件。打开后你会看到一个默认静止的立体地球,中国、印度等人口大国呈现为橙红色,人口较少的地区则显示为浅蓝色。你可以用鼠标拖拽旋转地球、滚轮缩放。锁定版本的 MapGlobe 默认不会自动旋转,点击地球也没有内建的暂停/恢复旋转功能;如需要自动旋转,必须在自定义 HTML 的 globe.viewControl 中设置 autoRotate: true,并自行监听点击事件切换该配置。
二、 3D地图与三维柱状图的结合
第二种常见的3D地图应用,是在二维平面地图上,用三维柱状图的高度来代表每个区域的数据值,常用于对比各省市销量、GDP等指标。
1. 理解数据格式:经纬度与数值
这种图表要求数据格式为包含三个信息的元组:(区域名称, [经度, 纬度, 数值])。经纬度决定了柱子在地图上的位置,数值决定了柱子的高度。
# 示例数据:部分省份的"销量"数据
example_data = [
("黑龙江省", [126.642464, 45.756967, 100]),
("内蒙古自治区", [111.670801, 40.818311, 300]),
("吉林省", [125.3245, 43.886841, 300]),
("辽宁省", [123.429096, 41.796767, 300]),
("河北省", [114.502461, 38.045474, 300]),
("上海市", [121.472644, 31.231706, 1300]), # 上海"销量"最高
("江苏省", [118.767413, 32.041544, 500]),
("浙江省", [120.153576, 30.287459, 450]),
("广东省", [113.280637, 23.125178, 900]),
]
print("示例数据结构:")
for item in example_data[:2]:
print(f" {item}")示例数据结构:
('黑龙江省', [126.642464, 45.756967, 100])
('内蒙古自治区', [111.670801, 40.818311, 300])2. 创建基础3D地图并设置样式
我们使用 Map3D 图表。首先通过 add_schema 来定义地图本身的视觉样式,如颜色、透明度、边框等。
from pyecharts.charts import Map3D
from pyecharts.globals import ChartType
# 创建基础3D地图
base_map = (
Map3D()
.add_schema(
itemstyle_opts=opts.ItemStyleOpts(
color="rgb(5,101,123)", # 地图区域颜色
opacity=1, # 不透明度
border_width=0.8, # 边界宽度
border_color="rgb(62,215,213)", # 边界颜色
)
)
.set_global_opts(title_opts=opts.TitleOpts(title="全国销量分布(基础地图)"))
)
print(f"基础3D地图已配置,地图样式已自定义。")3. 叠加三维柱状图与标签格式化难题
接下来,使用 .add() 方法并指定 type_=ChartType.BAR3D 来叠加三维柱状图。这里会遇到一个关键问题:如何正确显示柱子顶部的标签(Label)。
如果直接启用标签 (is_show=True) 而不做格式化,标签会显示为 NaN。这是因为默认的标签格式化器无法正确处理我们传入的 [经度, 纬度, 数值] 这种数据结构。
# 尝试直接添加三维柱状图(标签显示会有问题)
map_with_bar_na = (
Map3D()
.add_schema(itemstyle_opts=opts.ItemStyleOpts(color="rgb(5,101,123)", opacity=1, border_width=0.8, border_color="rgb(62,215,213)"))
.add(
series_name="销量",
data_pair=example_data,
type_=ChartType.BAR3D,
bar_size=1, # 柱子尺寸
shading="lambert", # 着色方式,影响立体感
label_opts=opts.LabelOpts(is_show=True), # 直接显示标签
)
.set_global_opts(title_opts=opts.TitleOpts(title="标签显示为NaN的例子"))
)
print("图表已创建,但柱子上方标签会显示为'NaN'。")4. 使用 JsCode 进行高级标签格式化
为了解决上述问题,我们需要使用 JsCode 来自定义标签的格式化函数。这个函数是一个 JavaScript 代码片段,它接收数据对象 data,并返回我们想要的字符串。
from pyecharts import options as opts
from pyecharts.charts import Map3D
from pyecharts.globals import ChartType
from pyecharts.commons.utils import JsCode
# 固定样本,便于独立运行和复现
example_data = [
("黑龙江省", [126.642464, 45.756967, 100]),
("内蒙古自治区", [111.670801, 40.818311, 300]),
("吉林省", [125.3245, 43.886841, 300]),
("辽宁省", [123.429096, 41.796767, 300]),
("河北省", [114.502461, 38.045474, 300]),
("上海市", [121.472644, 31.231706, 1300]),
("江苏省", [118.767413, 32.041544, 500]),
("浙江省", [120.153576, 30.287459, 450]),
("广东省", [113.280637, 23.125178, 900]),
]
# 定义JavaScript格式化函数
# data.name 是省份名称,data.value 是 [经度, 纬度, 数值] 数组
label_formatter = JsCode("""
function(data) {
// data.value 是一个数组,索引2的位置是我们的'销量'值
return data.name + ': ' + data.value[2];
}
""")
# 创建正确的3D地图+柱状图
final_chart = (
Map3D()
.add_schema(
itemstyle_opts=opts.ItemStyleOpts(
color="rgb(5,101,123)",
opacity=1,
border_width=0.8,
border_color="rgb(62,215,213)",
)
)
.add(
series_name="销量",
data_pair=example_data,
type_=ChartType.BAR3D,
bar_size=1,
shading="lambert",
label_opts=opts.LabelOpts(
is_show=True, # 显示标签
formatter=label_formatter, # 使用自定义格式化器
position="top", # 标签位置在柱子顶部
color="#fff" # 标签文字颜色
),
)
.set_global_opts(title_opts=opts.TitleOpts(title="3D地图-各省销量柱状图"))
)
final_chart.render("3d_map_with_bar.html")
print(f"3D地图柱状图已生成,图表类型: {type(final_chart).__name__}")
print(f"系列'销量'包含 {len(example_data)} 个数据点。")
print("提示:鼠标悬停在柱子上会显示提示框(Tooltip),柱顶显示格式化后的标签。")3D地图柱状图已生成,图表类型: Map3D
系列'销量'包含 9 个数据点。
提示:鼠标悬停在柱子上会显示提示框(Tooltip),柱顶显示格式化后的标签。交互与解读:生成的图表是一个可交互的3D中国地图。上海的柱子最高(1300),黑龙江的柱子最矮(100),一目了然。你可以:
- 拖拽:按住鼠标左键拖拽来旋转地图视角。
- 缩放:使用鼠标滚轮放大或缩小。
- 查看详情:鼠标悬停在任何柱子上,会弹出提示框显示省份、经纬度和具体数值;同时柱子顶部会一直显示我们格式化后的标签(如“上海市: 1300”)。
这种“地图+三维柱”的形式,比纯色地图更强调数据的对比,比二维柱状图更具空间感和视觉冲击力,是数据大屏中展示区域对比指标的利器。
📝 动手练一练
改造地球仪颜色:在第一个地球仪示例中,将
VisualMapOpts的range_color修改为[“green“, “white“, “red“],重新生成图表。描述一下颜色映射逻辑变成了什么?(提示:低值->?,高值->?)点击查看参考答案
# 修改颜色映射后的关键代码片段 visualmap_opts=opts.VisualMapOpts( min_=low_value, max_=high_value, range_color=["green", "white", "red"], # 修改此处 )
**答案**:颜色映射逻辑变为:人口数量越低的地区显示为**绿色**,数量居中的地区显示为**白色**,人口数量越高的地区显示为**红色**。这创建了一种从“安全/低”(绿)到“警告/高”(红)的视觉感受,中间以白色过渡。
</details>
2. **自定义3D柱状图标签**:在第二个示例的 `label_formatter` 的 JavaScript 函数中,尝试修改返回的字符串,使其格式变为“**省份(销量)**”,例如“**上海 (1300)**”。
<details>
<summary> 点击查看参考答案</summary>
```javascript
// 修改后的 JsCode 函数
function(data) {
return data.name + ' (' + data.value[2] + ')';
}
```
或者使用模板字符串语法(ES6)更简洁:
```javascript
function(data) {
return `${data.name} (${data.value[2]})`;
}
```
修改后,柱子顶部的标签将显示为“上海市 (1300)”这样的格式。
</details>
## 本章小结
本节我们深入探讨了 pyecharts 中两种强大的3D地图可视化方法:
1. **MapGlobe(地球仪)**:用于全球数据的宏观、交互式展示。核心在于准备 `(国家, 数值)` 格式的数据对,并通过 `VisualMap` 将数值映射为连续的颜色,呈现于可手动旋转的地球模型上。
2. **Map3D + BAR3D(三维柱状图地图)**:用于区域数据的对比分析。核心在于准备 `(区域, [经度, 纬度, 数值])` 格式的三元组数据,并利用 `JsCode` 解决复杂数据结构的标签格式化问题,最终生成可交互、可多角度观察的立体对比图。
这两种图表极大地丰富了空间数据可视化的表现力,从动态的全球视角到聚焦的区域对比,为构建专业级数据报告和交互式数据大屏提供了核心组件。
### 📋 行动清单
- [ ] 运行本节两个完整代码示例,分别生成地球仪和3D柱状图地图,在浏览器中体验旋转、缩放、悬停交互。
- [ ] 尝试将自己的数据集(如公司各城市销售额、全球项目分布)套用到本节的数据格式中,生成专属的3D地图。
- [ ] 探索 `Map3D` 中 `type_` 参数的其他可能,例如 `ChartType.LINES3D`(3D航线图)或 `ChartType.SCATTER3D`(3D散点图),思考它们适用于什么业务场景。
—— 小象教研组