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

列表中mpl.figure.Figure对象无法显示绘图的问题排查与解决问询

我来帮你拆解这个问题,找到根因并给出可行的解决方案~

问题原因分析

首先看你给出的示例代码,能发现一个明显的差异:self.fig是创建了坐标轴并绘制了折线的,而self.figs里的两个Figure完全是空的——没有任何坐标轴或绘图元素。如果这就是你测试时的情况,那“失效”的直接原因就是空Figure无法被Qt后端正常渲染,要么弹出空窗口,要么因为没有可绘制内容触发异常。

但你提到在其他测试中怀疑和对象销毁、列表可变特性有关,那大概率你的实际场景里,列表中的Figure是有绘图内容的,但还是无法正常显示。这种情况下,问题核心出在matplotlib Figure的生命周期管理和Qt后端的关联机制上:

  • 当你用mpl.figure.Figure()直接创建对象时,它不会被matplotlib的全局Figure管理器跟踪。如果这个Figure没有被Canvas、Manager这类对象持续持有,Python的垃圾回收机制可能会提前回收它,导致显示时找不到有效对象。
  • 列表虽然持有Figure的引用,但如果在创建到显示的过程中,Figure的后端关联属性(比如Canvas引用)被意外重置,也会导致渲染失败。
  • 至于你尝试的pickle复制方法,之所以没用是因为matplotlib的Figure包含大量和后端交互的复杂对象(比如Renderer、Canvas实例),这些对象是不可序列化的,pickle无法完整复制Figure的运行状态。
解决方案

针对不同场景,我整理了几个可行的方案:

方案1:先给列表中的Figure初始化绘图内容(针对示例空Figure场景)

如果你的问题只是因为列表里的Figure是空的,那只需要在创建时给它们添加坐标轴和绘图即可,修改__init__方法:

def __init__(self):
    self.figs = []
    # 为每个列表中的Figure创建坐标轴并绘图
    for _ in range(2):
        fig = mpl.figure.Figure()
        ax = fig.subplots()
        ax.plot([1,2],[3,4])
        self.figs.append(fig)
    self.fig = mpl.figure.Figure()
    ax = self.fig.subplots()
    ax.plot([1,2],[3,4])

这样再取出self.figs[0]时,它已经有可渲染的内容,就能正常显示了。

方案2:用matplotlib全局管理器创建Figure

改用plt.figure()创建Figure,这样Figure会被matplotlib的全局管理器跟踪,避免被意外回收:

import matplotlib.pyplot as plt
import matplotlib as mpl
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg, FigureManagerQT
from PyQt5.QtWidgets import QApplication
import sys

class Test:
    def __init__(self):
        # 使用plt.figure()创建,会被全局管理器自动跟踪
        self.figs = [plt.figure(), plt.figure()]
        # 给列表中的Figure添加绘图内容
        for fig in self.figs:
            ax = fig.subplots()
            ax.plot([1,2],[3,4])
        self.fig = plt.figure()
        ax = self.fig.subplots()
        ax.plot([1,2],[3,4])
    
    def show(self):
        # fig = self.fig # works
        fig = self.figs[0] # 现在可以正常工作
        canvas = FigureCanvasQTAgg(fig)
        figManager = FigureManagerQT(canvas, 0)

a = Test()
a.show()
# 必须启动Qt事件循环,否则窗口会立即关闭
app = QApplication(sys.argv)
sys.exit(app.exec_())

方案3:手动维护Figure与Canvas的引用关联

如果你必须用mpl.figure.Figure()创建对象,可以在创建Figure时就关联Canvas,并额外持有Canvas的引用,确保Figure不会被回收:

import matplotlib as mpl
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg, FigureManagerQT
from PyQt5.QtWidgets import QApplication
import sys

class Test:
    def __init__(self):
        self.figs = []
        self.canvases = []  # 额外保存Canvas引用,防止Figure被垃圾回收
        for _ in range(2):
            fig = mpl.figure.Figure()
            ax = fig.subplots()
            ax.plot([1,2],[3,4])
            # 提前创建Canvas并关联到Figure
            canvas = FigureCanvasQTAgg(fig)
            self.figs.append(fig)
            self.canvases.append(canvas)
        self.fig = mpl.figure.Figure()
        ax = self.fig.subplots()
        ax.plot([1,2],[3,4])
    
    def show(self):
        fig = self.figs[0]
        # 直接使用之前创建的Canvas,无需重新初始化
        canvas = self.canvases[0]
        figManager = FigureManagerQT(canvas, 0)

a = Test()
a.show()
app = QApplication(sys.argv)
sys.exit(app.exec_())

重要提醒

无论用哪个方案,都要记得启动Qt的事件循环——也就是代码末尾的QApplication初始化和exec_()调用,否则Qt窗口会无法正常显示或瞬间关闭。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.14 06:37:49