6

I have been bashing my head against the wall trying to update a graph using matplotlib with python and wxpython. I want to press a button and add data to a graph nested in a wx.notebook. Below is the code.

Thanks for the help

import wx
import matplotlib as mpl
import matplotlib.pyplot as plt
from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg as Canvas

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.canvas = Canvas(self, -1, self.figure)

        sizer = wx.BoxSizer(wx.VERTICAL)
        sizer.Add(self.canvas,1,wx.EXPAND)
        self.SetSizer(sizer)

class JBC(wx.Frame):
    def __init__(self, parent, id, title):
        wx.Frame.__init__(self, parent, id, title, size=(600,600))
        self.SetBackgroundColour(wx.Colour(236, 233, 216))

        self.nbG = wx.Notebook(self, -1, style=0, size=(400,400), pos=(0,0))       
        self.gSheet1 = self.add("Test").gca()

        calcButton = wx.Button(self, wx.NewId(), "Update", pos=(0, self.nbG.Position.y+400))

        #self.gSheet1.hold(False)
        #self.gSheet1.set_xlim(0,20)
        #self.gSheet1.set_ylim(0,20)
        #for i in range (2):
        #    self.gSheet1.plot([0,10],[1*i,1+i])

        #axes2 = plotter.add('figure 2').gca()
        #axes2.plot([1,2,3,4,5],[2,1,4,2,3])

        self.Bind(wx.EVT_BUTTON, self.OnCalculate, calcButton)

        self.Show(True)

    def OnCalculate(self, event):
        self.gSheet1.set_xlim(0,20)
        self.gSheet1.set_ylim(0,20)
        self.gSheet1.plot([1,2,3,4,5],[2,1,4,2,3])
        self.Update()

    def add(self,name="plot"):
       page = Plot(self.nbG)
       self.nbG.AddPage(page,name)
       return page.figure

    def Update(self):
        self.gSheet1.clear()
        plt.draw()
        print "Tried to redraw"


app = wx.App()
JBC(None, -1, "Test Title")
app.MainLoop()

1 Answer 1

4

Using this example as a guide, perhaps try this:

import wx
import matplotlib as mpl
mpl.use('WXAgg')
import matplotlib.pyplot as plt
from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg as Canvas

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.canvas = Canvas(self, -1, self.figure)

        sizer = wx.BoxSizer(wx.VERTICAL)
        sizer.Add(self.canvas,1,wx.EXPAND)
        self.SetSizer(sizer)

class JBC(wx.Frame):
    def __init__(self, parent, id, title):
        wx.Frame.__init__(self, parent, id, title, size=(600,600))
        self.SetBackgroundColour(wx.Colour(236, 233, 216))

        self.nbG = wx.Notebook(self, -1, style=0, size=(400,400), pos=(0,0))       
        self.gSheet1 = self.add("Test").gca()

        calcButton = wx.Button(self, wx.NewId(), "Update", pos=(0, self.nbG.Position.y+400))

        #self.gSheet1.hold(False)
        #self.gSheet1.set_xlim(0,20)
        #self.gSheet1.set_ylim(0,20)
        #for i in range (2):
        #    self.gSheet1.plot([0,10],[1*i,1+i])

        #axes2 = plotter.add('figure 2').gca()
        #axes2.plot([1,2,3,4,5],[2,1,4,2,3])

        self.Bind(wx.EVT_BUTTON, self.OnCalculate, calcButton)        
        # self.Show(True)

    def OnCalculate(self, event):
        self.gSheet1.set_xlim(0,20)
        self.gSheet1.set_ylim(0,20)
        self.gSheet1.plot([1,2,3,4,5],[2,1,4,2,3])
        self.Update()

    def add(self,name="plot"):
       page = Plot(self.nbG)
       self.nbG.AddPage(page,name)
       return page.figure

    def Update(self):
        self.gSheet1.clear()
        plt.draw()
        print "Tried to redraw"

if __name__ == '__main__':
    app = wx.App()
    frame=JBC(None, -1, "Test Title")
    frame.Show()
    app.MainLoop()

It is also possible to use matplotlib to draw an animated figure:

"""
Based on Tkinter bouncing ball code:
http://stackoverflow.com/q/13660042/190597 (arynaq) and
http://eli.thegreenplace.net/2008/08/01/matplotlib-with-wxpython-guis/
"""

