Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to update a plot with python and Matplotlib

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()
like image 710
user640145 Avatar asked Mar 01 '11 21:03

user640145


1 Answers

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()
like image 102
unutbu Avatar answered Oct 23 '22 03:10

unutbu