数据可视化交互

发布于:2025-06-10 ⋅ 阅读:(19) ⋅ 点赞:(0)

目录

目的

原理

环境

实验步骤

一、安装 pyecharts

二、下载数据 

三、实验任务

实验 1:AQI 横向对比条形图

实验 2:AQI 等级分布饼图

实验 3:多城市 AQI 对比仪表盘

实验 4:2D 地理 AQI 可视化 

实验 5:3D 地理 AQI 可视化

总结

目的

        1. 了解数据可视化的一般原则;

        2. 掌握数据可视化的分类;

        3. 掌握数据可视化的常见技术;

        4. 本次实验是对全国的空气质量进行可视化分析并进行数据统计技术对比。

原理

        设计可视化系统或选择交互方式的时候,除了能够完成任务本身之外,还要遵循一些基本的原则。例如,交互的延时性需要在用户可以接受的范围之内,并有效控制用户交互的成本。这些基本原则对交互的效果起着至关重要的作用富。

        另外,交互的技术有很多种,本次实验是对文本进行可视化生成词云图片与传统的统计技术对比。

        交互的原则、交互的分类以及常见的交互技术,尤其是几种常见的交互技术,只有熟练掌握并使用恰当,才可能设计出用户体验良好的可视化应用。尽管交互的技术有很多种,但交互技术本身并无优劣之分,选择哪种交互技术的依据是具体的场景和应用需求。

环境

        Python:v3.6

实验步骤

一、安装 pyecharts

二、下载数据 

        下载数据文件(data.txt),该文件表示了一些城市某天的空气质量指数(AQI),请完成如下实验。

三、实验任务

实验 1AQI 横向对比条形图

任务:使用 Pyecharts 绘制各城市 AQI 值的横向条形图,要求:

1. 按 AQI 从高到低排序;

2. 添加全局配置项:标题为城市 AQI 对比,坐标轴名称分别为“AQI 指数城市”;

3. 使 MarkLine 标记 AQI 均值线(参考值:80),并设置不同颜色区分高于/低于均值的城市。

代码实现如下:

from pyecharts import options as opts
from pyecharts.charts import Bar
from pyecharts.commons.utils import JsCode
import csv
# 示例数据(实际使用时请替换为从文件读取的数据)
data = [
    ("北京", 95), ("上海", 70), ("广州", 85), ("深圳", 72),
    ("杭州", 88), ("南京", 75), ("成都", 82), ("武汉", 78),
    ("西安", 92), ("厦门", 65), ("青岛", 73), ("大连", 68),
    ("长沙", 81), ("重庆", 87), ("天津", 90), ("宁波", 69)
]
# 按AQI从高到低排序
sorted_data = sorted(data, key=lambda x: x[1], reverse=True)
# 提取城市名和AQI值
cities = [city for city, aqi in sorted_data]
aqi_values = [aqi for city, aqi in sorted_data]
mean_aqi = 80  # 使用题目给定参考值
# 创建横向条形图
bar = (
    Bar(init_opts=opts.InitOpts(width="1200px", height="800px"))
    .add_xaxis(cities)
    .add_yaxis(
        "AQI指数",
        aqi_values,
        label_opts=opts.LabelOpts(is_show=True, position="right"),  # 显示数值标签在右侧
        itemstyle_opts=opts.ItemStyleOpts(
            color=JsCode(
                f"function(params) {{return params.value > {mean_aqi} ? '#FF4444' : '#3399FF';}}"
            )
        )
    )
    .reversal_axis()  # 反转坐标轴实现横向条形图
    .set_global_opts(
        title_opts=opts.TitleOpts(title="城市AQI对比"),
        xaxis_opts=opts.AxisOpts(name="AQI指数"),
        yaxis_opts=opts.AxisOpts(name="城市"),
        toolbox_opts=opts.ToolboxOpts(is_show=True),  # 添加工具箱
    )
    .set_series_opts(
        markline_opts=opts.MarkLineOpts(
            data=[
                opts.MarkLineItem(
                    y=mean_aqi,  # 横向条形图中用y表示数值
                    name=f"AQI均值线({mean_aqi})",
                    linestyle_opts=opts.LineStyleOpts(color="#FF9900", width=2, type_="dashed")
                )
            ]
        )
    )
)
# 渲染图表
bar.render("city_aqi_comparison.html")

结果如下: 

实验 2AQI 等级分布饼图

