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

如何在wxFrame的Matplotlib嵌入面板中实现动态竖线动画?

解决wxPython中Matplotlib动画在面板内不生效的问题

你的核心问题在于动画绑定的是plt新建的独立画布,而非Plot面板内的Matplotlib画布,且未在动画更新时刷新wx面板的画布,同时动画对象未被保留引用导致被垃圾回收。以下是修复后的完整代码:

# -*- coding: utf-8 -*-

import wx
import matplotlib as mpl
from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg as FigureCanvas
from matplotlib.backends.backend_wxagg import NavigationToolbar2WxAgg as NavigationToolbar
import numpy as np
from matplotlib.animation import FuncAnimation

class Inputs_Panel(wx.Panel):

    def __init__(self, parent):
        wx.Panel.__init__(self, parent, id=wx.ID_ANY, pos=wx.DefaultPosition, size=wx.Size(500, 300),
                          style=wx.TAB_TRAVERSAL)

        bSizer = wx.BoxSizer(wx.VERTICAL)

        self.m_show_plot_button = wx.Button(self, wx.ID_ANY, u"启动动画", wx.DefaultPosition, wx.DefaultSize, 0)
        bSizer.Add(self.m_show_plot_button, 0, wx.ALL | wx.EXPAND, 5)

        self.SetSizer(bSizer)
        self.Layout()

        # Connect Events
        self.m_show_plot_button.Bind(wx.EVT_BUTTON, self.m_show_plot_buttonOnButtonClick)

    def m_show_plot_buttonOnButtonClick(self, event):
        # 获取右侧Plot面板的画布和轴对象
        vis_panel = self.Parent.Parent.m_vis_panel
        ax1 = vis_panel.ax1
        figure = vis_panel.figure
        
        # 清空之前的绘图,避免重复绘制
        ax1.clear()
        
        x = np.arange(0, 150, 1)
        y = np.arange(0, 150, 1)

        ax1.plot(x, y)
        ax1.set_xlim([0, 150])
        ax1.set_ylim([0, 150])
        # 在Plot面板的轴上创建竖线
        v_line_GUI = ax1.axvline(0, color="cornflowerblue")

        def animate(i):
            # 更新竖线位置
            v_line_GUI.set_xdata([i])
            # 刷新wx面板内的Matplotlib画布
            vis_panel.canvas.draw_idle()

        # 创建动画并绑定到Plot面板的画布,同时保留引用避免被回收
        vis_panel.ani = FuncAnimation(figure, animate, frames=x.shape[0], interval=500, repeat=False)

class Plot(wx.Panel):
    def __init__(self, parent, id=-1, dpi=None, **kwargs):
        wx.Panel.__init__(self, parent, id=id, **kwargs)
        self.figure     = mpl.figure.Figure(dpi=dpi, figsize=(2, 2))
        self.ax1        = self.figure.add_subplot(121)
        self.ax2        = self.figure.add_subplot(122)
        self.canvas     = FigureCanvas(self, -1, self.figure)
        self.toolbar    = NavigationToolbar(self.canvas)
        self.toolbar.Realize()
        # 添加动画对象属性,用于保存动画引用
        self.ani = None

        sizer = wx.BoxSizer(wx.VERTICAL)
        sizer.Add(self.canvas, 1, wx.EXPAND)
        sizer.Add(self.toolbar, 0, wx.LEFT | wx.EXPAND)

        self.SetSizer(sizer)

class MyFrame(wx.Frame):

    def __init__(self, parent):
        wx.Frame.__init__(self, parent, id=wx.ID_ANY, title="Matplotlib动画演示", pos=wx.DefaultPosition,
                          size=wx.Size(800, 600), style=wx.DEFAULT_FRAME_STYLE | wx.TAB_TRAVERSAL)

        self.SetSizeHints(wx.DefaultSize, wx.DefaultSize)

        bSizer = wx.BoxSizer(wx.VERTICAL)

        self.m_splitter = wx.SplitterWindow(self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.SP_3D)
        self.m_splitter.Bind(wx.EVT_IDLE, self.m_splitterOnIdle)

        self.m_input_panel  = Inputs_Panel(self.m_splitter)
        self.m_vis_panel    = Plot(self.m_splitter)

        self.m_splitter.SplitVertically(self.m_input_panel, self.m_vis_panel, 200)
        bSizer.Add(self.m_splitter, 1, wx.EXPAND, 5)

        self.SetSizer(bSizer)
        self.Layout()

        self.Centre(wx.BOTH)

    def m_splitterOnIdle(self, event):
        self.m_splitter.SetSashPosition(200)
        self.m_splitter.Unbind(wx.EVT_IDLE)

if __name__ == "__main__":
    app = wx.App(redirect=False)
    frame = MyFrame(None)
    frame.Show(True)
    app.MainLoop()

关键修改说明:

  • 移除了plt.subplots()和plt.show(),改用Plot面板内已创建的figure和ax1对象,避免创建独立窗口。
  • 在动画更新函数animate中调用vis_panel.canvas.draw_idle(),强制刷新wx面板内的Matplotlib画布。
  • 在Plot类中添加self.ani属性,保存动画对象的引用,防止Python垃圾回收机制销毁动画。
  • 添加了ax1.clear(),避免每次点击按钮时重复绘制曲线。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.28 01:12:41