在日常工作中,你是否遇到過這種情況:你辛辛苦苦跑完數據,畫了一張圖表發給老闆或客户,結果對方盯着看了半天,問了一句:“所以,你想表達什麼?”
這就像講笑話沒人笑一樣尷尬。圖表的本質不是 “畫圖”,而是 “溝通”。
今天,我將分享 5 個提升可視化效果的原則,並用 Python 的 matplotlib 庫手把手教你如何實現。
1. 原則1:展示數據,而非裝飾
想象一下,你在閲讀一本小説,但每頁都充滿了無關的插圖,你會感到困惑和分心。
數據可視化也是如此——讀者需要的是數據本身,而不是華麗的裝飾。
所以,我們需要展示最重要的數據,而不是儘可能多的數據。
讓我們看看一個常見的錯誤做法和改進後的做法:
# 創建示例數據
np.random.seed(42)
categories = ["產品A", "產品B", "產品C", "產品D", "產品E"]
sales_bad = np.random.randint(50, 200, 5)
sales_good = np.random.randint(50, 200, 5)
# 錯誤做法:過度裝飾,數據不突出
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(14, 6))
# 左側:過度裝飾的圖表
ax1.bar(categories, sales_bad, color=["red", "blue", "green", "orange", "purple"])
# 添加不必要的元素
# ...
# 右側:簡潔聚焦的圖表
ax2.bar(categories, sales_good, color="steelblue", alpha=0.8)
# 在柱子上直接標註數值
for i, v in enumerate(sales_good):
ax2.text(i, v + 5, str(v), ha="center", fontweight="bold")
# 突出最高值
# ...
# 移除不必要的邊框
# ...
plt.tight_layout()
plt.show()
在這個示例中,根據原則1,我們主要改進了:
- 移除背景水印和過度裝飾
- 直接在柱狀圖上標註數值,避免視線來回移動
- 突出顯示最重要的數據點(產品C)
- 簡化標題,直接傳達核心信息
2. 原則2:減少混亂,保持簡潔
想象一下一個雜亂無章的房間,你想找一本書,卻要翻遍各個角落。
混亂的圖表也會讓讀者經歷同樣的挫折。
所以,每個額外的視覺元素都應該有明確的目的,否則就應該移除。
# 創建示例數據
np.random.seed(123)
months = [
"1月",
#...
"12月",
]
temperature = np.random.normal(20, 5, 12) + np.sin(np.linspace(0, 2 * np.pi, 12)) * 3
precipitation = (
np.random.normal(50, 15, 12) + np.cos(np.linspace(0, 2 * np.pi, 12)) * 20
)
# 左側:混亂的圖表
ax1.plot(months, temperature, "ro-", linewidth=2, markersize=8, label="温度")
# ...
# 創建第二個y軸(混亂的常見來源)
ax1b = ax1.twinx()
ax1b.plot(months, precipitation, "bs--", linewidth=2, markersize=8, label="降水量")
# ...
# 添加網格和過多標籤
# ...
# 右側:簡潔的圖表
# 分開顯示兩個指標
ax2a = plt.subplot(grid[0, 1])
ax2b = plt.subplot(grid[1, 1])
# 温度圖表
ax2a.plot(months, temperature, color="#E74C3C", linewidth=2.5)
ax2a.fill_between(months, temperature.min(), temperature, color="#E74C3C", alpha=0.1)
# 突出顯示最高温度
max_temp_idx = np.argmax(temperature)
ax2a.plot(
months[max_temp_idx], temperature[max_temp_idx], "o", color="#E74C3C", markersize=10
)
# ...
# 降水量圖表
ax2b.bar(months, precipitation, color="#3498DB", alpha=0.7)
# 突出顯示最高降水量
max_precip_idx = np.argmax(precipitation)
# ...
plt.show()
在這個示例中,根據原則2,我們主要改進了:
- 將雙Y軸圖表拆分為兩個獨立的圖表
- 移除過多的圖例和網格線
- 使用填充和標記突出關鍵數據點
- 簡化標題,每個圖表只表達一個核心信息
3. 原則3:圖文結合,引導讀者
好的可視化圖表就像一個會講故事的導遊,而文字就是它的講解詞。
文字應該幫助讀者理解數據,而不是製造障礙。
# 創建示例數據
np.random.seed(42)
years = np.arange(2010, 2023)
company_a = np.random.normal(100, 10, 13) + np.linspace(0, 50, 13)
company_b = np.random.normal(100, 10, 13) + np.linspace(0, 30, 13)
# 左側:缺乏引導的圖表
ax1.plot(years, company_a, "b-", linewidth=2, label="公司A")
ax1.plot(years, company_b, "r-", linewidth=2, label="公司B")
# 右側:圖文結合的圖表
ax2.plot(years, company_a, color="#2E86C1", linewidth=3, alpha=0.8)
ax2.plot(years, company_b, color="#E74C3C", linewidth=3, alpha=0.8)
# 直接標註線條,避免圖例
ax2.text(
2022.2, company_a[-1], "公司A", color="#2E86C1", fontweight="bold", va="center"
)
ax2.text(
2022.2, company_b[-1], "公司B", color="#E74C3C", fontweight="bold", va="center"
)
# 添加標題和副標題
# ...
# 添加關鍵事件註釋
# ...
# 突出關鍵數據點
# ...
# 簡潔的座標軸
# ...
plt.show()
在這個示例中,根據原則3,我們主要改進了:
- 直接在線條旁標註,消除圖例
- 使用標題直接傳達核心發現
- 添加註釋解釋關鍵事件
- 使用填充區域突出重要差異
4. 原則4:避免意麪圖,分解複雜信息
"意麪圖"是指線條交錯、難以分辨的圖表,就像一碗纏在一起的意大利麪。
當圖表變得過於複雜時,最好的方法是分解它。
# 創建示例數據:多個產品多年的銷售數據
np.random.seed(123)
years = np.arange(2015, 2024)
products = ['手機', '平板', '筆記本', '智能手錶', '耳機']
# 生成數據
sales_data = {}
for product in products:
base = np.random.randint(30, 80)
trend = np.linspace(0, np.random.randint(20, 60), 9)
noise = np.random.normal(0, 5, 9)
sales_data[product] = base + trend + noise
# 左側:意麪圖
colors = plt.cm.Set2(np.linspace(0, 1, len(products)))
for idx, (product, sales) in enumerate(sales_data.items()):
ax1.plot(years, sales, color=colors[idx], linewidth=2, marker='o', label=product)
# 右側:分解後的圖表 - 使用子圖
fig2, axes = plt.subplots(2, 3, figsize=(15, 8))
axes = axes.flatten()
# 繪製每個產品的獨立圖表
for idx, (product, sales) in enumerate(sales_data.items()):
ax = axes[idx]
ax.plot(years, sales, color='#2980B9', linewidth=2.5, marker='o', markersize=6)
# 填充區域
ax.fill_between(years, sales.min(), sales, color='#2980B9', alpha=0.1)
# 設置標題和標籤
# ...
# 標記最高點
max_idx = np.argmax(sales)
ax.plot(years[max_idx], sales[max_idx], 'o', color='#E74C3C', markersize=8)
# ...
# 簡化網格
# ...
# 隱藏最後一個子圖(我們只有5個產品)
axes[-1].axis('off')
plt.show()
在這個示例中,根據原則4,我們主要改進了:
- 將複雜的多線條圖表分解為多個簡單圖表
- 每個子圖聚焦一個產品,避免線條交錯
- 在每個子圖中獨立標註關鍵信息
- 保持一致的視覺風格便於比較
5. 原則5:從灰色開始,有策略地使用顏色
顏色是可視化中最強大的工具之一,但也是最容易被濫用的。
從灰度開始設計,可以確保你使用的每個顏色都有明確的目的。
# 創建示例數據
np.random.seed(123)
cities = ["北京", "上海", "廣州", "深圳", "成都", "武漢", "西安", "杭州"]
months = [
"1月",
# ...
"12月",
]
# 生成各城市的月度AQI數據
aqi_data = {}
for city in cities:
base = np.random.randint(60, 100) # 基礎AQI值
seasonal = np.sin(np.linspace(0, 2 * np.pi, 12)) * 20 # 季節性變化
noise = np.random.normal(0, 10, 12) # 隨機噪聲
aqi_data[city] = np.clip(base + seasonal + noise, 30, 180) # 限制在30-180之間
# 計算各城市的年平均AQI
avg_aqi = {city: np.mean(values) for city, values in aqi_data.items()}
# 創建圖表對比
fig = plt.figure(figsize=(12, 6))
# 階段1:全灰色基礎圖表
ax1 = plt.subplot(1, 2, 1)
# 全灰色版本
for city in cities:
ax1.plot(months, aqi_data[city], color="#7F8C8D", linewidth=1.5, alpha=0.6) # 灰色
# ...
# 階段2:識別關鍵數據後添加初步顏色
ax2 = plt.subplot(1, 2, 2)
# 找出空氣質量最好和最差的城市
sorted_cities = sorted(avg_aqi.items(), key=lambda x: x[1])
best_city = sorted_cities[0][0] # AQI最低的城市
worst_city = sorted_cities[-1][0] # AQI最高的城市
# ...
# 添加標籤
# ...
# 添加空氣質量標準線
# ...
plt.show()
在這個示例中,根據原則5,我們主要改進了:
- 從全灰色開始,確保圖表結構清晰
- 只對關鍵數據點使用強調色
- 使用顏色突出最重要的發現
- 通過細節點綴(如虛線、標記)提供額外上下文
6. 總結
數據可視化不僅僅是關於 plt.plot() 的技術,更多的是關於心理學和設計。
- 展示數據:把聚光燈打在重點上。
- 減少混亂:刪掉一切不必要的墨水。
- 圖文結合:標題就是結論,標註代替圖例。
- 避免意麪圖:複雜問題拆解看。
- 從灰色開始:剋制地使用顏色。
希望這些原則能幫你在下一次做圖時,畫出讓人眼前一亮的作品!
文中的代碼是一些核心的片段,完整的代碼共享在:可視化5個黃金原則.ipynb (訪問密碼: 6872)