資料科學 PYTHON 教學 視覺化 資料處理

Matplotlib 視覺化指南:結合 JSON 資料的完整實戰教程

好的,以下是您提供的 Matplotlib 視覺化指南內容,以 Markdown 格式重新輸出:

Matplotlib 視覺化指南

1. 通用的 Matplotlib 技巧

Matplotlib 是 Python 中最常用的 2D 繪圖工具,幾個核心概念包括:

  • Figure(圖像):整個視覺化畫布
  • Axes(座標軸):Figure 內的單個子圖
  • Axis(軸):x 軸和 y 軸
  • Artist(繪圖元素):圖形、標籤、圖例等

基礎設定

import matplotlib.pyplot as plt
import numpy as np
import json

# JSON 資料範例:
# 從 JSON 字串載入資料
json_data = '''
{
  "x_values": [0, 1, 2, 3, 4, 5],
  "y_values": [0, 1, 4, 9, 16, 25]
}
'''
data = json.loads(json_data)

# 基本繪圖流程
plt.figure()
plt.plot(data["x_values"], data["y_values"])
plt.xlabel("X 軸")
plt.ylabel("Y 軸")
plt.title("從 JSON 資料繪製的基本圖表")
plt.show()

2. 買一送一的介面

Matplotlib 提供兩種繪圖 API:

簡單介面(pyplot)

# 從 JSON 載入資料
json_data = '''{"x": [1, 2, 3], "y": [4, 5, 6]}'''
data = json.loads(json_data)

plt.plot(data["x"], data["y"])
plt.show()

面向對象 API(物件導向方式)

json_data = '''{"x": [1, 2, 3], "y": [4, 5, 6]}'''
data = json.loads(json_data)

fig, ax = plt.subplots()
ax.plot(data["x"], data["y"])
plt.show()

建議複雜圖表使用物件導向方式,可以更細緻控制。

3. 簡單的線條圖形

折線圖(Line Plot)

x = np.linspace(0, 10, 100)
y = np.sin(x)

# 轉換為 JSON 格式
json_data = json.dumps({"x": x.tolist(), "y": y.tolist()})
data = json.loads(json_data)

plt.plot(data["x"], data["y"], label="sin(x)")
plt.xlabel("X 軸")
plt.ylabel("Y 軸")
plt.title("從 JSON 資料繪製的基本折線圖")
plt.legend()
plt.show()

進階設定:

  • linestyle='dashed' 設定線條樣式
  • color='r' 設定顏色
  • marker='o' 添加數據點標記

4. 簡單的散佈圖

# 將隨機資料轉換為 JSON 格式
json_data = json.dumps({
    "x": np.random.rand(100).tolist(),
    "y": np.random.rand(100).tolist()
})
data = json.loads(json_data)

plt.scatter(data["x"], data["y"], color='blue', alpha=0.5)
plt.xlabel("X 軸")
plt.ylabel("Y 軸")
plt.title("從 JSON 資料繪製的散佈圖")
plt.show()

進階設定:

  • s= 設定點的大小
  • c= 設定顏色
  • alpha= 設定透明度

5. 視覺化誤差

# 建立並轉換為 JSON 格式
x = np.linspace(0, 10, 10)
y = np.sin(x)
error = np.random.rand(10) * 0.2

json_data = json.dumps({
    "x": x.tolist(),
    "y": y.tolist(),
    "error": error.tolist()
})
data = json.loads(json_data)

plt.errorbar(data["x"], data["y"], yerr=data["error"], fmt='-o', capsize=5)
plt.title("從 JSON 資料繪製的誤差棒圖")
plt.show()

進階參數:

  • yerr= Y 軸誤差
  • xerr= X 軸誤差
  • capsize= 設定誤差線端點大小

6. 密度圖和等高線圖

密度圖(Kernel Density Estimation, KDE)

import seaborn as sns

# 將隨機資料轉換為 JSON 格式
json_data = json.dumps({
    "data": np.random.randn(1000).tolist()
})
data = json.loads(json_data)

sns.kdeplot(data["data"], shade=True)
plt.title("從 JSON 資料繪製的密度圖")
plt.show()

等高線圖(Contour Plot)

