一、子图
1.plt.subplots() 绘制均匀状态下的子图
(1)核心参数
| 参数 | 作用 |
|---|---|
nrows, ncols |
子图的行数、列数(第一个数为行,第二个为列) |
figsize |
整个画布的大小,格式为 (宽, 高),单位英寸 |
sharex/sharey |
是否共享横 / 纵轴刻度,True 表示所有子图共用一套刻度 |
tight_layout() |
自动调整子图间距,避免标题、坐标轴标签重叠 |
(2)示例代码
# 1. 创建2行5列的画布,指定大小,共享xy轴
fig, axs = plt.subplots(2, 5, figsize=(10, 4), sharex=True, sharey=True)
# 2. 给整个画布加总标题,字号20
fig.suptitle('样例1', size=20)
# 3. 双层循环遍历每个子图(i行j列)
for i in range(2):
for j in range(5):
# 4. 在当前子图绘制散点图,用随机数生成数据
axs[i][j].scatter(np.random.randn(10), np.random.randn(10))
# 5. 给每个子图加标题,标注行号列号
axs[i][j].set_title('第%d行,第%d列'%(i+1,j+1))
# 6. 统一设置xy轴范围,保证所有子图刻度一致
axs[i][j].set_xlim(-5,5)
axs[i][j].set_ylim(-5,5)
# 7. 仅给最后一行加x轴标签,仅给第一列加y轴标签,避免重复
if i==1: axs[i][j].set_xlabel('横坐标')
if j==0: axs[i][j].set_ylabel('纵坐标')
# 8. 自动调整子图布局,防止文字重叠
fig.tight_layout()
效果:生成 2 行 ×5 列 共 10 个完全均匀的散点子图,所有子图共享 xy 轴,仅最后一行显示 x 轴标签、第一列显示 y 轴标签,布局整齐,无文字重叠。

2.极坐标子图 projection='polar'
除了常规直角坐标系,Matplotlib 支持通过 projection='polar' 创建极坐标图表:
示例代码
import numpy as np
import matplotlib.pyplot as plt
N = 150
# 生成半径r(0~2)
r = 2 * np.random.rand(N)
# 生成角度theta(0~2π)
theta = 2 * np.pi * np.random.rand(N)
# 点的面积与半径平方成正比,越远的点越大
area = 200 * r**2
# 用角度作为颜色映射的依据
colors = theta
# 创建极坐标子图
fig, ax = plt.subplots(subplot_kw={'projection': 'polar'}, figsize=(8, 8))
# 绘制极坐标散点图,用hsv色盘,设置透明度0.75
scatter = plt.scatter(theta, r,c=colors,s=area,cmap='hsv',alpha=0.75)
plt.show()
效果:生成极坐标散点图,点的大小随半径增大而变大,颜色随角度变化,常用于方向、角度相关的数据可视化。

3.使用GridSpec 绘制非均匀子图
(1)作用
GridSpec 可以实现非均匀子图布局,包含两种场景:
- 子图大小不同,但不跨行 / 跨列
- 子图跨行 / 跨列,实现合并效果
- 核心参数:
width_ratios(列宽比例)、height_ratios(行高比例),通过切片spec[i,j]实现子图合并
(2)示例
(a)非均匀大小(不跨行 / 列)
# 1. 创建画布
fig = plt.figure(figsize=(10, 4))
# 2. 创建2行5列的网格,指定列宽比例[1,2,3,4,5],行高比例[1,3]
spec = fig.add_gridspec(nrows=2, ncols=5, width_ratios=[1,2,3,4,5], height_ratios=[1,3])
fig.suptitle('样例2', size=20)
for i in range(2):
for j in range(5):
# 3. 按网格位置添加子图
ax = fig.add_subplot(spec[i, j])
ax.scatter(np.random.randn(10), np.random.randn(10))
ax.set_title('第%d行,第%d列'%(i+1,j+1))
# 4. 仅最后一行加x轴标签,第一列加y轴标签
if i==1: ax.set_xlabel('横坐标')
if j==0: ax.set_ylabel('纵坐标')
fig.tight_layout()
效果:生成 2 行 5 列子图,列宽从左到右按 1:2:3:4:5 递增,行高按 1:3(第二行更高),子图大小完全自定义,不改变行列结构。
(b)跨行 / 跨列合并子图
# 1. 创建2行6列的网格,自定义列宽、行高比例
fig = plt.figure(figsize=(10, 4))
spec = fig.add_gridspec(nrows=2, ncols=6, width_ratios=[2,2.5,3,1,1.5,2], height_ratios=[1,2])
fig.suptitle('样例3', size=20)
# sub1:第0行,前3列(:3),合并成一个宽子图
ax = fig.add_subplot(spec[0, :3])
ax.scatter(np.random.randn(10), np.random.randn(10))
# sub2:第0行,第3-4列(3:5),合并成一个中等宽度子图
ax = fig.add_subplot(spec[0, 3:5])
ax.scatter(np.random.randn(10), np.random.randn(10))
# sub3:第5列,所有行(:,5),合并成一个高子图
ax = fig.add_subplot(spec[:, 5])
ax.scatter(np.random.randn(10), np.random.randn(10))
# sub4:第1行,第0列,单独子图
ax = fig.add_subplot(spec[1, 0])
ax.scatter(np.random.randn(10), np.random.randn(10))
# sub5:第1行,第1-4列(1:5),合并成一个大宽子图
ax = fig.add_subplot(spec[1, 1:5])
ax.scatter(np.random.randn(10), np.random.randn(10))
fig.tight_layout()
效果:通过切片语法 spec[行范围, 列范围] 实现子图合并,比如 spec[0, :3] 表示第 0 行、前 3 列合并,最终生成完全自定义的非均匀布局,满足复杂可视化需求。

