本節課你將學到
- 理解數據可視化在AI中的重要作用
- 掌握Matplotlib的基本架構和核心概念
- 學會創建各種類型的圖表(線圖、柱狀圖、散點圖、餅圖等)
- 掌握圖表美化和自定義技巧
- 完成銷售趨勢圖表制作實戰項目
開始之前
什么是數據可視化?
數據可視化就是用圖形的方式展示數據,讓復雜的數字變成直觀的視覺信息。想象一下:
- 純數字表格:像密密麻麻的賬本,信息都在,但很難快速理解
- 可視化圖表:像一張清晰的地圖,一眼就能看出規律和趨勢
數據可視化的核心價值:
- 發現規律:肉眼很難從數字中發現的模式,在圖表中一目了然
- 傳達洞察:復雜的分析結果通過圖表變得容易理解
- 輔助決策:直觀的圖表幫助管理者快速做出決策
- 講述故事:數據背后的故事通過圖表生動地展現出來
為什么Matplotlib重要?
1. Python可視化的基石
- Matplotlib:Python可視化的底層引擎,功能最全面
- Seaborn:基于Matplotlib的高級統計圖表庫
- Plotly:交互式圖表庫,底層也參考了Matplotlib設計
- Pandas:內置的繪圖功能就是調用Matplotlib
2. AI項目中的關鍵應用
- 數據探索:在建模前理解數據分布和關系
- 特征分析:可視化特征重要性和相關性
- 模型評估:繪制ROC曲線、混淆矩陣等
- 結果展示:將模型預測結果可視化
3. 業界標準
- 科研論文:大多數機器學習論文的圖表都用Matplotlib制作
- 數據報告:企業級數據分析報告的標準工具
- 教學演示:AI課程和教程的首選可視化工具
環境要求
- 已完成前五講的環境配置
- Matplotlib已安裝(在第1講中已安裝)
- 建議同時安裝Seaborn用于高級圖表
Matplotlib基礎架構
導入和基本設置
# 標準導入方式
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd# 查看Matplotlib版本
print(f"Matplotlib版本: {plt.matplotlib.__version__}")# 設置中文字體支持
plt.rcParams['font.sans-serif'] = ['SimHei', 'Arial Unicode MS', 'DejaVu Sans']
plt.rcParams['axes.unicode_minus'] = False # 解決負號顯示問題# 設置圖表樣式
plt.style.use('default') # 可選:'seaborn', 'ggplot', 'classic'等# 設置默認圖表大小和分辨率
plt.rcParams['figure.figsize'] = (10, 6)
plt.rcParams['figure.dpi'] = 100print("? Matplotlib環境配置完成")
Matplotlib的兩種接口
# Matplotlib提供兩種編程接口
print("🎨 Matplotlib兩種接口演示")
print("=" * 35)# 準備示例數據
x = np.linspace(0, 10, 100)
y1 = np.sin(x)
y2 = np.cos(x)# 方式1:pyplot接口(類似MATLAB,簡單直觀)
print("📊 方式1: pyplot接口")
plt.figure(figsize=(12, 5))plt.subplot(1, 2, 1) # 1行2列的第1個子圖
plt.plot(x, y1, label='sin(x)', color='blue', linewidth=2)
plt.plot(x, y2, label='cos(x)', color='red', linewidth=2)
plt.title('Pyplot接口示例')
plt.xlabel('x值')
plt.ylabel('y值')
plt.legend()
plt.grid(True, alpha=0.3)# 方式2:面向對象接口(更靈活,適合復雜圖表)
print("🔧 方式2: 面向對象接口")
fig, ax = plt.subplots(1, 1, figsize=(6, 5)) # 創建圖形和軸對象ax.plot(x, y1, label='sin(x)', color='blue', linewidth=2)
ax.plot(x, y2, label='cos(x)', color='red', linewidth=2)
ax.set_title('面向對象接口示例')
ax.set_xlabel('x值')
ax.set_ylabel('y值')
ax.legend()
ax.grid(True, alpha=0.3)plt.tight_layout() # 自動調整子圖間距
plt.show()print("💡 建議:簡單圖表用pyplot,復雜圖表用面向對象接口")
Figure和Axes概念
# 理解Figure、Axes、Axis的層次結構
print(f"\n🏗? Matplotlib架構解析")
print("=" * 30)# Figure: 整個圖形窗口
# Axes: 具體的繪圖區域(可以有多個)
# Axis: 坐標軸(x軸、y軸)# 創建復雜的圖形布局
fig = plt.figure(figsize=(15, 10))
fig.suptitle('Matplotlib架構演示', fontsize=16, fontweight='bold')# 添加多個Axes(子圖)
ax1 = fig.add_subplot(2, 3, 1) # 2行3列的第1個
ax2 = fig.add_subplot(2, 3, 2) # 2行3列的第2個
ax3 = fig.add_subplot(2, 3, 3) # 2行3列的第3個
ax4 = fig.add_subplot(2, 1, 2) # 2行1列的第2個(占據下半部分)# 在每個Axes中繪制不同類型的圖表
# 子圖1:線圖
x = np.linspace(0, 10, 50)
ax1.plot(x, np.sin(x), 'b-', linewidth=2, label='sin(x)')
ax1.set_title('線圖示例')
ax1.set_xlabel('x')
ax1.set_ylabel('sin(x)')
ax1.legend()
ax1.grid(True, alpha=0.3)# 子圖2:散點圖
np.random.seed(42)
x_scatter = np.random.randn(50)
y_scatter = np.random.randn(50)
colors = np.random.rand(50)
ax2.scatter(x_scatter, y_scatter, c=colors, alpha=0.6, s=60)
ax2.set_title('散點圖示例')
ax2.set_xlabel('X值')
ax2.set_ylabel('Y值')# 子圖3:柱狀圖
categories = ['A', 'B', 'C', 'D', 'E']
values = [23, 45, 56, 78, 32]
bars = ax3.bar(categories, values, color=['red', 'green', 'blue', 'orange', 'purple'])
ax3.set_title('柱狀圖示例')
ax3.set_xlabel('類別')
ax3.set_ylabel('數值')# 在柱狀圖上添加數值標簽
for bar, value in zip(bars, values):ax3.text(bar.get_x() + bar.get_width()/2, bar.get_height() + 1,str(value), ha='center', va='bottom')# 子圖4:多系列折線圖
months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun']
sales_2023 = [120, 135, 148, 162, 151, 178]
sales_2024 = [125, 142, 156, 169, 163, 185]ax4.plot(months, sales_2023, marker='o', linewidth=2, label='2023年銷售')
ax4.plot(months, sales_2024, marker='s', linewidth=2, label='2024年銷售')
ax4.set_title('月度銷售對比')
ax4.set_xlabel('月份')
ax4.set_ylabel('銷售額(萬元)')
ax4.legend()
ax4.grid(True, alpha=0.3)plt.tight_layout()
plt.show()print("📋 架構總結:")
print(" - Figure: 整個圖形畫布")
print(" - Axes: 各個子圖區域")
print(" - Axis: x軸、y軸等坐標軸")
print(" - Artists: 所有可見元素(線條、文字、圖例等)")
基本圖表類型
線圖(Line Plot)
# 線圖詳解和應用
print(f"\n📈 線圖詳解")
print("=" * 20)# 創建示例數據
months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
temperature = [2, 4, 8, 14, 20, 25, 28, 27, 22, 16, 9, 4] # 某城市月平均氣溫
rainfall = [45, 38, 52, 61, 75, 89, 102, 95, 78, 67, 55, 48] # 月降雨量fig, (ax1, ax2, ax3) = plt.subplots(1, 3, figsize=(18, 6))# 基礎線圖
ax1.plot(months, temperature, color='red', linewidth=2, marker='o', markersize=6)
ax1.set_title('月平均氣溫變化', fontsize=14, fontweight='bold')
ax1.set_xlabel('月份')
ax1.set_ylabel('溫度 (°C)')
ax1.grid(True, alpha=0.3)
ax1.tick_params(axis='x', rotation=45)# 多系列線圖
ax2.plot(months, temperature, color='red', linewidth=2, marker='o', markersize=6, label='氣溫 (°C)')
ax2_twin = ax2.twinx() # 創建共享x軸的第二個y軸
ax2_twin.plot(months, rainfall, color='blue', linewidth=2, marker='s', markersize=6, label='降雨量 (mm)')ax2.set_title('氣溫與降雨量變化', fontsize=14, fontweight='bold')
ax2.set_xlabel('月份')
ax2.set_ylabel('溫度 (°C)', color='red')
ax2_twin.set_ylabel('降雨量 (mm)', color='blue')
ax2.tick_params(axis='x', rotation=45)
ax2.tick_params(axis='y', labelcolor='red')
ax2_twin.tick_params(axis='y', labelcolor='blue')# 組合圖例
lines1, labels1 = ax2.get_legend_handles_labels()
lines2, labels2 = ax2_twin.get_legend_handles_labels()
ax2.legend(lines1 + lines2, labels1 + labels2, loc='upper left')# 線型樣式展示
x = np.linspace(0, 10, 20)
ax3.plot(x, np.sin(x), '-', label='實線 solid', linewidth=2)
ax3.plot(x, np.sin(x + 0.5), '--', label='虛線 dashed', linewidth=2)
ax3.plot(x, np.sin(x + 1), '-.', label='點劃線 dashdot', linewidth=2)
ax3.plot(x, np.sin(x + 1.5), ':', label='點線 dotted', linewidth=2)ax3.set_title('線型樣式展示', fontsize=14, fontweight='bold')
ax3.set_xlabel('x值')
ax3.set_ylabel('y值')
ax3.legend()
ax3.grid(True, alpha=0.3)plt.tight_layout()
plt.show()print("📝 線圖使用場景:")
print(" - 時間序列數據(股價、氣溫、銷售趨勢等)")
print(" - 連續變量關系(函數圖像、回歸線等)")
print(" - 多組數據對比(不同年份、不同產品等)")
柱狀圖(Bar Plot)
# 柱狀圖詳解
print(f"\n📊 柱狀圖詳解")
print("=" * 20)# 準備數據
products = ['iPhone', 'Samsung', 'Huawei', 'Xiaomi', 'OPPO']
q1_sales = [45, 38, 25, 22, 18]
q2_sales = [48, 35, 28, 25, 20]
q3_sales = [52, 40, 30, 28, 22]fig, ((ax1, ax2), (ax3, ax4)) = plt.subplots(2, 2, figsize=(16, 12))# 1. 基礎柱狀圖
bars1 = ax1.bar(products, q1_sales, color=['#FF6B6B', '#4ECDC4', '#45B7D1', '#96CEB4', '#FFEAA7'])
ax1.set_title('Q1銷售額(單位:萬臺)', fontsize=14, fontweight='bold')
ax1.set_xlabel('品牌')
ax1.set_ylabel('銷售額')# 添加數值標簽
for bar, value in zip(bars1, q1_sales):ax1.text(bar.get_x() + bar.get_width()/2, bar.get_height() + 0.5,f'{value}萬', ha='center', va='bottom', fontweight='bold')# 2. 分組柱狀圖
x = np.arange(len(products)) # 標簽位置
width = 0.25 # 柱子寬度bars2_1 = ax2.bar(x - width, q1_sales, width, label='Q1', color='#FF6B6B', alpha=0.8)
bars2_2 = ax2.bar(x, q2_sales, width, label='Q2', color='#4ECDC4', alpha=0.8)
bars2_3 = ax2.bar(x + width, q3_sales, width, label='Q3', color='#45B7D1', alpha=0.8)ax2.set_title('季度銷售對比', fontsize=14, fontweight='bold')
ax2.set_xlabel('品牌')
ax2.set_ylabel('銷售額(萬臺)')
ax2.set_xticks(x)
ax2.set_xticklabels(products)
ax2.legend()# 3. 堆疊柱狀圖
ax3.bar(products, q1_sales, label='Q1', color='#FF6B6B', alpha=0.8)
ax3.bar(products, q2_sales, bottom=q1_sales, label='Q2', color='#4ECDC4', alpha=0.8)# 計算Q3的底部位置
q3_bottom = [q1 + q2 for q1, q2 in zip(q1_sales, q2_sales)]
ax3.bar(products, q3_sales, bottom=q3_bottom, label='Q3', color='#45B7D1', alpha=0.8)ax3.set_title('累計銷售額', fontsize=14, fontweight='bold')
ax3.set_xlabel('品牌')
ax3.set_ylabel('累計銷售額(萬臺)')
ax3.legend()# 4. 水平柱狀圖
ax4.barh(products, q1_sales, color=['#FF6B6B', '#4ECDC4', '#45B7D1', '#96CEB4', '#FFEAA7'])
ax4.set_title('Q1銷售額(水平)', fontsize=14, fontweight='bold')
ax4.set_xlabel('銷售額(萬臺)')
ax4.set_ylabel('品牌')# 添加數值標簽
for i, value in enumerate(q1_sales):ax4.text(value + 0.5, i, f'{value}萬', va='center', fontweight='bold')plt.tight_layout()
plt.show()print("📝 柱狀圖使用場景:")
print(" - 分類數據比較(銷售額、人口、得分等)")
print(" - 頻次分布(直方圖的離散版本)")
print(" - 多組數據對比(分組柱狀圖)")
print(" - 部分與整體關系(堆疊柱狀圖)")
散點圖(Scatter Plot)
# 散點圖詳解
print(f"\n🔹 散點圖詳解")
print("=" * 20)# 生成示例數據
np.random.seed(42)
n_points = 100# 數據集1:身高體重關系
height = np.random.normal(170, 10, n_points) # 身高(cm)
weight = 0.8 * height + np.random.normal(0, 5, n_points) - 80 # 體重(kg)
gender = np.random.choice(['男', '女'], n_points)# 數據集2:廣告投入與銷售額
ad_spend = np.random.uniform(10, 100, n_points) # 廣告投入(萬元)
sales = 2 * ad_spend + np.random.normal(0, 15, n_points) + 50 # 銷售額(萬元)
region = np.random.choice(['北區', '南區', '東區', '西區'], n_points)fig, ((ax1, ax2), (ax3, ax4)) = plt.subplots(2, 2, figsize=(16, 12))# 1. 基礎散點圖
ax1.scatter(height, weight, alpha=0.6, s=50, color='blue')
ax1.set_title('身高與體重關系', fontsize=14, fontweight='bold')
ax1.set_xlabel('身高 (cm)')
ax1.set_ylabel('體重 (kg)')
ax1.grid(True, alpha=0.3)# 添加趨勢線
z = np.polyfit(height, weight, 1) # 一次線性擬合
p = np.poly1d(z)
ax1.plot(height, p(height), "r--", alpha=0.8, linewidth=2, label=f'趨勢線: y={z[0]:.2f}x{z[1]:+.2f}')
ax1.legend()# 2. 分類散點圖(不同顏色表示不同類別)
colors = {'男': 'blue', '女': 'red'}
for g in ['男', '女']:mask = gender == gax2.scatter(height[mask], weight[mask], c=colors[g], label=g, alpha=0.6, s=50)ax2.set_title('按性別分類的身高體重關系', fontsize=14, fontweight='bold')
ax2.set_xlabel('身高 (cm)')
ax2.set_ylabel('體重 (kg)')
ax2.legend()
ax2.grid(True, alpha=0.3)# 3. 大小和顏色映射
# 點的大小表示銷售額,顏色表示地區
region_colors = {'北區': 'red', '南區': 'green', '東區': 'blue', '西區': 'orange'}
for r in ['北區', '南區', '東區', '西區']:mask = region == rax3.scatter(ad_spend[mask], sales[mask], c=region_colors[r], label=r, alpha=0.6, s=sales[mask]*2) # 點的大小與銷售額成正比ax3.set_title('廣告投入與銷售額關系\n(點大小=銷售額,顏色=地區)', fontsize=14, fontweight='bold')
ax3.set_xlabel('廣告投入 (萬元)')
ax3.set_ylabel('銷售額 (萬元)')
ax3.legend()
ax3.grid(True, alpha=0.3)# 4. 氣泡圖(三維數據的二維展示)
# 第三個維度用顏色和大小表示
profit_margin = np.random.uniform(0.1, 0.3, n_points) # 利潤率scatter = ax4.scatter(ad_spend, sales, c=profit_margin, s=profit_margin*1000, alpha=0.6, cmap='viridis')ax4.set_title('廣告投入、銷售額與利潤率關系\n(顏色和大小=利潤率)', fontsize=14, fontweight='bold')
ax4.set_xlabel('廣告投入 (萬元)')
ax4.set_ylabel('銷售額 (萬元)')# 添加顏色條
cbar = plt.colorbar(scatter, ax=ax4)
cbar.set_label('利潤率', rotation=270, labelpad=20)plt.tight_layout()
plt.show()print("📝 散點圖使用場景:")
print(" - 兩個連續變量關系(相關性分析)")
print(" - 異常值檢測(離群點識別)")
print(" - 聚類結果展示(不同顏色表示不同類別)")
print(" - 三維數據降維展示(顏色或大小表示第三維)")
餅圖(Pie Chart)
# 餅圖詳解
print(f"\n🥧 餅圖詳解")
print("=" * 15)# 準備數據
market_share = {'Android': 71.9,'iOS': 27.3,'Others': 0.8
}sales_by_region = {'華東': 35,'華南': 28,'華北': 22,'華中': 10,'其他': 5
}fig, ((ax1, ax2), (ax3, ax4)) = plt.subplots(2, 2, figsize=(16, 12))# 1. 基礎餅圖
labels1 = list(market_share.keys())
sizes1 = list(market_share.values())
colors1 = ['#FF9999', '#66B2FF', '#99FF99']wedges1, texts1, autotexts1 = ax1.pie(sizes1, labels=labels1, colors=colors1, autopct='%1.1f%%', startangle=90)ax1.set_title('全球移動操作系統市場份額', fontsize=14, fontweight='bold')# 美化文字
for autotext in autotexts1:autotext.set_color('white')autotext.set_fontweight('bold')# 2. 突出顯示餅圖
labels2 = list(sales_by_region.keys())
sizes2 = list(sales_by_region.values())
colors2 = ['#FF6B6B', '#4ECDC4', '#45B7D1', '#96CEB4', '#FFEAA7']
explode2 = (0.1, 0, 0, 0, 0) # 突出顯示第一個扇形wedges2, texts2, autotexts2 = ax2.pie(sizes2, labels=labels2, colors=colors2,autopct='%1.1f%%', startangle=90,explode=explode2, shadow=True)ax2.set_title('各地區銷售額分布', fontsize=14, fontweight='bold')# 3. 環形圖(甜甜圈圖)
wedges3, texts3, autotexts3 = ax3.pie(sizes2, labels=labels2, colors=colors2,autopct='%1.1f%%', startangle=90,wedgeprops=dict(width=0.5))ax3.set_title('各地區銷售額分布(環形圖)', fontsize=14, fontweight='bold')# 在中心添加總計信息
total_sales = sum(sizes2)
ax3.text(0, 0, f'總銷售額\n{total_sales}%', ha='center', va='center',fontsize=12, fontweight='bold')# 4. 嵌套餅圖
# 外環:大類別
outer_labels = ['移動設備', '電腦設備']
outer_sizes = [75, 25]
outer_colors = ['#FF6B6B', '#4ECDC4']# 內環:細分類別
inner_labels = ['手機', '平板', '筆記本', '臺式機']
inner_sizes = [50, 25, 15, 10]
inner_colors = ['#FF9999', '#FFB366', '#66B2FF', '#99CCFF']# 繪制外環
ax4.pie(outer_sizes, labels=outer_labels, colors=outer_colors,radius=1, startangle=90, labeldistance=1.1)# 繪制內環
ax4.pie(inner_sizes, labels=inner_labels, colors=inner_colors,radius=0.7, startangle=90, labeldistance=0.5)ax4.set_title('設備銷售額嵌套分布', fontsize=14, fontweight='bold')plt.tight_layout()
plt.show()print("📝 餅圖使用場景:")
print(" - 部分與整體的比例關系")
print(" - 分類數據的占比展示")
print(" - 市場份額、預算分配等")
print(" ?? 注意:類別過多時不適用(建議不超過7個)")
直方圖(Histogram)
# 直方圖詳解
print(f"\n📊 直方圖詳解")
print("=" * 20)# 生成示例數據
np.random.seed(42)
normal_data = np.random.normal(100, 15, 1000) # 正態分布數據
uniform_data = np.random.uniform(50, 150, 1000) # 均勻分布數據
exponential_data = np.random.exponential(2, 1000) # 指數分布數據# 學生成績數據(更真實的例子)
math_scores = np.random.normal(75, 12, 200)
english_scores = np.random.normal(78, 10, 200)fig, ((ax1, ax2), (ax3, ax4)) = plt.subplots(2, 2, figsize=(16, 12))# 1. 基礎直方圖
ax1.hist(normal_data, bins=30, color='skyblue', alpha=0.7, edgecolor='black')
ax1.set_title('正態分布數據直方圖', fontsize=14, fontweight='bold')
ax1.set_xlabel('數值')
ax1.set_ylabel('頻次')
ax1.axvline(normal_data.mean(), color='red', linestyle='--', label=f'均值: {normal_data.mean():.1f}')
ax1.legend()
ax1.grid(True, alpha=0.3)# 2. 多組數據對比
ax2.hist(math_scores, bins=20, alpha=0.7, label='數學成績', color='blue')
ax2.hist(english_scores, bins=20, alpha=0.7, label='英語成績', color='red')
ax2.set_title('數學與英語成績分布對比', fontsize=14, fontweight='bold')
ax2.set_xlabel('成績')
ax2.set_ylabel('人數')
ax2.legend()
ax2.grid(True, alpha=0.3)# 3. 不同分布類型對比
ax3.hist(normal_data, bins=30, alpha=0.5, label='正態分布', density=True)
ax3.hist(uniform_data, bins=30, alpha=0.5, label='均勻分布', density=True)
ax3.set_title('不同分布類型對比(密度)', fontsize=14, fontweight='bold')
ax3.set_xlabel('數值')
ax3.set_ylabel('密度')
ax3.legend()
ax3.grid(True, alpha=0.3)# 4. 累積直方圖
counts, bins, patches = ax4.hist(math_scores, bins=20, cumulative=True, alpha=0.7, color='green', edgecolor='black')
ax4.set_title('數學成績累積分布', fontsize=14, fontweight='bold')
ax4.set_xlabel('成績')
ax4.set_ylabel('累積人數')# 添加百分位線
percentiles = [25, 50, 75]
for p in percentiles:value = np.percentile(math_scores, p)ax4.axvline(value, color='red', linestyle='--', alpha=0.7)ax4.text(value, ax4.get_ylim()[1]*0.9, f'{p}th', ha='center', va='bottom', color='red', fontweight='bold')ax4.grid(True, alpha=0.3)plt.tight_layout()
plt.show()print("📝 直方圖使用場景:")
print(" - 數據分布形狀分析(正態、偏態、雙峰等)")
print(" - 異常值檢測(分布的尾部)")
print(" - 質量控制(過程能力分析)")
print(" - A/B測試結果比較")
圖表美化和自定義
顏色和樣式設置
# 圖表美化技巧
print(f"\n🎨 圖表美化技巧")
print("=" * 25)# 準備數據
months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun']
revenue = [120, 135, 128, 142, 156, 168]
profit = [24, 28, 25, 30, 35, 38]fig, ((ax1, ax2), (ax3, ax4)) = plt.subplots(2, 2, figsize=(16, 12))# 1. 默認樣式 vs 美化樣式對比
# 默認樣式
ax1.plot(months, revenue, label='收入')
ax1.plot(months, profit, label='利潤')
ax1.set_title('默認樣式')
ax1.legend()# 美化樣式
ax2.plot(months, revenue, color='#2E86AB', linewidth=3, marker='o', markersize=8, markerfacecolor='white', markeredgewidth=2,markeredgecolor='#2E86AB', label='收入')
ax2.plot(months, profit, color='#A23B72', linewidth=3, marker='s', markersize=8, markerfacecolor='white', markeredgewidth=2,markeredgecolor='#A23B72', label='利潤')ax2.set_title('美化樣式', fontsize=16, fontweight='bold', pad=20)
ax2.set_xlabel('月份', fontsize=12, fontweight='bold')
ax2.set_ylabel('金額(萬元)', fontsize=12, fontweight='bold')
ax2.legend(frameon=True, fancybox=True, shadow=True, fontsize=11)
ax2.grid(True, alpha=0.3, linestyle='--')
ax2.set_facecolor('#f8f9fa') # 設置背景色# 3. 顏色映射和漸變
x = np.linspace(0, 10, 100)
y = np.sin(x)
colors = plt.cm.viridis(np.linspace(0, 1, len(x))) # 使用顏色映射for i in range(len(x)-1):ax3.plot(x[i:i+2], y[i:i+2], color=colors[i], linewidth=3)ax3.set_title('顏色漸變效果', fontsize=14, fontweight='bold')
ax3.set_xlabel('x值')
ax3.set_ylabel('sin(x)')
ax3.grid(True, alpha=0.3)# 4. 高級樣式設置
# 創建專業的財務圖表
ax4.plot(months, revenue, color='#1f77b4', linewidth=4, marker='o', markersize=10, label='月收入', zorder=3)# 添加填充區域
ax4.fill_between(months, revenue, alpha=0.3, color='#1f77b4')# 添加注釋
max_revenue_idx = np.argmax(revenue)
ax4.annotate(f'最高收入\n{revenue[max_revenue_idx]}萬元', xy=(months[max_revenue_idx], revenue[max_revenue_idx]),xytext=(max_revenue_idx+0.5, revenue[max_revenue_idx]+10),arrowprops=dict(arrowstyle='->', color='red', lw=2),fontsize=12, fontweight='bold',bbox=dict(boxstyle="round,pad=0.3", facecolor='yellow', alpha=0.7))# 設置坐標軸樣式
ax4.spines['top'].set_visible(False) # 隱藏上邊框
ax4.spines['right'].set_visible(False) # 隱藏右邊框
ax4.spines['left'].set_linewidth(2) # 加粗左邊框
ax4.spines['bottom'].set_linewidth(2) # 加粗下邊框ax4.set_title('專業財務圖表樣式', fontsize=14, fontweight='bold')
ax4.set_xlabel('月份', fontsize=12)
ax4.set_ylabel('收入(萬元)', fontsize=12)
ax4.grid(True, alpha=0.3, axis='y')plt.tight_layout()
plt.show()print("🎨 美化技巧總結:")
print(" - 選擇協調的顏色搭配")
print(" - 適當使用透明度和陰影")
print(" - 添加網格線但保持低調")
print(" - 使用注釋突出重點信息")
print(" - 簡化邊框,突出數據本身")
子圖和布局
# 復雜布局和子圖管理
print(f"\n📐 復雜布局設計")
print("=" * 25)# 創建綜合分析儀表板
fig = plt.figure(figsize=(20, 12))# 定義網格布局
gs = fig.add_gridspec(3, 4, hspace=0.3, wspace=0.3)# 準備各種示例數據
np.random.seed(42)
time_data = pd.date_range('2024-01-01', periods=365, freq='D')
daily_sales = np.random.normal(1000, 200, 365) + 100 * np.sin(np.arange(365) * 2 * np.pi / 365)categories = ['A', 'B', 'C', 'D', 'E']
category_values = [45, 38, 32, 28, 22]regions = ['北區', '南區', '東區', '西區']
region_data = np.random.rand(4, 6) * 100# 1. 主要趨勢圖(占據兩行)
ax_main = fig.add_subplot(gs[0:2, 0:2])
ax_main.plot(time_data, daily_sales, color='#1f77b4', linewidth=1.5, alpha=0.8)# 添加移動平均線
window = 30
rolling_mean = pd.Series(daily_sales).rolling(window=window).mean()
ax_main.plot(time_data, rolling_mean, color='red', linewidth=3, label=f'{window}天移動平均')ax_main.set_title('年度銷售趨勢分析', fontsize=16, fontweight='bold')
ax_main.set_xlabel('日期')
ax_main.set_ylabel('銷售額')
ax_main.legend()
ax_main.grid(True, alpha=0.3)# 2. 分類分析餅圖
ax_pie = fig.add_subplot(gs[0, 2])
wedges, texts, autotexts = ax_pie.pie(category_values, labels=categories, autopct='%1.1f%%', startangle=90)
ax_pie.set_title('產品類別分布', fontsize=12, fontweight='bold')# 3. 地區對比柱狀圖
ax_bar = fig.add_subplot(gs[0, 3])
bars = ax_bar.bar(regions, [sum(region_data[i]) for i in range(4)], color=['#FF6B6B', '#4ECDC4', '#45B7D1', '#96CEB4'])
ax_bar.set_title('各地區銷售總額', fontsize=12, fontweight='bold')
ax_bar.set_ylabel('銷售額')# 添加數值標簽
for bar in bars:height = bar.get_height()ax_bar.text(bar.get_x() + bar.get_width()/2., height + 5,f'{height:.0f}', ha='center', va='bottom')# 4. 熱力圖
ax_heatmap = fig.add_subplot(gs[1, 2:4])
im = ax_heatmap.imshow(region_data, cmap='YlOrRd', aspect='auto')# 設置坐標軸標簽
ax_heatmap.set_xticks(range(6))
ax_heatmap.set_xticklabels(['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun'])
ax_heatmap.set_yticks(range(4))
ax_heatmap.set_yticklabels(regions)
ax_heatmap.set_title('地區月度銷售熱力圖', fontsize=12, fontweight='bold')# 添加數值標注
for i in range(4):for j in range(6):text = ax_heatmap.text(j, i, f'{region_data[i, j]:.0f}',ha="center", va="center", color="black", fontsize=8)# 添加顏色條
cbar = plt.colorbar(im, ax=ax_heatmap, shrink=0.8)
cbar.set_label('銷售額', rotation=270, labelpad=15)# 5. 分布分析直方圖
ax_hist = fig.add_subplot(gs[2, 0])
ax_hist.hist(daily_sales, bins=30, alpha=0.7, color='skyblue', edgecolor='black')
ax_hist.set_title('銷售額分布', fontsize=12, fontweight='bold')
ax_hist.set_xlabel('銷售額')
ax_hist.set_ylabel('天數')
ax_hist.axvline(np.mean(daily_sales), color='red', linestyle='--', label=f'均值: {np.mean(daily_sales):.0f}')
ax_hist.legend()# 6. 相關性散點圖
ax_scatter = fig.add_subplot(gs[2, 1])
x_corr = np.random.normal(50, 15, 100)
y_corr = 0.7 * x_corr + np.random.normal(0, 10, 100)
ax_scatter.scatter(x_corr, y_corr, alpha=0.6, s=50)# 添加趨勢線
z = np.polyfit(x_corr, y_corr, 1)
p = np.poly1d(z)
ax_scatter.plot(x_corr, p(x_corr), "r--", alpha=0.8)ax_scatter.set_title('銷售額與廣告投入相關性', fontsize=12, fontweight='bold')
ax_scatter.set_xlabel('廣告投入')
ax_scatter.set_ylabel('銷售額')
ax_scatter.grid(True, alpha=0.3)# 7. 箱線圖
ax_box = fig.add_subplot(gs[2, 2])
box_data = [np.random.normal(0, std, 100) for std in range(1, 5)]
bp = ax_box.boxplot(box_data, labels=['Q1', 'Q2', 'Q3', 'Q4'], patch_artist=True)colors = ['lightblue', 'lightgreen', 'lightyellow', 'lightcoral']
for patch, color in zip(bp['boxes'], colors):patch.set_facecolor(color)ax_box.set_title('季度銷售分布', fontsize=12, fontweight='bold')
ax_box.set_ylabel('銷售額變化率')# 8. 綜合統計表格
ax_table = fig.add_subplot(gs[2, 3])
ax_table.axis('tight')
ax_table.axis('off')# 創建統計表格
stats_data = [['指標', '數值'],['總銷售額', f'{sum(daily_sales):.0f}萬'],['平均日銷售', f'{np.mean(daily_sales):.0f}萬'],['最高日銷售', f'{max(daily_sales):.0f}萬'],['銷售天數', f'{len(daily_sales)}天'],['增長率', '+15.3%']
]table = ax_table.table(cellText=stats_data, cellLoc='center', loc='center',colWidths=[0.4, 0.4])
table.auto_set_font_size(False)
table.set_fontsize(10)
table.scale(1, 2)# 設置表格樣式
for i in range(len(stats_data)):if i == 0: # 標題行for j in range(2):table[(i, j)].set_facecolor('#4CAF50')table[(i, j)].set_text_props(weight='bold', color='white')else:for j in range(2):table[(i, j)].set_facecolor('#f0f0f0' if i % 2 == 0 else '#ffffff')ax_table.set_title('關鍵指標匯總', fontsize=12, fontweight='bold')# 添加總標題
fig.suptitle('銷售數據綜合分析儀表板', fontsize=20, fontweight='bold', y=0.98)plt.show()print("📊 復雜布局設計要點:")
print(" - 使用GridSpec進行精確布局控制")
print(" - 主要圖表占據更大空間")
print(" - 保持視覺平衡和邏輯關系")
print(" - 統一色彩主題和字體樣式")
print(" - 添加總標題增強整體性")
完整項目:銷售趨勢圖表制作
讓我們創建一個完整的銷售趨勢分析項目:
# sales_visualization.py - 銷售趨勢圖表制作項目
"""
使用Matplotlib創建專業的銷售趨勢分析圖表
演示數據可視化在業務分析中的應用
"""import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
from datetime import datetime, timedelta
import seaborn as snsclass SalesVisualizationManager:"""銷售數據可視化管理器"""def __init__(self):"""初始化可視化管理器"""# 設置中文字體和樣式plt.rcParams['font.sans-serif'] = ['SimHei', 'Arial Unicode MS']plt.rcParams['axes.unicode_minus'] = Falseplt.rcParams['figure.dpi'] = 100# 定義統一的顏色主題self.colors = {'primary': '#2E86AB','secondary': '#A23B72', 'success': '#4CAF50','warning': '#FF9800','danger': '#F44336','info': '#2196F3','light': '#F5F5F5','dark': '#333333'}# 設置默認樣式plt.style.use('default')print("📊 銷售數據可視化管理器初始化完成")def generate_sales_data(self, start_date='2023-01-01', days=365):"""生成模擬銷售數據參數:start_date: 開始日期days: 生成天數"""print(f"🎲 生成 {days} 天的銷售數據...")np.random.seed(42)# 生成日期序列date_range = pd.date_range(start=start_date, periods=days, freq='D')# 產品和地區信息products = ['iPhone', 'iPad', 'MacBook', 'AirPods', 'Apple Watch']regions = ['華東', '華南', '華北', '華中', '西部']records = []for date in date_range:for product in products:for region in regions:# 基礎銷售額(不同產品有不同基準)base_prices = {'iPhone': 5000, 'iPad': 3000, 'MacBook': 8000,'AirPods': 1500, 'Apple Watch': 2500}# 季節性因子day_of_year = date.timetuple().tm_ydayseasonal_factor = 1 + 0.3 * np.sin(2 * np.pi * day_of_year / 365)# 周末效應weekend_factor = 0.8 if date.weekday() >= 5 else 1.0# 地區系數region_factors = {'華東': 1.3, '華南': 1.2, '華北': 1.1, '華中': 0.9, '西部': 0.8}# 計算銷售額base_sales = base_prices[product]daily_sales = (base_sales * seasonal_factor * weekend_factor * region_factors[region] * np.random.normal(1, 0.2))# 確保為正數daily_sales = max(daily_sales, base_sales * 0.3)# 計算銷售數量quantity = max(1, int(daily_sales / (base_sales * 0.8) + np.random.normal(0, 0.5)))records.append({'Date': date,'Product': product,'Region': region,'Sales': round(daily_sales, 2),'Quantity': quantity,'Month': date.month,'Quarter': (date.month - 1) // 3 + 1,'Weekday': date.strftime('%A'),'IsWeekend': date.weekday() >= 5})self.sales_data = pd.DataFrame(records)print(f"? 銷售數據生成完成,共 {len(self.sales_data)} 條記錄")return self.sales_datadef create_time_series_charts(self):"""創建時間序列分析圖表"""print("📈 創建時間序列分析圖表...")# 準備時間序列數據daily_sales = self.sales_data.groupby('Date')['Sales'].sum().reset_index()monthly_sales = self.sales_data.groupby(self.sales_data['Date'].dt.to_period('M'))['Sales'].sum()weekly_sales = self.sales_data.groupby(self.sales_data['Date'].dt.to_period('W'))['Sales'].sum()fig, axes = plt.subplots(2, 2, figsize=(20, 12))fig.suptitle('銷售趨勢時間序列分析', fontsize=18, fontweight='bold')# 1. 日銷售趨勢ax1 = axes[0, 0]ax1.plot(daily_sales['Date'], daily_sales['Sales'], color=self.colors['primary'], linewidth=1, alpha=0.7)# 添加7天移動平均線daily_sales['MA7'] = daily_sales['Sales'].rolling(window=7).mean()ax1.plot(daily_sales['Date'], daily_sales['MA7'], color=self.colors['danger'], linewidth=3, label='7天移動平均')# 添加30天移動平均線daily_sales['MA30'] = daily_sales['Sales'].rolling(window=30).mean()ax1.plot(daily_sales['Date'], daily_sales['MA30'], color=self.colors['success'], linewidth=3, label='30天移動平均')ax1.set_title('日銷售額趨勢', fontsize=14, fontweight='bold')ax1.set_xlabel('日期')ax1.set_ylabel('銷售額(元)')ax1.legend()ax1.grid(True, alpha=0.3)# 2. 月度銷售趨勢ax2 = axes[0, 1]bars = ax2.bar(range(len(monthly_sales)), monthly_sales.values, color=self.colors['info'], alpha=0.8)# 添加趨勢線x_trend = range(len(monthly_sales))z = np.polyfit(x_trend, monthly_sales.values, 1)p = np.poly1d(z)ax2.plot(x_trend, p(x_trend), color=self.colors['danger'], linewidth=3, linestyle='--', label='趨勢線')ax2.set_title('月度銷售額趨勢', fontsize=14, fontweight='bold')ax2.set_xlabel('月份')ax2.set_ylabel('銷售額(元)')ax2.set_xticks(range(len(monthly_sales)))ax2.set_xticklabels([str(period) for period in monthly_sales.index], rotation=45)ax2.legend()# 添加數值標簽for i, bar in enumerate(bars):height = bar.get_height()ax2.text(bar.get_x() + bar.get_width()/2., height + height*0.01,f'{height/10000:.0f}萬', ha='center', va='bottom', fontsize=9)# 3. 周度銷售趨勢ax3 = axes[1, 0]ax3.plot(range(len(weekly_sales)), weekly_sales.values, marker='o', markersize=4, color=self.colors['secondary'], linewidth=2, markerfacecolor='white', markeredgewidth=2)ax3.set_title('周銷售額趨勢', fontsize=14, fontweight='bold')ax3.set_xlabel('周數')ax3.set_ylabel('銷售額(元)')ax3.grid(True, alpha=0.3)# 4. 季節性分析ax4 = axes[1, 1]# 按月份統計平均銷售額monthly_avg = self.sales_data.groupby('Month')['Sales'].mean()# 創建極坐標圖顯示季節性theta = np.linspace(0, 2*np.pi, 12)r = monthly_avg.values# 閉合曲線theta = np.concatenate([theta, [theta[0]]])r = np.concatenate([r, [r[0]]])ax4.plot(theta, r, color=self.colors['warning'], linewidth=3, marker='o')ax4.fill(theta, r, alpha=0.3, color=self.colors['warning'])ax4.set_thetagrids(np.arange(0, 360, 30), ['1月', '2月', '3月', '4月', '5月', '6月','7月', '8月', '9月', '10月', '11月', '12月'])ax4.set_title('月度銷售季節性分析(極坐標)', fontsize=14, fontweight='bold')plt.tight_layout()plt.show()print("? 時間序列圖表創建完成")def create_product_analysis_charts(self):"""創建產品分析圖表"""print("📱 創建產品分析圖表...")fig, axes = plt.subplots(2, 2, figsize=(18, 12))fig.suptitle('產品銷售分析', fontsize=18, fontweight='bold')# 1. 產品銷售額對比ax1 = axes[0, 0]product_sales = self.sales_data.groupby('Product')['Sales'].sum().sort_values(ascending=False)bars = ax1.bar(product_sales.index, product_sales.values, color=[self.colors['primary'], self.colors['secondary'], self.colors['success'], self.colors['warning'], self.colors['info']])ax1.set_title('各產品銷售額對比', fontsize=14, fontweight='bold')ax1.set_xlabel('產品')ax1.set_ylabel('銷售額(元)')ax1.tick_params(axis='x', rotation=45)# 添加數值標簽和百分比total_sales = product_sales.sum()for i, (bar, value) in enumerate(zip(bars, product_sales.values)):percentage = value / total_sales * 100ax1.text(bar.get_x() + bar.get_width()/2., bar.get_height() + value*0.01,f'{value/10000:.0f}萬\n({percentage:.1f}%)', ha='center', va='bottom', fontweight='bold')# 2. 產品市場份額餅圖ax2 = axes[0, 1]colors = [self.colors['primary'], self.colors['secondary'], self.colors['success'], self.colors['warning'], self.colors['info']]wedges, texts, autotexts = ax2.pie(product_sales.values, labels=product_sales.index,colors=colors, autopct='%1.1f%%', startangle=90,explode=(0.05, 0, 0, 0, 0)) # 突出最大份額ax2.set_title('產品市場份額分布', fontsize=14, fontweight='bold')# 美化餅圖文字for autotext in autotexts:autotext.set_color('white')autotext.set_fontweight('bold')autotext.set_fontsize(10)# 3. 產品月度趨勢對比ax3 = axes[1, 0]product_monthly = self.sales_data.groupby(['Month', 'Product'])['Sales'].sum().unstack()for i, product in enumerate(product_monthly.columns):ax3.plot(product_monthly.index, product_monthly[product], marker='o', linewidth=2, label=product, color=colors[i])ax3.set_title('各產品月度銷售趨勢', fontsize=14, fontweight='bold')ax3.set_xlabel('月份')ax3.set_ylabel('銷售額(元)')ax3.legend(bbox_to_anchor=(1.05, 1), loc='upper left')ax3.grid(True, alpha=0.3)# 4. 產品銷售數量與金額關系ax4 = axes[1, 1]product_stats = self.sales_data.groupby('Product').agg({'Sales': 'sum','Quantity': 'sum'}).reset_index()# 計算平均單價product_stats['AvgPrice'] = product_stats['Sales'] / product_stats['Quantity']# 氣泡圖:x=數量,y=銷售額,大小=平均單價scatter = ax4.scatter(product_stats['Quantity'], product_stats['Sales'],s=product_stats['AvgPrice']/10, alpha=0.6,c=range(len(product_stats)), cmap='viridis')# 添加產品名稱標注for i, row in product_stats.iterrows():ax4.annotate(row['Product'], (row['Quantity'], row['Sales']),xytext=(5, 5), textcoords='offset points',fontweight='bold')ax4.set_title('產品銷售數量vs金額關系\n(氣泡大小=平均單價)', fontsize=14, fontweight='bold')ax4.set_xlabel('銷售數量')ax4.set_ylabel('銷售額(元)')ax4.grid(True, alpha=0.3)plt.tight_layout()plt.show()print("? 產品分析圖表創建完成")def create_regional_analysis_charts(self):"""創建地區分析圖表"""print("🗺? 創建地區分析圖表...")fig, axes = plt.subplots(2, 2, figsize=(18, 12))fig.suptitle('地區銷售分析', fontsize=18, fontweight='bold')# 1. 地區銷售額對比ax1 = axes[0, 0]region_sales = self.sales_data.groupby('Region')['Sales'].sum().sort_values(ascending=True)bars = ax1.barh(region_sales.index, region_sales.values,color=self.colors['primary'])ax1.set_title('各地區銷售額對比', fontsize=14, fontweight='bold')ax1.set_xlabel('銷售額(元)')ax1.set_ylabel('地區')# 添加數值標簽for i, (bar, value) in enumerate(zip(bars, region_sales.values)):ax1.text(bar.get_width() + value*0.01, bar.get_y() + bar.get_height()/2,f'{value/10000:.0f}萬', va='center', fontweight='bold')# 2. 地區產品組合熱力圖ax2 = axes[0, 1]region_product = self.sales_data.groupby(['Region', 'Product'])['Sales'].sum().unstack()# 標準化數據以便比較region_product_norm = region_product.div(region_product.sum(axis=1), axis=0)im = ax2.imshow(region_product_norm.values, cmap='YlOrRd', aspect='auto')# 設置坐標軸ax2.set_xticks(range(len(region_product_norm.columns)))ax2.set_xticklabels(region_product_norm.columns, rotation=45)ax2.set_yticks(range(len(region_product_norm.index)))ax2.set_yticklabels(region_product_norm.index)ax2.set_title('地區產品組合熱力圖(比例)', fontsize=14, fontweight='bold')# 添加數值標注for i in range(len(region_product_norm.index)):for j in range(len(region_product_norm.columns)):text = ax2.text(j, i, f'{region_product_norm.iloc[i, j]:.2f}',ha="center", va="center", color="white", fontweight='bold')# 添加顏色條cbar = plt.colorbar(im, ax=ax2, shrink=0.8)cbar.set_label('產品占比', rotation=270, labelpad=15)# 3. 地區月度銷售趨勢ax3 = axes[1, 0]region_monthly = self.sales_data.groupby(['Month', 'Region'])['Sales'].sum().unstack()colors_region = [self.colors['primary'], self.colors['secondary'], self.colors['success'], self.colors['warning'], self.colors['info']]for i, region in enumerate(region_monthly.columns):ax3.plot(region_monthly.index, region_monthly[region], marker='o', linewidth=2, label=region, color=colors_region[i])ax3.set_title('各地區月度銷售趨勢', fontsize=14, fontweight='bold')ax3.set_xlabel('月份')ax3.set_ylabel('銷售額(元)')ax3.legend()ax3.grid(True, alpha=0.3)# 4. 地區銷售表現雷達圖ax4 = axes[1, 1]# 計算各地區的多個指標region_metrics = self.sales_data.groupby('Region').agg({'Sales': ['sum', 'mean', 'count'],'Quantity': 'sum'})# 扁平化列名region_metrics.columns = ['總銷售額', '平均訂單額', '訂單數', '總數量']# 標準化指標(0-1范圍)region_metrics_norm = region_metrics.div(region_metrics.max())# 選擇一個地區進行雷達圖展示selected_region = region_metrics_norm.index[0]values = region_metrics_norm.loc[selected_region].values# 設置雷達圖categories = region_metrics_norm.columnsN = len(categories)# 計算角度angles = [n / float(N) * 2 * np.pi for n in range(N)]angles += angles[:1] # 閉合圖形# 閉合數據values = np.concatenate([values, [values[0]]])# 轉換為極坐標ax4 = plt.subplot(2, 2, 4, projection='polar')ax4.plot(angles, values, 'o-', linewidth=2, color=self.colors['primary'])ax4.fill(angles, values, alpha=0.25, color=self.colors['primary'])# 設置標簽ax4.set_xticks(angles[:-1])ax4.set_xticklabels(categories)ax4.set_ylim(0, 1)ax4.set_title(f'{selected_region}銷售表現雷達圖', fontsize=14, fontweight='bold', pad=20)plt.tight_layout()plt.show()print("? 地區分析圖表創建完成")def create_comprehensive_dashboard(self):"""創建綜合儀表板"""print("📊 創建綜合銷售儀表板...")# 創建大型儀表板fig = plt.figure(figsize=(24, 16))gs = fig.add_gridspec(4, 6, hspace=0.3, wspace=0.3)# 計算關鍵指標total_sales = self.sales_data['Sales'].sum()total_quantity = self.sales_data['Quantity'].sum()avg_order_value = self.sales_data['Sales'].mean()num_orders = len(self.sales_data)# 1. 關鍵指標卡片(頂部)metrics = [('總銷售額', f'{total_sales/10000:.0f}萬元', self.colors['primary']),('總銷量', f'{total_quantity:,}件', self.colors['success']),('平均訂單', f'{avg_order_value:.0f}元', self.colors['warning']),('訂單數量', f'{num_orders:,}筆', self.colors['info'])]for i, (title, value, color) in enumerate(metrics):ax = fig.add_subplot(gs[0, i:i+1])ax.text(0.5, 0.7, value, ha='center', va='center', fontsize=24, fontweight='bold', color=color)ax.text(0.5, 0.3, title, ha='center', va='center', fontsize=14, color='gray')ax.set_xlim(0, 1)ax.set_ylim(0, 1)ax.axis('off')# 添加背景框ax.add_patch(plt.Rectangle((0.05, 0.1), 0.9, 0.8, facecolor=color, alpha=0.1, linewidth=2))# 2. 主要銷售趨勢圖(左上大圖)ax_main = fig.add_subplot(gs[1:3, 0:3])daily_sales = self.sales_data.groupby('Date')['Sales'].sum()ax_main.plot(daily_sales.index, daily_sales.values, color=self.colors['primary'], linewidth=1.5, alpha=0.7)# 添加移動平均線ma7 = daily_sales.rolling(window=7).mean()ma30 = daily_sales.rolling(window=30).mean()ax_main.plot(daily_sales.index, ma7, color=self.colors['danger'], linewidth=2, label='7天移動平均')ax_main.plot(daily_sales.index, ma30, color=self.colors['success'], linewidth=2, label='30天移動平均')ax_main.set_title('日銷售額趨勢分析', fontsize=16, fontweight='bold')ax_main.set_xlabel('日期')ax_main.set_ylabel('銷售額(元)')ax_main.legend()ax_main.grid(True, alpha=0.3)# 3. 產品銷售分布(右上)ax_product = fig.add_subplot(gs[1, 3:5])product_sales = self.sales_data.groupby('Product')['Sales'].sum()bars = ax_product.bar(range(len(product_sales)), product_sales.values,color=[self.colors['primary'], self.colors['secondary'], self.colors['success'], self.colors['warning'], self.colors['info']])ax_product.set_title('產品銷售額分布', fontsize=14, fontweight='bold')ax_product.set_xticks(range(len(product_sales)))ax_product.set_xticklabels(product_sales.index, rotation=45)ax_product.set_ylabel('銷售額(元)')# 4. 地區銷售餅圖(右中)ax_region = fig.add_subplot(gs[2, 3:5])region_sales = self.sales_data.groupby('Region')['Sales'].sum()wedges, texts, autotexts = ax_region.pie(region_sales.values, labels=region_sales.index,autopct='%1.1f%%', startangle=90)ax_region.set_title('地區銷售分布', fontsize=14, fontweight='bold')# 5. 月度銷售對比(右上角)ax_monthly = fig.add_subplot(gs[1:3, 5])monthly_sales = self.sales_data.groupby('Month')['Sales'].sum()bars = ax_monthly.bar(monthly_sales.index, monthly_sales.values,color=self.colors['info'], alpha=0.8)ax_monthly.set_title('月度銷售', fontsize=12, fontweight='bold')ax_monthly.set_xlabel('月份')ax_monthly.set_ylabel('銷售額')# 6. 銷售熱力圖(底部左)ax_heatmap = fig.add_subplot(gs[3, 0:2])# 創建周-月熱力圖self.sales_data['Week'] = self.sales_data['Date'].dt.isocalendar().weekweek_month_sales = self.sales_data.groupby(['Month', 'Week'])['Sales'].sum().unstack(fill_value=0)# 只選擇前12周week_month_sales = week_month_sales.iloc[:, :12]im = ax_heatmap.imshow(week_month_sales.values, cmap='YlOrRd', aspect='auto')ax_heatmap.set_title('月度-周度銷售熱力圖', fontsize=12, fontweight='bold')ax_heatmap.set_xlabel('周')ax_heatmap.set_ylabel('月份')ax_heatmap.set_yticks(range(len(week_month_sales.index)))ax_heatmap.set_yticklabels(week_month_sales.index)# 7. 銷售分布直方圖(底部中)ax_dist = fig.add_subplot(gs[3, 2:4])ax_dist.hist(self.sales_data['Sales'], bins=30, alpha=0.7, color=self.colors['secondary'], edgecolor='black')ax_dist.set_title('單筆銷售額分布', fontsize=12, fontweight='bold')ax_dist.set_xlabel('銷售額(元)')ax_dist.set_ylabel('頻次')ax_dist.axvline(self.sales_data['Sales'].mean(), color='red', linestyle='--', label=f'均值: {self.sales_data["Sales"].mean():.0f}')ax_dist.legend()# 8. 關鍵統計表格(底部右)ax_table = fig.add_subplot(gs[3, 4:6])ax_table.axis('tight')ax_table.axis('off')# 計算統計數據stats_data = [['統計指標', '數值'],['最高日銷售', f'{daily_sales.max()/10000:.1f}萬元'],['最低日銷售', f'{daily_sales.min()/10000:.1f}萬元'],['銷售標準差', f'{daily_sales.std()/10000:.1f}萬元'],['最佳產品', product_sales.idxmax()],['最佳地區', region_sales.idxmax()],['數據天數', f'{len(daily_sales)}天']]table = ax_table.table(cellText=stats_data, cellLoc='center', loc='center',colWidths=[0.5, 0.5])table.auto_set_font_size(False)table.set_fontsize(10)table.scale(1, 1.5)# 設置表格樣式for i in range(len(stats_data)):if i == 0:for j in range(2):table[(i, j)].set_facecolor(self.colors['primary'])table[(i, j)].set_text_props(weight='bold', color='white')else:for j in range(2):table[(i, j)].set_facecolor('#f8f9fa' if i % 2 == 0 else '#ffffff')ax_table.set_title('關鍵統計指標', fontsize=12, fontweight='bold')# 添加總標題和時間戳fig.suptitle('銷售數據綜合分析儀表板', fontsize=24, fontweight='bold', y=0.98)# 添加生成時間current_time = datetime.now().strftime('%Y-%m-%d %H:%M:%S')fig.text(0.99, 0.01, f'生成時間: {current_time}', ha='right', va='bottom', fontsize=10, color='gray')plt.show()print("? 綜合儀表板創建完成")def export_charts(self, format='png', dpi=300):"""導出圖表"""print(f"💾 導出圖表為 {format} 格式...")# 重新創建所有圖表并保存charts_info = [('時間序列分析', self.create_time_series_charts),('產品分析', self.create_product_analysis_charts),('地區分析', self.create_regional_analysis_charts),('綜合儀表板', self.create_comprehensive_dashboard)]for chart_name, chart_func in charts_info:plt.figure()chart_func()filename = f'sales_{chart_name}.{format}'plt.savefig(filename, dpi=dpi, bbox_inches='tight', facecolor='white', edgecolor='none')plt.close()print(f" ? {filename} 已保存")print("📁 所有圖表已導出完成")def demo_sales_visualization():"""銷售可視化完整演示"""print("🚀 銷售趨勢圖表制作項目演示")print("=" * 50)# 創建可視化管理器viz_manager = SalesVisualizationManager()# 生成示例數據viz_manager.generate_sales_data(days=365)# 數據概覽print(f"\n📋 數據概覽:")print(f"數據形狀: {viz_manager.sales_data.shape}")print(f"日期范圍: {viz_manager.sales_data['Date'].min()} 到 {viz_manager.sales_data['Date'].max()}")print(f"產品種類: {viz_manager.sales_data['Product'].nunique()}種")print(f"銷售地區: {viz_manager.sales_data['Region'].nunique()}個")# 創建各類分析圖表viz_manager.create_time_series_charts()viz_manager.create_product_analysis_charts()viz_manager.create_regional_analysis_charts()viz_manager.create_comprehensive_dashboard()print(f"\n🎉 銷售趨勢圖表制作項目演示完成!")print("📊 你已經學會了創建專業的數據可視化圖表")if __name__ == "__main__":demo_sales_visualization()
可視化最佳實踐
圖表選擇指南
# 可視化最佳實踐指南
print("📚 可視化最佳實踐")
print("=" * 30)def choose_chart_type(data_type, purpose):"""根據數據類型和目的選擇合適的圖表類型參數:data_type: 數據類型purpose: 分析目的"""chart_guide = {('時間序列', '趨勢分析'): '線圖',('分類數據', '比較大小'): '柱狀圖',('分類數據', '部分整體'): '餅圖',('兩個連續變量', '相關關系'): '散點圖',('單個連續變量', '分布形狀'): '直方圖',('多個數值變量', '綜合比較'): '雷達圖',('二維數據', '模式識別'): '熱力圖',('分類統計', '分布比較'): '箱線圖'}return chart_guide.get((data_type, purpose), '根據具體情況選擇')# 圖表選擇示例
scenarios = [('時間序列', '趨勢分析', '股價變化、銷售趨勢'),('分類數據', '比較大小', '各產品銷量對比'),('分類數據', '部分整體', '市場份額分析'),('兩個連續變量', '相關關系', '身高體重關系'),('單個連續變量', '分布形狀', '考試成績分布'),('多個數值變量', '綜合比較', '員工能力評估'),('二維數據', '模式識別', '地區產品銷售'),('分類統計', '分布比較', '不同組別的數據分布')
]print("📊 圖表類型選擇指南:")
for data_type, purpose, example in scenarios:chart_type = choose_chart_type(data_type, purpose)print(f" {data_type} + {purpose} → {chart_type}")print(f" 示例: {example}")print()
設計原則
# 可視化設計原則
print("🎨 可視化設計原則")
print("=" * 25)principles = [{'principle': '簡潔性原則','description': '去除不必要的裝飾,突出數據本身','good_practice': ['使用簡潔的配色', '避免3D效果', '減少圖表垃圾'],'bad_practice': ['過多的顏色', '復雜的背景', '無關的裝飾元素']},{'principle': '準確性原則', 'description': '確保圖表準確反映數據','good_practice': ['從0開始的y軸', '合適的比例尺', '清晰的標簽'],'bad_practice': ['截斷的y軸', '誤導的比例', '模糊的標簽']},{'principle': '可讀性原則','description': '確保觀眾能夠輕松理解圖表','good_practice': ['清晰的字體', '合適的大小', '有效的顏色對比'],'bad_practice': ['太小的字體', '低對比度', '難以區分的顏色']},{'principle': '一致性原則','description': '在同一報告中保持視覺風格統一','good_practice': ['統一的配色方案', '一致的字體', '相同的圖例位置'],'bad_practice': ['混亂的顏色使用', '不同的字體樣式', '隨意的布局']}
]for principle in principles:print(f"🔵 {principle['principle']}")print(f" {principle['description']}")print(f" ? 好的做法: {', '.join(principle['good_practice'])}")print(f" ? 避免: {', '.join(principle['bad_practice'])}")print()
學習總結
通過本節課的學習,你已經掌握了:
? Matplotlib基礎概念
- 理解了數據可視化在AI中的重要作用
- 掌握了Figure、Axes、Axis的層次結構
- 學會了pyplot和面向對象兩種編程接口
? 基本圖表類型
- 熟練創建線圖、柱狀圖、散點圖、餅圖、直方圖
- 掌握了各種圖表的適用場景和最佳實踐
- 學會了圖表的美化和自定義技巧
? 高級可視化技能
- 掌握了復雜布局和子圖管理
- 學會了創建綜合性的數據分析儀表板
- 理解了顏色、樣式、注釋等美化要素
? 實際項目經驗
- 完成了完整的銷售趨勢分析項目
- 體驗了從數據到洞察的可視化流程
- 學會了創建專業級的數據分析報告
? 最佳實踐認知
- 了解了圖表類型的選擇原則
- 掌握了可視化設計的核心要素
- 學會了避免常見的可視化陷阱
下節課預告
第7講我們將學習OpenAI API使用,這是當前最熱門的AI應用開發技能:
- OpenAI API的基本概念和注冊流程
- GPT模型的API調用和參數設置
- 提示詞工程的技巧和最佳實踐
- 構建智能問答系統項目
- 處理API限制和錯誤處理
掌握OpenAI API將讓你能夠構建各種智能應用!
🎉 恭喜完成第6講!
你已經掌握了數據可視化這項重要技能。好的可視化能讓數據說話,讓復雜的分析結果變得直觀易懂。現在你可以創建專業的圖表和儀表板,為數據分析和AI項目增添強大的展示能力!