X, Y = np.meshgrid(np.linspace(-3, 3, 100), np.linspace(-3, 3, 100))
Z = np.sin(X) * np.cos(Y)

# 轉換為 JSON 格式(注意:大型網格資料會產生較大的 JSON 字串)
json_data = json.dumps({
    "Z": Z.tolist()
})
data = json.loads(json_data)

plt.contourf(X, Y, data["Z"], levels=20, cmap="viridis")
plt.colorbar()
plt.title("從 JSON 資料繪製的等高線圖")
plt.show()

7. 直方圖、分箱法及密度

直方圖(Histogram)

# 將隨機資料轉換為 JSON 格式
json_data = json.dumps({
    "values": np.random.randn(1000).tolist()
})
data = json.loads(json_data)

plt.hist(data["values"], bins=30, alpha=0.7, color='blue', edgecolor='black')
plt.title("從 JSON 資料繪製的直方圖")
plt.show()

關鍵參數:

  • bins= 分箱數
  • alpha= 透明度
  • density=True 轉換為密度函數

8. 自訂圖表的圖例

# 將資料轉換為 JSON 格式
json_data = json.dumps({
    "x": np.linspace(0, 10, 100).tolist(),
    "y": np.sin(np.linspace(0, 10, 100)).tolist()
})
data = json.loads(json_data)

plt.plot(data["x"], data["y"], label="sin(x)", linestyle="--", color="r")
plt.legend(loc="upper right")
plt.title("從 JSON 資料繪製的帶圖例圖表")
plt.show()
  • loc= 設定圖例位置
  • fontsize= 設定大小
  • frameon=False 移除背景

9. 自訂色彩條

X, Y = np.meshgrid(np.linspace(-3, 3, 50), np.linspace(-3, 3, 50))
Z = np.sin(X) * np.cos(Y)

# 轉換為 JSON 格式
json_data = json.dumps({
    "Z": Z.tolist()
})
data = json.loads(json_data)

plt.contourf(X, Y, data["Z"], cmap="coolwarm")
cbar = plt.colorbar()
cbar.set_label("數值")
plt.title("從 JSON 資料繪製的帶色彩條圖表")
plt.show()

10. 多重子圖表

x = np.linspace(0, 10, 100)
y = np.sin(x)
X, Y = np.meshgrid(np.linspace(-3, 3, 30), np.linspace(-3, 3, 30))
Z = np.sin(X) * np.cos(Y)

# 轉換為 JSON 格式
json_data = json.dumps({
    "x": x.tolist(),
    "y": y.tolist(),
    "Z": Z.tolist(),
    "random_data": np.random.randn(1000).tolist()
})
data = json.loads(json_data)

fig, axs = plt.subplots(2, 2, figsize=(10, 8))

axs[0, 0].plot(data["x"], data["y"], 'r')
axs[0, 0].set_title("折線圖")

axs[0, 1].scatter(data["x"], data["y"])
axs[0, 1].set_title("散佈圖")

axs[1, 0].hist(data["random_data"], bins=30)
axs[1, 0].set_title("直方圖")

axs[1, 1].contourf(X, Y, data["Z"])
axs[1, 1].set_title("等高線圖")

plt.tight_layout()
plt.suptitle("從 JSON 資料繪製的多重子圖表", y=1.05)
plt.show()

11. 文字和註解

# 將資料轉換為 JSON 格式
json_data = json.dumps({
    "x": np.linspace(0, 10, 100).tolist(),
    "y": np.sin(np.linspace(0, 10, 100)).tolist(),
    "annotations": [
        {"x": 5, "y": 0, "text": "中間點"},
        {"x": 7, "y": 0.7, "text": "局部最大值", "xytext": [6, 1]}
    ]
})
data = json.loads(json_data)

plt.plot(data["x"], data["y"])
plt.text(data["annotations"][0]["x"], data["annotations"][0]["y"],
         data["annotations"][0]["text"], fontsize=12, color="red")
plt.annotate(data["annotations"][1]["text"],
             xy=(data["annotations"][1]["x"], data["annotations"][1]["y"]),
             xytext=(data["annotations"][1]["xytext"][0], data["annotations"][1]["xytext"][1]),
             arrowprops=dict(facecolor='black'))
plt.title("從 JSON 資料繪製的帶註解圖表")
plt.show()

