Matplotlib 把 AnchoredText 加到 Figure,保存时却报 NoneType 没有 bbox
AnchoredText 仅加到 Figure 且未提供锚定矩形,绘制时可能读取空 axes.bbox。按标注归属添加到 Axes,或明确 Figure 坐标矩形。
fig.add_artist(AnchoredText(...)) 没有立刻报错,直到窗口重绘或 savefig() 才出现 AttributeError: 'NoneType' object has no attribute 'bbox'。先检查这个文本框要相对整张 Figure,还是相对其中某个 Axes 定位。
import matplotlib.pyplot as plt
from matplotlib.offsetbox import AnchoredText
fig, ax = plt.subplots()
fig.add_artist(AnchoredText("Example", loc="upper right"))
fig.savefig("figure.png")
loc 指定了角落,却没有提供用于锚定的矩形。正式 Matplotlib 3.11.2 中,未设置 bbox_to_anchor 时仍会读取 self.axes.bbox;仅把 Artist 加到 Figure,不会替它关联一个 Axes。这个失败也可能延迟到布局计算或导出阶段。
标注属于某个坐标轴时,让 Axes 持有它
图内某个子图的说明框,可通过对应坐标轴添加:
fig, ax = plt.subplots()
label = AnchoredText("Example", loc="upper right")
ax.add_artist(label)
fig.savefig("axes-label.png")
Axes.add_artist() 会设置 Artist 的 axes 归属,默认锚定矩形便有了对象。多子图时要选择正确的 ax;不要为了消除异常随便用第一个坐标轴,否则窗口缩放和布局调整后,文本框可能跟着错误的子图移动。
确实要相对整张图时,给出矩形与坐标变换
全图级标注不应依赖某个 Axes 的默认边框,可以显式指定归一化 Figure 范围:
fig, ax = plt.subplots()
label = AnchoredText(
"Example",
loc="upper right",
bbox_to_anchor=(0, 0, 1, 1),
bbox_transform=fig.transFigure,
)
fig.add_artist(label)
fig.savefig("figure-label.png")
四元组表示锚定矩形的左下角、宽和高,fig.transFigure 将它解释为整张 Figure 的归一化坐标。只填 (0, 0, 1, 1) 却漏掉变换,会落入不同的坐标解释,位置未必正确。不要把这里的 Figure 坐标直接换成数据坐标值。
这两种处理分别表达子图标注和全图标注。没有哪一种适合所有布局,也不需要修改 Matplotlib 安装目录里的 get_bbox_to_anchor()。
验收应触发真实绘制和输出,不能止于创建 Artist。检查保存文件中的文本、边框及位置,再调整窗口大小或导出尺寸,确认它随预定对象移动;使用 tight 或 constrained 布局的项目,还要检查是否裁切、是否挤占其他元素。示例输出采用独立文件名,实际工作应保留已有图和输入数据。
如果已经提供有效的锚定矩形,仍在其他对象上报 bbox,应沿完整调用栈定位那个对象。这里确认的是 AnchoredText 缺省锚定与 axes 归属,不能把所有 NoneType.bbox 都归给同一个添加方法,也不能把开发分支中的讨论当作某个正式版本已经改变默认行为。


