Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

matplotlib: how to refresh figure.canvas

I can't understand how to refresh FigureCanvasWxAgg instance. Here is the example:


import wx
import matplotlib
from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg as FigureCanvas
from matplotlib.figure import Figure

class MainFrame(wx.Frame): 
    def __init__(self): 
        wx.Frame.__init__(self, None, wx.NewId(), "Main") 
        self.sizer = wx.BoxSizer(wx.VERTICAL)

        self.figure = Figure(figsize=(1,2))
        self.axe = self.figure.add_subplot(111)
        self.figurecanvas = FigureCanvas(self, -1, self.figure)

        self.buttonPlot = wx.Button(self, wx.NewId(), "Plot")
        self.buttonClear = wx.Button(self, wx.NewId(), "Clear")

        self.sizer.Add(self.figurecanvas, proportion=1, border=5, flag=wx.ALL | wx.EXPAND)
        self.sizer.Add(self.buttonPlot, proportion=0, border=2, flag=wx.ALL)
        self.sizer.Add(self.buttonClear, proportion=0, border=2, flag=wx.ALL)
        self.SetSizer(self.sizer)

        self.figurecanvas.Bind(wx.EVT_LEFT_DCLICK, self.on_dclick)
        self.buttonPlot.Bind(wx.EVT_BUTTON, self.on_button_plot)
        self.buttonClear.Bind(wx.EVT_BUTTON, self.on_button_clear)

        self.subframe_opened = False

    def on_dclick(self, evt):
        self.subframe = SubFrame(self, self.figure)
        self.subframe.Show(True)
        self.subframe_opened = True

    def on_button_plot(self, evt):
        self.axe.plot(range(10), color='green')
        self.figurecanvas.draw()

    def on_button_clear(self, evt):
        if self.subframe_opened:
            self.subframe.Close()
        self.figure.set_canvas(self.figurecanvas)
        self.axe.clear()
        self.figurecanvas.draw()


class SubFrame(wx.Frame): 
    def __init__(self, parent, figure): 
        wx.Frame.__init__(self, parent, wx.NewId(), "Sub")
        self.sizer = wx.BoxSizer(wx.VERTICAL)
        self.figurecanvas = FigureCanvas(self, -1, figure)
        self.sizer.Add(self.figurecanvas, proportion=1, border=5, flag=wx.ALL | wx.EXPAND)
        self.SetSizer(self.sizer)

        self.Bind(wx.EVT_CLOSE, self.on_close)

    def on_close(self, evt):
        self.GetParent().subframe_opened = False
        evt.Skip()



class MyApp(wx.App):
    def OnInit(self):
        frame = MainFrame()
        frame.Show(True)
        self.SetTopWindow(frame)
        return True

app = MyApp(0)
app.MainLoop()    

I'm interested in the following sequence of operations:

  • run a script
  • resize the main frame
  • press Plot button
  • double click on plot
  • press Clear button

Now I get a mess on main frame plot. If I resize the frame it redraws properly. My question is what should I add to my code to do that without resizing?

By a "mess" I mean something like this:

http://img227.imageshack.us/img227/5407/mess.png

Thanks in advance.

like image 847
Alex Avatar asked Mar 14 '10 11:03

Alex


People also ask

How do I refresh a plot in Matplotlib?

To update the plot with x and y values, we use ion() function. To plot the line, we use plot() function. To define labels, we use xlabel() and ylabel() function. Then we update the variables x and y with set_xdate() and set_ydata() function.


1 Answers

As I said in the comments, I don't think that the figure canvas refresh is your problem, in fact I think it's doing exactly what it's supposed to (redrawing itself based on it's last state [ie as it was in your subplot]). I think your problem is more that the wxFrame is not refreshing.

The easiest way to fix that would be to make it resize itself on your "Clear" event. Something like:

def on_button_clear(self, evt):
    if self.subframe_opened:
        self.subframe.Close()
    self.figure.set_canvas(self.figurecanvas)
    self.axe.clear()
    self.figurecanvas.draw()  
    self.SetSize((self.Size[0],self.figurecanvas.Size[1]))

The set size would cause the frame and all the controls it contains to be redrawn.

That said, I think sharing your figure between the two figurecanvas is dangerous. I was able to produce some serious errors by clicking/resizing things in different combinations. On occasion your figure would be garbage collected when the subframe was closed, making it unavailable to your main frame.

like image 183
Mark Avatar answered Oct 04 '22 15:10

Mark