12. 自訂刻度

# 將資料轉換為 JSON 格式
json_data = json.dumps({
    "x": np.linspace(0, 10, 100).tolist(),
    "y": np.sin(np.linspace(0, 10, 100)).tolist(),
    "xticks": {"positions": [0, 2, 4, 6, 8, 10], "labels": ["A", "B", "C", "D", "E", "F"]},
    "yticks": {"positions": [-1, 0, 1], "labels": ["Low", "Mid", "High"]}
})
data = json.loads(json_data)

plt.plot(data["x"], data["y"])
plt.xticks(data["xticks"]["positions"], labels=data["xticks"]["labels"])
plt.yticks(data["yticks"]["positions"], labels=data["yticks"]["labels"])
plt.title("從 JSON 資料繪製的自訂刻度圖表")
plt.show()

13. 客製化 Matplotlib:系統配置和樣式表

# 將樣式設定轉換為 JSON 格式
json_data = json.dumps({
    "style": "ggplot",
    "params": {
        "font.size": 12,
        "axes.labelcolor": "blue"
    },
    "x": np.linspace(0, 10, 100).tolist(),
    "y": np.sin(np.linspace(0, 10, 100)).tolist()
})
data = json.loads(json_data)

plt.style.use(data["style"])  # 內建樣式
plt.rcParams["font.size"] = data["params"]["font.size"]
plt.rcParams["axes.labelcolor"] = data["params"]["axes.labelcolor"]

plt.plot(data["x"], data["y"])
plt.title("從 JSON 資料繪製的客製化樣式圖表")
plt.show()

14. 在 Matplotlib 中的三維繪圖法

from mpl_toolkits.mplot3d import Axes3D

# 將資料轉換為 JSON 格式
json_data = json.dumps({
    "x": np.random.randn(100).tolist(),
    "y": np.random.randn(100).tolist(),
    "z": np.random.randn(100).tolist()
})
data = json.loads(json_data)

fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')

ax.scatter(data["x"], data["y"], data["z"])
plt.title("從 JSON 資料繪製的 3D 散佈圖")
plt.show()

15. Basemap 的地理資料

from mpl_toolkits.basemap import Basemap

# 將地圖設定轉換為 JSON 格式
json_data = json.dumps({
    "projection": "mill",
    "llcrnrlat": -60,
    "urcrnrlat": 80,
    "llcrnrlon": -180,
    "urcrnrlon": 180,
    "points": {
        "lats": [20, 30, 40, 50],
        "lons": [0, 60, 120, -60]
    }
})
data = json.loads(json_data)

m = Basemap(projection=data["projection"],
            llcrnrlat=data["llcrnrlat"],
            urcrnrlat=data["urcrnrlat"],
            llcrnrlon=data["llcrnrlon"],
            urcrnrlon=data["urcrnrlon"])
m.drawcoastlines()

# 繪製點
x, y = m(data["points"]["lons"], data["points"]["lats"])
m.scatter(x, y, marker='o', color='red')

plt.title("從 JSON 資料繪製的地理圖")
plt.show()

16. 使用 Seaborn 進行視覺化

import seaborn as sns

