使用 Matplotlib 创建 CSV 数据的实时图

Posted

技术标签:

【中文标题】使用 Matplotlib 创建 CSV 数据的实时图【英文标题】:Creating a live plot of CSV data with Matplotlib 【发布时间】:2015-11-02 12:18:09 【问题描述】:

我正在尝试使用 Matplotlib 来可视化一些测量结果。测量通常持续约 24 小时,并将在 csv 中包含约 30k 行数据。我一直在努力让我的情节真正动画化。我可以执行代码,它会显示截至当前时间点的快照,但仅此而已。当我尝试自动缩放它时,没有任何绘图,它只是默认为两个轴上的 -.6 到 +.6 的视图。我应该调用 plt.draw() 来让它工作吗?这是我目前所拥有的:

import numpy as np
import datetime as dt
import matplotlib
import matplotlib.pyplot as plt
from matplotlib import animation

FMT = '%Y-%m-%d %H:%M:%S.%f'
data = np.genfromtxt('sampleData.csv', delimiter=',', skip_header=5,
                 names=['x', 'y', 'z', 'w'], dtype=['object', 'int8', 'int8', 'float'])                  

mytime = [dt.datetime.strptime(i.decode('ascii'), FMT) for i in data['x']]
thickness = data['w']

fig = plt.figure()
axes = fig.add_subplot(111)
line, = axes.plot([], [], '.')
plt.show(block=False)

def init():
    line.set_data([],[]) 
    return line,

fig.canvas.draw()

def animate(i):
    xdata = mytime[:i]
    ydata = thickness[:i]
    line.set_data(xdata, ydata)
    plt.draw()
    axes.relim()
    axes.autoscale(True,'both',True) 
    axes.autoscale_view(True,True,True)
    return line,

anim = animation.FuncAnimation(fig, animate, init_func=init,  
                           interval=0, blit=True)

plt.show()

这是来自 CSV 的数据示例行:

2013-09-25 14:51:15.329091,1,0,439.80,,,,0,0,

【问题讨论】:

你的意思是还有数据传入并且情节没有更新吗?或者您想要现有数据的移动动画? 有数据进来,直到我停止它。我相信我已经让它工作了,但它的绘图速度太慢了。我正在以大约 60Hz 的频率进行测量,现在我看着这个我不确定 matplotlib 能否跟上。有什么建议吗? 一方面,如果我通过 CSV 文件传递​​所有数据,我不会期望能够管理这样的速度。 (注意:你实际上并没有回答我的问题,如果你改进了代码,你还没有更新问题中的文字。没有帮助。) 目前还不清楚您要在这里实现什么,所以我将尝试改写@cphlewis 的问题。您说您正在使用 CSV 文件。这意味着现有的静态数据存储。然后您使用animation 并谈论一段时间内的传入数据,这意味着输入数据。那么 - 你能解释发生了什么 - 是否有另一个过程不断附加/替换 .csv 并且你想在新数据进入时更新绘图?或者您想对csv 中的数据进行动画处理,就好像它是“实时”传入的?还是别的什么? 对不起,伙计们,我看到了混乱。我的测量程序不断写入 .csv。它不会更改以前的数据,只是逐行添加。我正在尝试显示不断增长的数据的实时视觉效果。我看到的问题是,在最初的 15 或 20 秒后,视觉效果会大大减慢,直至基本上停止。 【参考方案1】:

你有两个问题。一是因为你实际上画了两次东西,二是纯粹是人类心理(随着时间的推移,情节似乎变慢了,因为你在 10000 上加 1 点,而不是在 10 或 100 上加 1 点)。


让我们先讨论双抽:

FuncAnimation 会为你绘制东西,但是通过告诉它使用 blitting,它只会更新轴的内部而不是刻度等。因此,你需要手动调用 draw,但动画也会打电话给draw_artist

您应该能够通过删除 blit=Trueplt.draw() 获得至少 2 倍的加速

此外,通过设置interval=0,你会强制它不断地绘制,这将有效地强制事物锁定。将间隔设置为更合理的值,例如25(间隔以毫秒为单位。“25”为 40 fps。)。

例如,这对我来说很流畅:

import numpy as np
import matplotlib.pyplot as plt
from matplotlib import animation

