【Python数据科学实战之路】第5章 | 数据可视化基础:用Matplotlib讲好数据故事

Python版本 :Python 3.12+
开发工具 :PyCharm 或 VS Code
操作系统:Windows / macOS / Linux (通用)


摘要:数据可视化是连接数据与洞察的桥梁。本章从"为什么可视化"出发,系统讲解Matplotlib 3.x最新特性、图表选择方法论、专业级样式定制,帮助你建立数据可视化思维,创建出版级质量的图表。


学习目标

完成本章学习后,你将能够:

  • 理解数据可视化的核心目的与认知心理学基础
  • 根据数据类型和分析目标选择最优图表
  • 掌握Matplotlib 3.x的面向对象编程范式
  • 运用样式表、颜色映射、布局技巧创建专业图表
  • 建立可复用的可视化工作流

1. 为什么需要数据可视化

1.1 认知心理学视角

人类大脑处理视觉信息的速度远快于文本。研究表明:

信息类型 大脑处理时间 记忆留存率
纯文本 数分钟 10%
表格数据 数分钟 20%
图表 数秒 65%
故事化图表 数秒 80%

数据可视化的核心价值:

  1. 模式识别:快速发现趋势、周期、异常值
  2. 沟通效率:一张图胜过千言万语
  3. 探索性分析:在数据中寻找假设和洞察
  4. 决策支持:为业务决策提供直观依据

1.2 数据可视化的三大原则

原则一:准确呈现数据

  • 避免扭曲数据比例(如截断Y轴)
  • 使用合适的坐标轴刻度
  • 确保数据标签清晰可读

原则二:降低认知负荷

  • 遵循"数据墨水比"原则:去除无关装饰
  • 使用一致的视觉编码
  • 合理运用颜色、形状、大小

原则三:讲述数据故事

  • 明确图表要回答的问题
  • 突出关键信息
  • 引导读者视线

2. 图表选择决策指南

2.1 按数据类型选择

数据类型 定义 推荐图表 示例
分类数据 离散的类别 柱状图、条形图、饼图 产品类别销售额
时间序列 按时间排列 折线图、面积图 月度销售趋势
数值关系 两个连续变量 散点图、气泡图 广告投入vs销售额
分布特征 数据分布情况 直方图、箱线图、密度图 考试成绩分布
地理空间 位置相关数据 地图、热力图 各省份销售分布
多维比较 多个维度对比 雷达图、平行坐标图 产品性能评估

2.2 按分析目标选择

复制代码
分析目标
    |
    +-- 比较大小 → 柱状图 / 条形图 / 雷达图
    |
    +-- 展示趋势 → 折线图 / 面积图 / 瀑布图
    |
    +-- 显示占比 → 饼图 / 环形图 / 树状图
    |
    +-- 分析关系 → 散点图 / 热力图 / 气泡图
    |
    +-- 观察分布 → 直方图 / 箱线图 / 小提琴图
    |
    +-- 识别异常 → 箱线图 / 散点图

2.3 常见图表选择误区

错误做法 问题 正确替代
用饼图展示超过7个类别 难以区分小扇区 柱状图或合并为"其他"
用折线图展示分类排名 暗示虚假趋势 柱状图按值排序
3D柱状图 扭曲数据比例 2D柱状图
双Y轴图表 难以比较 分面图或归一化
彩虹色映射 色盲不友好 Viridis等感知均匀色图

3. Matplotlib架构与核心概念

3.1 Matplotlib简介

Matplotlib是Python最经典的数据可视化库,由John Hunter于2003年创建。2025年最新版本(3.10+)带来了:

  • 改进的样式系统:更现代的默认样式
  • 增强的颜色支持:更好的色盲友好型色图
  • 性能优化:大规模数据渲染更快
  • 更好的类型提示:IDE支持更完善

3.2 三层架构模型

