Skip to content

Matplotlib savefig 保存图片:标签截断、bbox_inches 与空白图修复

发布于

更新于

针对 Matplotlib savefig 的中文排障:用 bbox_inches='tight' 修复标签截断,设置 DPI/PNG/SVG/PDF,并避免 plt.show() 后保存空白图。

如果你搜索的是 Matplotlib 如何保存图片,先记住这个组合:fig.savefig("plot.png", dpi=300, bbox_inches="tight")。它能解决多数标签被截断、边距异常和导出分辨率不够的问题。

这篇中文版本不和官方 API 文档竞争完整参数表,而是聚焦真实排障:bbox_inches='tight' 什么时候该用、layout="constrained" 什么时候更稳、如何避免 plt.show() 后保存出空白图,以及 PNG/SVG/PDF/DPI 怎么选。

savefig 快速排障

fig.savefig(
    "plot.png",
    dpi=300,
    bbox_inches="tight",
    pad_inches=0.1,
)
你遇到的问题优先尝试
标签、标题、图例被截断bbox_inches="tight"
新写的绘图代码plt.subplots(layout="constrained")
保存后图片是空白savefig(),再 plt.show()
边框空白太多bbox_inches="tight", pad_inches=0
需要论文或报告高清图dpi=300 或保存为 SVG/PDF

plt.show() 后图片空白:先保存再显示

如果 plt.show() 之后再调用 savefig(),某些后端会关闭或清空当前 figure,导致保存出来是空白图。最稳妥的写法是先保存,再显示:

fig, ax = plt.subplots()
ax.plot([1, 2, 3], [1, 4, 9])
fig.savefig("chart.png", dpi=300, bbox_inches="tight")
plt.show()

🧠 这是怎么回事?

当标签超出坐标轴范围时,Matplotlib 不会自动扩展画布大小。 常见原因包括:

  • LaTeX 表达式渲染出高度较大的符号
  • 设置了很大的 fontsize
  • 标签很长或刻度标签被旋转
  • 子图网格太紧凑,留白不足

示例:

matplotlib-savefig-label-clipping-example

import matplotlib.pyplot as plt
 
plt.figure()
plt.ylabel(r'$\ln\left(\frac{x_a-x_b}{x_a-x_c}\right)$')
plt.xlabel(r'$\ln\left(\frac{x_a-x_d}{x_a-x_e}\right)$', fontsize=50)
plt.title('Example with matplotlib 3.4.2\nLabel clipping example')
plt.show()

在屏幕上显示时 ylabel 没问题,但保存成文件时,xlabel 往往会被截掉一部分


✅ 1. 现代首选方案:使用 layout="constrained"(推荐)

在当前 Matplotlib 中,推荐优先使用更明确的 layout="constrained"

fig, ax = plt.subplots(layout="constrained")

示例:

matplotlib-constrained-layout-example.png

fig, ax = plt.subplots(figsize=(7, 5), layout="constrained")
ax.set_xlabel("Very long bottom label that usually gets clipped", fontsize=16)
ax.set_ylabel("Tall math label:\n$\\frac{x_a - x_b}{x_c}$")
fig.savefig("figure.png")

✔ 优点

  • 现代、稳定
  • tight_layout() 更好用
  • 对 colorbar、legend 和多子图布局的支持更好

⚠ 缺点

  • 在子图很多的大型网格上,计算会稍微慢一点

如果你在写新的 Matplotlib 代码,这应该是你的默认选择


✅ 2. 用 subplots_adjust 手动调节边距

这仍然是一个简单而有效的方法:

plt.subplots_adjust(bottom=0.15)

或者在 figure 上调用:

plt.gcf().subplots_adjust(bottom=0.18)

逐步增大边距参数,直到标签不再被截断或重叠。

matplotlib-subplots-adjust-margins.png


✅ 3. 使用 tight_layout()(较旧但仍实用)

tight_layout() 会自动调整内边距:

fig, axes = plt.subplots(ncols=2, nrows=2, figsize=(8, 6))
for ax in axes.flatten():
    ax.set_xlabel("Example X label")
    ax.set_ylabel("Example Y label")
 
plt.tight_layout()
plt.show()

说明

  • 适合结构简单的图
  • 和 legend、colorbar 一起时可能不够稳定
  • 现在一般优先推荐 layout="constrained"

✅ 4. 保存时使用 bbox_inches="tight"(非常好用的快速修复)

这是一个修复裁剪问题很常见的写法:

plt.savefig("myfile.png", bbox_inches="tight")

适用场景

  • 想快速修复问题,又不想改布局代码
  • 希望文件中包含和屏幕上显示一致的所有内容

matplotlib-tight-layout-subplots.png


✅ 5. 使用 rcParams 开启自动布局

如果你想要一个对所有图都生效的“全局解决方案”: matplotlib-bbox-inches-tight-example.png

在运行时更新 rcParams:

from matplotlib import rcParams
rcParams.update({"figure.autolayout": True})

或者在 matplotlibrc 文件中配置:

figure.autolayout : True

这样可以在不同机器和环境之间保持输出行为的一致性。


📌 总结表:应该用哪种方法?

方法什么时候用最适合的场景
layout="constrained"首选默认方案现代布局、多子图、legend 等
bbox_inches='tight'导出文件时需要快速修复单图导出
tight_layout()维护旧代码、历史代码简单的子图网格
subplots_adjust()需要完全手动控制布局、精细排版论文/期刊级别的排版微调
figure.autolayout=True想设置为项目级默认行为多机器、多环境下保证一致性

💡 让图像更完美的一些小技巧

✔ 提高 DPI,减少长标签导致的裁剪问题

plt.savefig("fig.png", dpi=200, bbox_inches="tight")

✔ 除非必要,不要用过大的字体

字体过大时,更容易让标签伸出绘图区域,增加裁剪风险。

✔ 对 colorbar:优先使用 constrained_layout

在包含 colorbar 的布局中,它的表现通常明显优于 tight_layout


📊 用 PyGWalker 构建可视化,无需手动调布局

如果你主要是为了可视化 DataFrame 而使用 Matplotlib,其实很多时候可以不必自己调布局。

你可以直接:

  • 加载 DataFrame
  • 拖拽字段
  • 即刻生成各种图表

借助开源可视化工具 PyGWalker

PyGWalker for Data visualization (opens in a new tab)

使用方式示例:

pip install pygwalker
import pygwalker as pyg
gwalker = pyg.walk(df)

也可以在线体验:

KaggleGoogle ColabGitHub

常见问题

  1. Matplotlib 保存图片时标签被截断怎么办? 最快的修复是 fig.savefig("plot.png", bbox_inches="tight")。如果是新代码,优先在创建图像时使用 plt.subplots(layout="constrained")

  2. bbox_inches="tight" 是什么意思? 它会在保存时重新计算导出区域,把坐标轴标签、标题、图例和注释等可见元素包含进去。

  3. 什么时候用 layout="constrained",什么时候用 bbox_inches='tight' 新写绘图代码时用 layout="constrained";已经生成好的图想快速导出完整内容时,用 bbox_inches='tight'

  4. 为什么 plt.show() 后保存图片是空白? 有些后端会在 plt.show() 后关闭或注销当前 figure。请先调用 fig.savefig(...)plt.savefig(...),再调用 plt.show()

  5. 保存 PNG 应该用多少 DPI? 网页和演示一般用 150 DPI,报告和打印用 300 DPI;如果需要矢量图,优先保存 SVG 或 PDF。

相关指南