Python从线程中更新Matplotlib

问题描述 投票:3回答:2

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

由于命令行的输出,我可以看到线程正在运行。但由于某些原因,持有图的数字不会显示出来。

火箭符号只会上下跳动,而不会显示出来。见附件截图。

简单的例子中,情节只有创建的,使用plt.show()命令可以正常工作。

我想不通我到底做错了什么。我希望你们中的任何人可能有一个想法。

谢谢

编辑:这里提出的解决方案 如何在matplotlib中更新一个情节? 对我来说是行不通的,因为我不想被限制在一定的帧数内(使用Matplotlib的动画框架)。我需要以1Hz的速度持续更新情节。

图不显示

python multithreading macos matplotlib python-multithreading
2个回答
2
投票

我不认为你可以在主线程之外运行matplotlib GUI。因此,在主线程中保持绘图,并使用一个 FuncAnimation 来引导绘图,下面的方法似乎很有效。

由于 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()
© www.soinside.com 2019 - 2024. All rights reserved.