我试图在matplotlib中获得实时频谱分析仪类型图。我已经得到了一些代码(在StackOverflow上的其他帖子的帮助下),如下所示:
import time
import numpy as np
import matplotlib.pyplot as plt
plt.axis([0, 1000, 0, 1])
plt.ion()
plt.show()
i=0
np.zeros([1,500],'float')
lines=plt.plot(y[0])
while 1:
i=i+1
lines.pop(0).remove()
y = np.random.rand(1,100)
lines=plt.plot(y[0])
plt.draw()
代码有效,我得到了我想要的东西,但是有一个严重的问题。一段时间后,情节窗口会冻结。我知道程序仍在运行,检查 i 变量(我在Anaconda / Spyder中运行代码,因此我可以看到变量)。然而,情节窗口将显示"无响应"如果我通过ctrl + c终止Spyder中的python程序,那么绘图窗口将恢复生命并显示最新的情节。
我在这里是如何进一步调试问题的。有人帮忙吗?
由于
答案 0 :(得分:1)
我不确定添加plt.pause
是否能完全解决您的问题。应用程序崩溃可能需要更长时间。应用程序使用的内存似乎会随着时间的推移不断增加(即使在添加plt.pause
之后)。以下两条建议可以帮助您解决当前问题:
我不会在remove
和plot
的每次迭代中移除/重新创建线条艺术家,而是在整个动画中使用相同的艺术家,只需更新其ydata
。
我会使用显式处理程序来获取斧头和数字,并在图show
和draw
上明确调用manager
和canvas
而不是去通过pyplot
进行隐式调用,遵循post by tcaswell中提供的建议。
按照上面的说法,代码看起来像这样:
import numpy as np
import matplotlib.pyplot as plt
fig, ax = plt.subplots()
ax.axis([0, 100, 0, 1])
y = np.random.rand(100)
lines = ax.plot(y)
fig.canvas.manager.show()
i=0
while 1:
i=i+1
y = np.random.rand(100)
lines[0].set_ydata(y)
fig.canvas.draw()
fig.canvas.flush_events()
我运行上面的代码大约10分钟,应用程序使用的内存一直保持稳定,而当前代码使用的内存(没有plt.pause
)增加了大约30MiB在同一时期。
答案 1 :(得分:0)
为了回答自己,我通过添加
解决了这个问题plt.pause(0.01)
之后
plt.draw()
这可能允许GUI在新数据进入之前完成绘图并在某处清除缓冲区(我的猜测)。
答案 2 :(得分:0)
我知道我迟到了回答这个问题,但对于你的问题,你可以查看"操纵杆"包。它基于line.set_data()和canvas.draw()方法,可选轴重新缩放,因此最有可能比删除行和添加新行更快。它还允许交互式文本记录或图像绘图(除了图形绘图)。 无需在单独的线程中执行您自己的循环,包就可以处理它,只需提供您希望的更新频率。此外,终端在实时绘图时仍然可用于更多监控命令,这是使用"而真正的"环。 请参阅http://www.github.com/ceyzeriat/joystick/或https://pypi.python.org/pypi/joystick(使用pip install操纵杆进行安装)
尝试:
import joystick as jk
import numpy as np
import time
class test(jk.Joystick):
# initialize the infinite loop decorator
_infinite_loop = jk.deco_infinite_loop()
def _init(self, *args, **kwargs):
"""
Function called at initialization, see the doc
"""
self._t0 = time.time() # initialize time
self.xdata = np.array([self._t0]) # time x-axis
self.ydata = np.array([0.0]) # fake data y-axis
# create a graph frame
self.mygraph = self.add_frame(jk.Graph(name="test", size=(500, 500), pos=(50, 50), fmt="go-", xnpts=100, xnptsmax=1000, xylim=(None, None, 0, 1)))
@_infinite_loop(wait_time=0.2)
def _generate_data(self): # function looped every 0.2 second to read or produce data
"""
Loop starting with the simulation start, getting data and
pushing it to the graph every 0.2 seconds
"""
# concatenate data on the time x-axis
self.xdata = jk.core.add_datapoint(self.xdata, time.time(), xnptsmax=self.mygraph.xnptsmax)
# concatenate data on the fake data y-axis
self.ydata = jk.core.add_datapoint(self.ydata, np.random.random(), xnptsmax=self.mygraph.xnptsmax)
self.mygraph.set_xydata(t, self.ydata)
t = test()
t.start()
t.stop()