复制代码
┌─────────────────────────────────────────────────────────┐
│                    脚本层 (pyplot)                       │
│              快速绘图,类似MATLAB接口                      │
├─────────────────────────────────────────────────────────┤
│                   艺术家层 (Artist)                       │
│    Figure → Axes → Axis → Tick/Label/Line/...           │
│              精细控制每一个视觉元素                        │
├─────────────────────────────────────────────────────────┤
│                   后端层 (Backend)                        │
│    TkAgg / Qt5Agg / Agg / SVG / PDF ...                  │
│              渲染输出到屏幕或文件                          │
└─────────────────────────────────────────────────────────┘

3.3 核心对象关系

复制代码
Figure (画布)
    └── Axes (子图1)
    │       ├── XAxis (X轴)
    │       │       └── Ticks, Labels
    │       ├── YAxis (Y轴)
    │       │       └── Ticks, Labels
    │       ├── Lines (线条)
    │       ├── Patches (填充)
    │       └── Text (文本)
    └── Axes (子图2)
            └── ...

3.4 两种编程风格对比

面向对象风格(推荐)

python 复制代码
import matplotlib.pyplot as plt
import numpy as np

# 显式创建Figure和Axes
fig, ax = plt.subplots(figsize=(10, 6))

x = np.linspace(0, 10, 100)
ax.plot(x, np.sin(x), label='sin(x)')
ax.set_title('正弦函数', fontsize=14)
ax.set_xlabel('x')
ax.set_ylabel('y')
ax.legend()

plt.show()

pyplot风格(快速探索)

python 复制代码
import matplotlib.pyplot as plt
import numpy as np

x = np.linspace(0, 10, 100)
plt.plot(x, np.sin(x), label='sin(x)')
plt.title('正弦函数')
plt.xlabel('x')
plt.ylabel('y')
plt.legend()
plt.show()
风格 适用场景 优点 缺点
面向对象 复杂图表、多子图、生产代码 清晰、灵活、可维护 代码稍长
pyplot 快速探索、简单图表 简洁、快速 难以处理复杂布局

4. 基础图表类型实战

4.1 折线图:展示趋势变化

适用场景:时间序列数据、连续变化趋势

python 复制代码
import matplotlib.pyplot as plt
import numpy as np

# 生成模拟数据
months = ['1月', '2月', '3月', '4月', '5月', '6月', '7月', '8月', '9月', '10月', '11月', '12月']
sales_2024 = [120, 135, 148, 162, 155, 178, 185, 192, 188, 205, 218, 235]
sales_2025 = [135, 142, 158, 175, 188, 195, 210, 225, 238, 245, 258, 270]

# 创建图表
fig, ax = plt.subplots(figsize=(12, 6))

# 绘制折线
ax.plot(months, sales_2024, marker='o', linewidth=2.5, markersize=6, 
        color='#2E86AB', label='2024年', alpha=0.8)
ax.plot(months, sales_2025, marker='s', linewidth=2.5, markersize=6, 
        color='#A23B72', label='2025年', alpha=0.8)

# 添加数据标签
for i, (m, v) in enumerate(zip(months, sales_2025)):
    if i % 2 == 0:  # 每隔一个显示,避免拥挤
        ax.annotate(f'{v}', (i, v), textcoords="offset points", 
                   xytext=(0, 10), ha='center', fontsize=8)

# 样式设置
ax.set_title('月度销售额趋势对比', fontsize=16, fontweight='bold', pad=20)
ax.set_xlabel('月份', fontsize=12)
ax.set_ylabel('销售额(万元)', fontsize=12)
ax.legend(loc='upper left', frameon=True, fancybox=True, shadow=True)
ax.grid(True, linestyle='--', alpha=0.3)
ax.set_ylim(100, 300)

# 添加增长率标注
growth_rate = ((sales_2025[-1] - sales_2024[-1]) / sales_2024[-1]) * 100
ax.text(11, 280, f'同比增长: +{growth_rate:.1f}%', 
        bbox=dict(boxstyle='round', facecolor='wheat', alpha=0.5),
        fontsize=10, ha='center')

plt.tight_layout()
plt.show()

折线图最佳实践

  • 时间轴从左到右,符合阅读习惯
  • 数据点较多时减少标记使用
  • 多条线使用明显区分的颜色
  • 添加网格线辅助读数

4.2 柱状图:比较类别大小

适用场景:类别数据比较、排名展示

python 复制代码
import matplotlib.pyplot as plt
import numpy as np