# 將資料轉換為 JSON 格式
json_data = '''
{
  "data": [
    {"day": "Sun", "total_bill": 16.99, "tip": 1.01, "sex": "Female", "smoker": "No", "time": "Dinner"},
    {"day": "Sun", "total_bill": 10.34, "tip": 1.66, "sex": "Male", "smoker": "No", "time": "Dinner"},
    {"day": "Sun", "total_bill": 21.01, "tip": 3.50, "sex": "Male", "smoker": "No", "time": "Dinner"},
    {"day": "Sun", "total_bill": 23.68, "tip": 3.31, "sex": "Male", "smoker": "No", "time": "Dinner"},
    {"day": "Sun", "total_bill": 24.59, "tip": 3.61, "sex": "Female", "smoker": "No", "time": "Dinner"},
    {"day": "Sun", "total_bill": 25.29, "tip": 4.71, "sex": "Male", "smoker": "No", "time": "Dinner"},
    {"day": "Sat", "total_bill": 20.65, "tip": 3.35, "sex": "Male", "smoker": "No", "time": "Dinner"},
    {"day": "Sat", "total_bill": 17.92, "tip": 4.08, "sex": "Male", "smoker": "No", "time": "Dinner"},
    {"day": "Sat", "total_bill": 20.29, "tip": 2.75, "sex": "Female", "smoker": "No", "time": "Dinner"},
    {"day": "Sat", "total_bill": 15.77, "tip": 2.23, "sex": "Female", "smoker": "No", "time": "Dinner"},
    {"day": "Thur", "total_bill": 14.83, "tip": 3.02, "sex": "Female", "smoker": "No", "time": "Lunch"},
    {"day": "Thur", "total_bill": 21.58, "tip": 3.92, "sex": "Male", "smoker": "No", "time": "Lunch"},
    {"day": "Thur", "total_bill": 12.60, "tip": 1.00, "sex": "Male", "smoker": "Yes", "time": "Lunch"},
    {"day": "Thur", "total_bill": 16.31, "tip": 2.00, "sex": "Male", "smoker": "Yes", "time": "Lunch"},
    {"day": "Fri", "total_bill": 17.89, "tip": 2.00, "sex": "Male", "smoker": "Yes", "time": "Lunch"},
    {"day": "Fri", "total_bill": 19.77, "tip": 2.00, "sex": "Male", "smoker": "No", "time": "Lunch"}
  ]
}
'''
data = json.loads(json_data)

# 將 JSON 資料轉換為 pandas DataFrame
import pandas as pd
tips_df = pd.DataFrame(data["data"])

# 繪製箱型圖
sns.boxplot(x="day", y="total_bill", data=tips_df)
plt.title("從 JSON 資料繪製的 Seaborn 箱型圖")
plt.show()

# 繪製熱圖
pivot_data = tips_df.pivot_table(index="day", columns="time", values="total_bill", aggfunc="mean")
sns.heatmap(pivot_data, annot=True, cmap="YlGnBu")
plt.title("從 JSON 資料繪製的 Seaborn 熱圖")
plt.show()

# 繪製小提琴圖
sns.violinplot(x="day", y="total_bill", hue="sex", data=tips_df, split=True)
plt.title("從 JSON 資料繪製的 Seaborn 小提琴圖")
plt.show()

以下是用 Markdown 格式編排的內容:

17. 互動式儀表板與 JSON 資料整合

import json
import pandas as pd
import matplotlib.pyplot as plt
from matplotlib.gridspec import GridSpec

# 從 JSON 資料來源載入複雜資料集
json_data = '''
{
  "sales": [
    {"month": "Jan", "revenue": 12000, "costs": 8000, "profit": 4000, "category": "Electronics"},
    {"month": "Feb", "revenue": 15000, "costs": 9000, "profit": 6000, "category": "Electronics"},
    {"month": "Mar", "revenue": 18000, "costs": 10000, "profit": 8000, "category": "Electronics"},
    {"month": "Jan", "revenue": 8000, "costs": 5000, "profit": 3000, "category": "Clothing"},
    {"month": "Feb", "revenue": 10000, "costs": 6000, "profit": 4000, "category": "Clothing"},
    {"month": "Mar", "revenue": 12000, "costs": 7000, "profit": 5000, "category": "Clothing"},
    {"month": "Jan", "revenue": 5000, "costs": 3000, "profit": 2000, "category": "Food"},
    {"month": "Feb", "revenue": 7000, "costs": 4000, "profit": 3000, "category": "Food"},
    {"month": "Mar", "revenue": 9000, "costs": 5000, "profit": 4000, "category": "Food"}
  ],
  "metadata": {
    "title": "季度銷售報告",
    "colors": {
      "Electronics": "#1f77b4",
      "Clothing": "#ff7f0e",
      "Food": "#2ca02c"
    }
  }
}
'''

data = json.loads(json_data)
df = pd.DataFrame(data["sales"])

# 創建儀表板
fig = plt.figure(figsize=(15, 10))
gs = GridSpec(2, 3, figure=fig)

# 設置標題
fig.suptitle(data["metadata"]["title"], fontsize=16)

# 1. 收入趨勢圖
ax1 = fig.add_subplot(gs[0, :2])
for category in df["category"].unique():
    category_data = df[df["category"] == category]
    ax1.plot(category_data["month"], category_data["revenue"],
             marker='o', label=category, color=data["metadata"]["colors"][category])
