Python Matplotlib交互式打印-几帧后冻结
我在让matplotlib与交互式绘图配合使用时遇到问题。。。我看到的是,在显示了几帧模拟数据后,matplotlib挂起,不再显示 基本上,我一直在玩一些科学模拟,希望能够在结果生成时绘制出来,而不是在最后使用pylab.show() 我找到了一个很久以前的烹饪书例子,它似乎做了我想做的事情——简单地说(尽管数据不同)。食谱在这里 我四处搜索了一下,我知道有些人以前有过这些问题——但当时似乎没有好的解决办法。我想知道是否有人在这里找到了一个好的解决方案 我在matplotlib上尝试了一些“后端”…TkAgg似乎在一些帧上工作。。。。qt4agg不显示帧。我还没有正确安装GTK 我正在运行最新的pythonxy(2.7.3) 有人有什么建议吗Python Matplotlib交互式打印-几帧后冻结,python,matplotlib,plot,interactive,pythonxy,Python,Matplotlib,Plot,Interactive,Pythonxy,我在让matplotlib与交互式绘图配合使用时遇到问题。。。我看到的是,在显示了几帧模拟数据后,matplotlib挂起,不再显示 基本上,我一直在玩一些科学模拟,希望能够在结果生成时绘制出来,而不是在最后使用pylab.show() 我找到了一个很久以前的烹饪书例子,它似乎做了我想做的事情——简单地说(尽管数据不同)。食谱在这里 我四处搜索了一下,我知道有些人以前有过这些问题——但当时似乎没有好的解决办法。我想知道是否有人在这里找到了一个好的解决方案 我在matplotlib上尝试了一些“后
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)
编辑:
编辑的代码-以消除出现的一些样式问题。好的。。。所以我把一些可能对我有用的东西弄乱了 基本上,它有点像一个淡化的gui——但我希望它是一个我可以导入的类,并且基本上忘记了它的细节(希望如此) 不过我应该说,这是我第一次尝试在python中使用线程或GUI,所以这段代码附带了一个健康警告 **不过,我不会将这个问题标记为已回答,因为我相信更有经验的人会有更好的解决方案
'''
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()
linux上带有matplotlib 1.1的Python 2.7。值得一提的是,在这种情况下,调用
ioff
(在使用ion
的循环中没有额外的draw调用)在性能上没有任何差异。但是,ioff
可能(即允许)导致后端的主循环停止(也可能不停止,具体行为取决于后端)。这就是为什么我猜测这个问题无论如何都是由于ioff
造成的。如果改用matplotlib.animations
模块,会发生什么情况?(在本例中,FuncAnimation
最简单。)此外,最好避免使用pylab import*中的,除非您使用的是shell中的东西,但这纯粹是一个风格问题,在本例中不会影响您的问题。无论如何,请改用matplotlib.pyplot
(惯例是import matplotlib.pyplot as plt
,以避免过于冗长的代码)。。。。我之前很快就看过了,但我不太确定这是我想要的。基本上我可能是错的,但它似乎希望您创建一个matplotlib反复调用的函数,每次都更新显示的数据。我想要的是另一种方式——这里我刚刚使用了‘sin’作为虚拟对象——但实际上在我的代码中,我做的是数值积分……这需要相当长的时间+其他稍微改变分析的逻辑内容。我希望我的代码调用matplot lib,而不是相反。至于pyplot
vspylab
部分,pyplot
只是matplotlib的核心,而pylab
是matplotlib
,numpy
,以及matplotlib.mlab
都集成在一起。这是一个巨大的名称空间,区分事物的来源确实更好。当然,这主要是风格上的,但如果没有其他帮助的话,它会让你更容易找到合适的帮助地点。再次感谢-我恐怕我通常使用spyder来开发-但在这种情况下,肯定不是spyder造成了问题-我从cmd和IPython获得了相同的效果。因此,我怀疑这可能与windows上的python\matplotlib有关,因为它在linux上适用。我曾在使用wx做一些事情时大吃一惊-这似乎在基本层面上可行-我想我会看看它在我的代码中工作得有多好。好吧,所以我将它标记为已回答-因为有人提到我的许多问题尚未标记为已回答,使我在未来获得帮助的可能性降低。。。。我们编织了一张多么纠结的网啊!