任务:基于 AQI 等级划分(优//轻度污染/中度污染/重度污染),绘制饼图并添加交互功能:

1. 使用 Pie 图表展示各等级下城市数量占比;

2. 标签显示百分比和等级名称,突出显示占比最大的扇区;

3. 添加点击事件:单击扇区时弹出该等级详细城市数量及城市名称列表。

代码实现如下:

import matplotlib.pyplot as plt
from matplotlib.patches import Patch
import numpy as np
# 原始数据(保持不变)
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
}
# AQI等级划分标准(保持不变)
aqi_levels = {
    "优": (0, 50),
    "良": (51, 100),
    "轻度污染": (101, 150),
    "中度污染": (151, 200),
    "重度污染": (201, 300)
}
# 分类城市到各个AQI等级(保持不变)
level_cities = {level: [] for level in aqi_levels}
for city, aqi in data.items():
    for level, (low, high) in aqi_levels.items():
        if low <= aqi <= high:
            level_cities[level].append((city, aqi))
            break
# 计算每个等级的城市数量(保持不变)
level_counts = {level: len(cities) for level, cities in level_cities.items()}
total_cities = sum(level_counts.values())
# 修复字体问题:设置中文字体为SimHei(需系统支持)
plt.rcParams['font.sans-serif'] = ['SimHei']  # 设置中文字体
plt.rcParams['axes.unicode_minus'] = False  # 正确显示负号
# 调整颜色映射(更符合环保主题)
colors = [
    '#006400',  # 优 - 绿色
    '#00FFFF',  # 良 - 青色
    '#FFD700',  # 轻度污染 - 金色
    '#FFA500',  # 中度污染 - 橙色
    '#FF0000'  # 重度污染 - 红色
]
# 准备饼图数据(保持不变)
labels = level_counts.keys()
sizes = level_counts.values()
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},
    pctdistance=0.85
)
# 设置标题(字体大小调整)
ax.set_title('城市AQI等级分布', fontsize=18, pad=30)
# 优化图例样式
legend_elements = [Patch(facecolor=color, edgecolor='black', label=label, linewidth=1.5)
                   for label, color in zip(labels, colors)]
ax.legend(
    handles=legend_elements,
    loc='upper left',
    bbox_to_anchor=(1, 1),  # 图例位置调整到右侧
    fontsize=11,
    title='AQI等级',
    title_fontsize=12
)
# 点击事件处理函数(保持不变)
def on_click(event):
    if event.inaxes != ax:
        return

    for i, wedge in enumerate(wedges):
        if wedge.contains_point((event.x, event.y)):
            level = labels[i]
            cities = level_cities[level]
            count = level_counts[level]

            fig_popup, ax_popup = plt.subplots(figsize=(8, 6))
            fig_popup.canvas.manager.set_window_title(f'AQI {level} 城市详情')

            ax_popup.set_title(f'AQI {level} 城市 ({count}/{total_cities})', fontsize=14)
            ax_popup.axis('off')

            sorted_cities = sorted(cities, key=lambda x: x[1])
            city_text = "\n".join([f"{city}: {aqi}" for city, aqi in sorted_cities])
            ax_popup.text(
                0.5, 0.5, city_text,
                ha='center', va='center',
                fontsize=10,
                bbox=dict(facecolor='white', alpha=0.9, edgecolor='lightgray')
            )

            plt.tight_layout()
            plt.show()
            break
# 连接点击事件(保持不变)
fig.canvas.mpl_connect('button_press_event', on_click)
plt.tight_layout()
plt.show()

结果如下: 

实验 3:多城市 AQI 对比仪表盘

任务:使用 Tab Page 组件构建多图表仪表盘:

1. 第一选项卡:显示 AQI 10 城市的横向条形图;

2. 第二选项卡:展示西北地区城市 AQI 散点数据(添加回归线)与东部城市 AQI 散点数据(添加回归线)的对比;

3. 第三选项卡:组合折线图(各地区 AQI 指数的变化);

4. 要求所有图表共享主题风格(如 ThemeType.DARK)。

代码实现如下:

from pyecharts import options as opts
from pyecharts.charts import Bar, Scatter, Line, Tab
from pyecharts.globals import ThemeType
import numpy as np
from sklearn.linear_model import LinearRegression

# 解析文件内容
data = []
content = """
"海门", 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
"""

