实验8
实验名称
数据可视化交互
实验目的
- 了解数据可视化的一般原则;
- 掌握数据可视化的分类;
- 掌握数据可视化的常见技术;
- 本次实验是对全国的空气质量进行可视化分析并进行数据统计技术对比。
实验原理
设计可视化系统或选择交互方式的时候,除了能够完成任务本身之外,还要遵循一些基本的原则。例如,交互的延时性需要在用户可以接受的范围之内,并有效控制用户交互的成本。这些基本原则对交互的效果起着至关重要的作用富。
另外,交互的技术有很多种,本次实验是对文本进行可视化生成词云图片与传统的统计技术对比。
交互的原则、交互的分类以及常见的交互技术,尤其是几种常见的交互技术,只有熟练掌握并使用恰当,才可能设计出用户体验良好的可视化应用。尽管交互的技术有很多种,但交互技术本身并无优劣之分,选择哪种交互技术的依据是具体的场 景和应用需求。
实验环境
实验步骤
一、安装 pyecharts
pip install pyecharts
二、下载数据
下载数据文件(data.txt),该文件表示了一些城市某天的空 气质量指数(AQI)。
三、实验
实验 1:AQI 横向对比条形图
任务:使用 Pyecharts 绘制各城市 AQI 值的横向条形图
要求:1. 按 AQI 从高到低排序
2. 添加全局配置项:标题为“城市 AQI 对比”,坐标轴名称分别 为“AQI 指数”和“城市”
3. 使 MarkLine 标记 AQI 均值线(参考值:80),并设置不同 颜色区分高于/低于均值的城市
1 from pyecharts import options as opts
2 from pyecharts.charts import Bar
3 import pandas as pd
4
5 # 从文件中读取数据
6 def read_data_from_file(file_path):
7 with open(file_path, "r", encoding="utf-8") as file:
8 data = file.read().strip().replace('"', '').split(", ")
9 return data
10
11 # 文件路径
12 file_path = "data.txt"
13
14 # 读取数据
15 data = read_data_from_file(file_path)
16
17 # 将数据转换为DataFrame
18 cities = data[::2]
19 aqis = []
20
21 # 清理数据并转换为整数
22 for aqi in data[1::2]:
23 try:
24 # 去除可能存在的非数字字符
25 cleaned_aqi = ''.join(filter(str.isdigit, aqi))
26 aqis.append(int(cleaned_aqi))
27 except ValueError:
28 print(f"Warning: Could not convert '{aqi}' to an integer. Skipping this value.")
29 aqis.append(None) # 如果转换失败,添加None作为占位符
30
31 # 去除无效数据(AQI值为None的行)
32 df = pd.DataFrame({"City": cities, "AQI": aqis})
33 df = df.dropna(subset=["AQI"]) # 删除AQI值为NaN的行
34
35 # 按AQI从高到低排序
36 df_sorted = df.sort_values(by="AQI", ascending=False)
37
38 # 创建更小的条形图(原尺寸为1600x800,现调整为800x400)
39 bar = Bar(init_opts=opts.InitOpts(width="1200px", height="600px"))
40
41 # 添加数据
42 bar.add_xaxis(df_sorted["City"].tolist())
43 bar.add_yaxis("AQI", df_sorted["AQI"].tolist(),
44 label_opts=opts.LabelOpts(position="right", font_size=10)) # 减小标签字体
45
46 # 设置全局配置项
47 bar.set_global_opts(
48 title_opts=opts.TitleOpts(title="城市 AQI 对比", title_textstyle_opts=opts.TextStyleOpts(font_size=14)),
49 yaxis_opts=opts.AxisOpts(name="AQI 指数", axislabel_opts=opts.LabelOpts(font_size=10)),
50 xaxis_opts=opts.AxisOpts(name="城市", axislabel_opts=opts.LabelOpts(font_size=10)),
51 visualmap_opts=opts.VisualMapOpts(
52 max_=280,
53 is_piecewise=True,
54 pieces=[
55 {"max": 80, "color": "#50d89f"}, # 低于均值的颜色
56 {"min": 80, "color": "#ff5722"} # 高于均值的颜色
57 ],
58 pos_right="10%", # 调整视觉映射位置,避免遮挡图表
59 textstyle_opts=opts.TextStyleOpts(font_size=10) # 减小视觉映射文字大小
60 )
61 )
62
63 # 设置系列配置项(包括标记线)
64 bar.set_series_opts(
65 markline_opts=opts.MarkLineOpts(
66 data=[opts.MarkLineItem(y=80, name="AQI 均值线")],
67 linestyle_opts=opts.LineStyleOpts(color="#ff0000", width=1.5, type_="dashed") # 减小标记线宽度
68 )
69 )
70
71 # 设置横向条形图
72 bar.reversal_axis()
73 # 渲染图表到 HTML 文件
74 bar.render("C:/Users/Administrator/Desktop/city_aqi_contrast.html")
实验 2:AQI 等级分布饼图
任务:基于 AQI 等级划分(优/良/轻度污染/中度污染/重度污 染),绘制饼图并添加交互功能:
1. 使用 Pie 图表展示各等级下城市数量占比
2. 标签显示百分比和等级名称,突出显示占比最大的扇区
3. 添加点击事件:单击扇区时弹出该等级详细城市数量及城市 名称列表
1 from pyecharts import options as opts
2 from pyecharts.charts import Pie
3 from pyecharts.globals import ThemeType
4 import pandas as pd
5
6 # 从文件中读取数据
7 def read_data_from_file(file_path):
8 with open(file_path, "r", encoding="utf-8") as file:
9 data = file.read().strip().replace('"', '').split(", ")
10 return data
11
12 # 文件路径
13 file_path = "data.txt"
14
15 # 读取数据
16 data = read_data_from_file(file_path)
17
18 # 将数据转换为DataFrame
19 cities = data[::2]
20 aqis = []
21
22 # 清理数据并转换为整数
23 for aqi in data[1::2]:
24 try:
25 # 去除可能存在的非数字字符
26 cleaned_aqi = ''.join(filter(str.isdigit, aqi))
27 aqis.append(int(cleaned_aqi))
28 except ValueError:
29 print(f"Warning: Could not convert '{aqi}' to an integer. Skipping this value.")
30 aqis.append(None) # 如果转换失败,添加None作为占位符
31
32 # 去除无效数据(AQI值为None的行)
33 df = pd.DataFrame({"City": cities, "AQI": aqis})
34 df = df.dropna(subset=["AQI"]) # 删除AQI值为NaN的行
35
36 # AQI等级划分
37 def classify_aqi(aqi):
38 if aqi <= 50:
39 return "优"
40 elif aqi <= 100:
41 return "良"
42 elif aqi <= 150:
43 return "轻度污染"
44 elif aqi <= 200:
45 return "中度污染"
46 elif aqi <= 300:
47 return "重度污染"
48 else:
49 return "严重污染"
50
51 # 添加等级列
52 df["等级"] = df["AQI"].apply(classify_aqi)
53
54 # 统计每个等级的城市数量
55 grade_counts = df["等级"].value_counts().reset_index()
56 grade_counts.columns = ["等级", "城市数量"]
57
58 # 创建饼图
59 pie = (
60 Pie(init_opts=opts.InitOpts(theme=ThemeType.LIGHT))
61 .add(
62 series_name="AQI等级分布",
63 data_pair=[list(z) for z in zip(grade_counts["等级"], grade_counts["城市数量"])],
64 radius=["30%", "70%"],
65 label_opts=opts.LabelOpts(
66 is_show=True,
67 formatter="{b}: {c} ({d}%)", # 显示等级名称、城市数量和百分比
68 font_size=12,
69 color="#000",
70 ),
71 emphasis_opts=opts.LabelOpts( # 修改为直接设置高亮时的标签样式
72 is_show=True,
73 font_size=16,
74 color="#000",
75 ),
76 )
77 .set_global_opts(
78 title_opts=opts.TitleOpts(title="AQI等级分布饼图"),
79 legend_opts=opts.LegendOpts(
80 orient="vertical", pos_top="15%", pos_left="2%"
81 ),
82 )
83 .set_series_opts(
84 tooltip_opts=opts.TooltipOpts(
85 trigger="item",
86 formatter="{a} <br/>{b}: {c} ({d}%)",
87 ),
88 label_opts=opts.LabelOpts(is_show=True),
89 )
90 )
91 # 渲染图表
92 pie.render("C:/Users/Administrator/Desktop/aqi_grade_distribution.html")
实验 3:多城市 AQI 对比仪表盘
任务:使用 Tab 或 Page 组件构建多图表仪表盘:
1. 第一选项卡:显示 AQI 前 10 城市的横向条形图
2. 第二选项卡:展示西北地区城市 AQI 散点数据(添加回归 线)与东部城市 AQI 散点数据(添加回归线)的对比
3. 第三选项卡:组合折线图(各地区 AQI 指数的变化)
4. 要求所有图表共享主题风格(如 ThemeType.DARK)
1 from pyecharts import options as opts
2 from pyecharts.charts import Bar, Scatter, Line, Tab
3 from pyecharts.globals import ThemeType
4 import pandas as pd
5 import numpy as np
6 from sklearn.linear_model import LinearRegression
7
8
9 # 从文件中读取数据(优化数据清洗逻辑)
10 def read_data_from_file(file_path):
11 with open(file_path, "r", encoding="utf-8") as file:
12 data = file.read().strip().replace('"', '').split(", ")
13 city_aqi_pairs = [(data[i].strip(), data[i + 1].strip()) for i in range(0, len(data), 2)]
14 return pd.DataFrame(city_aqi_pairs, columns=["City", "AQI"])
15
16
17 # 文件路径
18 file_path = "data.txt"
19
20 # 读取并处理数据
21 df = read_data_from_file(file_path)
22 df["AQI"] = pd.to_numeric(df["AQI"], errors="coerce")
23 df = df.dropna(subset=["AQI"]).astype({"AQI": int})
24
25
26 # 第一选项卡:AQI 前10城市横向条形图(主题在图表内设置)
27 def tab1_top10_aqi_bar():
28 top10_df = df.nlargest(10, "AQI")
29 return (
30 Bar(init_opts=opts.InitOpts(theme=ThemeType.DARK, width="800px", height="400px"))
31 .add_xaxis(top10_df["City"].tolist())
32 .add_yaxis(
33 "AQI",
34 top10_df["AQI"].tolist(),
35 label_opts=opts.LabelOpts(position="right", font_size=10)
36 )
37 .reversal_axis()
38 .set_global_opts(
39 title_opts=opts.TitleOpts(title="🚀 AQI 前10城市", pos_left="center"),
40 yaxis_opts=opts.AxisOpts(name="AQI 指数"),
41 xaxis_opts=opts.AxisOpts(name="城市", axislabel_opts=opts.LabelOpts(font_size=10)),
42 legend_opts=opts.LegendOpts(is_show=False)
43 )
44 )
45
46
47 # 第二选项卡:西北与东部地区散点对比(修正X轴标签逻辑)
48 def tab2_scatter_with_regression():
49 northwest_cities = {"乌鲁木齐", "银川", "西宁", "兰州", "西安"}
50 east_cities = {"上海", "杭州", "南京", "青岛", "厦门", "苏州", "宁波"}
51
52 northwest_df = df[df["City"].isin(northwest_cities)].sort_values("AQI")
53 east_df = df[df["City"].isin(east_cities)].sort_values("AQI")
54
55 def get_index_data(df_region):
56 return pd.DataFrame({
57 "index": np.arange(len(df_region)),
58 "city": df_region["City"],
59 "aqi": df_region["AQI"]
60 })
61
62 nw_idx = get_index_data(northwest_df)
63 ea_idx = get_index_data(east_df)
64
65 def fit_regression(x, y):
66 x_np = x.values.reshape(-1, 1)
67 y_np = y.values
68 model = LinearRegression()
69 model.fit(x_np, y_np)
70 return model.predict(x_np)
71
72 nw_reg = fit_regression(nw_idx["index"], nw_idx["aqi"])
73 ea_reg = fit_regression(ea_idx["index"], ea_idx["aqi"])
74
75 scatter = (
76 Scatter(init_opts=opts.InitOpts(theme=ThemeType.DARK, width="800px", height="450px"))
77 .add_xaxis(nw_idx["index"].tolist())
78 .add_yaxis(
79 "西北地区",
80 [list(z) for z in zip(nw_idx["index"], nw_idx["aqi"])],
81 symbol_size=12,
82 label_opts=opts.LabelOpts(is_show=True, position="top"),
83 itemstyle_opts=opts.ItemStyleOpts(color="#00FFFF")
84 )
85 .add_xaxis(ea_idx["index"].tolist())
86 .add_yaxis(
87 "东部地区",
88 [list(z) for z in zip(ea_idx["index"], ea_idx["aqi"])],
89 symbol_size=12,
90 label_opts=opts.LabelOpts(is_show=True, position="top"),
91 itemstyle_opts=opts.ItemStyleOpts(color="#FF6B6B")
92 )
93 .set_global_opts(
94 title_opts=opts.TitleOpts(title="🌏 西北 vs 东部地区AQI对比", pos_left="center"),
95 xaxis_opts=opts.AxisOpts(
96 name="城市索引(按AQI排序)",
97 # 使用lambda函数根据索引范围显示对应城市名
98 axislabel_opts=opts.LabelOpts(
99 formatter=lambda x: "\n".join(nw_idx["city"]) if x < len(nw_idx) else "\n".join(ea_idx["city"])
100 ),
101 axistick_opts=opts.AxisTickOpts(is_show=False)
102 ),
103 yaxis_opts=opts.AxisOpts(name="AQI 指数"),
104 legend_opts=opts.LegendOpts(pos_left="2%", pos_top="10%")
105 )
106 )
107
108 line = (
109 Line()
110 .add_xaxis(nw_idx["index"].tolist())
111 .add_yaxis(
112 "西北回归线",
113 nw_reg.tolist(),
114 linestyle_opts=opts.LineStyleOpts(color="#00FFFF", width=2, type_="dashed")
115 )
116 .add_xaxis(ea_idx["index"].tolist())
117 .add_yaxis(
118 "东部回归线",
119 ea_reg.tolist(),
120 linestyle_opts=opts.LineStyleOpts(color="#FF6B6B", width=2, type_="dashed")
121 )
122 )
123 return scatter.overlap(line)
124
125 # 第三选项卡:各地区AQI趋势组合折线图(主题在图表内设置)
126 def tab3_combined_line():
127 regions = {
128 "西北地区": {"乌鲁木齐", "银川", "西宁", "兰州", "西安"},
129 "东部地区": {"上海", "杭州", "南京", "青岛", "厦门", "宁波"},
130 "中部地区": {"武汉", "长沙", "郑州", "合肥", "南昌", "太原"}
131 }
132
133 region_data = []
134 for name, cities in regions.items():
135 region_df = df[df["City"].isin(cities)].sort_values("City")
136 region_data.append((name, region_df["AQI"].tolist()))
137
138 line = (
139 Line(init_opts=opts.InitOpts(theme=ThemeType.DARK, width="800px", height="400px"))
140 )
141
142 for name, values in region_data:
143 line.add_xaxis(list(regions[name])) # 使用固定城市顺序
144 line.add_yaxis(
145 name,
146 values,
147 is_smooth=True,
148 symbol="circle",
149 markpoint_opts=opts.MarkPointOpts(
150 data=[opts.MarkPointItem(type_="max", name="最大值")]
151 )
152 )
153
154 return line.set_global_opts(
155 title_opts=opts.TitleOpts(title="📈 各地区AQI趋势对比", pos_left="center"),
156 yaxis_opts=opts.AxisOpts(name="AQI 指数"),
157 xaxis_opts=opts.AxisOpts(name="城市"),
158 legend_opts=opts.LegendOpts(pos_right="2%", orient="vertical")
159 )
160
161 # 创建Tab组件(不再传递init_opts)
162 tab = Tab()
163 tab.add(tab1_top10_aqi_bar(), "🔝 AQI前10城市")
164 tab.add(tab2_scatter_with_regression(), "🌎 地区散点对比")
165 tab.add(tab3_combined_line(), "📊 地区趋势分析")
166
167 # 渲染图表
168 tab.render("C:/Users/Administrator/Desktop/aqi_dashboard_tab.html")


