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

使用Matplotlib SubFigure添加等高线标签时遇_cachedRenderer属性错误

Matplotlib SubFigure 中使用 ax.clabel 报错 AttributeError 的解决办法

在使用Matplotlib的SubFigure布局时,调用ax.clabel()为等高线添加标签会抛出AttributeError: 'SubFigure' object has no attribute '_cachedRenderer'错误,以下是问题复现、原因分析及解决办法:

复现代码

import matplotlib.pyplot as plt
import numpy as np

delta = 0.025
x = np.arange(-3.0, 3.0, delta)
y = np.arange(-2.0, 2.0, delta)
X, Y = np.meshgrid(x, y)
Z1 = np.exp(-X**2 - Y**2)
Z2 = np.exp(-(X - 1)**2 - (Y - 1)**2)
Z = (Z1 - Z2) * 2

fig = plt.figure(constrained_layout=True)

subfigs = fig.subfigures(1, 2)
for i, subfig in enumerate(subfigs.flat):
    axs = subfig.subplots(2, 1)
    for j, ax in enumerate(axs):
        CS = ax.contour(X, Y, Z)
        ax.clabel(CS)
plt.show()

错误信息

---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
~\AppData\Local\Temp\ipykernel_35648\2613963086.py in <module>
     17     for j, ax in enumerate(axs):
     18         CS = ax.contour(X, Y, Z)
---> 19         ax.clabel(CS)
     20 plt.show()

~\anaconda3\lib\site-packages\matplotlib\axes\_axes.py in clabel(self, CS, levels, **kwargs)
   6333             All other parameters are documented in `~.ContourLabeler.clabel`.
   6334         """
-> 6335         return CS.clabel(levels, **kwargs)
   6336 
   6337     #### Data analysis

~\anaconda3\lib\site-packages\matplotlib\contour.py in clabel(self, levels, fontsize, inline, inline_spacing, fmt, colors, use_clabeltext, manual, rightside_up, zorder)
    233                     self, inline, inline_spacing))
    234         else:
-> 235             self.labels(inline, inline_spacing)
    236 
    237         self.labelTextsList = cbook.silent_list('text.Text', self.labelTexts)

~\anaconda3\lib\site-packages\matplotlib\contour.py in labels(self, inline, inline_spacing)
    580             con = self.collections[icon]
    581             trans = con.get_transform()
-> 582             lw = self._get_nth_label_width(idx)
    583             additions = []
    584             paths = con.get_paths()

~\anaconda3\lib\site-packages\matplotlib\contour.py in _get_nth_label_width(self, nth)
    283                       size=self.labelFontSizeList[nth],
    284                       fontproperties=self.labelFontProps)
-> 285             .get_window_extent(mpl.tight_layout.get_renderer(fig)).width)
    286 
    287     @_api.deprecated("3.5")

~\anaconda3\lib\site-packages\matplotlib\tight_layout.py in get_renderer(fig)
    204 
    205 def get_renderer(fig):
-> 206     if fig._cachedRenderer:
    207         return fig._cachedRenderer
    208     else:

AttributeError: 'SubFigure' object has no attribute '_cachedRenderer'

问题原因

报错根源在于Matplotlib的等高线标签计算逻辑中,错误地将SubFigure对象传递给了get_renderer()函数,而SubFigure并没有主Figure才有的_cachedRenderer属性,导致属性查找失败。

可行解决方案

方案1:禁用inline标签模式

调用ax.clabel()时添加inline=False参数,绕开需要计算标签宽度的逻辑:

import matplotlib.pyplot as plt
import numpy as np

delta = 0.025
x = np.arange(-3.0, 3.0, delta)
y = np.arange(-2.0, 2.0, delta)
X, Y = np.meshgrid(x, y)
Z1 = np.exp(-X**2 - Y**2)
Z2 = np.exp(-(X - 1)**2 - (Y - 1)**2)
Z = (Z1 - Z2) * 2

fig = plt.figure(constrained_layout=True)

subfigs = fig.subfigures(1, 2)
for i, subfig in enumerate(subfigs.flat):
    axs = subfig.subplots(2, 1)
    for j, ax in enumerate(axs):
        CS = ax.contour(X, Y, Z)
        # 添加inline=False参数
        ax.clabel(CS, inline=False)
plt.show()

此方法会将标签显示在等高线外侧,而非嵌入线条中,但能避免报错。

方案2:提前触发主Figure渲染

在创建SubFigure之前,先调用fig.canvas.draw()生成主Figure的缓存渲染器,这样后续clabel逻辑即使误传SubFigure,也能 fallback 使用主渲染器:

import matplotlib.pyplot as plt
import numpy as np

delta = 0.025
x = np.arange(-3.0, 3.0, delta)
y = np.arange(-2.0, 2.0, delta)
X, Y = np.meshgrid(x, y)
Z1 = np.exp(-X**2 - Y**2)
Z2 = np.exp(-(X - 1)**2 - (Y - 1)**2)
Z = (Z1 - Z2) * 2

fig = plt.figure(constrained_layout=True)
# 提前触发主图渲染,生成cachedRenderer
fig.canvas.draw()

subfigs = fig.subfigures(1, 2)
for i, subfig in enumerate(subfigs.flat):
    axs = subfig.subplots(2, 1)
    for j, ax in enumerate(axs):
        CS = ax.contour(X, Y, Z)
        ax.clabel(CS)
plt.show()

此方法保留inline标签的显示效果,是更贴近需求的临时解决办法。

方案3:替换为普通Subplots布局

如果SubFigure并非必须,可以改用传统的fig.subplots()布局,避免SubFigure带来的兼容性问题:

import matplotlib.pyplot as plt
import numpy as np

delta = 0.025
x = np.arange(-3.0, 3.0, delta)
y = np.arange(-2.0, 2.0, delta)
X, Y = np.meshgrid(x, y)
Z1 = np.exp(-X**2 - Y**2)
Z2 = np.exp(-(X - 1)**2 - (Y - 1)**2)
Z = (Z1 - Z2) * 2

fig, axs = plt.subplots(2, 2, constrained_layout=True)
for ax in axs.flat:
    CS = ax.contour(X, Y, Z)
    ax.clabel(CS)
plt.show()

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.23 02:24:55