数据可视化交互

实验目的

  1. 了解数据可视化的一般原则
  2. 掌握数据可视化的分类
  3. 掌握数据可视化的常见技术
  4. 本次实验是对全国的空气质量进行可视化分析并进行数
    据统计技术对比

实验原理

  • 设计可视化系统或选择交互方式的时候,除了能够完成任务本身之外,还要遵循一些基本的原则。例如,交互的延时性需要在用户可以接受的范围之内,并有效控制用户交互的成本。这些基本原则对交互的效果起着至关重要的作用富。另外,交互的技术有很多种,本次实验是对文本进行可视
    化生成词云图片与传统的统计技术对比。交互的原则、交互的分类以及常见的交互技术,尤其是几种常见的交互技术,只有熟练掌握并使用恰当,才可能设计出用户体验良好的可视化应用。尽管交互的技术有很多种,但交互技术本身并无优劣之分,选择哪种交互技术的依据是具体的场景和应用需求。

实验环境

  • Python:v3.6

实验步骤

一、安装 pyecharts

在这里插入图片描述

二、下载数据

下载数据文件(data.txt),该文件表示了一些城市某天的空气质量指数(AQI)。
在这里插入图片描述

三、实验任务

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

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

  1. 按AQI从高到低排序

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

  3. 使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等级划分(优/良/轻度污染/中度污染/重度污
染),绘制饼图并添加交互功能:

  1. 使用Pie图表展示各等级下城市数量占比
  2. 标签显示百分比和等级名称,突出显示占比最大的扇区
  3. 添加点击事件:单击扇区时弹出该等级详细城市数量及城市
    名称列表
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组件构建多图表仪表盘:

  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.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值的立体分布)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值