# 处理数据
items = content.replace('"', '').split(', ')
for i in range(0, len(items), 2):
    city = items[i].strip()
    aqi = int(items[i+1].strip())
    data.append((city, aqi))

# 排序数据
sorted_data = sorted(data, key=lambda x: x[1], reverse=True)

# 1. 第一选项卡: AQI前10城市横向条形图
top_10_cities = [x[0] for x in sorted_data[:10]]
top_10_aqi = [x[1] for x in sorted_data[:10]]

bar = (
    Bar(init_opts=opts.InitOpts(theme=ThemeType.DARK))
    .add_xaxis(top_10_cities)
    .add_yaxis("AQI指数", top_10_aqi, color="#FFA500")  
    .reversal_axis()
    .set_series_opts(
        label_opts=opts.LabelOpts(position="right"),
        itemstyle_opts=opts.ItemStyleOpts(color="#FFA500")  
    )
    .set_global_opts(
        title_opts=opts.TitleOpts(title="AQI排名前10城市"),
        xaxis_opts=opts.AxisOpts(name="AQI值"),
        yaxis_opts=opts.AxisOpts(name="城市"),
    )
)

# 2. 第二选项卡: 西北与东部城市AQI对比散点图
# 定义西北和东部城市
northwest_cities = ["西安", "兰州", "西宁", "银川", "乌鲁木齐", "呼和浩特",
                   "克拉玛依", "库尔勒", "咸阳", "渭南", "宝鸡", "金昌"]
east_cities = ["上海", "北京", "天津", "广州", "深圳", "杭州", "南京", "苏州",
              "宁波", "青岛", "济南", "厦门", "福州", "大连", "沈阳", "烟台"]

# 提取数据
nw_data = [(city, aqi) for city, aqi in data if city in northwest_cities]
east_data = [(city, aqi) for city, aqi in data if city in east_cities]

# 准备散点图数据 - 使用数值索引作为x轴
nw_points = [[i, aqi] for i, (city, aqi) in enumerate(nw_data)]
east_points = [[i + len(nw_data), aqi] for i, (city, aqi) in enumerate(east_data)]

# 创建散点图
scatter = (
    Scatter(init_opts=opts.InitOpts(theme=ThemeType.DARK))
    .add_xaxis([p[0] for p in nw_points])
    .add_yaxis(
        "西北城市",
        [p[1] for p in nw_points],
        symbol_size=15,
        label_opts=opts.LabelOpts(is_show=False),
        color="#FFA500"  # 修改为橙色
    )
    .add_xaxis([p[0] for p in east_points])
    .add_yaxis(
        "东部城市",
        [p[1] for p in east_points],
        symbol_size=15,
        label_opts=opts.LabelOpts(is_show=False),
        color="#FFA500"  # 修改为橙色
    )
    .set_global_opts(
        title_opts=opts.TitleOpts(title="西北与东部城市AQI对比"),
        xaxis_opts=opts.AxisOpts(
            name="城市索引",
            type_="value",
            min_=0,
            max_=len(nw_data) + len(east_data) - 1
        ),
        yaxis_opts=opts.AxisOpts(name="AQI值"),
        tooltip_opts=opts.TooltipOpts(
            formatter="城市索引: {c0}<br/>AQI值: {c1}",
            trigger="item"
        )
    )
)

# 添加回归线 - 简单实现
# 西北城市回归线
nw_x = [p[0] for p in nw_points]
nw_y = [p[1] for p in nw_points]
nw_regression = [
    [min(nw_x), np.mean(nw_y)],
    [max(nw_x), np.mean(nw_y)]
]

# 东部城市回归线
east_x = [p[0] for p in east_points]
east_y = [p[1] for p in east_points]
east_regression = [
    [min(east_x), np.mean(east_y)],
    [max(east_x), np.mean(east_y)]
]

# 添加回归线到图表
scatter.set_series_opts(
    markline_opts=[
        opts.MarkLineOpts(
            data=[
                {"coord": nw_regression[0]},
                {"coord": nw_regression[1]}
            ],
            linestyle_opts=opts.LineStyleOpts(width=2, type_="dashed", color="#FFA500"),  
            label_opts=opts.LabelOpts(is_show=True, formatter="西北平均AQI")
        ),
        opts.MarkLineOpts(
            data=[
                {"coord": east_regression[0]},
                {"coord": east_regression[1]}
            ],
            linestyle_opts=opts.LineStyleOpts(width=2, type_="dashed", color="#FFA500"),  
            label_opts=opts.LabelOpts(is_show=True, formatter="东部平均AQI")
        )
    ]
)

