Matplotlib动画TclError: 堆栈空间不足(无限循环?)
我正在尝试实现一个动画,这个动画在不确定的时间间隔内重新绘制。我的想法是添加两个线程,一个线程用来打开图形,另一个线程用来处理从主线程推送过来的更新。
import threading
import matplotlib.pyplot as plt
from Queue import Queue
import numpy
import time
class JobPlotter(object):
def __init__(self, log=None, **kwargs):
self.axes = None
self.lines = None
self.queue = Queue(maxsize=1)
self.fig = None
def update(self, data):
print 'Update'
self.queue.put(data)
def _draw_plot(self, labels, data):
self.fig = plt.figure()
self.axes = []
plt.ion()
for idx in range(len(labels)):
ax = self.fig.add_subplot(len(labels), 1, idx)
ax.plot(range(len(data[idx])), data[idx], label=labels[idx])
self.axes.append(ax)
print 'show'
self.fig.canvas.draw()
def setup(self):
print 'Setup: Start'
data = self.queue.get()
print 'Setup: Got Data'
labels = data[0]
data = numpy.array(data[1:]).T
data_plot = threading.Thread(None, self._draw_plot, 'PlotDraw', (labels, data))
data_plot.daemon = True
data_plot.start()
print 'Setup: Done'
while True:
self.loop()
def loop(self):
data = self.queue.get()
print 'Loop: Got Data'
labels = data[0]
data = numpy.array(data[1:]).T
for idx in range(len(labels)):
self.axes[idx].plot(range(len(data[idx])), data[idx], label=labels[idx])
self.fig.canvas.draw()
print 'Loop: Done'
if __name__ == '__main__':
foo = JobPlotter()
data_plot = threading.Thread(None, foo.setup, 'PlotDraw', ())
data_plot.daemon = True
data_plot.start()
data = [['test'], [1], [2], [3], [4], [5], [6]]
while True:
temp = [[(x[0]*3) % 8] for x in data[1:]]
data = [data[0]]
data.extend(temp)
foo.update(data)
time.sleep(5)
代码可以运行,但在第二次调用更新时,在绘制请求时就出问题了:
Setup: StartUpdate
Setup: Got Data
Setup: Done
show
Update
Loop: Got Data
Exception in thread PlotDraw:
Traceback (most recent call last):
File "C:\Python27\lib\threading.py", line 810, in __bootstrap_inner
self.run()
File "C:\Python27\lib\threading.py", line 763, in run
self.__target(*self.__args, **self.__kwargs)
File "D:/src/EE_EVT_Scripts/Sensors/PrintWeld/aniator.py", line 50, in setup
self.loop()
File "D:/src/EE_EVT_Scripts/Sensors/PrintWeld/aniator.py", line 62, in loop
plt.draw()
File "C:\Python27\lib\site-packages\matplotlib\pyplot.py", line 555, in draw
get_current_fig_manager().canvas.draw()
File "C:\Python27\lib\site-packages\matplotlib\backends\backend_tkagg.py", line 349, in draw
tkagg.blit(self._tkphoto, self.renderer._renderer, colormode=2)
File "C:\Python27\lib\site-packages\matplotlib\backends\tkagg.py", line 20, in blit
tk.call("PyAggImagePhoto", photoimage, id(aggimage), colormode, id(bbox_array))
TclError: out of stack space (infinite loop?)
Update
Update
我是不是漏掉了什么?
1 个回答
0
我觉得问题有两个方面。首先,我需要在创建图形之前把pyplt设置为交互模式,这可以通过调用 plt.ion()
来实现。然后,我需要把所有的 show()
替换成 draw()
。这样做可以在交互模式下打开图形。
import threading
import matplotlib.pyplot as plt
from Queue import Queue
import numpy
import time
class JobPlotter(object):
def __init__(self, log=None, **kwargs):
self.axes = None
self.lines = None
self.queue = Queue(maxsize=1)
self.fig = None
def update(self, data):
print 'Update'
self.queue.put(data)
def _draw_plot(self, labels, data):
plt.ion()
self.fig = plt.figure()
self.axes = []
for idx in range(len(labels)):
ax = self.fig.add_subplot(len(labels), 1, idx)
ax.plot(range(len(data[idx])), data[idx], label=labels[idx])
self.axes.append(ax)
print 'show'
self.fig.canvas.draw()
def setup(self):
print 'Setup: Start'
data = self.queue.get()
print 'Setup: Got Data'
labels = data[0]
data = numpy.array(data[1:]).T
self._draw_plot(labels,data)
# data_plot = threading.Thread(None, self._draw_plot, 'PlotDraw', (labels, data))
# data_plot.daemon = True
# data_plot.start()
print 'Setup: Done'
while True:
self.loop()
def loop(self):
data = self.queue.get()
print 'Loop: Got Data'
labels = data[0]
data = numpy.array(data[1:]).T
for idx in range(len(labels)):
self.axes[idx].plot(range(len(data[idx])), data[idx], label=labels[idx])
self.fig.canvas.draw()
print 'Loop: Done'
if __name__ == '__main__':
foo = JobPlotter()
data_plot = threading.Thread(None, foo.setup, 'PlotDraw', ())
data_plot.daemon = True
data_plot.start()
data = [['test','bar'], [1,2], [2,6], [3,7], [4,8], [5,8], [6,5]]
while True:
# temp = [[(i*3) % 16] for x in data[1:] for i in x]
# data = [data[0]]
# data.extend(temp)
foo.update(data)
time.sleep(5)