tight_layout()必加:只要有多个子图,一定要调用这个方法,避免标题、标签重叠。- 共享轴刻度 :当子图数据范围一致时,用
sharex=True/sharey=True统一刻度,提升可读性。- 切片语法 :
GridSpec的切片和 Python 列表切片完全一致,start:end左闭右开,:表示全部。- 比例设置 :
width_ratios/height_ratios是相对比例,不是绝对像素,画布缩放时比例保持不变。
特性 plt.subplots()GridSpec布局灵活性 仅支持均匀网格 支持非均匀大小、跨行 / 跨列,完全自定义 适用场景 简单、规则的子图布局 复杂、非规则的子图布局 代码复杂度 简单,适合新手 稍复杂,适合进阶需求 核心优势 快速生成,代码简洁 布局高度灵活,适配复杂可视化
二.子图上的方法
1.Axes 与 plt 的关系
- plt(pyplot):类似 MATLAB 的接口,操作全局画布,适合快速出图。
- ax(Axes 对象) :具体的子图对象,推荐在 Jupyter/DSW 中优先使用 ax,能精准控制单个子图,避免全局混乱。
- 通用逻辑 :ax 上的方法和 plt 完全同名,只是调用方式从
plt.xxx()变成了ax.xxx()。
2.基础绘图方法(ax 上的各类图表)
| 方法 | 作用 | 代码示例 | 关键参数说明 |
|---|---|---|---|
| plot | 绘制折线 / 曲线 | ax.plot([1,2], [2,1]) |
传入 x、y 数据列表 |
| hist | 绘制直方图 | ax.hist(np.random.randn(1000)) |
输入数据数组,自动分箱统计 |
| scatter | 散点图 | 见前文 | x, y 坐标,点的大小 (s)、颜色 (c) |
| bar/barh | 柱状图 / 水平柱状图 | ax.bar(x, height) |
x 轴位置,柱高,宽度 |
| pie | 饼图 | ax.pie(values) |
数值列表,标签 labels |
3.辅助线与网格(精修图表)
(1)绘制辅助线
| 方法 | 类型 | 代码示例 | 含义 |
|---|---|---|---|
| axhline | 水平辅助线 | ax.axhline(y=0.5, xmin=0.2, xmax=0.8) |
在 y=0.5 处画一条水平线,范围 xmin 到 xmax |
| axvline | 垂直辅助线 | ax.axvline(x=0.5, ymin=0.2, ymax=0.8) |
在 x=0.5 处画一条垂直线 |
| axline | 任意直线 | axline([0,0],[1,1]) |
绘制穿过 (0,0) 和 (1,1) 的直线 |
(2)添加网格
ax.grid(True) # 显示灰色网格
- 进阶参数:
axis='x'只显示 x 轴网格,linestyle='--'修改虚线样式。
4.轴与标题的设置(规范坐标)
利用 ax 对象可以精准控制坐标轴的刻度、范围和名称:
ax.set_xscale('log') # 设置x轴为对数坐标(普通坐标为linear)
ax.set_title('子标题1') # 设置子图标题
ax.set_xlabel('对数坐标') # 设置x轴标签
ax.set_ylabel('普通坐标') # 设置y轴标签
效果对比
- 左图 :x 轴采用对数刻度(
10^0, 10^1, 10^2...),数据增长呈指数级展示。 - 右图:x 轴采用普通线性刻度,数据呈直线增长。
5.注释与标注
除了基础绘图,ax 支持添加丰富的文本和箭头注释:
(1)绘制箭头
ax.arrow(x=0, y=0, dx=1, dy=1, head_width=0.03, facecolor='red')
dx/dy:箭头的长度和方向。head_width/head_length:箭头头部的大小。
(2)添加普通文字
ax.text(x=0, y=0, s='这是一段文字', color='green', rotation=70)
rotation:文字旋转角度。
(3)带箭头的注释(最常用)
ax.annotate('这是中点',
xy=(0.5, 0.5), # 箭头指向的位置
xytext=(0.8, 0.2),# 文字位置
arrowprops=dict(facecolor='yellow', edgecolor='black')) # 箭头样式
6.图例与位置控制(legend)
(1)基础用法
先在绘图时指定 label,再通过 ax.legend() 显示:
ax.plot([1,2], [2,1], label="line1")
ax.plot([1,1], [1,2], label="line2")
ax.legend(loc=1)
(2)loc 参数对照表
| string | code | 位置说明 |
|---|---|---|
best |
0 |
最佳位置(自动避开数据重叠) |
upper right |
1 |
右上角(默认位置) |
upper left |
2 |
左上角 |
lower left |
3 |
左下角 |
lower right |
4 |
右下角 |
right |
5 |
右侧(垂直居中) |
center left |
6 |
左侧居中 |
center right |
7 |
右侧居中 |
lower center |
8 |
底部居中 |
upper center |
9 |
顶部居中 |
center |
10 |
正中心 |