# 数据准备
products = ['产品A', '产品B', '产品C', '产品D', '产品E', '产品F']
q1_sales = [320, 280, 350, 290, 310, 275]
q2_sales = [340, 300, 365, 310, 325, 295]

# 创建分组柱状图
fig, ax = plt.subplots(figsize=(11, 6))

x = np.arange(len(products))
width = 0.35

bars1 = ax.bar(x - width/2, q1_sales, width, label='第一季度', 
               color='#3498db', edgecolor='white', linewidth=1)
bars2 = ax.bar(x + width/2, q2_sales, width, label='第二季度', 
               color='#e74c3c', edgecolor='white', linewidth=1)

# 添加数值标签
def add_labels(bars):
    for bar in bars:
        height = bar.get_height()
        ax.annotate(f'{int(height)}',
                    xy=(bar.get_x() + bar.get_width() / 2, height),
                    xytext=(0, 3), textcoords="offset points",
                    ha='center', va='bottom', fontsize=9)

add_labels(bars1)
add_labels(bars2)

# 样式设置
ax.set_xlabel('产品', fontsize=12)
ax.set_ylabel('销售额(万元)', fontsize=12)
ax.set_title('季度产品销售额对比', fontsize=16, fontweight='bold', pad=20)
ax.set_xticks(x)
ax.set_xticklabels(products)
ax.legend()
ax.set_ylim(0, 420)
ax.spines['top'].set_visible(False)
ax.spines['right'].set_visible(False)

plt.tight_layout()
plt.show()

柱状图变体

类型 代码 适用场景
水平柱状图 ax.barh() 类别名称较长
堆叠柱状图 bottom参数 展示构成比例
百分比堆叠 归一化后绘制 比较相对构成

4.3 散点图:探索变量关系

适用场景:相关性分析、聚类发现、异常值检测

python 复制代码
import matplotlib.pyplot as plt
import numpy as np

# 生成模拟数据
np.random.seed(42)
n = 100
advertising = np.random.uniform(10, 100, n)
sales = 2.5 * advertising + np.random.normal(0, 15, n) + 50
profit = 0.3 * sales + np.random.normal(0, 5, n)

# 创建气泡图(散点图扩展)
fig, ax = plt.subplots(figsize=(11, 7))

# 气泡大小映射利润
sizes = (profit / profit.max()) * 500 + 50

scatter = ax.scatter(advertising, sales, c=profit, s=sizes, 
                    cmap='RdYlGn', alpha=0.6, edgecolors='black', linewidth=0.5)

# 添加趋势线
z = np.polyfit(advertising, sales, 1)
p = np.poly1d(z)
ax.plot(advertising, p(advertising), "r--", alpha=0.8, linewidth=2, label=f'趋势线: y={z[0]:.2f}x+{z[1]:.2f}')

# 添加颜色条
cbar = plt.colorbar(scatter, ax=ax)
cbar.set_label('利润(万元)', fontsize=11)

# 样式设置
ax.set_xlabel('广告投入(万元)', fontsize=12)
ax.set_ylabel('销售额(万元)', fontsize=12)
ax.set_title('广告投入与销售额关系分析\n(气泡大小代表利润)', fontsize=14, fontweight='bold')
ax.legend()
ax.grid(True, linestyle='--', alpha=0.3)

# 添加相关系数标注
corr = np.corrcoef(advertising, sales)[0, 1]
ax.text(0.05, 0.95, f'相关系数: {corr:.3f}', transform=ax.transAxes,
        bbox=dict(boxstyle='round', facecolor='white', alpha=0.8),
        fontsize=10, verticalalignment='top')

plt.tight_layout()
plt.show()

4.4 饼图与环形图:展示占比

适用场景:部分与整体关系、份额展示(类别不超过7个)

python 复制代码
import matplotlib.pyplot as plt

# 数据
labels = ['品牌A', '品牌B', '品牌C', '品牌D', '其他']
sizes = [35, 25, 20, 15, 5]
colors = ['#FF6B6B', '#4ECDC4', '#45B7D1', '#96CEB4', '#FFEAA7']
explode = (0.05, 0, 0, 0, 0)

