📊 阅读时长:12分钟 | 关键词:Matplotlib、subplot子图、axes画图中图、savefig保存、动态图

引言

一篇论文或报告中,常常需要把多张图放在一起对比。Matplotlib 提供了 subplot() 排布子图和 axes() 画图中图两种方式,最后用 savefig() 保存为图片文件。这是 Matplotlib 系列的收官篇。

一、plt.subplot() 创建子图

在一个画布上按"行 × 列"的网格排布多个子图:

plt.subplot(2, 2, 1)    2行 × 2列,第1个位置
plt.subplot(2, 2, 2)    2行 × 2列,第2个位置
plt.subplot(2, 2, 3)    2行 × 2列,第3个位置
plt.subplot(2, 2, 4)    2行 × 2列,第4个位置

┌─────────┬─────────┐
│   (1)   │   (2)   │
├─────────┼─────────┤
│   (3)   │   (4)   │
└─────────┴─────────┘
import matplotlib.pyplot as plt
import numpy as np

plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False

x = np.linspace(-3, 3, 50)
y1 = 2*x + 1
y2 = x**2
y3 = np.sin(x)
y4 = np.tan(x)

plt.figure(figsize=(10, 8))

# 2行2列,第1个
plt.subplot(2, 2, 1)
plt.plot(x, y1)
plt.title('直线')

# 2行2列,第2个
plt.subplot(2, 2, 2)
plt.plot(x, y2, color='red')
plt.title('抛物线')

# 2行2列,第3个
plt.subplot(2, 2, 3)
plt.plot(x, y3, color='green')
plt.title('正弦曲线')

# 2行2列,第4个
plt.subplot(2, 2, 4)
plt.plot(x, y4, color='orange')
plt.title('正切曲线')

plt.tight_layout()    # 自动调整子图间距
plt.show()

参数plt.subplot(nrows, ncols, index)

参数 说明
nrows 行数
ncols 列数
index 第几个子图(从 1 开始,按行从左到右编号)
不规则布局

子图不必占满规则网格——可以在部分位置画图:

plt.figure(figsize=(10, 6))

# 2行1列,第1个(占上半部分整行)
plt.subplot(2, 1, 1)
plt.plot(x, y1, color='blue')
plt.title('直线')

# 2行3列,第4个(下半部分左侧)
plt.subplot(2, 3, 4)
plt.plot(x, y2, color='red')
plt.title('抛物线')

# 2行3列,第5个(下半部分中间)
plt.subplot(2, 3, 5)
plt.plot(x, y3, color='green')
plt.title('正弦曲线')

# 2行3列,第6个(下半部分右侧)
plt.subplot(2, 3, 6)
plt.plot(x, y4, color='orange')
plt.title('正切曲线')

plt.tight_layout()
plt.show()
┌────────────────────────────┐
│          (1) 上半部         │
│        2行1列 第1个         │
├─────────┬────────┬─────────┤
│  (4)    │  (5)   │   (6)   │
│ 2行3列  │ 2行3列 │ 2行3列  │
│ 第4个   │ 第5个  │ 第6个   │
└─────────┴────────┴─────────┘

💡 技巧:上半用 subplot(2,1,1),下半用 subplot(2,3,4)subplot(2,3,6),Matplotlib 自动对齐。

二、plt.axes() 画图中图

axes() 不强求网格布局,而是在画布的任意位置上独立放置一个坐标系:

x = np.linspace(-3, 3, 50)
y1 = 2*x + 1
y2 = x**2
y3 = np.sin(x)

plt.figure(figsize=(8, 6))

# 主图:占画布 80%,左下角在 (10%, 10%) 位置
plt.axes([0.1, 0.1, 0.8, 0.8])
plt.title('直线')
plt.plot(x, y1)

# 小图1:占画布 25%,放在右上角 (20%, 60%) 位置
plt.axes([0.2, 0.6, 0.25, 0.25])
plt.title('抛物线')
plt.plot(x, y2, color='red')

# 小图2:占画布 25%,放在右下角 (60%, 20%) 位置
plt.axes([0.6, 0.2, 0.25, 0.25])
plt.plot(x, y3, color='green')
plt.title('余弦曲线')

plt.show()
[0.1, 0.1, 0.8, 0.8] 这四个数字的含义:

  0.1, 0.1  → 坐标框左下角在画布 10%, 10% 的位置
  0.8, 0.8  → 坐标框的宽和高都是画布的 80%

💡 axes() 适合"主图 + 局部放大"、"主图 + 辅助子图"这类非规则布局。

三、plt.savefig() 保存图像

plt.figure()
x = np.linspace(-3, 3, 50)
plt.plot(x, np.sin(x), color='blue')
plt.title('正弦曲线')

# 保存到文件
plt.savefig('./sine_wave.jpg')
plt.savefig('./sine_wave.png', dpi=300)          # 高分辨率 PNG
plt.savefig('./sine_wave.svg')                    # 矢量图(放大不失真)
参数 说明
fname 文件路径,后缀决定格式(.jpg / .png / .svg / .pdf
dpi 分辨率,默认 100,设 300 适合印刷
bbox_inches 'tight' 自动裁剪白边
facecolor 背景颜色

四、bonus:动态图(plt.pause)

数据变化时,可以用 plt.pause()plt.clf() 做简单的动画效果:

y2 = []
y1 = np.linspace(-3, 3, 50)

for i in y1**2:
    y2.append(i)
    plt.clf()              # 清除上一次的数据
    plt.plot(y2)
    plt.pause(0.1)          # 暂停 0.1 秒
    # 你会看到曲线一段一段"生长"出来

plt.savefig('./parabola.jpg')
  • plt.clf() = clear figure,清除当前画布
  • plt.pause(seconds) = 暂停指定的秒数

小结

函数 用途 用法
plt.subplot(r, c, i) 规则网格布局 2×2 四宫格、1×3 横向排列
plt.axes([l, b, w, h]) 任意位置放坐标系 主图+局部放大、画图中图
plt.savefig(path) 保存为图片文件 png/jpg/svg/pdf 多种格式
plt.clf() + plt.pause() 动态更新 简单动画效果

🎉 Matplotlib 系列完结

篇目 内容
(一) plt.plot() 基础绘图、figure 画布、中文显示
(二) 坐标轴设置、spines 边框、legend 图例、text 标注
(三) scatter 散点图、bar 条形图、imshow 热力图
(四) subplot 子图、axes 画图中图、savefig 保存

掌握了这 4 篇,日常数据可视化基本够了。之后遇到更高级的需求(3D 图、交互式图表),Seaborn 和 Plotly 会是好帮手。


本文是「Python从入门到数据分析」系列的第 22 篇,也是 Matplotlib 系列的终篇。🎯 全系列 22 篇文章,从 Python 基础变量到数据分析可视化,完整覆盖了"入门到数据分析"的全路径。

📚 全系列导航
Python 基础 → 函数/模块/面向对象 → NumPy → Pandas → Matplotlib

更多推荐