# 3. 第三选项卡: 各地区AQI变化折线图
# 定义地区
regions = {
    "华北": ["北京", "天津", "石家庄", "太原", "呼和浩特", "包头", "唐山", "保定"],
    "华东": ["上海", "南京", "杭州", "合肥", "福州", "济南", "苏州", "宁波"],
    "华南": ["广州", "深圳", "南宁", "海口", "厦门", "珠海", "汕头"],
    "华中": ["武汉", "郑州", "长沙", "南昌", "宜昌", "洛阳"],
    "东北": ["沈阳", "大连", "长春", "哈尔滨", "鞍山", "吉林"],
    "西南": ["重庆", "成都", "贵阳", "昆明", "拉萨"],
    "西北": ["西安", "兰州", "西宁", "银川", "乌鲁木齐"]
}

# 计算各地区平均AQI
region_avg = {}
for region, cities in regions.items():
    region_aqi = [aqi for city, aqi in data if city in cities]
    if region_aqi:  # 确保列表不为空
        region_avg[region] = sum(region_aqi) / len(region_aqi)
    else:
        region_avg[region] = 0

# 按地区名称排序
sorted_regions = sorted(region_avg.keys())
avg_aqi = [region_avg[region] for region in sorted_regions]

line = (
    Line(init_opts=opts.InitOpts(theme=ThemeType.DARK))
    .add_xaxis(sorted_regions)
    .add_yaxis(
        "平均AQI",
        avg_aqi,
        is_smooth=True,
        label_opts=opts.LabelOpts(is_show=True),
        linestyle_opts=opts.LineStyleOpts(width=3, color="#FFA500"),  
        symbol="circle",
        symbol_size=10,
        itemstyle_opts=opts.ItemStyleOpts(color="#FFA500")  
    )
    .set_global_opts(
        title_opts=opts.TitleOpts(title="各地区平均AQI指数"),
        xaxis_opts=opts.AxisOpts(name="地区"),
        yaxis_opts=opts.AxisOpts(name="平均AQI值"),
        tooltip_opts=opts.TooltipOpts(trigger="axis"),
    )
)

# 创建选项卡
tab = Tab()
tab.add(bar, "AQI Top 10")
tab.add(scatter, "地区对比")
tab.add(line, "区域变化")

# 输出图表
tab.render("aqi_dashboard.html")
print("仪表盘已生成: aqi_dashboard.html")

第一选项卡: 

第二选项卡:  

第三选项卡:

实验 42D 地理 AQI 可视化 

任务:结合 Geo 实现二维地理可视化:

1. 在中国地图上标记城市位置,使用不同颜色表示 AQI 值;

2. 展示不同地区 AQI 数值。

代码实现如下:

from pyecharts import options as opts
from pyecharts.charts import Geo
from pyecharts.globals import ChartType, SymbolType, ThemeType
import json

# 数据准备
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)
]

# 定义颜色分段
pieces = [
    {"min": 0, "max": 50, "label": "0-50(优)", "color": "#096"},
    {"min": 51, "max": 100, "label": "51-100(良)", "color": "#ffde33"},
    {"min": 101, "max": 150, "label": "101-150(轻度污染)", "color": "#ff9933"},
    {"min": 151, "max": 200, "label": "151-200(中度污染)", "color": "#cc0033"},
    {"min": 201, "max": 300, "label": "201-300(重度污染)", "color": "#660099"},
    {"min": 301, "max": 500, "label": ">300(严重污染)", "color": "#7e0023"}
]

# 创建地理坐标系图表
geo = (
    Geo(init_opts=opts.InitOpts(theme=ThemeType.DARK, width="1200px", height="800px"))
    .add_schema(
        maptype="china",
        itemstyle_opts=opts.ItemStyleOpts(color="#323c48", border_color="#111"),
        zoom=1.2
    )
    .add(
        series_name="AQI指数",
        data_pair=data,
        type_=ChartType.EFFECT_SCATTER,
        symbol_size=8,
        label_opts=opts.LabelOpts(
            is_show=False,
            formatter="{b}"
        ),
        tooltip_opts=opts.TooltipOpts(
            formatter="{b}: {c}",
            trigger="item"
        )
    )
    .set_series_opts(
        itemstyle_opts=opts.ItemStyleOpts(border_width=0.5, border_color="#fff")
    )
    .set_global_opts(
        title_opts=opts.TitleOpts(
            title="中国城市AQI地理分布",
            subtitle="数据来源: 模拟数据",
            pos_left="center",
            title_textstyle_opts=opts.TextStyleOpts(color="#fff"),
            subtitle_textstyle_opts=opts.TextStyleOpts(color="#aaa")
        ),
        visualmap_opts=opts.VisualMapOpts(
            is_piecewise=True,
            pieces=pieces,
            pos_left="right",
            pos_top="center",
            textstyle_opts=opts.TextStyleOpts(color="#ddd")
        ),
        legend_opts=opts.LegendOpts(is_show=False)
    )
)