import wx
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.figure as mplfig
import scipy.spatial.distance as dist
import matplotlib.backends.backend_wxagg as mwx

class Frame(wx.Frame):
    def __init__(self):
        wx.Frame.__init__(self, None, wx.ID_ANY, size = (800, 600))
        self.panel = wx.Panel(self)        
        self.fig = mplfig.Figure(figsize = (5, 4), dpi = 100)
        self.ax = self.fig.add_subplot(111)
        self.vbox = wx.BoxSizer(wx.VERTICAL)        
        self.canvas = mwx.FigureCanvasWxAgg(self.panel, wx.ID_ANY, self.fig)
        self.toolbar = mwx.NavigationToolbar2WxAgg(self.canvas)
        self.button = wx.Button(self.panel, wx.ID_ANY, "Quit")
        self.vbox.Add(self.canvas, 1, wx.LEFT | wx.TOP | wx.GROW)
        self.vbox.Add(self.toolbar, 0, wx.EXPAND)        
        self.vbox.Add(
            self.button, 0, border = 3,
            flag = wx.ALIGN_LEFT | wx.ALL | wx.ALIGN_CENTER_VERTICAL)
        self.panel.SetSizer(self.vbox)
        self.vbox.Fit(self)
        self.toolbar.update()
        self.update = self.animate().next
        self.timer = wx.Timer(self)
        self.timer.Start(1)
        self.Bind(wx.EVT_BUTTON, self.OnCloseWindow, self.button)        
        self.Bind(wx.EVT_TIMER, lambda event: self.update())
        self.Bind(wx.EVT_CLOSE, self.OnCloseWindow)

    def OnCloseWindow(self, evt):
        self.timer.Stop()
        del self.timer
        self.Destroy()

    def animate(self):
        N = 100                                             #Number of particles
        R = 10000                                           #Box width
        pR = 5                                               #Particle radius

        r = np.random.randint(0, R, (N, 2))                  #Position vector
        v = np.random.randint(-R/100, R/100, (N, 2))           #velocity vector
        a = np.array([0, -10])                               #Forces
        v_limit = R/2                                       #Speedlimit

        line, = self.ax.plot([], 'o')
        line2, = self.ax.plot([], 'o')                           #Track a particle
        self.ax.set_xlim(0, R+pR)
        self.ax.set_ylim(0, R+pR)        

        while True:
            v = v+a                                           #Advance
            r = r+v

            #Collision tests
            r_hit_x0 = np.where(r[:, 0]<0)                   #Hit floor?
            r_hit_x1 = np.where(r[:, 0]>R)                   #Hit roof?
            r_hit_LR = np.where(r[:, 1]<0)                   #Left wall?
            r_hit_RR = np.where(r[:, 1]>R)                   #Right wall?

            #Stop at walls
            r[r_hit_x0, 0] = 0
            r[r_hit_x1, 0] = R
            r[r_hit_LR, 1] = 0
            r[r_hit_RR, 1] = R

            #Reverse velocities
            v[r_hit_x0, 0] = -0.9*v[r_hit_x0, 0]
            v[r_hit_x1, 0] = -v[r_hit_x1, 0]
            v[r_hit_LR, 1] = -0.95*v[r_hit_LR, 1]
            v[r_hit_RR, 1] = -0.99*v[r_hit_RR, 1]

            #Collisions
            D = dist.squareform(dist.pdist(r))
            ind1, ind2 = np.where(D < pR)
            unique = (ind1 < ind2)
            ind1 = ind1[unique]
            ind2 = ind2[unique]

            for i1, i2 in zip(ind1, ind2):
                eps = np.random.rand()
                vtot = v[i1, :]+v[i2, :]
                v[i1, :] = -(1-eps)*vtot
                v[i2, :] = -eps*vtot

            line.set_ydata(r[:, 1])
            line.set_xdata(r[:, 0])
            line2.set_ydata(r[:N/5, 1])
            line2.set_xdata(r[:N/5, 0])
            self.canvas.draw()
            yield True

def main():
    app = wx.App(False)
    frame = Frame()
    frame.Show(True)
    app.MainLoop()

if __name__ == '__main__':
    main()
Sign up to request clarification or add additional context in comments.

2 Comments

Instead of using update button, is it not possible to use dynamic plotting with matplotlib here?

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.