Хорошо ... Итак, я собрал кое-что, что может мне помочь ....
По сути, это что-то вроде разбавленного графического интерфейса, но я надеюсь, что это класс, который я могу импортировать и в основном забыть о деталях (вот надеюсь).
Я должен сказать, что это моя первая попытка распараллелить ИЛИ guis на python, поэтому этот код содержит предупреждение о вреде для здоровья.
** Я не собираюсь отмечать этот вопрос как ответ, потому что уверен, что у более опытного найдется лучшее решение.
'''
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()
person
JPH
schedule
26.11.2012
ioff
? (Нет очевидной причины для этого.) Будет ли у вас такое же поведение, если вы не позвонитеioff
? Я не могу воспроизвести ваши проблемы, чего бы это ни стоило, но рискну предположить, что это потому, что вы звонитеioff
, а потом рисуете сюжет. - person Joe Kington   schedule 26.11.2012ioff
, заключалась в том, что, насколько мне известно, в интерактивном режиме, когда вы меняете что-то на графике, это вызывает перерисовку. то, что я пытаюсь сделать здесь, - это минимизировать количество перерисовок, чтобы мои симуляции не сильно замедлялись. В любом случае - его удаление не помогает - по крайней мере, мне - интересно, что вы можете запустить его нормально. Могу я спросить, какую версию Python и т. Д. Вы используете? - person JPH   schedule 26.11.2012ioff
(и никаких дополнительных вызовов отрисовки внутри вашего цикла сion
). Однакоioff
может (т. Е. Разрешено) вызвать остановку основного цикла серверной части (или не может, точное поведение зависит от серверной части). Вот почему я предполагал, что проблема связана сioff
, во всяком случае. Что произойдет, если вместо этого вы воспользуетесь модулемmatplotlib.animations
? matplotlib.org/api/animation_api.html (в этом случае проще всего использоватьFuncAnimation
.) - person Joe Kington   schedule 26.11.2012from pylab import *
, если вы не используете что-то из оболочки, но это чисто стилистическая проблема и в данном случае не повлияет на вашу проблему. В любом случае используйте вместо этогоmatplotlib.pyplot
(соглашение -import matplotlib.pyplot as plt
, чтобы избежать чрезмерно многословного кода). - person Joe Kington   schedule 26.11.2012pyplot
vspylab
,pyplot
- это просто ядро matplotlib, тогда какpylab
- этоmatplotlib
,numpy
иmatplotlib.mlab
в одном лице. Это гигантское пространство имен, и действительно лучше различать, откуда что происходит. Конечно, все это в основном стилистическое, но это значительно упрощает поиск подходящего места для помощи, если не что иное. - person Joe Kington   schedule 26.11.2012FuncAnimation
, если вы хотите вызвать обновление, но не слишком сложно сделать наоборот.) Я снимаю в темноте, так как не вижу такой же проблемы на linux, но, во всяком случае, я могу сделать несколько предположений. - person Joe Kington   schedule 26.11.2012cmd
и запуститеpython filename.py
) - person Joe Kington   schedule 26.11.2012