# 创建环形图
fig, ax = plt.subplots(figsize=(9, 9))

wedges, texts, autotexts = ax.pie(sizes, explode=explode, labels=labels, 
                                   colors=colors, autopct='%1.1f%%',
                                   shadow=False, startangle=90,
                                   wedgeprops=dict(width=0.5, edgecolor='white'))

# 美化文本
for autotext in autotexts:
    autotext.set_color('white')
    autotext.set_fontweight('bold')
    autotext.set_fontsize(11)

# 添加中心文字
ax.text(0, 0, '2025\n市场份额', ha='center', va='center', fontsize=14, fontweight='bold')

ax.set_title('市场份额分布', fontsize=16, fontweight='bold', pad=20)

plt.tight_layout()
plt.show()

4.5 直方图与密度图:展示分布

适用场景:数据分布特征、正态性检验、多组对比

python 复制代码
import matplotlib.pyplot as plt
import numpy as np
from scipy import stats

# 生成数据
np.random.seed(42)
group_a = np.random.normal(75, 10, 1000)
group_b = np.random.normal(70, 15, 1000)

# 创建图表
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(14, 5))

# 左侧:直方图
ax1.hist(group_a, bins=30, alpha=0.7, label='A组', color='#3498db', edgecolor='white')
ax1.hist(group_b, bins=30, alpha=0.7, label='B组', color='#e74c3c', edgecolor='white')
ax1.set_xlabel('分数', fontsize=12)
ax1.set_ylabel('频数', fontsize=12)
ax1.set_title('成绩分布直方图', fontsize=14, fontweight='bold')
ax1.legend()
ax1.grid(True, linestyle='--', alpha=0.3)

# 右侧:密度图
x_range = np.linspace(30, 110, 200)
kde_a = stats.gaussian_kde(group_a)
kde_b = stats.gaussian_kde(group_b)

ax2.fill_between(x_range, kde_a(x_range), alpha=0.5, color='#3498db', label='A组')
ax2.fill_between(x_range, kde_b(x_range), alpha=0.5, color='#e74c3c', label='B组')
ax2.axvline(np.mean(group_a), color='#3498db', linestyle='--', linewidth=2, label=f'A组均值: {np.mean(group_a):.1f}')
ax2.axvline(np.mean(group_b), color='#e74c3c', linestyle='--', linewidth=2, label=f'B组均值: {np.mean(group_b):.1f}')
ax2.set_xlabel('分数', fontsize=12)
ax2.set_ylabel('密度', fontsize=12)
ax2.set_title('成绩分布密度图', fontsize=14, fontweight='bold')
ax2.legend()
ax2.grid(True, linestyle='--', alpha=0.3)

plt.tight_layout()
plt.show()

5. 专业样式定制

5.1 使用样式表(Style Sheets)

Matplotlib 3.x提供了多种内置样式:

python 复制代码
import matplotlib.pyplot as plt

# 查看所有可用样式
print(plt.style.available)

# 常用推荐样式:
# 'seaborn-v0_8-whitegrid' - 白色网格,适合出版物
# 'seaborn-v0_8-darkgrid'  - 深色网格,适合演示
# 'ggplot'                 - R语言风格
# 'bmh'                    - Bayesian Methods风格
# 'fivethirtyeight'        - 538网站风格

# 应用样式
plt.style.use('seaborn-v0_8-whitegrid')

5.2 自定义样式配置

python 复制代码
import matplotlib.pyplot as plt

# 创建自定义样式配置
plt.rcParams.update({
    # 图形尺寸
    'figure.figsize': (10, 6),
    'figure.dpi': 100,
  
    # 字体设置
    'font.size': 11,
    'axes.titlesize': 14,
    'axes.labelsize': 12,
    'xtick.labelsize': 10,
    'ytick.labelsize': 10,
    'legend.fontsize': 10,
  
    # 线条设置
    'lines.linewidth': 2,
    'lines.markersize': 6,
  
    # 网格设置
    'axes.grid': True,
    'grid.alpha': 0.3,
    'grid.linestyle': '--',
  
    # 颜色循环
    'axes.prop_cycle': plt.cycler(color=['#2E86AB', '#A23B72', '#F18F01', '#C73E1D', '#6A994E']),
  
    # 保存设置
    'savefig.dpi': 300,
    'savefig.bbox': 'tight',
    'savefig.facecolor': 'white'
})

