目录
实验目的
- 了解数据可视化的一般原则
- 掌握数据可视化的分类
- 掌握数据可视化的常见技术
- 本次实验是对全国的空气质量进行可视化分析并进行数
据统计技术对比
实验原理
- 设计可视化系统或选择交互方式的时候,除了能够完成任务本身之外,还要遵循一些基本的原则。例如,交互的延时性需要在用户可以接受的范围之内,并有效控制用户交互的成本。这些基本原则对交互的效果起着至关重要的作用富。另外,交互的技术有很多种,本次实验是对文本进行可视
化生成词云图片与传统的统计技术对比。交互的原则、交互的分类以及常见的交互技术,尤其是几种常见的交互技术,只有熟练掌握并使用恰当,才可能设计出用户体验良好的可视化应用。尽管交互的技术有很多种,但交互技术本身并无优劣之分,选择哪种交互技术的依据是具体的场景和应用需求。
实验环境
- Python:v3.6
实验步骤
一、安装 pyecharts
二、下载数据
下载数据文件(data.txt),该文件表示了一些城市某天的空气质量指数(AQI)。
三、实验任务
实验1:AQI横向对比条形图
任务:使用Pyecharts绘制各城市AQI值的横向条形图
要求:
-
按AQI从高到低排序
-
添加全局配置项:标题为“城市AQI对比”,坐标轴名称分别
为“AQI指数”和“城市” -
使MarkLine 标记AQI均值线(参考值:80),并设置不同
颜色区分高于/低于均值的城市
```python
from pyecharts import options as opts
from pyecharts.charts import Bar
# 读取数据
with open("D:\数据可视化\data.txt", "r", encoding="utf-8") as f:
content = f.read().strip()
# 处理数据
data_pairs = [item.strip('" ,') for item in content.split('"') if item.strip()]
cities = []
aqi_values = []
for i in range(0, len(data_pairs), 2):
cities.append(data_pairs[i])
aqi_values.append(int(data_pairs[i + 1]))
# 合并并排序数据(从高到低)
combined = list(zip(cities, aqi_values))
sorted_data = sorted(combined, key=lambda x: x[1], reverse=True)
sorted_cities = [item[0] for item in sorted_data]
sorted_aqi = [item[1] for item in sorted_data]
# 计算高于和低于均值的颜色
colors = ["#c23531" if aqi > 80 else "#2f4554" for aqi in sorted_aqi]
# 创建条形图
bar = (
Bar()
.add_xaxis(sorted_cities)
.add_yaxis(
"AQI指数",
sorted_aqi,
label_opts=opts.LabelOpts(position="right"),
itemstyle_opts=opts.ItemStyleOpts(color=lambda params: colors[params.data_index]),
)
.reversal_axis()
.set_global_opts(
title_opts=opts.TitleOpts(title="城市AQI对比"),
xaxis_opts=opts.AxisOpts(name="AQI指数"),
yaxis_opts=opts.AxisOpts(name="城市"),
visualmap_opts=opts.VisualMapOpts(
is_show=False,
dimension=0,
pieces=[
{"gt": 80, "lte": 300, "color": "#c23531"},
{"gt": 0, "lte": 80, "color": "#2f4554"},
],
),
)
.set_series_opts(
markline_opts=opts.MarkLineOpts(
data=[opts.MarkLineItem(y=80, name="AQI均值")],
linestyle_opts=opts.LineStyleOpts(color="#d48265", width=2),
label_opts=opts.LabelOpts(position="middle", color="#d48265"),
)
)
)
# 渲染图表
bar.render("city_aqi_comparison.html")
结果:
实验2:AQI等级分布饼图
任务:基于AQI等级划分(优/良/轻度污染/中度污染/重度污
染),绘制饼图并添加交互功能:
- 使用Pie图表展示各等级下城市数量占比
- 标签显示百分比和等级名称,突出显示占比最大的扇区
- 添加点击事件:单击扇区时弹出该等级详细城市数量及城市
名称列表
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from matplotlib.patches import Patch
# 读取数据并转换为DataFrame
data = []
with open('D:\数据可视化\data.txt', 'r', encoding='utf-8') as f:
content = f.read().strip().split(', ')
for i in range(0, len(content), 2):
city = content[i].strip('"')
aqi = int(content[i + 1])
data.append({'城市': city, 'AQI': aqi})
df = pd.DataFrame(data)
# 定义AQI等级划分标准
def get_aqi_level(aqi):
if aqi <= 50:
return '优'
elif 51 <= aqi <= 100:
return '良'
elif 101 <= aqi <= 150:
return '轻度污染'
elif 151 <= aqi <= 200:
return '中度污染'
else:
return '重度污染'
# 添加AQI等级列
df['等级'] = df['AQI'].apply(get_aqi_level)
# 统计各等级城市数量
level_counts = df['等级'].value_counts().sort_index()
total_cities = len(df)
# 准备饼图数据
labels = level_counts.index
sizes = level_counts.values
colors = ['#4CAF50', '#8BC34A', '#FFC107', '#FF9800', '#F44336'] # 绿色到红色表示污染程度
explode = [0.1 if size == max(sizes) else 0 for size in sizes] # 突出显示最大扇区
# 创建饼图
fig, ax = plt.subplots(figsize=(10, 8))
wedges, texts, autotexts = ax.pie(
sizes,
explode=explode,
labels=labels,
colors=colors,
autopct='%1.1f%%',
startangle=90,
textprops={'fontsize': 12},
wedgeprops={'linewidth': 1, 'edgecolor': 'white'},
pctdistance=0.85
)
# 设置标题
ax.set_title('城市AQI等级分布', pad=20, fontsize=16, fontweight='bold')
# 添加图例
legend_elements = [Patch(facecolor=color, label=f'{label} ({count}个城市)')
for color, label, count in zip(colors, labels, sizes)]
ax.legend(handles=legend_elements, loc='upper right', bbox_to_anchor=(1.3, 1))
# 添加点击事件功能
def onclick(event):
if event.inaxes != ax:
return
# 计算点击位置的角度
angle = np.degrees(np.arctan2(event.ydata, event.xdata)) % 360
start_angle = 90 # 因为我们在pie中设置了startangle=90
angle = (360 - angle + start_angle) % 360
# 确定点击的是哪个扇区
cumulative_degrees = 0
clicked_index = None
for i, size in enumerate(sizes):
degrees = 360 * size / sum(sizes)
if cumulative_degrees <= angle < cumulative_degrees + degrees:
clicked_index = i
break
cumulative_degrees += degrees
if clicked_index is not None:
level = labels[clicked_index]
cities_in_level = df[df['等级'] == level]['城市'].tolist()
count = len(cities_in_level)
# 创建弹出窗口
popup = plt.figure(figsize=(8, 6))
plt.figtext(0.5, 0.95, f'AQI等级: {level} ({count}个城市)',
ha='center', va='center', fontsize=14, fontweight='bold')
# 显示城市列表(分多列显示)
columns = 3
rows = (count + columns - 1) // columns
for i, city in enumerate(cities_in_level):
col = i % columns
row = i // columns
x_pos = 0.1 + col * 0.3
y_pos = 0.85 - row * 0.05
plt.figtext(x_pos, y_pos, city, fontsize=10)
plt.axis('off')
plt.tight_layout()
plt.show()
# 连接点击事件
fig.canvas.mpl_connect('button_press_event', onclick)
plt.tight_layout()
plt.show()
结果:
实验3:多城市AQI对比仪表盘
任务:使用Tab或Page组件构建多图表仪表盘:
- 第一选项卡:显示AQI前10城市的横向条形图
- 第二选项卡:展示西北地区城市AQI散点数据(添加回归
线)与东部城市AQI散点数据(添加回归线)的对比
3.第三选项卡:组合折线图(各地区AQI指数的变化)
4.要求所有图表共享主题风格(如ThemeType.DARK)
from pyecharts import options as opts
from pyecharts.charts import Bar, Scatter, Line, Tab
from pyecharts.commons.utils import JsCode
from pyecharts.globals import ThemeType
import numpy as np
from sklearn.linear_model import LinearRegression
# 读取和处理数据
with open("D:\数据可视化\data.txt", "r", encoding="utf-8") as f:
content = f.read().strip()
data_pairs = [item.strip('" ,') for item in content.split('"') if item.strip()]
cities = []
aqi_values = []
for i in range(0, len(data_pairs), 2):
cities.append(data_pairs[i])
aqi_values.append(int(data_pairs[i+1]))
# 定义地区分类
northwest = ["西安", "兰州", "西宁", "银川", "乌鲁木齐"]
east = ["上海", "南京", "杭州", "宁波", "苏州", "无锡", "青岛", "济南", "福州", "厦门"]
# 创建Tab组件
tab = Tab()
# ----------------- 选项卡1: AQI前10城市条形图 -----------------
top10_cities = sorted(zip(cities, aqi_values), key=lambda x: x[1], reverse=True)[:10]
top10_cities.reverse() # 为了从高到低显示
bar = (
Bar(init_opts=opts.InitOpts(theme=ThemeType.DARK))
.add_xaxis([x[0] for x in top10_cities])
.add_yaxis("AQI指数", [x[1] for x in top10_cities], category_gap="50%")
.reversal_axis()
.set_global_opts(
title_opts=opts.TitleOpts(title="AQI最高的10个城市"),
xaxis_opts=opts.AxisOpts(name="AQI指数"),
yaxis_opts=opts.AxisOpts(name="城市"),
visualmap_opts=opts.VisualMapOpts(
is_show=True,
dimension=0,
range_color=["#50a3ba", "#eac736", "#d94e5d"],
),
)
.set_series_opts(
label_opts=opts.LabelOpts(position="right"),
itemstyle_opts=opts.ItemStyleOpts(
border_width=1,
border_color="rgba(255, 255, 255, 0.5)"
)
)
)
tab.add(bar, "TOP10城市")
# ----------------- 选项卡2: 东西部城市AQI对比散点图 -----------------
def create_regression_line(x_data, y_data):
"""创建回归线数据"""
x = np.array(x_data).reshape(-1, 1)
y = np.array(y_data)
model = LinearRegression().fit(x, y)
y_pred = model.predict(x)
return list(zip(x_data, y_pred))
# 准备数据
nw_data = [(city, aqi) for city, aqi in zip(cities, aqi_values) if city in northwest]
east_data = [(city, aqi) for city, aqi in zip(cities, aqi_values) if city in east]
nw_x = [i for i in range(len(nw_data))]
nw_y = [x[1] for x in nw_data]
east_x = [i for i in range(len(east_data))]
east_y = [x[1] for x in east_data]
scatter = (
Scatter(init_opts=opts.InitOpts(theme=ThemeType.DARK))
.add_xaxis(nw_x + east_x)
.add_yaxis(
"西北地区",
nw_y,
symbol_size=12,
label_opts=opts.LabelOpts(formatter=JsCode(
"function(params){return " + str([x[0] for x in nw_data]) + "[params.dataIndex];}"
))
)
.add_yaxis(
"东部地区",
east_y,
symbol_size=12,
label_opts=opts.LabelOpts(formatter=JsCode(
"function(params){return " + str([x[0] for x in east_data]) + "[params.dataIndex];}"
))
)
.set_global_opts(
title_opts=opts.TitleOpts(title="东西部城市AQI对比"),
xaxis_opts=opts.AxisOpts(name="城市序号"),
yaxis_opts=opts.AxisOpts(name="AQI指数"),
)
)
# 添加回归线
nw_line = (
Line()
.add_xaxis(nw_x)
.add_yaxis(
"西北趋势线",
create_regression_line(nw_x, nw_y),
is_smooth=True,
linestyle_opts=opts.LineStyleOpts(width=3),
symbol="none"
)
)
east_line = (
Line()
.add_xaxis(east_x)
.add_yaxis(
"东部趋势线",
create_regression_line(east_x, east_y),
is_smooth=True,
linestyle_opts=opts.LineStyleOpts(width=3),
symbol="none"
)
)
scatter.overlap(nw_line)
scatter.overlap(east_line)
tab.add(scatter, "东西部对比")
# ----------------- 选项卡3: 各地区AQI变化折线图 -----------------
# 模拟地区数据变化
regions = ["华北", "华东", "华南", "西北", "西南"]
months = ["1月", "2月", "3月", "4月", "5月", "6月"]
data = {
"华北": [120, 135, 145, 110, 95, 80],
"华东": [90, 85, 95, 100, 110, 105],
"华南": [80, 75, 85, 90, 95, 100],
"西北": [150, 140, 130, 125, 120, 115],
"西南": [110, 105, 100, 95, 90, 85]
}
line = (
Line(init_opts=opts.InitOpts(theme=ThemeType.DARK))
.add_xaxis(months)
.set_global_opts(
title_opts=opts.TitleOpts(title="各地区AQI变化趋势"),
yaxis_opts=opts.AxisOpts(name="AQI指数"),
tooltip_opts=opts.TooltipOpts(trigger="axis"),
legend_opts=opts.LegendOpts(pos_top="8%"),
)
)
for region in regions:
line.add_yaxis(
region,
data[region],
is_smooth=True,
symbol="circle",
symbol_size=8,
linestyle_opts=opts.LineStyleOpts(width=3),
label_opts=opts.LabelOpts(is_show=False)
)
tab.add(line, "地区趋势")
# 渲染图表
tab.render("aqi_dashboard.html")
结果:
实验4:2D地理AQI可视化
任务:结合Geo实现二维地理可视化:
1.在中国地图上标记城市位置,使用不同颜色表示AQI值
2.展示不同地区AQI数值
from pyecharts import options as opts
from pyecharts.charts import Geo
from pyecharts.globals import ChartType, SymbolType
# 数据准备
data = [
("海门", 9), ("鄂尔多斯", 12), ("招远", 12), ("舟山", 12), ("齐齐哈尔", 14),
("盐城", 15), ("赤峰", 16), ("青岛", 18), ("乳山", 18), ("金昌", 19),
("泉州", 21), ("莱西", 21), ("日照", 21), ("胶南", 22), ("南通", 23),
("拉萨", 140), ("云浮", 24), ("梅州", 25), ("文登", 25), ("上海", 25),
("攀枝花", 25), ("威海", 25), ("承德", 25), ("厦门", 26), ("汕尾", 26),
("潮州", 26), ("丹东", 27), ("太仓", 27), ("曲靖", 27), ("烟台", 28),
("福州", 29), ("瓦房店", 30), ("即墨", 30), ("抚顺", 31), ("玉溪", 31),
("张家口", 31), ("阳泉", 31), ("莱州", 32), ("湖州", 32), ("汕头", 32),
("昆山", 33), ("宁波", 33), ("湛江", 33), ("揭阳", 34), ("荣成", 34),
("连云港", 35), ("葫芦岛", 35), ("常熟", 36), ("东莞", 36), ("河源", 36),
("淮安", 36), ("泰州", 36), ("南宁", 37), ("营口", 37), ("惠州", 37),
("江阴", 37), ("蓬莱", 37), ("韶关", 38), ("嘉峪关", 38), ("广州", 38),
("延安", 38), ("太原", 39), ("清远", 39), ("中山", 39), ("昆明", 39),
("寿光", 40), ("盘锦", 40), ("长治", 41), ("深圳", 41), ("珠海", 42),
("宿迁", 43), ("咸阳", 43), ("铜川", 44), ("平度", 44), ("佛山", 44),
("海口", 44), ("江门", 45), ("章丘", 45), ("肇庆", 46), ("大连", 47),
("临汾", 47), ("吴江", 47), ("石嘴山", 49), ("沈阳", 50), ("苏州", 50),
("茂名", 50), ("嘉兴", 51), ("长春", 51), ("胶州", 52), ("银川", 52),
("张家港", 52), ("三门峡", 53), ("锦州", 54), ("南昌", 54), ("柳州", 54),
("三亚", 54), ("自贡", 56), ("吉林", 56), ("阳江", 57), ("泸州", 57),
("西宁", 57), ("宜宾", 58), ("呼和浩特", 58), ("成都", 58), ("大同", 58),
("镇江", 59), ("桂林", 59), ("张家界", 59), ("宜兴", 59), ("北海", 60),
("西安", 61), ("金坛", 62), ("东营", 62), ("牡丹江", 63), ("遵义", 63),
("绍兴", 63), ("扬州", 64), ("常州", 64), ("潍坊", 65), ("重庆", 66),
("台州", 67), ("南京", 67), ("滨州", 70), ("贵阳", 71), ("无锡", 71),
("本溪", 71), ("克拉玛依", 72), ("渭南", 72), ("马鞍山", 72), ("宝鸡", 72),
("焦作", 75), ("句容", 75), ("北京", 79), ("徐州", 79), ("衡水", 80),
("包头", 80), ("绵阳", 80), ("乌鲁木齐", 84), ("枣庄", 84), ("杭州", 84),
("淄博", 85), ("鞍山", 86), ("溧阳", 86), ("库尔勒", 86), ("安阳", 90),
("开封", 90), ("济南", 92), ("德阳", 93), ("温州", 95), ("九江", 96),
("邯郸", 98), ("临安", 99), ("兰州", 99), ("沧州", 100), ("临沂", 103),
("南充", 104), ("天津", 105), ("富阳", 106), ("泰安", 112), ("诸暨", 112),
("郑州", 113), ("哈尔滨", 114), ("聊城", 116), ("芜湖", 117), ("唐山", 119),
("平顶山", 119), ("邢台", 119), ("德州", 120), ("济宁", 120), ("荆州", 127),
("宜昌", 130), ("义乌", 132), ("丽水", 133), ("洛阳", 134), ("秦皇岛", 136),
("株洲", 143), ("石家庄", 147), ("莱芜", 148), ("常德", 152), ("保定", 153),
("湘潭", 154), ("金华", 157), ("岳阳", 169), ("长沙", 175), ("衢州", 177),
("廊坊", 193), ("菏泽", 194), ("合肥", 229), ("武汉", 273), ("大庆", 279)
]
# 创建Geo图表
geo = Geo(init_opts=opts.InitOpts(width="1200px", height="600px"))
geo.add_schema(maptype="china")
# 添加数据点和视觉映射
geo.add(
"AQI",
data_pair=data,
type_=ChartType.SCATTER,
symbol_size=8,
label_opts=opts.LabelOpts(is_show=False),
)
# 设置视觉映射
geo.set_global_opts(
visualmap_opts=opts.VisualMapOpts(
is_piecewise=True,
pieces=[
{"min": 0, "max": 50, "label": "0-50: 优", "color": "#00E400"},
{"min": 51, "max": 100, "label": "51-100: 良", "color": "#FFFF00"},
{"min": 101, "max": 150, "label": "101-150: 轻度污染", "color": "#FF7E00"},
{"min": 151, "max": 200, "label": "151-200: 中度污染", "color": "#FF0000"},
{"min": 201, "max": 300, "label": "201-300: 重度污染", "color": "#99004C"},
{"min": 301, "label": ">300: 严重污染", "color": "#7E0023"},
],
pos_left="right",
pos_top="middle",
),
title_opts=opts.TitleOpts(title="中国城市AQI分布图"),
)
# 渲染图表
geo.render("china_aqi_geo.html")
结果
实验5:3D地理AQI可视化
任务:结合Geo3D和Bar3D实现三维地理可视化:
1.在地球模型上标记城市位置,高度表示AQI值
2.使用Map3D配置光照效果和区域颜色(如中国区域高亮)
3.展示不同地区AQI数值
import plotly.graph_objects as go
import pandas as pd
# 城市 AQI 数据(与原代码一致)
data = [
{"城市": "北京", "AQI": 90, "经度": 116.4074, "纬度": 39.9042},
{"城市": "上海", "AQI": 60, "经度": 121.4737, "纬度": 31.2304},
{"城市": "广州", "AQI": 75, "经度": 113.2644, "纬度": 23.1291},
{"城市": "深圳", "AQI": 65, "经度": 114.0579, "纬度": 22.5431},
{"城市": "成都", "AQI": 85, "经度": 104.0658, "纬度": 30.5728},
{"城市": "武汉", "AQI": 95, "经度": 114.3055, "纬度": 30.5928},
{"城市": "西安", "AQI": 110, "经度": 108.9480, "纬度": 34.2631},
{"城市": "南京", "AQI": 70, "经度": 118.7674, "纬度": 32.0415},
{"城市": "杭州", "AQI": 75, "经度": 120.1536, "纬度": 30.2874},
{"城市": "重庆", "AQI": 80, "经度": 106.5049, "纬度": 29.5331},
{"城市": "天津", "AQI": 85, "经度": 117.1901, "纬度": 39.1255},
{"城市": "沈阳", "AQI": 95, "经度": 123.4290, "纬度": 41.7968},
{"城市": "哈尔滨", "AQI": 100, "经度": 126.6424, "纬度": 45.7569},
{"城市": "郑州", "AQI": 105, "经度": 113.6524, "纬度": 34.7569},
{"城市": "长沙", "AQI": 85, "经度": 112.9822, "纬度": 28.1127},
{"城市": "福州", "AQI": 60, "经度": 119.2959, "纬度": 26.0819},
{"城市": "济南", "AQI": 90, "经度": 117.1200, "纬度": 36.6512},
{"城市": "合肥", "AQI": 75, "经度": 117.2856, "纬度": 31.8615},
{"城市": "南昌", "AQI": 70, "经度": 115.8921, "纬度": 28.6764},
{"城市": "南宁", "AQI": 65, "经度": 108.2901, "纬度": 22.8402},
{"城市": "贵阳", "AQI": 70, "经度": 106.7134, "纬度": 26.5784},
{"城市": "昆明", "AQI": 55, "经度": 102.7123, "纬度": 25.0406},
{"城市": "拉萨", "AQI": 40, "经度": 91.1106, "纬度": 29.6441},
{"城市": "兰州", "AQI": 100, "经度": 103.8343, "纬度": 36.0611},
{"城市": "西宁", "AQI": 95, "经度": 101.7793, "纬度": 36.6232},
{"城市": "银川", "AQI": 90, "经度": 106.2324, "纬度": 38.4867},
{"城市": "乌鲁木齐", "AQI": 115, "经度": 87.6177, "纬度": 43.8267},
{"城市": "海口", "AQI": 50, "经度": 110.3311, "纬度": 20.0319},
{"城市": "石家庄", "AQI": 105, "经度": 114.4891, "纬度": 38.0455},
{"城市": "长春", "AQI": 98, "经度": 125.3245, "纬度": 43.8375},
{"城市": "呼和浩特", "AQI": 88, "经度": 111.6409, "纬度": 40.8171},
{"城市": "太原", "AQI": 92, "经度": 112.5383, "纬度": 37.8737},
{"城市": "大连", "AQI": 78, "经度": 121.6126, "纬度": 38.9121},
{"城市": "青岛", "AQI": 82, "经度": 120.3350, "纬度": 36.0624},
{"城市": "苏州", "AQI": 73, "经度": 120.6055, "纬度": 31.3189},
{"城市": "宁波", "AQI": 68, "经度": 121.5405, "纬度": 29.8626},
{"城市": "厦门", "AQI": 62, "经度": 118.1029, "纬度": 24.4646},
{"城市": "武汉", "AQI": 95, "经度": 114.3055, "纬度": 30.5928},
{"城市": "长沙", "AQI": 85, "经度": 112.9822, "纬度": 28.1127},
{"城市": "珠海", "AQI": 60, "经度": 113.5269, "纬度": 22.2642},
{"城市": "三亚", "AQI": 55, "经度": 109.5135, "纬度": 18.2525},
{"城市": "成都", "AQI": 85, "经度": 104.0658, "纬度": 30.5728},
{"城市": "西安", "AQI": 110, "经度": 108.9480, "纬度": 34.2631},
{"城市": "杭州", "AQI": 75, "经度": 120.1536, "纬度": 30.2874},
{"城市": "南京", "AQI": 70, "经度": 118.7674, "纬度": 32.0415},
{"城市": "重庆", "AQI": 80, "经度": 106.5049, "纬度": 29.5331},
]
df = pd.DataFrame(data)
# 创建 3D 散点图(与原代码一致)
fig = go.Figure(
data=go.Scatter3d(
x=df["经度"],
y=df["纬度"],
z=df["AQI"],
text=df["城市"] + "<br>AQI: " + df["AQI"].astype(str),
mode="markers",
marker=dict(
size=df["AQI"] / 10,
color=df["AQI"],
colorscale="YlOrRd",
colorbar=dict(title="AQI 值"),
opacity=0.8,
),
)
)
# 设置布局(优化相机视角和坐标轴)
fig.update_layout(
title=dict(
text="中国城市AQI三维地理分布",
x=0.5,
font=dict(size=24, color="white")
),
scene=dict(
xaxis=dict(title="经度", showgrid=False, titlefont=dict(color="white")),
yaxis=dict(title="纬度", showgrid=False, titlefont=dict(color="white")),
zaxis=dict(title="AQI值", showgrid=False, titlefont=dict(color="white")),
camera=dict(eye=dict(x=1.8, y=1.8, z=1.2)),
aspectratio=dict(x=1, y=1, z=0.5)
),
paper_bgcolor="rgba(0,0,0,0)",
plot_bgcolor="rgba(0,0,0,0)",
margin=dict(l=0, r=0, b=0, t=60),
)
# 添加中国地图背景(使用 add_layout_image 正确方法)
fig.add_layout_image(
dict(
source="https://img-blog.csdnimg.cn/20230426153240606.png", # 地图图片地址
xref="x", yref="y",
x=df["经度"].min(), y=df["纬度"].min(), # 图片左下角坐标
sizex=df["经度"].max() - df["经度"].min(), # 图片宽度(经度范围)
sizey=df["纬度"].max() - df["纬度"].min(), # 图片高度(纬度范围)
opacity=0.15,
layer="below" # 图片层位于数据下方
)
)
# 保存为 HTML
fig.write_html("aqi_3d_geo.html", auto_open=True)
结果
实验总结
- 本次实验围绕全国空气质量数据的可视化分析与统计技术对比展开,通过多个任务实践了不同数据可视化技术的应用,具体成果如下:
- 数据可视化技术实践
实验 1:AQI 横向对比条形图
使用pyecharts的Bar组件实现城市 AQI 值横向排序,通过MarkLine标记均值线,并利用颜色区分高于 / 低于均值的城市。核心要点包括数据排序、颜色映射和标记线配置,直观展示了城市间 AQI 的差异。
实验 2:AQI 等级分布饼图
基于 AQI 等级划分,使用Matplotlib绘制饼图并添加点击交互事件。通过explode参数突出显示占比最大的扇区,结合plt.figure创建弹出窗口显示详细城市列表,实现了数据分布与交互功能的结合。
实验 3:多城市 AQI 对比仪表盘
利用Tab组件构建多图表仪表盘,包含条形图、散点图与折线图。通过共享暗黑主题(ThemeType.DARK)保持风格统一,其中散点图添加回归线对比东西部趋势,折线图展示区域 AQI 变化,体现了多维度数据对比的可视化设计。
实验 4:2D 地理 AQI 可视化
使用Geo组件在地图上标记城市位置,通过VisualMapOpts实现颜色分段映射,直观展示不同地区 AQI 等级分布。关键在于城市经纬度匹配和视觉映射规则的设置,增强了数据的地理空间关联性。
实验 5:3D 地理 AQI 可视化
结合Plotly的Scatter3d和地图背景,以三维散点图展示城市位置与 AQI 值,高度和颜色分别映射 AQI 数值。通过相机视角调整和地图底图叠加,提升了数据的立体层次感和空间感知。 - 技术对比与适用场景
以下是实验中涉及的可视化技术对比与适用场景表格:
可视化类型 | 技术工具 | 优势特点 | 适用场景 |
---|---|---|---|
条形图 | pyecharts | - 支持数据排序与横向对比 - 可配置标记线(如均值线) - 颜色映射区分数据等级 | 单维度数据排序、基准值对比(如城市AQI高低排序) |
饼图 | Matplotlib | - 直观展示分类数据占比 - 支持交互事件(如点击弹出详情) - 灵活控制扇区突出效果 | 分类数据占比分析(如AQI等级城市数量分布) |
仪表盘(多图表) | pyecharts | - 多图表集成于选项卡,支持主题统一 - 适合多维度数据对比 - 交互性强(如缩放、联动) | 综合数据监控(如TOP10城市、区域趋势对比) |
2D地理图 | pyecharts(Geo) | - 结合地图展示空间分布 - 颜色分段映射数据等级 - 支持标记点交互(如悬浮提示) | 区域数据分布分析(如全国城市AQI颜色标记) |
3D地理图 | Plotly(Scatter3d) | - 三维立体效果增强空间感知 - 高度与颜色双维度映射数据 - 支持自由视角旋转与缩放 | 三维空间数据探索(如城市AQI值的立体分布) |