You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Matplotlib子图作文本容器时tight_layout大文本下布局失效问题

Matplotlib布局问题:tight_layout下文本换行导致子图超出边界

问题描述

在Matplotlib中,将subfigure作为文本载体时,启用tight_layout且文本量较大时会出现布局失效问题:子图会超出figure的边界,仿佛文本并未换行。

复现代码

import pandas as pd
from matplotlib import pyplot as plt

# Paramters for A4 Paper
fullheight = 11.69
fullwidth = 8.27

# how the subfigures dive the space
fig0_factor = 0.7
fig1_factor = 0.3

# generate the figure
fig = plt.figure(constrained_layout = True, figsize=(fullwidth, fullheight)) 

# generate 2 subfigures
subfigs = fig.subfigures(2,height_ratios=[fig0_factor,fig1_factor])


# fill the fist subfigure
axes = subfigs[0].subplots(nrows=1)
# some plot
ax = plt.plot([0,0],[-1,1], lw=1, c='b', figure=subfigs[0])
# some text
subfigs[0].text(0.55, 0.00001, 'Figure 1', ha='center', va='center', rotation='horizontal',weight='bold')

# fill the second subfigure
text_ax = subfigs[1].subplots(1)
# make its background transparent
subfigs[1].patch.set_alpha(0.0)
# remove the axis, not removing it makes no difference regarding the problem
text_ax.set_axis_off()

# generate some text
message = ['word']*50 # 50 is enough to make the problem visable, my usecase has a way longer text
message = ' '.join(message)    

# fill in the Text and wrap it
text_ax.text(0.00001, 0.8, message, horizontalalignment='left', verticalalignment='top',size=7, wrap=True)


# call tight layout
# this is neccecary for the whole plot, that is not shown for simplicity reasons
# explaination: subfigure one would be an array of subplots with different scales and descriptions, 
#               ever changing depending on the data that is to be plotted, so tight_layout mittigates
#               a lot of tideos formatting
fig.tight_layout()

现象说明

可以看到图的右边缘超出了整个面板。若关闭文本换行(wrap=False),则可明确原因:布局计算采用的是未换行文本的尺寸。

问询

是否存在其他方法,能让子图中的文本渲染时,布局正确识别文本换行后的边界而非未换行的边界?


解决方法

1. 放弃tight_layout,改用constrained_layout(推荐)

代码中已经设置了constrained_layout = True,但后续调用fig.tight_layout()会导致两种布局机制冲突。constrained_layout会自动处理文本换行后的边界计算,只需移除tight_layout的调用即可解决问题。

修改后的关键代码:

# 保留constrained_layout设置
fig = plt.figure(constrained_layout = True, figsize=(fullwidth, fullheight)) 

# ... 其他代码不变 ...

# 移除该行调用
# fig.tight_layout()

2. 手动计算换行文本尺寸并调整子图

若必须使用tight_layout,可手动获取文本渲染后的实际尺寸,再调整子图边界:

  • 先触发一次画布绘制,确保文本已经渲染
  • 获取文本对象的实际包围盒,以此调整子图的显示范围

示例代码片段:

# 添加文本后先绘制画布
fig.canvas.draw()

# 获取文本对象的实际尺寸
text_obj = text_ax.text(0.00001, 0.8, message, horizontalalignment='left', verticalalignment='top',size=7, wrap=True)
bbox = text_obj.get_window_extent().transformed(text_ax.transAxes.inverted())

# 调整子图右边距,预留少量缓冲空间
text_ax.set_xlim(0, bbox.width * 1.05)

# 再调用tight_layout
fig.tight_layout()

3. 用textwrap提前手动换行

借助Python的textwrap模块,按子图宽度提前将文本分割为多行,让tight_layout能直接识别文本的实际行数与宽度:

import textwrap

# 根据子图宽度和字体大小计算最大字符宽度
max_char_width = int(text_ax.get_window_extent().width / text_ax.figure.dpi * 72 / 7)
wrapped_message = textwrap.fill(message, width=max_char_width)

# 传入提前换行后的文本,无需再设置wrap=True
text_ax.text(0.00001, 0.8, wrapped_message, horizontalalignment='left', verticalalignment='top',size=7)

内容的提问来源于stack exchange,提问作者Alexander Vocaet

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.03 22:01:01