ax1.set_title("收入趨勢")
ax1.set_xlabel("月份")
ax1.set_ylabel("收入")
ax1.legend()

# 2. 餅圖 - 各類別總收入
ax2 = fig.add_subplot(gs[0, 2])
category_totals = df.groupby("category")["revenue"].sum()
ax2.pie(category_totals, labels=category_totals.index, autopct='%1.1f%%',
        colors=[data["metadata"]["colors"][cat] for cat in category_totals.index])
ax2.set_title("各類別總收入")

# 3. 長條圖 - 各月份收入、成本、利潤
ax3 = fig.add_subplot(gs[1, :])
months = df["month"].unique()
x = np.arange(len(months))
width = 0.25

revenue_by_month = df.groupby("month")["revenue"].sum()
costs_by_month = df.groupby("month")["costs"].sum()
profit_by_month = df.groupby("month")["profit"].sum()

ax3.bar(x - width, revenue_by_month, width, label='收入')
ax3.bar(x, costs_by_month, width, label='成本')
ax3.bar(x + width, profit_by_month, width, label='利潤')

ax3.set_xticks(x)
ax3.set_xticklabels(months)
ax3.set_title("各月份收入、成本與利潤")
ax3.set_xlabel("月份")
ax3.set_ylabel("金額")
ax3.legend()

plt.tight_layout()
plt.subplots_adjust(top=0.9)
plt.show()

18. 時間序列資料視覺化

import json
import pandas as pd
import matplotlib.pyplot as plt
from matplotlib.dates import DateFormatter

# 從 JSON 資料來源載入時間序列資料
json_data = '''
{
  "timeData": [
    {"date": "2024-01-01", "value": 100, "category": "A"},
    {"date": "2024-01-02", "value": 105, "category": "A"},
    {"date": "2024-01-03", "value": 110, "category": "A"},
    {"date": "2024-01-04", "value": 115, "category": "A"},
    {"date": "2024-01-05", "value": 118, "category": "A"},
    {"date": "2024-01-06", "value": 125, "category": "A"},
    {"date": "2024-01-07", "value": 130, "category": "A"},
    {"date": "2024-01-01", "value": 80, "category": "B"},
    {"date": "2024-01-02", "value": 82, "category": "B"},
    {"date": "2024-01-03", "value": 87, "category": "B"},
    {"date": "2024-01-04", "value": 95, "category": "B"},
    {"date": "2024-01-05", "value": 100, "category": "B"},
    {"date": "2024-01-06", "value": 110, "category": "B"},
    {"date": "2024-01-07", "value": 115, "category": "B"}
  ],
  "settings": {
    "title": "時間序列資料視覺化",
    "colors": {"A": "blue", "B": "red"}
  }
}
'''

data = json.loads(json_data)
df = pd.DataFrame(data["timeData"])
df["date"] = pd.to_datetime(df["date"])

# 創建時間序列圖
plt.figure(figsize=(12, 6))

for category in df["category"].unique():
    category_data = df[df["category"] == category]
    plt.plot(category_data["date"], category_data["value"],
             marker='o', label=category, color=data["settings"]["colors"][category])

plt.title(data["settings"]["title"])
plt.xlabel("日期")
plt.ylabel("數值")
plt.legend()
plt.grid(True, linestyle='--', alpha=0.7)

# 格式化 x 軸日期
plt.gca().xaxis.set_major_formatter(DateFormatter('%Y-%m-%d'))
plt.gcf().autofmt_xdate()  # 自動旋轉日期標籤

plt.tight_layout()
plt.show()

19. 互動式金融圖表

import json
import pandas as pd
import matplotlib.pyplot as plt
from matplotlib.finance import candlestick_ohlc
import matplotlib.dates as mdates

