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.gShe开发者_开发百科et1.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()
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()
精彩评论