# 添加热力图效果
geo.add(
    series_name="AQI热力",
    data_pair=data,
    type_=ChartType.HEATMAP,
    symbol_size=5,
    blur_size=6,
    point_size=3
)

# 渲染图表
geo.render("china_aqi_geo.html")
print("地理可视化已生成: china_aqi_geo.html")

结果如下: 

实验 53D 地理 AQI 可视化

任务:结合 Geo3D Bar3D 实现三维地理可视化:

1. 在地球模型上标记城市位置,高度表示 AQI

2. 使用 Map3D 配置光照效果和区域颜色(如中国区域高亮)

3. 展示不同地区 AQI 数值。

代码实现如下:

import pandas as pd
import numpy as np
import plotly.graph_objects as go

# 第一步:从 data.txt 读取城市和 AQI
file_path = "G:/数据可视化/data.txt"
city_aqi_data = []

with open(file_path, 'r', encoding='utf-8') as file:
    lines = file.readlines()

for line in lines:
    items = line.replace('"', '').strip().split(', ')
    for i in range(0, len(items) - 1, 2):
        try:
            city = items[i].strip().replace('"', '')
            aqi = int(items[i + 1].strip().rstrip(','))
            city_aqi_data.append((city, aqi))
        except:
            continue

# 创建 DataFrame(前30城市)
df = pd.DataFrame(city_aqi_data, columns=["City", "AQI"]).drop_duplicates("City")
df = df.sort_values(by="AQI", ascending=False).head(30).reset_index(drop=True)

# 第二步:添加模拟经纬度(如果你没有真实数据)
np.random.seed(42)
df["Lon"] = np.random.uniform(85, 125, size=len(df))
df["Lat"] = np.random.uniform(21, 45, size=len(df))

# 第三步:构建 3D 图
fig = go.Figure(data=[go.Scatter3d(
    x=df["Lon"],
    y=df["Lat"],
    z=df["AQI"],
    text=df["City"],
    mode='markers+text',
    marker=dict(
        size=6,
        color=df["AQI"],
        colorscale='Blues',  
        colorbar=dict(title="AQI"),
        opacity=0.8
    )
)])

fig.update_layout(
    title=dict(
        text="中国城市 AQI 三维地理可视化(经度、纬度、AQI)",
        font=dict(size=26),  # 放大标题字体
        x=0.5  # 居中
    ),
    scene=dict(
        xaxis_title='经度',
        yaxis_title='纬度',
        zaxis_title='AQI',
        xaxis=dict(range=[75, 135]),
        yaxis=dict(range=[18, 55]),
        zaxis=dict(range=[0, df["AQI"].max() + 20])
    ),
    width=1200,
    height=1000,
    template="plotly_white"
)

fig.write_html("china_aqi_3d_plotly.html")
fig.show()

结果如下: 

总结 

        实验详细描述了一个关于全国空气质量指数(AQI)数据可视化的实验项目,通过多种可视化技术分析城市空气质量分布与特征。实验分为五个部分:横向条形图对比各城市AQI值并按均值线区分高低污染;饼图展示AQI等级分布及交互式城市列表查询;仪表盘整合前10城市条形图、区域散点回归分析和趋势折线图;2D地理可视化通过地图标记城市位置并以颜色和大小表示AQI数值;3D地理可视化则在地球模型上用高度和颜色呈现AQI差异,并高亮中国区域。
        实验强调交互设计原则与多维度数据展示,通过条形图排序、饼图分级、散点回归、地理映射等技术,系统化呈现了空气质量的空间分布、等级占比及区域对比,最终形成了一套完整的可视化分析方案,兼顾科学性、直观性与用户体验。


网站公告

今日签到

点亮在社区的每一天
去签到