Matplotlib动画TclError: 堆栈空间不足(无限循环?)

0 投票
1 回答
737 浏览
提问于 2025-05-01 10:01

我正在尝试实现一个动画,这个动画在不确定的时间间隔内重新绘制。我的想法是添加两个线程,一个线程用来打开图形,另一个线程用来处理从主线程推送过来的更新。

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)

撰写回答