【问题标题】:Update wxpython figure canvas with new figure用新图形更新 wxpython 图形画布
【发布时间】:2015-08-30 13:46:23
【问题描述】:

在 wxPython 应用程序中,我嵌入了一个带有 matplotlib 图的 FigureCanvas。我希望能够通过加载一个新的来切换图形。但是,该数字没有更新。

对类似主题的回答表明panel.canvas.draw()panel.Refresh() 应该可以解决问题,但我也尝试过panel.Update()panel.canvas.Refresh()。我担心这只有在您想用相同的图形重绘画布 时才有效?

所以我的问题是:如何替换画布内的图形并使其更新?

下面是一个小(非工作)示例。首先,一个图形加载了一个轴。如果您从嵌入式外壳类型 panel.LoadFigure() 中创建一个带有 2x2 子图的新图形并将其放入画布中。但是新图没有显示出来。

import numpy as np
import wx
from wx.py.shell import Shell

from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg as FigureCanvas
import matplotlib.pyplot as plt


class ShellPanel(wx.Panel):
    def __init__(self, parent):
        wx.Panel.__init__(self, parent)
        self.shell = Shell(self)
        self.sizer = wx.BoxSizer(wx.VERTICAL)
        self.sizer.Add(self.shell, 1, wx.GROW)
        self.SetSizer(self.sizer)
        self.Layout()
        self.Fit()


class FigurePanel(wx.Panel):
    def __init__(self, parent):

        wx.Panel.__init__(self, parent)
        self.parent = parent
        self.sizer = wx.BoxSizer(wx.VERTICAL)
        self.figure, ax = plt.subplots()
        self.canvas = FigureCanvas(self, -1, self.figure)
        self.shellpanel = ShellPanel(self)
        s1 = wx.BoxSizer(wx.VERTICAL)
        s1.Add(self.canvas, 0, wx.GROW)
        s1.Add(self.shellpanel, 1 , wx.EXPAND)
        self.sizer.Add(s1, 5, wx.GROW)

        self.SetSizer(self.sizer)
        self.Layout()
        self.Fit()

    def LoadFigure(self):
        self.figure, ax = plt.subplots(2, 2)
        self.canvas.draw()
        self.Refresh()


class FigureFrame(wx.Frame):
    def __init__(self, parent, id, title, size):
        wx.Frame.__init__(self, parent, id, title, size=size)

if __name__ == "__main__":
    app = wx.App(False)
    fr = FigureFrame(None, -1, title='Figure Loader', size=(wx.DisplaySize()[0]/2, wx.DisplaySize()[1]*3/4))
    panel = FigurePanel(fr)
    fr.Show()
    app.MainLoop()

