Python从线程更新Matplotlib [英] Python update Matplotlib from threads
问题描述
我对python世界还很陌生,不幸的是我还没有找到任何解决方案.
I'm pretty new to the python world and unfortunately I could not find any solution to this yet.
我正在Mac OS X 10.13.2上以matplotlib == 1.3.1运行python 3.6
I'm running python 3.6 with matplotlib==1.3.1 on Mac OS X 10.13.2
当前,我正在尝试构建一个小型软件,该软件以4Hz的频率获取数据并以1Hz的频率在图中显示所获取的数据.因此,我创建了一个在线程中运行以获取数据的类,并创建了另一个类以更新实际图.在它们之间有一个数据类,它将保存数据,并用作这两个类之间的接口.
Currently I'm trying to build a small software which fetches data at 4Hz and displays the fetched data in a plot at 1Hz. Therefore I created a class which runs in a thread to fetch the data and another class to update the actual plots. In-between there is a data class which will hold the data and is used as interface inbetween the two classes.
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()
由于命令行输出,我可以看到线程正在运行.但是由于某些原因,显示这些图的图形不会显示.
I can see that the threads are running due to the command line output. But for some reason the figure holding the plots won't show up.
火箭符号只会上下弹跳而不显示.请参阅附件的屏幕截图.
The rocket symbol will just bounce up and down instead of showing up. See attached Screenshot.
仅创建图并使用plt.show()命令的简单示例可以很好地工作.
Simple examples where the plot is only created ones and the plt.show() command is used works fine.
我不知道自己在做什么错.我希望你们中的任何一个都有一个主意.
I can't figure out what I'm doing wrong. I hope anyone of you might have an idea.
谢谢!
此处介绍的解决方案如何在matplotlib中更新图?对我不起作用,因为我不想局限于一定数量的帧(使用Matplotlib动画框架).我需要连续以1Hz的频率更新图.
Solutions presented here How to update a plot in matplotlib? will not work for me because I don't want to be limited to a certain number of frames (using the animation framework of Matplotlib). I need to update the plot with 1Hz continiously.
推荐答案
我认为您不能在主线程之外运行matplotlib GUI.因此,将绘图保留在主线程中,并使用FuncAnimation
来控制绘图,以下似乎可以正常工作.
I don't think you can run matplotlib GUI outside the main thread. So keeping the plotting in the main thread and using a FuncAnimation
to steer the plotting, the following seems to work fine.
由于while True
循环,即使关闭了窗口,它也将永远运行,因此对于任何实际应用程序,仍应对其进行调整.
Due to the while True
loop it will run forever, even after closing the window, so for any real world application this should still be adjusted.
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()
这篇关于Python从线程更新Matplotlib的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!