[英]Python Matplotlib interactive plotting - freezes after a few frames
I am having a problem getting matplotlib to work well with interactive plotting... what I see is that after displaying a few frames of my simulated data matplotlib hangs-and doesn't display any more.我在让 matplotlib 与交互式绘图配合良好时遇到了问题……我看到的是,在显示几帧我的模拟数据后,matplotlib 挂起,不再显示。
Basically I've been playing around a bit with science simulations - and would like to be able to plot my results as they are being made - rather than at the end - using pylab.show().基本上我一直在玩科学模拟 - 并且希望能够在制作结果时绘制我的结果 - 而不是最后 - 使用 pylab.show()。
I found a cookbook example from a while back that seems to do what I would want - in simple terms (although obv. the data is different).不久前我发现了一个食谱示例,它似乎可以满足我的要求 - 简单来说(尽管数据不同)。 The cookbook is here... http://www.scipy.org/Cookbook/Matplotlib/Animations#head-2f6224cc0c133b6e35c95f4b74b1b6fc7d3edca4食谱在这里...... http://www.scipy.org/Cookbook/Matplotlib/Animations#head-2f6224cc0c133b6e35c95f4b74b1b6fc7d3edca4
I have searched around a little and I know that some people had these problems before - Matplotlib animation either freezes after a few frames or just doesn't work but it seems at the time there were no good solutions.我已经搜索了一点,我知道有些人以前遇到过这些问题 - Matplotlib 动画要么在几帧后冻结,要么就不起作用,但当时似乎没有好的解决方案。 I was wondering if someone has since found a good solution here.我想知道是否有人在这里找到了一个好的解决方案。
I have tried a few 'backends' on matplotlib....TkAgg seems to work for a few frames.... qt4agg doesn't show the frames.我在 matplotlib 上尝试了一些“后端”....TkAgg 似乎适用于几帧.... qt4agg 不显示帧。 I haven't yet got GTK to install properly.我还没有让 GTK 正确安装。
I am running the most recent pythonxy(2.7.3).我正在运行最新的 pythonxy(2.7.3)。
Anyone have any advice?有人有什么建议吗?
import matplotlib
matplotlib.use('TkAgg') # 'Normal' Interactive backend. - works for several frames
#matplotlib.use('qt4agg') # 'QT' Interactive backend. - doesn't seem to work at all
#matplotlib.use('GTKAgg') # 'GTK' backend - can't seem to get this to work.... -
import matplotlib.pyplot as plt
import time
import numpy as np
plt.ion()
tstart = time.time() # for profiling
x = np.arange(0,2*np.pi,0.01) # x-array
line, = plt.plot(x,np.sin(x))
#plt.ioff()
for i in np.arange(1,200):
line.set_ydata(np.sin(x+i/10.0)) # update the data
line.axes.set_title('frame number {0}'.format(i))
plt.draw() # redraw the canvas
print 'FPS:' , 200/(time.time()-tstart)
EDIT :编辑:
edited code - to get rid of some style issues brought up.编辑代码 - 摆脱一些风格问题带来的。
Ok... So I have mangled together something that may sort of work for me....好的......所以我已经把一些可能对我有用的东西混合在一起......
Basically it is something like a watered down gui - but i'm hoping that it is a class i can import and basically forget about the details of (here's hoping).基本上它就像一个淡化的 gui - 但我希望它是一个我可以导入的类并且基本上忘记了(这里是希望)的细节。
I should say though - this is my first attempt at threading OR guis in python - so this code comes with a health warning.我应该说 - 这是我第一次尝试在 python 中线程或 guis - 所以这段代码带有健康警告。
** I'm not going to mark the question as answered though - because i'm sure someone more experienced will have a better solution. ** 不过,我不会将问题标记为已回答 - 因为我相信更有经验的人会有更好的解决方案。
'''
JP
Attempt to get multiple updating of matplotlibs working.
Uses WX to create an 'almost' gui with a mpl in the middle of it.
Data can be queued to this object - or you can directly plot to it.
Probably will have some limitations atm
- only really thinking about 2d plots for now -
but presumably can work around this for other implimentations.
- the working code seems to need to be put into another thread.
Tried to put the wx mainloop into another thread,
but it seemed unhappy. :(
Classes of Interest :
GraphData - A silly class that holds data to be plotted.
PlotFigure - Class of wx frame type.
Holds a mpl figure in it + queue to queue data to.
The frame will plot the data when it refreshes it's canvas
ThreadSimulation - This is not to do with the plotting
it is a test program.
Modified version of:
Copyright (C) 2003-2005 Jeremy O'Donoghue and others
License: This work is licensed under the PSF. A copy should be included
with this source code, and is also available at
http://www.python.org/psf/license.html
'''
import threading
import collections
import time
import numpy as np
import matplotlib
matplotlib.use('WXAgg')
from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg
from matplotlib.backends.backend_wx import NavigationToolbar2Wx
from matplotlib.figure import Figure
import wx
class GraphData(object):
'''
A silly class that holds data to be plotted.
'''
def __init__(self, xdatainit, ydatainit):
self.xdata = xdatainit
self.ydata = ydatainit
class PlotFigure(wx.Frame):
def __init__(self ):
'''
Initialises the frame.
'''
wx.Frame.__init__(self, None, -1, "Test embedded wxFigure")
self.timerid = wx.NewId()
self.fig = Figure((5,4), 75)
self.canvas = FigureCanvasWxAgg(self, -1, self.fig)
self.toolbar = NavigationToolbar2Wx(self.canvas)
self.toolbar.Realize()
# On Windows, default frame size behaviour is incorrect
# you don't need this under Linux
tw, th = self.toolbar.GetSizeTuple()
fw, fh = self.canvas.GetSizeTuple()
self.toolbar.SetSize(wx.Size(fw, th))
# Now put all into a sizer
sizer = wx.BoxSizer(wx.VERTICAL)
# This way of adding to sizer allows resizing
sizer.Add(self.canvas, 1, wx.LEFT|wx.TOP|wx.GROW)
# Best to allow the toolbar to resize!
sizer.Add(self.toolbar, 0, wx.GROW)
self.SetSizer(sizer)
self.Fit()
wx.EVT_TIMER(self, self.timerid, self.onTimer)
self.dataqueue = collections.deque()
# Add an axes and a line to the figure.
self.axes = self.fig.add_subplot(111)
self.line, = self.axes.plot([],[])
def GetToolBar(self):
'''
returns default toolbar.
'''
return self.toolbar
def onTimer(self, evt):
'''
Every timer period this is called.
Want to redraw the canvas.
'''
#print "onTimer"
if len(self.dataqueue) > 0 :
data = self.dataqueue.pop()
x = data.xdata
y = data.ydata
xmax = max(x)
xmin = min(x)
ymin = round(min(y), 0) - 1
ymax = round(max(y), 0) + 1
self.axes.set_xbound(lower=xmin, upper=xmax)
self.axes.set_ybound(lower=ymin, upper=ymax)
self.line.set_xdata(x)
self.line.set_ydata(y)
# Redraws the canvas - does this even if the data isn't updated...
self.canvas.draw()
def onEraseBackground(self, evt):
'''
this is supposed to prevent redraw flicker on some X servers...
'''
pass
class ThreadSimulation(threading.Thread):
'''
Simulation Thread - produces data to be displayed in the other thread.
'''
def __init__(self, nsimloops, datastep, pltframe, slowloop = 0):
threading.Thread.__init__(self)
self.nsimloops = nsimloops
self.datastep = datastep
self.pltframe = pltframe
self.slowloop=slowloop
def run(self):
'''
This is the simulation function.
'''
nsimloops = self.nsimloops
datastep = self.datastep
pltframe = self.pltframe
print 'Sim Thread: Starting.'
tstart = time.time() # for profiling
# Define Data to share between threads.
x = np.arange(0,2*np.pi,datastep) # x-array
y = np.sin(x )
# Queues up the data and removes previous versions.
pltframe.dataqueue.append(GraphData(x,y))
for i in range(len(pltframe.dataqueue)-1):
pltframe.dataqueue.popleft()
pltframe.dataqueue
for i in np.arange(1, nsimloops):
x = x + datastep
y = np.sin(x)
# Queues up the data and removes previous versions.
pltframe.dataqueue.append(GraphData(x,y))
for i in range(len(pltframe.dataqueue)-1):
pltframe.dataqueue.popleft()
#pltframe.dataqueue
if self.slowloop > 0 :
time.sleep(self.slowloop)
tstop= time.time()
print 'Sim Thread: Complete.'
print 'Av Loop Time:' , (tstop-tstart)/ nsimloops
if __name__ == '__main__':
# Create the wx application.
app = wx.PySimpleApp()
# Create a frame with a plot inside it.
pltframe = PlotFigure()
pltframe1 = PlotFigure()
# Initialise the timer - wxPython requires this to be connected to
# the receiving event handler
t = wx.Timer(pltframe, pltframe.timerid)
t.Start(100)
pltframe.Show()
pltframe1.Show()
npoints = 100
nsimloops = 20000
datastep = 2 * np.pi/ npoints
slowloop = .1
#Define and start application thread
thrd = ThreadSimulation(nsimloops, datastep, pltframe,slowloop)
thrd.setDaemon(True)
thrd.start()
pltframe1.axes.plot(np.random.rand(10),np.random.rand(10))
app.MainLoop()
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.