y = np.random.normal(0, 1, 10000).cumsum(axis=0)
x = np.arange(y.size)

fig, ax = plt.subplots()
line, = ax.plot([], [], '.')
ax.margins(0.05)

def init():
    line.set_data(x[:2],y[:2])
    return line,

def animate(i):
    i = min(i, x.size)
    xdata = x[:i]
    ydata = y[:i]
    line.set_data(xdata, ydata)
    ax.relim()
    ax.autoscale()
    return line,

anim = animation.FuncAnimation(fig, animate, init_func=init, interval=25)

plt.show()

我还添加了ax.margins(0.05) 以避免坐标轴限制捕捉到下一个最接近的“偶数”数字并给出“生涩”的外观。


但是,由于您正在逐步绘制越来越多的数据,因此变化率将似乎变慢,这仅仅是因为随着时间的推移,似乎越来越少的数据会发生变化。在 10000 的末尾加一个点几乎不会引起注意,但是在 10 的末尾加一个点非常很明显。

因此,情节看起来在开始时比在结束时更“令人兴奋”,即使它以相同的速度更新。

这与 matplotlib 无关,是您选择为数据设置动画的方式的结果。

要解决这个问题,您可以考虑在数据中移动一个“滑动窗口”并一次绘制恒定数量的点。举个例子:

import numpy as np
import matplotlib.pyplot as plt
from matplotlib import animation

y = np.random.normal(0, 1, 1000000).cumsum(axis=0)
x = np.arange(y.size) + 1

fig, ax = plt.subplots()
line, = ax.plot([], [], 'k-')
ax.margins(0.05)

def init():
    line.set_data(x[:2],y[:2])
    return line,

def animate(i):
    win = 300
    imin = min(max(0, i - win), x.size - win)
    xdata = x[imin:i]
    ydata = y[imin:i]
    line.set_data(xdata, ydata)
    ax.relim()
    ax.autoscale()
    return line,

anim = animation.FuncAnimation(fig, animate, init_func=init, interval=25)

plt.show()

【讨论】:

谢谢乔!对于我的具体实现,查看整个情节的形状更有益,但我会将您的第二个示例放在我的后袋中,以用于我想到的其他项目。我也很感谢您清理我的代码,我对此有些陌生。您所做的更改帮助我意识到我在进行这种可视化时完全错了。当我修改您的代码并运行它时,我注意到它只显示 .csv 中的数据,直到我执行我的代码。我看到的减速是数据用完了,我的代码需要更长的时间才能到达那里。 @MBlankfield - 很高兴为您提供帮助!我省略了重新读取 csv 文件部分,所以正如你提到的,它读取一次。要有效地从 csv 文件中获取“实时”更新,您需要一个稍微复杂一些的解决方案。此时您可能会考虑将内容存储在数据库或 HDF 中,因为这将使查询最近写入的点变得更加容易/更快。 或者,您可以直接从仪器中读取数据,这样您的代码既负责绘图又负责写入日志文件。【参考方案2】:

我有下面的列作为熊猫过滤器列的操作:

    Object      A_START_TIME   B_START_TIME  B_STOP_TIME       A_STOP_TIME
0     17          27158762       27158803      27178575          27259032 

1     18          27259557       27259605      27263225          27323232

2     19          27323266       27323299      27332959          27341878

我正在考虑绘制如下所述的内容:

for 17 : A_START_TIME----[B_START_TIME========B_STOP_TIME]-------A_STOP_TIME

For 18 : A_START_TIME----[B_START_TIME========B_STOP_TIME]-------A_STOP_TIME

【讨论】:

以上是关于使用 Matplotlib 创建 CSV 数据的实时图的主要内容,如果未能解决你的问题,请参考以下文章

如何使用matplotlib绘制复数(Argand图)

Matplotlib/Genfromtxt:针对时间的多个图,跳过丢失的数据点,来自 .csv

如何在 python 中使用 matplotlib 和 pandas 绘制 CSV 数据

Python+pandas+matplotlib数据分析与可视化案例

在 PyQt5 中使用 Matplotlib 绘制 CSV 文件

从 matplotlib 中的 .CSV 文件制作多线图