【问题讨论】:

    标签: python matplotlib wxpython


    【解决方案1】:

    您是否有任何理由尝试在已定义的Figure 上创建新的Figure 而不仅仅是新的Axes

    我会这样写你的代码:

    def LoadFigure(self):
        self.figure.clf()  # clear current figure
        # add arbitrary number of new Axes
        self.figure.add_subplot(221)
        self.figure.add_subplot(222)
        self.figure.add_subplot(223)
        self.figure.add_subplot(224)
        self.canvas.draw()  # refresh canvas
    

    编辑:根据您的评论,我认为问题在于您正在创建一个新人物,但您的 Canvas 仍在引用旧人物。我不知道您是否可以直接在FigureCanvas 属性中进行更改,也许有更多经验的人可以提供更好的答案。目前,我将Destroy 之前的画布,并使用您的新图形创建一个新的FigureCanvas 对象。

    def LoadFigure(self):
        self.figure, ax = plt.subplots(2, 2)
        self.canvas.Destroy()
        self.canvas = FigureCanvas(self, -1, self.figure)
        self.canvas.draw()
    

    【讨论】:

    • 原因是我从文件中加载腌制的数字。 IE。 fig = pickle.load(filename)。这每次都会给出一个新的数字。所以我想做的是用这个更新的图形更新画布。正如您在示例中所展示的那样,我编写的示例代码有些愚蠢。
    • @pathoren 好的,我现在明白了。我修改了我的答案,为您提供我认为可行的东西,但它并不漂亮,可能有更好的方法
    • 谢谢@Diziet。我有一个类似的解决方案作为备用计划,但希望有一种更清洁的方法。我等待一段时间接受您的回答,看看是否有任何其他建议。
    • 受您关于画布链接到旧图的评论的启发,我发现您可以使用self.canvas.figure = new_figure 来确保画布更新为正确的图。据我所知,这似乎有效。
    • 似乎没有其他人给出答案,所以我接受你作为工作的人(连同我之前的评论)!
    【解决方案2】:

    尝试使用 Figure 本身来制作您的图形,而不是 pyplot。它通常对我有用,因为它给了你更多即兴发挥的空间。

    #!/usr/bin/python
    
    # -*- coding: utf-8 -*-
    
    import numpy as np
    import wx
    from wx.py.shell import Shell
    from matplotlib.figure import Figure
    from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg as FigureCanvas
    import matplotlib.pyplot as plt
    
    
    class ShellPanel(wx.Panel):
        def __init__(self, parent):
            wx.Panel.__init__(self, parent)
            self.shell = Shell(self)
            self.sizer = wx.BoxSizer(wx.VERTICAL)
            self.sizer.Add(self.shell, 1, wx.GROW)
            self.SetSizer(self.sizer)
            self.Layout()
            self.Fit()
    
    
    class FigurePanel(wx.Panel):
        def __init__(self, parent):
    
            wx.Panel.__init__(self, parent)
            self.parent = parent
            self.sizer = wx.BoxSizer(wx.VERTICAL)
            self.figure = Figure(figsize = (8,6.1), dpi =60)
            self.ax = self.figure.add_subplot(1,1,1)
            self.enlarged_figure = Figure(figsize = (8,6.1), dpi = 100)
            self.ax2 = self.enlarged_figure.add_subplot(2,1,2)
            self.canvas = FigureCanvas(self, -1, self.figure)
            self.canvas.Show()
            self.enlarged_canvas = FigureCanvas(self,-1,self.enlarged_figure)
            self.enlarged_canvas.Show()
    
            self.shellpanel = ShellPanel(self)
            s1 = wx.BoxSizer(wx.VERTICAL)
            s1.Add(self.canvas, 0, wx.GROW)
            s1.Add(self.shellpanel, 1 , wx.EXPAND)
            self.sizer.Add(s1, 5, wx.GROW)
            self.SetSizer(self.sizer)
            self.Layout()
            self.Fit()
    
        def LoadFigure(self):
            self.figure, ax = plt.subplots(2, 2)
            self.canvas.draw()
            self.Refresh()
    
    
    class FigureFrame(wx.Frame):
        def __init__(self, parent, id, title, size):
            wx.Frame.__init__(self, parent, id, title, size=size)
    
    if __name__ == "__main__":
        app = wx.App(False)
        fr = FigureFrame(None, -1, title='Figure Loader', size=(wx.DisplaySize()[0]/2, wx.DisplaySize()[1]*3/4))
        panel = FigurePanel(fr)
        fr.Show()
        app.MainLoop()
    

    在 shell 中键入“panel.LoadFigure()”,新图形会很快出现然后消失。然后输入“panel.canvas.draw()”,新的图形就会出现。然后键入“panel.LoadFigure()”以加载旧图。重复。

    我不知道为什么在 MainLoop() 继续后该图形仍然隐藏,但这是对您的问题的快速修复。

    【讨论】:

    • 经过一番研究,我认为当主框架的孩子创建这些数字时,它们无法保持显示。例如,如果您要创建一个名为“myFrame”的新类,然后将 FigurePanel 和 ShellPanel 原样放在那里,它实际上甚至不会显示外壳面板,因为它是在 FigurePanel 类中创建的。但是,如果您在主父级“myFrame”中创建它,那么它将保持显示状态。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-10-01
    • 1970-01-01
    • 2012-01-07
    • 1970-01-01
    • 1970-01-01
    • 2012-02-24
    相关资源
    最近更新 更多