# 從 JSON 資料來源載入股票資料
json_data = '''
{
  "stockData": [
    {"date": "2024-01-01", "open": 100, "high": 105, "low": 98, "close": 103, "volume": 1000},
    {"date": "2024-01-02", "open": 103, "high": 110, "low": 102, "close": 108, "volume": 1200},
    {"date": "2024-01-03", "open": 108, "high": 115, "low": 107, "close": 112, "volume": 1500},
    {"date": "2024-01-04", "open": 112, "high": 118, "low": 110, "close": 115, "volume": 1800},
    {"date": "2024-01-05", "open": 115, "high": 120, "low": 113, "close": 118, "volume": 1600},
    {"date": "2024-01-08", "open": 118, "high": 122, "low": 116, "close": 120, "volume": 1400},
    {"date": "2024-01-09", "open": 120, "high": 125, "low": 118, "close": 122, "volume": 1700},
    {"date": "2024-01-10", "open": 122, "high": 128, "low": 120, "close": 125, "volume": 2000}
  ],
  "settings": {
    "title": "股票價格走勢",
    "ticker": "EXAMPLE"
  }
}
'''

data = json.loads(json_data)
df = pd.DataFrame(data["stockData"])
df["date"] = pd.to_datetime(df["date"])
df["date_num"] = mdates.date2num(df["date"])

# 準備資料為 OHLC 格式
ohlc = df[["date_num", "open", "high", "low", "close"]].values

# 創建 K 線圖和成交量圖
fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(12, 8), gridspec_kw={'height_ratios': [3, 1]}, sharex=True)

# K 線圖
candlestick_ohlc(ax1, ohlc, width=0.6, colorup='green', colordown='red')
ax1.set_title(f"{data['settings']['title']} - {data['settings']['ticker']}")
ax1.set_ylabel('價格')
ax1.grid(True)

# 成交量圖
ax2.bar(df["date_num"], df["volume"], width=0.6, color='blue', alpha=0.7)
ax2.set_ylabel('成交量')
ax2.grid(True)

# 格式化 x 軸日期
ax2.xaxis.set_major_formatter(mdates.DateFormatter('%Y-%m-%d'))
plt.gcf().autofmt_xdate()

plt.tight_layout()
plt.show()

20. 結合 Matplotlib 與 JSON 資料的進階技巧

import json
import pandas as pd
import matplotlib.pyplot as plt
import matplotlib.ticker as mtick
from matplotlib.gridspec import GridSpec

# 從 JSON 資料來源載入商業指標資料
json_data = '''
{
  "businessMetrics": {
    "monthlyRevenue": [
      {"month": "Jan", "revenue": 120000, "target": 100000},
      {"month": "Feb", "revenue": 130000, "target": 110000},
      {"month": "Mar", "revenue": 150000, "target": 120000},
      {"month": "Apr", "revenue": 160000, "target": 130000},
      {"month": "May", "revenue": 180000, "target": 140000},
      {"month": "Jun", "revenue": 190000, "target": 150000}
    ],
    "customerSegments": [
      {"segment": "Enterprise", "count": 50, "value": 120000},
      {"segment": "SMB", "count": 200, "value": 80000},
      {"segment": "Startup", "count": 400, "value": 40000},
      {"segment": "Individual", "count": 1000, "value": 20000}
    ],
    "satisfaction": [
      {"quarter": "Q1", "score": 8.5},
      {"quarter": "Q2", "score": 8.7},
      {"quarter": "Q3", "score": 9.0},
      {"quarter": "Q4", "score": 9.2}
    ]
  },
  "settings": {
    "colors": {
      "primary": "#1f77b4",
      "secondary": "#ff7f0e",
      "positive": "#2ca02c",
      "negative": "#d62728"
    },
    "companyName": "TechCorp Inc."
  }
}
'''

data = json.loads(json_data)

# 創建綜合儀表板
fig = plt.figure(figsize=(15, 10))
gs = GridSpec(2, 3, figure=fig)

# 設置標題
fig.suptitle(f"{data['settings']['companyName']} - 業務績效儀表板", fontsize=16)

# 1. 收入與目標對比圖
revenue_df = pd.DataFrame(data["businessMetrics"]["monthlyRevenue"])
ax1 = fig.add_subplot(gs[0, :2])

x = np.arange(len(revenue_df["month"]))
width = 0.35

ax1.bar(x - width/2, revenue_df["revenue"], width, label='實際收入',
        color=data["settings"]["colors"]["primary"])
ax1.bar(x + width/2, revenue_df["target"], width, label='目標收入',
        color=data["settings"]["colors"]["secondary"], alpha=0.7)

