目錄
【實驗目的】
【實驗原理】
【實驗環境】
【實驗步驟】
一、安裝 pyecharts
二、下載數據
三、實驗任務
實驗 1:AQI 橫向對比條形圖
代碼說明:
運行結果:
實驗 2:AQI 等級分布餅圖
實驗 3:多城市 AQI 對比儀表盤
實驗 4:2D 地理 AQI 可視化
實驗 5:3D 地理 AQI 可視化
【實驗總結】
【實驗目的】
- 了解數據可視化的一般原則
- 掌握數據可視化的分類
- 掌握數據可視化的常見技術
- 本次實驗是對全國的空氣質量進行可視化分析并進行數據統計技術對比
【實驗原理】
????????設計可視化系統或選擇交互方式的時候,除了能夠完成任務本身之外,還要遵循一些基本的原則。例如,交互的延時性需要在用戶可以接受的范圍之內,并有效控制用戶交互的成本。這些基本原則對交互的效果起著至關重要的作用富。
????????另外,交互的技術有很多種,本次實驗是對文本進行可視化生成詞云圖片與傳統的統計技術對比。
????????交互的原則、交互的分類以及常見的交互技術,尤其是幾種常見的交互技術,只有熟練掌握并使用恰當,才可能設計出用戶體驗良好的可視化應用。盡管交互的技術有很多種,但交互技術本身并無優劣之分,選擇哪種交互技術的依據是具體的場景和應用需求。
【實驗環境】
????????Python:v3.11
【實驗步驟】
一、安裝 pyecharts
????????pip install pyecharts
二、下載數據
????????下載數據文件(data.txt),該文件表示了一些城市某天的空氣質量指數(AQI),請完成如下實驗。
三、實驗任務
實驗 1:AQI 橫向對比條形圖
????????任務:使用 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 re# 解析文件內容
data_str = '''
"海門", 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值
pattern = re.compile(r'"([^"]+)",\s*(\d+)')
matches = pattern.findall(data_str)
cities = [match[0] for match in matches]
aqi_values = [int(match[1]) for match in matches]# 創建城市 - AQI配對列表并排序
city_aqi = list(zip(cities, aqi_values))
sorted_city_aqi = sorted(city_aqi, key=lambda x: x[1], reverse=True)# 分離排序后的數據
sorted_cities = [item[0] for item in sorted_city_aqi]
sorted_aqi = [item[1] for item in sorted_city_aqi]# 計算均值線位置
mean_aqi = 80# 找到"綿陽"在排序后的列表中的索引
target_city = "綿陽"
target_index = None
for index, (city, aqi) in enumerate(sorted_city_aqi):if city == target_city and aqi == mean_aqi:target_index = indexbreak# 如果找不到綿陽,嘗試找到第一個AQI為80的城市
if target_index is None:for index, aqi in enumerate(sorted_aqi):if aqi == mean_aqi:target_index = indexbreak# 如果仍然找不到,使用平均值位置
if target_index is None:target_index = len(sorted_aqi) // 2print(f"警告: 未找到AQI值為{mean_aqi}的城市,使用中間位置")# 創建橫向條形圖
bar = (Bar().add_xaxis(sorted_cities) # 城市名稱作為X軸.add_yaxis(series_name="AQI指數",y_axis=sorted_aqi, # AQI值作為Y軸label_opts=opts.LabelOpts(position="right"),# 設置條形顏色:高于均值紅色,低于均值綠色# 注意:這里使用大于等于80作為分界,確保80在紅色區域itemstyle_opts=opts.ItemStyleOpts(color=JsCode(f'''function(params) {{return params.value >= {mean_aqi} ? '#d14a61' : '#91cc75';}}'''))).reversal_axis() # 反轉坐標軸,使圖表變為橫向.set_global_opts(title_opts=opts.TitleOpts(title="城市 AQI 對比"),xaxis_opts=opts.AxisOpts(name="城市",axislabel_opts=opts.LabelOpts(font_size=8)),yaxis_opts=opts.AxisOpts(name="AQI 指數"),# 添加數據縮放功能,便于查看所有城市datazoom_opts=opts.DataZoomOpts(type_="inside",orient="vertical",range_start=0,range_end=100)).set_series_opts(markline_opts=opts.MarkLineOpts(# 使用找到的索引對應的位置作為標記線位置(y坐標)data=[opts.MarkLineItem(y=target_index, name="均值")],label_opts=opts.LabelOpts(position="middle", formatter=f"均值: {mean_aqi}"),linestyle_opts=opts.LineStyleOpts(color="blue", type_="dashed")))
)# 渲染圖表
bar.render("city_aqi_comparison.html")
代碼說明:
數據處理:
-
原始數據解析為元組列表
-
使用
sorted()
函數按 AQI 值降序排列 -
分離城市名稱和 AQI 數值
圖形配置:
-
reversal_axis()
實現橫向條形圖 -
itemstyle_opts
通過 JsCode 動態設置顏色: -
高于均值(80)顯示紅色
-
低于均值顯示綠色
-
全局配置包含:
-
居中標題 "城市 AQI 對比"
-
坐標軸名稱 "AQI 指數" 和 "城市"
-
顯示工具箱方便交互
-
藍色虛線均值標記線
-
顏色區分:
-
紅色條形代表 AQI 高于均值(80)
-
綠色條形代表 AQI 低于均值(80)
運行結果:
????????生成city_aqi_comparison.html
文件,打開后可看到:橫向條形圖按 AQI 從高到低排列(大慶 279 最高,海門 9 最低);紅色 / 綠色條形清晰區分均值上下;藍色虛線標注均值線 80;右側顯示具體 AQI 數值;支持縮放、下載等工具箱功能。
?
實驗 2:AQI 等級分布餅圖
????????任務:基于 AQI 等級劃分(優/良/輕度污染/中度污染/重度污染),繪制餅圖并添加交互功能:
????????1. 使用 Pie 圖表展示各等級下城市數量占比
????????2. 標簽顯示百分比和等級名稱,突出顯示占比最大的扇區
????????3. 添加點擊事件:單擊扇區時彈出該等級詳細城市數量及城市名稱列表
#!/usr/bin/env python3
# -*- coding: utf-8 -*-import plotly.graph_objects as go# 解析數據文件內容
data_str = '"海門", 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 = data_str.split(', ')
cities = []
aqi_values = []for i in range(0, len(items)):if not items[i]:continueif items[i].startswith('"'):city = items[i].strip('"')if i + 1 < len(items) and items[i + 1].isdigit():aqi = int(items[i + 1])cities.append(city)aqi_values.append(aqi)elif items[i].isdigit():pass# 定義AQI等級標準
def classify_aqi(aqi):if aqi <= 50:return "優"elif aqi <= 100:return "良"elif aqi <= 150:return "輕度污染"elif aqi <= 200:return "中度污染"else:return "重度污染"# 分類城市到各AQI等級
categories = ["優", "良", "輕度污染", "中度污染", "重度污染"]
category_cities = {cat: [] for cat in categories}
category_counts = {cat: 0 for cat in categories}for city, aqi in zip(cities, aqi_values):category = classify_aqi(aqi)category_cities[category].append(city)category_counts[category] += 1# 準備餅圖數據
sizes = [category_counts[cat] for cat in categories]
total = sum(sizes)
percentages = [f'{size / total * 100:.1f}%' for size in sizes]# 找出最大扇區
max_index = sizes.index(max(sizes))# 創建餅圖
fig = go.Figure()# 為每個等級添加自定義數據 - 城市列表
custom_data = []
for cat in categories:# 將城市列表轉換為HTML格式,每行顯示一個城市city_list = "<br>".join(category_cities[cat])custom_data.append(f"<b>{cat}等級城市 ({category_counts[cat]}個):</b><br><br>{city_list}")# 添加餅圖
fig.add_trace(go.Pie(labels=categories,values=sizes,textinfo='label+percent',hoverinfo='label+value+percent',hole=0.3,pull=[0.1 if i == max_index else 0 for i in range(len(categories))],marker=dict(colors=['#1f77b4', '#2ca02c', '#ff7f0e', '#d62728', '#9467bd']),customdata=custom_data, # 存儲城市列表信息hovertemplate="<b>%{label}</b><br>城市數量: %{value}<br>占比: %{percent}<extra></extra>",textfont_size=16
))# 設置布局
fig.update_layout(title='城市AQI等級分布',title_font_size=24,title_x=0.5,legend_title='AQI等級',annotations=[dict(text=f'城市總數: {total}',x=0.5, y=0.5,font_size=18,showarrow=False)],template="plotly_white",hoverlabel=dict(bgcolor="white",font_size=16,font_family="Arial")
)# 自定義JavaScript代碼,用于處理點擊事件
custom_js = """
// 等待Plotly圖表加載完成
document.addEventListener('DOMContentLoaded', function() {const plotDiv = document.getElementById('myDiv');if (plotDiv) {plotDiv.on('plotly_click', function(data) {// 獲取點擊的點const point = data.points[0];// 獲取自定義數據(城市列表)const cityList = point.customdata;// 創建模態框const modal = document.createElement('div');modal.style.cssText = 'position:fixed;top:0;left:0;width:100%;height:100%;background-color:rgba(0,0,0,0.7);display:flex;justify-content:center;align-items:center;z-index:1000;';// 創建內容框const content = document.createElement('div');content.style.cssText = 'background-color:white;padding:20px;border-radius:10px;max-width:80%;max-height:80%;overflow-y:auto;box-shadow:0 4px 8px rgba(0,0,0,0.2);';// 添加標題const title = document.createElement('h3');title.style.cssText = 'margin-top:0;color:#333;';title.innerHTML = point.label + '等級城市詳情';content.appendChild(title);// 添加城市列表const list = document.createElement('div');list.innerHTML = cityList;content.appendChild(list);// 添加關閉按鈕const closeBtn = document.createElement('button');closeBtn.innerHTML = '關閉';closeBtn.style.cssText = 'margin-top:15px;padding:8px 16px;background-color:#4CAF50;color:white;border:none;border-radius:4px;cursor:pointer;';closeBtn.onclick = function() {document.body.removeChild(modal);};content.appendChild(closeBtn);// 添加到模態框modal.appendChild(content);// 添加到文檔document.body.appendChild(modal);// 點擊模態框背景關閉modal.onclick = function(event) {if (event.target === modal) {document.body.removeChild(modal);}};});}
});
"""# 將圖表保存為HTML文件,并嵌入自定義JavaScript
with open("aqi_distribution.html", "w", encoding="utf-8") as f:# 獲取HTML內容html_content = fig.to_html(include_plotlyjs='cdn',full_html=True,div_id='myDiv',config={'responsive': True})# 在HTML頭部添加UTF-8編碼聲明head_start = html_content.find('<head>') + 6encoding_meta = '<meta charset="UTF-8">'html_content = html_content[:head_start] + encoding_meta + html_content[head_start:]# 在body結束前添加自定義JavaScriptbody_end = html_content.rfind('</body>')html_content = html_content[:body_end] + f'<script>{custom_js}</script>' + html_content[body_end:]# 寫入文件f.write(html_content)print("圖表已保存為 aqi_distribution.html,請在瀏覽器中打開查看交互效果。")
實驗 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).reversal_axis().set_series_opts(label_opts=opts.LabelOpts(position="right")).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),).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),).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="#1E90FF"),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),symbol="circle",symbol_size=10,).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")
上述代碼使用 PyEcharts 創建了一個包含三個選項卡的儀表盤,用于可視化城市 AQI 數據:
-
第一選項卡:AQI Top 10 城市橫向條形圖
-
第二選項卡:西北與東部城市 AQI 對比散點圖
-
第三選項卡:各地區平均 AQI 折線圖
所有圖表使用深色主題(ThemeType.DARK
)。數據處理:從給定的文本內容解析城市和 AQI 數據;將數據轉換為?(城市, AQI)
?元組列表;按 AQI 值降序排序。
????????第一選項卡:AQI Top 10。提取 AQI 最高的 10 個城市;創建橫向條形圖:X 軸:AQI 值;Y 軸:城市名稱;條形方向:水平(reversal_axis()
);標簽顯示在右側。
????????第二選項卡:地區對比。定義西北和東部城市列表,準備散點圖數據:西北城市使用索引 0-11;東部城市使用索引 12-27;添加回歸線:西北城市:橙色水平虛線,顯示"西北平均AQI"標簽;東部城市:藍色水平虛線,顯示"東部平均AQI"標簽。散點圖配置:X 軸:城市索引(0-27);Y 軸:AQI 值;提示框顯示城市索引和 AQI 值。
????????第三選項卡:區域變化。定義 7 個地理區域(華北、華東等),計算每個區域的平均 AQI,創建平滑折線圖:X 軸:區域名稱(按字母排序)‘’Y 軸:平均 AQI 值,帶圓形標記點。
????????儀表盤集成:使用?Tab
?組件集成三個圖表輸出為 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_str = """
"海門", 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 = data_str.strip().split(', ')
data_pairs = [(items[i].strip('"'), int(items[i+1]))for i in range(0, len(items), 2)]# 創建地理坐標系
geo = (Geo(init_opts=opts.InitOpts(width="1200px", height="800px")).add_schema(maptype="china",itemstyle_opts=opts.ItemStyleOpts(color="#323c48", border_color="#111"),).add(series_name="AQI",data_pair=data_pairs,type_=ChartType.SCATTER,symbol_size=8,label_opts=opts.LabelOpts(is_show=False),).set_series_opts().set_global_opts(visualmap_opts=opts.VisualMapOpts(is_piecewise=True,pieces=[{"min": 0, "max": 50, "label": "0-50 (優)", "color": "#93CE07"},{"min": 51, "max": 100, "label": "51-100 (良)", "color": "#FBDB0F"},{"min": 101, "max": 150, "label": "101-150 (輕度)", "color": "#FC7D02"},{"min": 151, "max": 200, "label": "151-200 (中度)", "color": "#FD0100"},{"min": 201, "max": 300, "label": "201-300 (重度)", "color": "#AA069F"},{"min": 301, "label": ">300 (嚴重)", "color": "#AC3B2A"},],pos_left="10px",pos_bottom="20px",orient="horizontal"),title_opts=opts.TitleOpts(title="中國城市 AQI 分布可視化",subtitle="數據來源:模擬數據",pos_left="center"),tooltip_opts=opts.TooltipOpts(formatter="{b}: {c} AQI",trigger="item"),legend_opts=opts.LegendOpts(is_show=False))
)# 生成HTML文件
geo.render("china_aqi_visualization.html")
代碼說明:
數據解析:將文本數據解析成?(城市名, AQI值)
?的元組列表。
地理坐標系設置:使用?Geo
?組件創建中國地圖,設置合適的地圖尺寸和背景樣式。
可視化效果:使用散點圖(Scatter)在地圖上標記城市位置,點的大小固定為8像素,關閉城市標簽顯示避免重疊。
分段顏色映射:根據中國空氣質量指數標準分段:0-50:綠色(優),51-100:黃色(良),101-150:橙色(輕度污染),151-200:紅色(中度污染),201-300:紫色(重度污染),300:深紅色(嚴重污染)。水平放置的顏色指示條。
交互功能:鼠標懸停時顯示城市名稱和AQI值,支持地圖縮放和拖動。
實驗 5:3D 地理 AQI 可視化
????????任務:結合 Geo3D 和 Bar3D 實現三維地理可視化:
????????1. 在地球模型上標記城市位置,高度表示 AQI 值
????????2. 使用 Map3D 配置光照效果和區域顏色(如中國區域高亮)
????????3. 展示不同地區 AQI 數值
import json
from pyecharts import options as opts
from pyecharts.charts import Map3D
from pyecharts.globals import ChartType, ThemeType# 解析數據文件內容
data_str = '''
"海門", 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 = [item.strip().replace('"', '') for item in data_str.split(',')]
city_aqi = []
for i in range(0, len(items), 2):city = items[i]aqi = int(items[i + 1])city_aqi.append((city, aqi))# 創建3D地球可視化
map3d = (Map3D(init_opts=opts.InitOpts(width="1600px", height="800px", theme=ThemeType.DARK)).add_schema(# 使用地球模型maptype="world",# 地球樣式配置itemstyle_opts=opts.ItemStyleOpts(color="rgba(5, 50, 80, 0.7)", # 海洋顏色border_color="rgba(0, 100, 200, 0.5)", # 邊界線),# 光照配置light_opts=opts.Map3DLightOpts(main_color="#fff",main_intensity=1.2,main_alpha=55,main_beta=10,ambient_intensity=0.4),# 視圖控制view_control_opts=opts.Map3DViewControlOpts(auto_rotate=True,auto_rotate_speed=5,distance=150,min_distance=50,max_distance=300,alpha=30,beta=20,),# 修改:移除重復的 itemstyle_opts,添加 map3d_label 配置map3d_label=opts.Map3DLabelOpts(is_show=True,text_style=opts.TextStyleOpts(color="#fff",font_size=8,background_color="rgba(0,0,0,0)")),)# 添加數據點 - 使用柱狀高度表示AQI值.add(series_name="AQI",data_pair=city_aqi,type_=ChartType.BAR3D,# 柱狀圖配置bar_size=1.5, # 柱子粗細shading="realistic", # 更真實的渲染效果min_height=0.5, # 最小高度# 柱體樣式itemstyle_opts=opts.ItemStyleOpts(color="rgb(255, 100, 0)", # 基礎顏色opacity=0.9,border_width=0.5,border_color="rgba(255,255,255,0.5)"),# 標簽配置label_opts=opts.LabelOpts(is_show=True,formatter="{b}: {c}",position="top",color="#ffcc00",font_size=10))# 全局配置.set_global_opts(title_opts=opts.TitleOpts(title="全國城市AQI 3D可視化",subtitle="柱狀高度表示AQI值",pos_left="center",title_textstyle_opts=opts.TextStyleOpts(color="#fff",font_size=24)),visualmap_opts=opts.VisualMapOpts(is_show=True,dimension=0,pos_left="10",pos_top="center",range_text=["高污染", "低污染"],range_color=["#d73027", "#fc8d59", "#fee090", "#e0f3f8", "#4575b4"],min_=min(aqi for _, aqi in city_aqi),max_=max(aqi for _, aqi in city_aqi),textstyle_opts=opts.TextStyleOpts(color="#fff")),# 圖例配置legend_opts=opts.LegendOpts(is_show=False))
)# 生成HTML文件
map3d.render("aqi_3d_earth.html")
上述代碼使用 pyecharts`庫創建了一個全國城市空氣質量指數(AQI)的3D地球可視化圖表。
????????數據處理:從長字符串 data_str中提取城市名稱和對應的AQI值,通過字符串分割和處理構建數據對列表 city_aqi將數據轉換為 (城市名, AQI值)`的元組形式,便于后續圖表使用。創建一個3D地圖對象,設置寬度、高度和暗色主題。 使用全球地圖作為底圖 - 設置海洋顏色為深藍色,邊界線為淺藍色 - 配置光照效果增強立體感 - 設置自動旋轉和視角控制參數 - 添加地圖標簽樣式。
????????數據可視化 :使用 BAR3D?類型,通過柱狀高度表示AQI值,柱子粗細和最小高度 - 真實感渲染效果 - 橙色系顏色主題 - 柱體頂部顯示城市名和AQI值標簽 ,添加漸變色視覺映射,從藍色(低污染)到紅色(高污染),地球會自動旋轉,展示各個角度的城市數據,側邊欄提供污染程度的顏色參考,每個數據點上方顯示具體數值 ,支持縮放、旋轉和視角調整 ,輸出生成一個獨立的HTML文件 aqi_3d_earth.html。
【實驗總結】
????????本次實驗以全國城市空氣質量指數(AQI)為對象,借 Pyecharts 庫完成多類型可視化任務。
- 可視化原則落地:遵循交互體驗原則,如實驗1給橫向條形圖加數據縮放、均值標記,實驗2為餅圖設點擊彈窗,保障交互高效,助用戶理解數據。
- 技術分類實踐:覆蓋條形圖、餅圖、Geo、Map3D、Tab儀表盤等可視化類型,驗證不同場景技術選型邏輯。
- 核心技術掌握:熟用Pyecharts配置樣式、處理交互,結合數據清洗、簡單建模,實現“數據 - 可視化 - 交互分析”閉環。
- 地理編碼匹配(實驗5):初始3D地球因world地圖不支持中文城市致數據“扎堆”,改用china地圖、聚焦中國視角,解決坐標映射問題。
- 交互邏輯優化(實驗2):餅圖點擊事件需自定義JS實現模態框,精細處理DOM與數據傳遞,實現“點擊扇區 - 彈詳情”交互,增強探索性。
- 多圖表協同(實驗3):構建Tab儀表盤時,統一主題、協調數據維度,分層封裝配置,實現多視角連貫展示。?