如何更新wxFrame中嵌入的matplotlib绘图?

lbsnaicq  于 2023-03-30  发布在  其他
关注(0)|答案(1)|浏览(111)

我试图创建一个由垂直wxplitter和两个面板(Inputs_Panel和Plotting_Panel)组成的应用程序,其中左侧用于阅读输入,右侧用于绘制这些输入。
基于几个例子,我能够绘制'xy'图,我需要在绘图面板上的按钮时,输入面板被按下。
如果我在一个新窗口中绘制xy图和移动的垂直线,一切都按预期工作。但是,我不能在绘图面板中动画垂直线。
这是我的代码:

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

import wx
import wx.xrc
import matplotlib as mpl
import matplotlib.pyplot as plt
from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg as FigureCanvas
from matplotlib.backends.backend_wxagg import NavigationToolbar2WxAgg as NavigationToolbar
import numpy as np
import pathlib
from matplotlib.animation import FuncAnimation
import mpl_toolkits.axes_grid1
import matplotlib.widgets
import os

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"MyButton", 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 __del__(self):
        pass

    # Virtual event handlers, overide them in your derived class
    def m_show_plot_buttonOnButtonClick(self, event):
        fig, (ax1, ax2) = plt.subplots(nrows=1, ncols=2)

        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])
        v_line = ax1.axvline(20, color="cornflowerblue")

        self.Parent.Parent.m_vis_panel.ax1.plot(x, y)
        # v_line_GUI = self.Parent.Parent.m_vis_panel.ax1.axvline(0, color="cornflowerblue")

        def animate(i):
            print(i)

            # Update position of the vertical line that follows the value of the plotted variable of the model
            v_line.set_xdata([i])
            # v_line_GUI.set_xdata([i])

        ani = FuncAnimation(fig, animate, frames=x.shape[0], interval=500, repeat=False)

        plt.show()

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()

        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=wx.EmptyString, pos=wx.DefaultPosition,
                          size=wx.Size(500, 300), style=wx.DEFAULT_FRAME_STYLE | wx.TAB_TRAVERSAL)

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

        bSizer = wx.BoxSizer(wx.VERTICAL)

        bSizer.SetMinSize(wx.Size(150, 200))
        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, 0)
        bSizer.Add(self.m_splitter, 1, wx.EXPAND, 5)

        self.SetSizer(bSizer)
        self.Layout()

        self.Centre(wx.BOTH)

    def __del__(self):
        pass

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

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

提前感谢您的任何帮助。亲切的问候。Tmoover

a9wyjsp7

a9wyjsp71#

这是我自己的解决方案,在wxFrame中动画matplotlib图。

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

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

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"MyButton", 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 __del__(self):
        pass

    # Virtual event handlers, overide them in your derived class
    def m_show_plot_buttonOnButtonClick(self, event):
        x = np.arange(0, 150, 1)
        y = np.arange(0, 150, 1)
        self.Parent.Parent.m_vis_panel.draw_plot(x, y)

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(111)
        self.canvas     = FigureCanvas(self, -1, self.figure)
        self.toolbar    = NavigationToolbar(self.canvas)
        self.toolbar.Realize()

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

        self.SetSizer(sizer)

    def draw_plot(self, x, y):
        self.ax1.cla()

        # Plot 'xy' values
        self.ax1.plot(x, y)

        # Create vertical line that moves along 'xy' plot
        v_line = self.ax1.axvline(0, color="cornflowerblue")

        # Create point to display 'xy' plot value for each instant
        point, = self.ax1.plot([], [], marker="o", color="crimson", ms=15)

        # Show value of variable 'y'
        t1 = self.ax1.text(0, 0, '')

        def update(i):
            # Update position of the point
            point.set_data(x[i], y[i])

            # Update position of the value of variable 'y'
            t1.set_position((float(x[i]), float(y[i]) * 1.05))
            t1.set_text(str(np.round(y[i], 3)))

            # Update position of the vertical line according to the value of 'x' variable
            v_line.set_xdata([i])

        ani = FuncAnimation(self.figure, update, frames=x.shape[0], interval=50, repeat=False)
        
        # Draw plot
        self.figure.canvas.draw()

class MyFrame(wx.Frame):

    def __init__(self, parent):
        wx.Frame.__init__(self, parent, id=wx.ID_ANY, title=wx.EmptyString, pos=wx.DefaultPosition,
                          size=wx.Size(500, 300), style=wx.DEFAULT_FRAME_STYLE | wx.TAB_TRAVERSAL)

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

        bSizer = wx.BoxSizer(wx.VERTICAL)

        bSizer.SetMinSize(wx.Size(150, 200))
        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, 0)
        bSizer.Add(self.m_splitter, 1, wx.EXPAND, 5)

        self.SetSizer(bSizer)
        self.Layout()

        self.Centre(wx.BOTH)

    def __del__(self):
        pass

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

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

TMoover

相关问题