# 添加百分比標籤
for i, (r, t) in enumerate(zip(revenue_df["revenue"], revenue_df["target"])):
    percentage = (r / t - 1) * 100
    color = data["settings"]["colors"]["positive"] if percentage >= 0 else data["settings"]["colors"]["negative"]
    ax1.text(i, max(r, t) + 5000, f"{percentage:.1f}%", ha='center', color=color, fontweight='bold')

ax1.set_title("月度收入與目標對比")
ax1.set_xlabel("月份")
ax1.set_ylabel("收入 ($)")
ax1.set_xticks(x)
ax1.set_xticklabels(revenue_df["month"])
ax1.legend()
ax1.grid(axis='y', linestyle='--', alpha=0.7)
ax1.yaxis.set_major_formatter('${x:,.0f}')

# 2. 客戶群體分析 - 氣泡圖
segment_df = pd.DataFrame(data["businessMetrics"]["customerSegments"])
ax2 = fig.add_subplot(gs[0, 2])

sizes = segment_df["value"] / segment_df["value"].max() * 1000  # 氣泡大小標準化

scatter = ax2.scatter(segment_df["count"], segment_df["value"], s=sizes,
                      alpha=0.6, c=range(len(segment_df)), cmap='viridis')

# 添加標籤
for i, segment in enumerate(segment_df["segment"]):
    ax2.annotate(segment,
                 (segment_df["count"].iloc[i], segment_df["value"].iloc[i]),
                 ha='center', va='center', fontweight='bold')

ax2.set_title("客戶群體分析")
ax2.set_xlabel("客戶數量")
ax2.set_ylabel("總價值 ($)")
ax2.grid(True, linestyle='--', alpha=0.7)
ax2.yaxis.set_major_formatter('${x:,.0f}')

# 3. 滿意度走勢圖
satisfaction_df = pd.DataFrame(data["businessMetrics"]["satisfaction"])
ax3 = fig.add_subplot(gs[1, :])

ax3.plot(satisfaction_df["quarter"], satisfaction_df["score"], marker='o',
         linewidth=3, color=data["settings"]["colors"]["primary"])

# 添加基準線
ax3.axhline(y=8.0, color='gray', linestyle='--', alpha=0.5)
ax3.text(0, 8.0, "基準線", va='bottom', ha='left', color='gray')

# 設定 y 軸範圍從 7 到 10
ax3.set_ylim(7, 10)

# 計算趨勢
start_score = satisfaction_df["score"].iloc[0]
end_score = satisfaction_df["score"].iloc[-1]
improvement = ((end_score / start_score) - 1) * 100

ax3.set_title(f"客戶滿意度走勢 (提升 {improvement:.1f}%)")
ax3.set_xlabel("季度")
ax3.set_ylabel("滿意度分數 (0-10)")
ax3.grid(True, linestyle='--', alpha=0.7)

# 格式化刻度為百分比
fmt = '%.1f'
ax3.yaxis.set_major_formatter(mtick.FormatStrFormatter(fmt))

# 增加註解
for i, score in enumerate(satisfaction_df["score"]):
    ax3.annotate(f"{score}",
                 (satisfaction_df["quarter"].iloc[i], score),
                 textcoords="offset points",
                 xytext=(0, 10),
                 ha='center')

plt.tight_layout()
plt.subplots_adjust(top=0.9)
plt.show()

結語

這份完整的 Matplotlib 視覺化指南涵蓋了從基礎到進階的各種技巧,每個範例都加入了使用 JSON 格式資料來產出圖表的示例。透過這種方式,你可以輕鬆將從 API 獲取的 JSON 資料直接用於視覺化分析。主要優點包括:

  1. 資料與視覺化分離:JSON 格式允許將資料與視覺化代碼分離,使程式更易於維護
  2. API 整合友好:大多數網路 API 返回 JSON 格式資料,本指南提供直接整合的方法
  3. 可序列化和存儲:JSON 格式便於資料的存儲和傳輸
  4. 動態視覺化:容易更新資料源而不需修改視覺化代碼

這些技巧從簡單的線條圖形到複雜的互動式儀表板,都能幫助你更高效地處理和視覺化 JSON 格式的資料。

希望這份指南對你使用 Matplotlib 與 JSON 資料結合的視覺化工作有所幫助!