实验 4:2D 地理 AQI 可视化
任务:结合 Geo 实现二维地理可视化:
1. 在中国地图上标记城市位置,使用不同颜色表示 AQI 值
2. 展示不同地区 AQI 数值
1 from pyecharts import options as opts
2 from pyecharts.charts import Geo
3 import pandas as pd
4
5 # 读取数据并处理(与原代码一致)
6 def read_data_from_file(file_path):
7 with open(file_path, "r", encoding="utf-8") as file:
8 data = file.read().strip().replace('"', '').split(", ")
9 return data
10
11 file_path = "data.txt"
12 data = read_data_from_file(file_path)
13 cities = data[::2]
14 aqis = [int(''.join(filter(str.isdigit, aqi))) for aqi in data[1::2]]
15 df = pd.DataFrame({"City": cities, "AQI": aqis}).dropna()
16 df_sorted = df.sort_values(by="AQI", ascending=False)
17
18 # 创建 Geo 地理可视化图表
19 c = (
20 Geo(init_opts=opts.InitOpts(width="1200px", height="600px")) # 设置图表尺寸
21 .add_schema(
22 maptype="china", # 指定中国地图
23 label_opts=opts.LabelOpts(is_show=False), # 隐藏地图标签
24 itemstyle_opts=opts.ItemStyleOpts(
25 color="#323c48", # 地图背景色
26 border_color="#404a59" # 地图边界色
27 )
28 )
29 # 添加城市数据(坐标由系统自动解析,需确保城市名正确)
30 .add(
31 series_name="AQI 分布",
32 data_pair=list(zip(df_sorted["City"], df_sorted["AQI"])),
33 type_="scatter", # 散点图标记
34 symbol_size=8, # 标记点大小
35 label_opts=opts.LabelOpts(is_show=False), # 隐藏标记标签
36 )
37 # 设置全局视觉映射(颜色渐变)
38 .set_global_opts(
39 title_opts=opts.TitleOpts(title="中国城市 AQI 地理分布", subtitle="数据来源:data.txt"),
40 visualmap_opts=opts.VisualMapOpts(
41 is_piecewise=True, # 分段显示
42 max_=df_sorted["AQI"].max(), # 最大值自动获取
43 min_=df_sorted["AQI"].min(), # 最小值自动获取
44 range_color=["#50CD9F", "#FFF288", "#FF6B6B"], # 颜色区间(绿→黄→红)
45 textstyle_opts=opts.TextStyleOpts(color="#000"), # 图例文字颜色
46 pos_right="5%", # 图例位置
47 pos_top="10%"
48 )
49 )
50 )
51
52 # 渲染生成 HTML 文件
53 c.render("C:/Users/Administrator/Desktop/city_aqi_geo.html")
实验 5:3D 地理 AQI 可视化
任务:结合 Geo3D 和 Bar3D 实现三维地理可视化:
1. 在地球模型上标记城市位置,高度表示 AQI 值
2. 使用 Map3D 配置光照效果和区域颜色(如中国区域高亮)
3. 展示不同地区 AQI 数值
1 from pyecharts.charts import Map3D
2 from pyecharts.globals import ChartType, ThemeType
3 from pyecharts import options as opts
4 import json
5
6 # 城市经纬度数据,这里只列出部分城市,实际中需要补充完整
7 city_coordinates = {
8 "海门": [121.15, 31.89],
9 "鄂尔多斯": [109.7813, 39.6082],
10 "招远": [120.38, 37.35],
11 "舟山": [122.21, 30.03],
12 "齐齐哈尔": [123.97, 47.33],
13 "盐城": [120.13, 33.38],
14 "赤峰": [118.87, 42.25],
15 "青岛": [120.33, 36.07],
16 "乳山": [121.52, 36.92],
17 "金昌": [102.19, 38.52],
18 "泉州": [118.58, 24.93],
19 "莱西": [120.53, 36.86],
20 "日照": [119.46, 35.42],
21 "胶南": [119.97, 35.88],
22 "南通": [121.05, 32.01],
23 "拉萨": [91.11, 29.97],
24 "云浮": [112.02, 22.93],
25 "梅州": [116.12, 24.58],
26 "文登": [122.05, 36.45],
27 "上海": [121.47, 31.23],
28 "攀枝花": [101.72, 26.58],
29 "威海": [122.12, 37.5],
30 "承德": [117.93, 40.97],
31 "厦门": [118.08, 24.48],
32 "汕尾": [115.37, 22.78],
33 "潮州": [116.63, 23.65],
34 "丹东": [124.37, 40.13],
35 "太仓": [121.1, 31.45],
36 "曲靖": [103.79, 25.51],
37 "烟台": [121.39, 37.52],
38 "福州": [119.3, 26.08],
39 "瓦房店": [121.98, 39.63],
40 "即墨": [120.43, 36.37],
41 "抚顺": [123.93, 41.95],
42 "玉溪": [102.52, 24.35],
43 "张家口": [114.87, 40.82],
44 "阳泉": [113.57, 37.85],
45 "莱州": [119.94, 37.18],
46 "湖州": [120.1, 30.86],
47 "汕头": [116.68, 23.34],
48 "昆山": [120.96, 31.38],
49 "宁波": [121.56, 29.86],
50 "湛江": [110.35, 21.27],
51 "揭阳": [116.36, 23.55],
52 "荣成": [122.41, 37.16],
53 "连云港": [119.16, 34.59],
54 "葫芦岛": [120.83, 40.71],
55 "常熟": [120.74, 31.64],
56 "东莞": [113.75, 23.04],
57 "河源": [114.68, 23.74],
58 "淮安": [119.15, 33.5],
59 "泰州": [120.01, 32.49],
60 "南宁": [108.33, 22.84],
61 "营口": [122.18, 40.65],
62 "惠州": [114.4, 23.09],
63 "江阴": [120.26, 31.91],
64 "蓬莱": [120.75, 37.8],
65 "韶关": [113.62, 24.84],
66 "嘉峪关": [98.28, 39.77],
67 "广州": [113.23, 23.16],
68 "延安": [109.47, 35.59],
69 "太原": [112.53, 37.87],
70 "清远": [113.01, 23.7],
71 "中山": [113.39, 22.52],
72 "昆明": [102.73, 25.04],
73 "寿光": [118.73, 37.87],
74 "盘锦": [122.07, 41.12],
75 "长治": [113.1, 36.18],
76 "深圳": [114.07, 22.62],
77 "珠海": [113.57, 22.27],
78 "宿迁": [118.3, 33.97],
79 "咸阳": [108.72, 34.36],
80 "铜川": [109.15, 35.09],
81 "平度": [119.97, 36.77],
82 "佛山": [113.11, 23.03],
83 "海口": [110.35, 20.02],
84 "江门": [113.06, 22.58],
85 "章丘": [117.53, 36.65],
86 "肇庆": [112.44, 23.05],
87 "大连": [121.62, 38.92],
88 "临汾": [111.5, 36.08],
89 "吴江": [120.63, 31.16],
90 "石嘴山": [106.39, 39.04],
91 "沈阳": [123.43, 41.8],
92 "苏州": [120.62, 31.32],
93 "茂名": [110.92, 21.66],
94 "嘉兴": [120.76, 30.77],
95 "长春": [125.35, 43.88],
96 "胶州": [120.03, 36.49],
97 "银川": [106.27, 38.47],
98 "张家港": [120.57, 31.94],
99 "三门峡": [111.19, 34.78],
100 "锦州": [121.13, 41.11],
101 "南昌": [115.89, 28.68],
102 "柳州": [109.4, 24.28],
103 "三亚": [109.51, 18.25],
104 "自贡": [104.77, 29.33],
105 "吉林": [126.57, 43.87],
106 "阳江": [111.95, 21.85],
107 "泸州": [105.43, 28.87],
108 "西宁": [101.77, 36.62],
109 "宜宾": [104.63, 28.75],
110 "呼和浩特": [111.65, 40.82],
111 "成都": [104.07, 30.57],
112 "大同": [113.3, 40.07],
113 "镇江": [119.44, 32.2],
114 "桂林": [110.29, 25.28],
115 "张家界": [110.47, 29.13],
116 "宜兴": [119.82, 31.36],
117 "北海": [109.12, 21.49],
118 "西安": [108.95, 34.27],
119 "金坛": [119.56, 31.74],
120 "东营": [118.49, 37.46],
121 "牡丹江": [129.61, 44.6],
122 "遵义": [106.9, 27.73],
123 "绍兴": [120.58, 30.05],
124 "扬州": [119.42, 32.39],
125 "常州": [119.96, 31.79],
126 "潍坊": [119.11, 36.72],
127 "重庆": [106.55, 29.57],
128 "台州": [121.42, 28.65],
129 "南京": [118.78, 32.04],
130 "滨州": [118.01, 37.38],
131 "贵阳": [106.71, 26.57],
132 "无锡": [120.29, 31.55],
133 "本溪": [123.73, 41.3],
134 "克拉玛依": [84.77, 45.59],
135 "渭南": [109.5, 34.52],
136 "马鞍山": [118.48, 31.56],
137 "宝鸡": [107.15, 34.38],
138 "焦作": [113.21, 35.24],
139 "句容": [119.41, 31.95],
140 "北京": [116.41, 39.9],
141 "徐州": [117.18, 34.27],
142 "衡水": [115.72, 37.73],
143 "包头": [110.3, 40.65],
144 "绵阳": [104.73, 31.57],
145 "乌鲁木齐": [87.68, 43.82],
146 "枣庄": [117.55, 34.86],
147 "杭州": [120.19, 30.26],
148 "淄博": [118.05, 36.8],
149 "鞍山": [122.97, 41.12],
150 "溧阳": [119.48, 31.43],
151 "库尔勒": [86.06, 41.77],
152 "安阳": [114.35, 36.1],
153 "开封": [114.31, 34.79],
154 "济南": [117.0, 36.65],
155 "德阳": [104.37, 31.13],
156 "温州": [120.65, 28.01],
157 "九江": [115.97, 29.71],
158 "邯郸": [114.47, 36.6],
159 "临安": [119.72, 30.23],
160 "兰州": [103.83, 36.06],
161 "沧州": [116.83, 38.31],
162 "临沂": [118.35, 35.05],
163 "南充": [106.09, 30.84],
164 "天津": [117.2, 39.13],
165 "富阳": [119.95, 30.05],
166 "泰安": [117.08, 36.2],
167 "诸暨": [120.23, 29.71],
168 "郑州": [113.63, 34.76],
169 "哈尔滨": [126.63, 45.75],
170 "聊城": [115.97, 36.45],
171 "芜湖": [118.38, 31.33],
172 "唐山": [118.18, 39.63],
173 "平顶山": [113.29, 33.75],
174 "邢台": [114.5, 37.05],
175 "德州": [116.29, 37.45],
176 "济宁": [116.59, 35.37],
177 "荆州": [112.23, 30.33],
178 "宜昌": [111.29, 30.55],
179 "义乌": [120.06, 29.32],
180 "丽水": [119.92, 28.45],
181 "洛阳": [112.44, 34.62],
182 "秦皇岛": [119.57, 39.95],
183 "株洲": [113.13, 27.83],
184 "石家庄": [114.48, 38.03],
185 "莱芜": [117.67, 36.2],
186 "常德": [111.69, 29.05],
187 "保定": [115.48, 38.85],
188 "湘潭": [112.91, 27.87],
189 "金华": [119.64, 29.08],
190 "岳阳": [113.09, 29.37],
191 "长沙": [112.98, 28.19],
192 "衢州": [118.88, 28.97],
193 "廊坊": [116.7, 39.53],
194 "菏泽": [115.48, 35.23],
195 "合肥": [117.27, 31.86],
196 "武汉": [114.31, 30.52],
197 "大庆": [125.03, 46.56],
198 }
199
200 def load_data(file_path):
201 with open(file_path, 'r', encoding='utf-8') as f:
202 content = f.read().strip()
203 content = content[:-1]
204 data = json.loads(f"[{content}]")
205 return [(data[i], data[i+1]) for i in range(0, len(data), 2)]
206
207 data = load_data("data.txt")
208 cities = [x[0] for x in data]
209 aqi_values = [x[1] for x in data]
210
211 # 将城市名称与经纬度匹配
212 map_data = []
213 for city, aqi in data:
214 if city in city_coordinates:
215 map_data.append([city, [city_coordinates[city][0], city_coordinates[city][1], aqi]])
216
217 map3d = (
218 Map3D(init_opts=opts.InitOpts(theme=ThemeType.DARK, width="100%", height="600px"))
219 .add_schema(
220 itemstyle_opts=opts.ItemStyleOpts(
221 color="#1E90FF",
222 opacity=1,
223 border_width=0.8,
224 border_color="#404a59",
225 ),
226 map3d_label=opts.Map3DLabelOpts(
227 is_show=False,
228 ),
229 light_opts=opts.Map3DLightOpts(
230 main_color="#fff",
231 main_intensity=1.2,
232 is_main_shadow=True,
233 main_alpha=55,
234 main_beta=10,
235 ambient_intensity=0.3,
236 ),
237 view_control_opts=opts.Map3DViewControlOpts(
238 distance=100, alpha=45, beta=30
239 ),
240 )
241 .add(
242 series_name="AQI",
243 data_pair=map_data,
244 type_=ChartType.BAR3D,
245 bar_size=1,
246 shading="color",
247 label_opts=opts.LabelOpts(is_show=False),
248 )
249 .set_global_opts(
250 title_opts=opts.TitleOpts(title="中国城市AQI 3D分布"),
251 visualmap_opts=opts.VisualMapOpts(
252 min_=min(aqi_values),
253 max_=max(aqi_values),
254 range_color=["#313695", "#4575b4", "#74add1", "#abd9e9", "#e0f3f8",
255 "#ffffbf", "#fee090", "#fdae61", "#f46d43", "#d73027", "#a50026"],
256 is_show=True,
257 ),
258 )
259 )
260 map3d.render("D://A.615//experiment5_aqi_3d.html")
实验总结
实验总结
实验中遇到的问题及解决方案
1. 数据清洗与格式转换问题
2. 城市坐标匹配与地理可视化偏差
3. 图表性能与信息过载问题
4. 多图表集成与主题一致性问题
实验心得
1. 数据可视化的核心价值:从 “展示” 到 “交互”
2. 技术选型与场景适配的重要性
3. 数据预处理是可视化的基础
4. 交互设计需平衡 “功能” 与 “体验”
5. 地理可视化的拓展空间
未来改进方向
本次实验通过实战掌握了数据可视化的核心技术与交互原则,深刻体会到 “可视化不仅是图表绘制,更是数据故事的讲述”。从基础图表到 3D 地理可视化,每一步都需兼顾数据准确性、交互流畅性与视觉美观性。未来可将该技术应用于环保监测、城市管理等领域,通过数据可视化助力决策优化与公众科普。

浙公网安备 33010602011771号