Python 从线程更新 Matplotlib

der*_*lix 3 python macos multithreading matplotlib python-multithreading

我对 python 世界还很陌生,不幸的是我还找不到任何解决方案。

我在 Mac OS X 10.13.2 上运行 python 3.6 和 matplotlib==1.3.1

目前我正在尝试构建一个小型软件,它以 4Hz 的频率获取数据,并以 1Hz 的频率在绘图中显示获取的数据。因此,我创建了一个在线程中运行的类来获取数据,并创建了另一个类来更新实际的绘图。中间有一个数据类,它将保存数据并用作两个类之间的接口。

import matplotlib.pyplot as plt
import numpy as np
import threading
import random
import time

class MyDataClass():

    def __init__(self):

        self.XData = [0]
        self.YData = [0]


class MyPlotClass(threading.Thread):

    def __init__(self, dataClass):

        threading.Thread.__init__(self)

        self._dataClass = dataClass
        self._period = 1
        self._nextCall = time.time()

        self.hLine, = plt.plot(0, 0)

        plt.ion()

    def run(self):

        while True:
            self.hLine.set_data(self._dataClass.XData, self._dataClass.YData)
            plt.draw()
            print("updated %i datapoints" % len(self._dataClass.XData))
            # sleep until next execution
            self._nextCall = self._nextCall + self._period
            time.sleep(self._nextCall - time.time())


class MyDataFetchClass(threading.Thread):

    def __init__(self, dataClass):

        threading.Thread.__init__(self)

        self._dataClass = dataClass
        self._period = 0.25
        self._nextCall = time.time()

    def run(self):

        while True:
            # add data to data class
            self._dataClass.XData.append(self._dataClass.XData[-1] + 1)
            self._dataClass.YData.append(random.randint(0, 256))
            print("Added (%i, %i)" % (self._dataClass.XData[-1], self._dataClass.YData[-1]))
            # sleep until next execution
            self._nextCall = self._nextCall + self._period
            time.sleep(self._nextCall - time.time())


data = MyDataClass()
fetcher = MyDataFetchClass(data)
plotter = MyPlotClass(data)

fetcher.start()
plotter.start()

fetcher.join()
plotter.join()
Run Code Online (Sandbox Code Playgroud)

由于命令行输出,我可以看到线程正在运行。但由于某种原因,持有地块的人物不会出现。

火箭符号只会上下弹跳,而不是显示出来。请参阅随附的屏幕截图。

仅创建绘图并使用 plt.show() 命令的简单示例可以正常工作。

我不明白我做错了什么。我希望你们中的任何人都有一个想法。

谢谢!

编辑:此处提出的解决方案如何更新 matplotlib 中的绘图?对我不起作用,因为我不想限制在一定数量的帧(使用 Matplotlib 的动画框架)。我需要以 1Hz 连续更新绘图。

图没显示出来

Imp*_*est 5

我认为你不能在主线程之外运行 matplotlib GUI。因此,将绘图保留在主线程中并使用 aFuncAnimation来引导绘图,以下内容似乎工作正常。

由于while True循环它将永远运行,即使在关闭窗口之后也是如此,因此对于任何现实世界的应用程序,仍然应该进行调整。

import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
import numpy as np
import threading
import random
import time

class MyDataClass():

    def __init__(self):

        self.XData = [0]
        self.YData = [0]


class MyPlotClass():

    def __init__(self, dataClass):

        self._dataClass = dataClass

        self.hLine, = plt.plot(0, 0)

        self.ani = FuncAnimation(plt.gcf(), self.run, interval = 1000, repeat=True)


    def run(self, i):  
        print("plotting data")
        self.hLine.set_data(self._dataClass.XData, self._dataClass.YData)
        self.hLine.axes.relim()
        self.hLine.axes.autoscale_view()


class MyDataFetchClass(threading.Thread):

    def __init__(self, dataClass):

        threading.Thread.__init__(self)

        self._dataClass = dataClass
        self._period = 0.25
        self._nextCall = time.time()


    def run(self):

        while True:
            print("updating data")
            # add data to data class
            self._dataClass.XData.append(self._dataClass.XData[-1] + 1)
            self._dataClass.YData.append(random.randint(0, 256))
            # sleep until next execution
            self._nextCall = self._nextCall + self._period;
            time.sleep(self._nextCall - time.time())


data = MyDataClass()
plotter = MyPlotClass(data)
fetcher = MyDataFetchClass(data)

fetcher.start()
plt.show()
#fetcher.join()
Run Code Online (Sandbox Code Playgroud)