5.3 颜色映射(Colormap)选择指南

类型 用途 推荐色图
顺序型 从低到高的连续数据 viridis, plasma, Blues, Greens
发散型 有明确中心点的数据 RdBu, coolwarm, bwr
分类型 离散类别数据 Set1, Set2, tab10, Pastel1
感知均匀 色盲友好 viridis, cividis, magma
python 复制代码
import matplotlib.pyplot as plt
import numpy as np

# 展示不同色图效果
fig, axes = plt.subplots(2, 3, figsize=(15, 8))

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

cmaps = ['viridis', 'plasma', 'coolwarm', 'RdBu', 'Set1', 'tab10']

for ax, cmap in zip(axes.flat, cmaps):
    if cmap in ['Set1', 'tab10']:
        # 分类色图展示
        im = ax.imshow(Z > 0, cmap=cmap, aspect='auto')
    else:
        im = ax.imshow(Z, cmap=cmap, aspect='auto')
    ax.set_title(f'色图: {cmap}', fontsize=12)
    ax.axis('off')
    plt.colorbar(im, ax=ax, fraction=0.046, pad=0.04)

plt.suptitle('Matplotlib常用色图展示', fontsize=16, fontweight='bold')
plt.tight_layout()
plt.show()

5.4 中文显示配置

python 复制代码
import matplotlib.pyplot as plt
import matplotlib.font_manager as fm

# 方法1:使用rcParams全局设置
plt.rcParams['font.sans-serif'] = ['SimHei', 'Microsoft YaHei', 'Arial Unicode MS']
plt.rcParams['axes.unicode_minus'] = False  # 解决负号显示问题

# 方法2:查找系统中文字体
fonts = [f.name for f in fm.fontManager.ttflist if 'CJK' in f.name or 'Chinese' in f.name]
print("可用中文字体:", fonts[:10])

# 方法3:使用特定字体文件
# from matplotlib import font_manager
# font_path = 'C:/Windows/Fonts/simhei.ttf'
# prop = font_manager.FontProperties(fname=font_path)
# ax.set_title('中文标题', fontproperties=prop)

6. 多子图布局技巧

6.1 基础布局:subplots

python 复制代码
import matplotlib.pyplot as plt
import numpy as np

# 创建2x2子图,共享x轴
fig, axes = plt.subplots(2, 2, figsize=(12, 10), sharex=True, sharey=False)

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

# 子图1:正弦
axes[0, 0].plot(x, np.sin(x), color='#2E86AB', linewidth=2)
axes[0, 0].set_title('正弦函数')
axes[0, 0].grid(True)

# 子图2:余弦
axes[0, 1].plot(x, np.cos(x), color='#A23B72', linewidth=2)
axes[0, 1].set_title('余弦函数')
axes[0, 1].grid(True)

# 子图3:正切(限制y范围)
axes[1, 0].plot(x, np.tan(x), color='#F18F01', linewidth=2)
axes[1, 0].set_title('正切函数')
axes[1, 0].set_ylim(-5, 5)
axes[1, 0].grid(True)

# 子图4:指数
axes[1, 1].plot(x, np.exp(-x/3), color='#6A994E', linewidth=2)
axes[1, 1].set_title('指数衰减')
axes[1, 1].grid(True)

# 设置共享标签
fig.text(0.5, 0.02, 'x(弧度)', ha='center', fontsize=12)
fig.text(0.02, 0.5, 'y值', va='center', rotation='vertical', fontsize=12)

plt.suptitle('三角函数家族', fontsize=16, fontweight='bold', y=0.98)
plt.tight_layout(rect=[0.03, 0.03, 1, 0.96])
plt.show()

6.2 复杂布局:GridSpec

python 复制代码
import matplotlib.pyplot as plt
import matplotlib.gridspec as gridspec
import numpy as np

fig = plt.figure(figsize=(14, 10))

