如何调整图形与表格的布局比例,并避免 plt.savefig() 保存图像时被裁剪?
可以用 plt.subplots() 创建左右两个子图,通过 gridspec_kw={"width_ratios": [2, 1]} 设置宽度比例,左侧放折线图,右侧放表格。这样就不需要使用 subplot2grid()。保存时,将目录和文件名合成一个完整路径传入,并设置 bbox_inches="tight",使导出范围包含图形和表格。
原来的布局为什么容易被裁剪?
这段代码把表格放在了绘图区右侧:
the_table = plt.table(
cellText=df.to_numpy(),
colLabels=df.columns,
loc="top",
bbox=[1.1, 0, 1, 1],
)
bbox 的格式是 [left, bottom, width, height],这里使用 Axes 坐标:绘图区左下角是 (0, 0),右上角是 (1, 1)。
[1.1, 0, 1, 1] 表示表格左边缘在绘图区右侧以外,距离为绘图区宽度的 0.1 倍;表格本身与绘图区等宽、等高,所以两者看起来各占一半。把表格画在绘图区外,并不会让 Figure 画布自动变宽,超出保存范围的部分就可能被裁掉。
原来的保存调用也有问题:
plt.savefig(path, "table_test.png")
savefig() 不接受用两个位置参数分别传入目录和文件名,这样调用会报错。需要先把目录和文件名拼成一个路径。
用两个子图设置 2∶1 的宽度比例
将图形和表格分别放在独立的 Axes 中,就能直接控制两者的布局,表格也不必放到绘图区外。
from pathlib import Path
import pandas as pd
import matplotlib.pyplot as plt
df = pd.DataFrame({
"Month": [
"Jan", "Feb", "Mar", "Apr", "May", "Jun",
"Jul", "Aug", "Sept", "Oct", "Nov", "Dec"
],
"2024": [
1945, 1290, 1662, 1500, 1355, 1469,
1209, 1429, 1662, 1350, 1525, 1625
],
"2025": [
1695, 1767, 1475, 1518, 1556, 1441,
1467, 1557, 1421, 1460, 950, 715
],
})
fig, (ax_plot, ax_table) = plt.subplots(
nrows=1,
ncols=2,
figsize=(12, 5),
gridspec_kw={"width_ratios": [2, 1]},
constrained_layout=True,
)
# 左侧:折线图
ax_plot.plot(df["Month"], df["2024"], color="green", label="2024")
ax_plot.plot(df["Month"], df["2025"], color="red", label="2025")
ax_plot.set_title("Revenues")
ax_plot.legend()
# 右侧:表格
ax_table.set_axis_off()
the_table = ax_table.table(
cellText=df.to_numpy(),
colLabels=df.columns,
cellLoc="center",
bbox=[0, 0, 1, 1],
)
the_table.auto_set_font_size(False)
the_table.set_fontsize(10)
# 保存到当前目录
output_file = Path("table_test.png")
fig.savefig(
output_file,
dpi=300,
bbox_inches="tight",
pad_inches=0.1,
)
plt.show()
几个参数的作用:
width_ratios=[2, 1]将两个子图区域的宽度比设为2∶1。ax_table.set_axis_off()隐藏表格所在子图的坐标轴。bbox=[0, 0, 1, 1]让表格填满右侧 Axes。constrained_layout=True自动调整子图间距,为标题、刻度等内容留出空间。
这里的 2∶1 是两个 Axes 区域的宽度比例。整张图片还包含页边空白、子图间距和刻度文字,因此最终图片的像素宽度并不会严格按三等分分配。
保存时如何包含完整内容?
保存时可以这样设置:
fig.savefig(
output_file,
bbox_inches="tight",
pad_inches=0.1,
)
bbox_inches="tight" 根据参与边界计算的图形元素确定保存范围,pad_inches=0.1 则在这个范围外留出 0.1 英寸的空白。
如果 path 是输出目录,需要先拼接文件名:
output_file = Path(path) / "table_test.png"
fig.savefig(output_file, bbox_inches="tight", pad_inches=0.1)
输出目录需要事先存在。如果 path 已经是包含文件名的完整路径,直接传入即可:
fig.savefig(path, bbox_inches="tight", pad_inches=0.1)
如果仍然把表格放在绘图区外,可以显式将表格加入保存边界计算:
plt.savefig(
"table_test.png",
bbox_inches="tight",
bbox_extra_artists=[the_table],
pad_inches=0.1,
)
当表格没有被自动计入保存范围时,可以使用这种写法;图形与表格的宽度比例仍需另外设置。
使用时还要注意什么?
bbox_inches="tight" 只负责确定导出范围,无法解决文字重叠或表格列宽不足的问题。表格内容拥挤时,可以增大 figsize、减小字体,或调整列宽。提高 dpi 只能提高位图输出分辨率,不能修复布局。
建议用 fig.savefig() 明确保存对应的 Figure,并在 plt.show() 之前保存。原代码中的 print(plt) 只会输出模块信息;显示图像应使用 plt.show()。
备注:内容仅供参考。
