Python 从线程更新 Matplotlib

Python update Matplotlib from threads

我是 python 世界的新手,不幸的是我还找不到任何解决方案。

我是 运行 python 3.6,matplotlib==1.3.1 Mac OS X 10.13.2

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

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()

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

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

仅创建绘图且使用 plt.show() 命令的简单示例效果很好。

我不知道我做错了什么。我希望你们中的任何人都有想法。

谢谢!

编辑:这里 How to update a plot in matplotlib? 提供的解决方案对我不起作用,因为我不想被限制在一定数量的帧(使用 Matplotlib 的动画框架)。我需要连续更新1Hz的情节。

Figure not showing up

我认为您无法在主线程之外 运行 matplotlib GUI。因此,将绘图保留在主线程中并使用 FuncAnimation 来引导绘图,以下似乎工作正常。

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

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()