# 创建3x3网格,设置间距
gs = gridspec.GridSpec(3, 3, figure=fig, hspace=0.3, wspace=0.3,
                       left=0.05, right=0.95, top=0.95, bottom=0.05)

# 大图:占据左上2x2
ax1 = fig.add_subplot(gs[0:2, 0:2])
data = np.random.randn(1000).cumsum()
ax1.plot(data, color='#2E86AB', linewidth=1.5)
ax1.fill_between(range(len(data)), data, alpha=0.3, color='#2E86AB')
ax1.set_title('累积随机游走', fontsize=12, fontweight='bold')
ax1.grid(True, alpha=0.3)

# 右上:直方图
ax2 = fig.add_subplot(gs[0, 2])
ax2.hist(np.random.randn(1000), bins=20, color='#A23B72', edgecolor='white', alpha=0.8)
ax2.set_title('分布直方图', fontsize=10)

# 右中:散点图
ax3 = fig.add_subplot(gs[1, 2])
x, y = np.random.randn(2, 100)
ax3.scatter(x, y, c=y, cmap='viridis', alpha=0.6, edgecolors='black', linewidth=0.5)
ax3.set_title('散点分布', fontsize=10)

# 底部通栏:多线图
ax4 = fig.add_subplot(gs[2, :])
for i in range(5):
    ax4.plot(np.random.randn(100).cumsum(), label=f'系列{i+1}', linewidth=1.5)
ax4.set_title('多系列趋势对比', fontsize=12, fontweight='bold')
ax4.legend(loc='upper left', ncol=5)
ax4.grid(True, alpha=0.3)

plt.suptitle('复杂仪表板布局示例', fontsize=16, fontweight='bold', y=0.98)
plt.show()

6.3 子图布局速查表

布局需求 方法 示例代码
均匀网格 plt.subplots(nrows, ncols) fig, axes = plt.subplots(2, 3)
共享坐标轴 sharex/sharey参数 plt.subplots(2, 2, sharex=True)
非均匀布局 GridSpec gridspec.GridSpec(3, 3)
嵌套子图 fig.add_subplot() fig.add_subplot(gs[0:2, 0:2])
调整间距 plt.tight_layout() plt.tight_layout(pad=3.0)

7. 图表导出与保存

7.1 保存参数详解

python 复制代码
import matplotlib.pyplot as plt
import numpy as np

fig, ax = plt.subplots(figsize=(10, 6))
x = np.linspace(0, 10, 100)
ax.plot(x, np.sin(x), linewidth=2)
ax.set_title('示例图表')

# 高质量PNG(位图)
plt.savefig('chart.png', 
            dpi=300,              # 分辨率
            bbox_inches='tight',  # 去除多余空白
            facecolor='white',    # 背景色
            edgecolor='none',     # 边框
            format='png')

# 矢量图SVG(网页/印刷)
plt.savefig('chart.svg',
            bbox_inches='tight',
            facecolor='white')

# PDF(学术论文)
plt.savefig('chart.pdf',
            bbox_inches='tight',
            facecolor='white',
            metadata={'Creator': 'Matplotlib', 'Title': '示例图表'})

plt.show()

7.2 格式选择指南

格式 类型 优点 缺点 适用场景
PNG 位图 兼容性好,文件小 放大失真 网页、PPT
JPG 位图 照片压缩率高 有损压缩 照片类图表
SVG 矢量 无限缩放,可编辑 复杂图形文件大 网页、交互
PDF 矢量 印刷质量高 需要PDF阅读器 学术论文
EPS 矢量 LaTeX兼容 较老格式 LaTeX文档

8. 避坑小贴士

8.1 中文显示乱码

症状:中文显示为方框或乱码

解决方案

python 复制代码
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'] = ['SimHei', 'Microsoft YaHei']
plt.rcParams['axes.unicode_minus'] = False

8.2 图表元素重叠

症状:标题、标签、图例相互重叠

解决方案

python 复制代码
# 自动调整布局
plt.tight_layout()

# 或手动调整
plt.subplots_adjust(hspace=0.3, wspace=0.3, top=0.9)

8.3 颜色可读性问题

症状:颜色过于相近,色盲用户难以区分

