Matplotlib 布局引擎:为什么推荐 constrained_layout 而不是 tight_layout
为什么选择 constrained_layout 而不是 tight_layout ?
-
证据 1
constrained_layout是2019年引入的新引擎,而 tight_layout 是2013年引入的老引擎,
matplotlib/layout_engine.py第 13-18 行明确写道:Matplotlib has two built-in layout engines: - `.TightLayoutEngine` was the first layout engine added to Matplotlib. See also :ref:`tight_layout_guide`. - `.ConstrainedLayoutEngine` is more modern and generally gives better results. See also :ref:`constrainedlayout_guide`. -
证据 2
tight_layout 画完图后,临时生硬地挤压子图,而constrained_layout 在画图过程中,智能、弹性地分配空间,
_constrained_layout.py第 1-47 行详细描述了算法:- 使用
GridSpec进行约束 - 通过求解器(solver)计算最优布局
- 在绘制阶段就保证内容完整
- 使用
-
证据3 代码优雅度
ConstrainedLayoutEngine通过execute()方法在每次draw()时自动调用,不需要手动干预,而 tight_layout 每次画图后手动调用。
constrained_layout 的缺点
- 复杂布局可能失败,会给出警告而非静默出错,
_constrained_layout.py第 43-44 行:It's possible that the margins take up the whole figure, in which case the algorithm is not applied and a warning is raised. - 性能开销大,CL 在每次
draw()时都执行(layout_engine.py第 5-6 行),对于大量子图确实有开销。
使用方法
-
使用其对应的参数:subplots、figure、subplot_mosaic,例如:
plt.subplots(layout="constrained") -
通过rcParams激活,例如:
plt.rcParams['figure.constrained_layout.use'] = True"figure.constrained_layout.use": True, "savefig.bbox": "standard", # 保持默认,确保导出尺寸 = figsize- bbox_inches=“tight” 是向内裁剪,pad_inches 是外向填充,pad_inches 依赖 bbox_inches=“tight”,如果bbox_inches=“standard”,那么 pad_inches 失效
- "figure.constrained_layout.use"为True就是启用约束布局:自动协调子图/标签间距,并确保导出尺寸严格等于 figsize(需保持 savefig.bbox 为默认值 None,避免被 “tight” 覆盖导致尺寸偏差)
根据源码
matplotlib/rcsetup.py第 555-566 行的validate_bbox函数def validate_bbox(s): if isinstance(s, str): s = s.lower() if s == 'tight': return s if s == 'standard': return None raise ValueError("bbox should be 'tight' or 'standard'") elif s is not None: # Backwards compatibility. None is equivalent to 'standard'. raise ValueError("bbox should be 'tight' or 'standard'") return s与第 1276-1277 行
"savefig.bbox": validate_bbox, # "tight", or "standard" (= None) "savefig.pad_inches": validate_float,可知:
savefig.bbox的有效值
设置值 内部存储 实际效果 'tight''tight'裁剪到内容边界 + 应用 pad_inches 'standard'None使用完整 figsize,不裁剪 NoneNone等同于 'standard'savefig.pad_inches的有效值 只能是浮点数
savefig(bbox_inches="tight", pad_inches="layout")与"savefig.pad_inches"有何不同
matplotlib/backend_bases.py 第 2090-2169 行
pad_inches : float or 'layout', default: :rc:`savefig.pad_inches`
matplotlib/backend_bases.py 第 2159-2169 行
if bbox_inches == "tight": # 第一层:必须 tight
bbox_inches = self.figure.get_tightbbox(...)
if (isinstance(layout_engine, ConstrainedLayoutEngine) and # 第二层:必须 CL
pad_inches == "layout"):
h_pad = layout_engine.get()["h_pad"] # ← 只有两个条件同时满足才走到这里
w_pad = layout_engine.get()["w_pad"]
else:
# 缺任何一个,都回退到这里
pad_inches = rcParams['savefig.pad_inches']
h_pad = w_pad = pad_inches
rcParams['savefig.pad_inches'] = "layout"只接受数字,savefig(bbox_inches="tight", pad_inches="layout")支持"layout"savefig(bbox_inches="tight", pad_inches="layout")往往与figsize相差较大,除非 仅使用ConstrainedLayoutEngine 处理不好,再考虑使用- 使用方法:
pad_inches="layout" 生效 ├── 必须 bbox_inches="tight" └── 必须使用 ConstrainedLayoutEngine ├── "figure.constrained_layout.use": True └── 或 layout="constrained"(创建 figure 时)"figure.constrained_layout.use": True # 或 layout="constrained"(创建 figure 时) savefig(bbox_inches="tight", pad_inches="layout") # bbox_inches="tight" 是向内裁剪,pad_inches是外向填充,pad_inches依赖 bbox_inches="tight",如果bbox_inches="standard",那么 pad_inches失效
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐


所有评论(0)