解决方案

python 复制代码
# 使用色盲友好的色图
plt.set_cmap('viridis')  # 或 cividis, plasma

# 不仅依赖颜色,同时使用线型/标记
ax.plot(x, y1, 'o-', color='blue', label='系列1')
ax.plot(x, y2, 's--', color='red', label='系列2')

8.4 坐标轴误导

症状:截断Y轴导致趋势被夸大

正确做法

python 复制代码
# 折线图Y轴通常应从0开始
ax.set_ylim(0, None)

# 如果必须截断,使用断轴标记
from matplotlib.patches import FancyBboxPatch
# 添加断轴视觉提示

8.5 饼图使用不当

症状:类别过多,小扇区难以区分

解决方案

python 复制代码
# 只展示前N个,其余合并为"其他"
top_n = 5
other_sum = sizes[top_n:].sum()
plot_sizes = sizes[:top_n].tolist() + [other_sum]
plot_labels = labels[:top_n] + ['其他']

9. 实战练习

练习1:销售数据仪表板

创建一个包含以下元素的综合报表:

  • 月度销售额趋势折线图(含同比标注)
  • 产品类别占比环形图
  • 区域销售对比水平柱状图
  • 销售目标达成率仪表盘

练习2:学术图表复现

选择一篇顶级期刊(如Nature/Science)中的图表,使用Matplotlib复现,注意:

  • 字体大小和样式(通常使用无衬线字体)
  • 坐标轴刻度和标签位置
  • 图例位置和样式
  • 导出为300dpi的TIFF或PDF格式

练习3:交互式探索

使用以下代码模板,探索不同参数对图表的影响:

python 复制代码
import matplotlib.pyplot as plt
import numpy as np
from ipywidgets import interact

@interact(alpha=(0.1, 1.0, 0.1), bins=(5, 50, 5))
def explore_histogram(alpha=0.7, bins=20):
    data = np.random.randn(1000)
    plt.hist(data, bins=bins, alpha=alpha, color='skyblue', edgecolor='black')
    plt.title(f'Histogram: alpha={alpha}, bins={bins}')
    plt.show()

本章小结

核心概念回顾

概念 要点
可视化目的 模式识别、沟通效率、探索分析、决策支持
图表选择 按数据类型和分析目标选择最优图表
Matplotlib架构 脚本层、艺术家层、后端层三层模型
编程风格 面向对象风格推荐用于生产代码
样式定制 使用样式表、rcParams、颜色映射
布局技巧 subplots用于均匀布局,GridSpec用于复杂布局

进阶学习路径

  1. Seaborn:基于Matplotlib的统计可视化库
  2. Plotly:交互式可视化
  3. Altair:声明式可视化语法
  4. 数据可视化设计理论:《The Visual Display of Quantitative Information》

如果本章内容对你有帮助,欢迎点赞、收藏、评论交流。你的支持是我持续创作的动力!

相关推荐
NGC_66112 小时前
Java基础面试题2
java·开发语言·python
vx-程序开发2 小时前
springboot具备推荐和预警机制的大学生兼职平台的设计与实现-计算机毕业设计源码17157
java·c++·spring boot·python·spring·django·php
EnCi Zheng2 小时前
11a. 阿里云大模型API调用基础
人工智能·python·阿里云·云计算
MoRanzhi12033 小时前
Pillow 图像算术运算与通道计算
图像处理·人工智能·python·计算机视觉·pillow·图像差异检测·图像算术运算
怪侠_岭南一只猿3 小时前
爬虫阶段三实战练习题二:使用 Selenium 模拟爬取拉勾网职位表
css·爬虫·python·selenium·html
前端付豪3 小时前
自动学习建议解决薄弱知识点
前端·python·openai
deephub3 小时前
LangGraph vs Semantic Kernel:状态图与内核插件的两条技术路线对比
人工智能·python·深度学习·大语言模型·agent
与虾牵手3 小时前
多轮对话 API 怎么实现?从原理到代码,踩完坑我总结了这套方案
python·aigc·ai编程
geovindu3 小时前
python: Simple Factory Pattern
开发语言·python·设计模式·简单工厂模式