我想以一种快速更新的方式实时绘制.

我拥有的数据:

  • 通过串行端口以62.5 Hz的频率到达
  • 数据对应32个传感器(因此绘制32条线与时间).
  • 32点*62.5Hz=2000点/秒

我当前的绘图循环存在的问题是,它的运行速度低于62.5[赫兹],这意味着从串行端口输入I miss some data.

我正在寻找此问题的任何解决方案,以便:

  • 要保存来自串行端口的所有数据.
  • 绘制数据(甚至跳过几个点/使用平均值/删除旧点,只保留最近的点)

这是我的代码,我使用随机数据来模拟串口数据.

import numpy as np 
import time 
import matplotlib.pyplot as plt

#extra plot debugging
hz_ = [] #list of speed
time_=[] #list for time vs Hz plot


 #store all data generated
store_data = np.zeros((1, 33))
 #only data to plot 
to_plot = np.zeros((1, 33)) 
 #color each line 
colours = [f"C{i}" for i in range (1,33)]

fig,ax = plt.subplots(1,1, figsize=(10,8))
ax.set_xlabel('time(s)')
ax.set_ylabel('y')
ax.set_ylim([0, 300])
ax.set_xlim([0, 200])

start_time = time.time()
for i in range (100):
    loop_time = time.time()
     #make data with col0=time and col[1:11] = y values
    data = np.random.randint(1,255,(1,32)).astype(float) #simulated data, usually comes in at 62.5 [Hz]
    data =  np.insert(data, 0, time.time()-start_time).reshape(1,33) #adding time for first column
    store_data = np.append(store_data, data , axis=0)
    to_plot = store_data[-100:,]
    
    for i in range(1, to_plot.shape[1]):
        ax.plot(to_plot[:,0], to_plot[:,i],c = colours[i-1], marker=(5, 2), linewidth=0, label=i)
        #ax.lines = ax.lines[-33:] #This soluition speeds it up, to clear old code. 

    fig.canvas.draw()  
    fig.canvas.flush_events()
    Hz = 1/(time.time()-loop_time)
     #for time vs Hz plot
    hz_.append(Hz)
    time_.append( time.time()-start_time)
    print(1/(time.time()-loop_time), "Hz - frequncy program loops at")
   
 #extra fig showing how speed drops off vs time
fig,ax = plt.subplots(1,1, figsize=(10,8))
fig.suptitle('Decreasingn Speed vs Time', fontsize=20)
ax.set_xlabel('time(s)')
ax.set_ylabel('Hz')

ax.plot(time_, hz_)
fig.show()

enter image description here

我在使用

ax.lines = ax.lines[-33:]

to remove older points, and this speed up the plotting, but still slower than the speed i aquire data. enter image description here

任何确保我收集所有数据并绘制一般趋势线(即使不是所有点)的库/解决方案都可以.也许是一些并行采集数据和绘图的东西?

推荐答案

您可以try 使用两个单独的进程:

  • 一个用于获取和存储数据
  • 一个用于绘制数据

下面有两个基本的脚本来理解这个 idea .

以下是生成数据的gen.py脚本:

#!/usr/bin/env python3

import time
import random

LIMIT_TIME = 100  # s
DATA_FILENAME = "data.txt"


def gen_data(filename, limit_time):
    start_time = time.time()
    elapsed_time = time.time() - start_time
    with open(filename, "w") as f:
        while elapsed_time < limit_time:
            f.write(f"{time.time():30.12f} {random.random():30.12f}\n")  # produces 64 bytes
            f.flush()
            elapsed = time.time() - start_time
            

gen_data(DATA_FILENAME, LIMIT_TIME)

下面是plot.py脚本,用于绘制数据(从this one修改):

#!/usr/bin/env python3


import io
import time
import matplotlib.pyplot as plt
import matplotlib as mpl
import matplotlib.animation


BUFFER_LEN = 64
DATA_FILENAME = "data.txt"
PLOT_LIMIT = 20
ANIM_FILENAME = "video.gif"


fig, ax = plt.subplots(1, 1, figsize=(10,8))
ax.set_title("Plot of random numbers from `gen.py`")
ax.set_xlabel("time / s")
ax.set_ylabel("random number / #")
ax.set_ylim([0, 1])


def get_data(filename, buffer_len, delay=0.0):
    with open(filename, "r") as f:
        f.seek(0, io.SEEK_END)
        data = f.read(buffer_len)
        if delay:
            time.sleep(delay)
    return data


def animate(i, xs, ys, limit=PLOT_LIMIT, verbose=False):
    # grab the data
    try:
        data = get_data(DATA_FILENAME, BUFFER_LEN)
        if verbose:
            print(data)
        x, y = map(float, data.split())
        if x > xs[-1]:
            # Add x and y to lists
            xs.append(x)
            ys.append(y)
            # Limit x and y lists to 10 items
            xs = xs[-limit:]
            ys = ys[-limit:]
        else:
            print(f"W: {time.time()} :: STALE!")
    except ValueError:
        print(f"W: {time.time()} :: EXCEPTION!")
    else:
        # Draw x and y lists
        ax.clear()
        ax.set_ylim([0, 1])
        ax.plot(xs, ys)


# save video (only to attach here) 
#anim = mpl.animation.FuncAnimation(fig, animate, fargs=([time.time()], [None]), interval=1, frames=3 * PLOT_LIMIT, repeat=False)
#anim.save(ANIM_FILENAME, writer='imagemagick', fps=10)
#print(f"I: Saved to `{ANIM_FILENAME}`")

# show interactively
anim = mpl.animation.FuncAnimation(fig, animate, fargs=([time.time()], [None]), interval=1)
plt.show()
plt.close()

Anim

请注意,我还包括并注释掉了用于生成上述动画GIF的代码部分.

我相信这足够让你走了.

Python相关问答推荐

使用Python OpenCV的文本检测分割

如何将桌子刮成带有Se的筷子/要求/Beautiful Soup ?

Python中的函数中是否有充分的理由接受float而不接受int?

如何使用stride_tricks.as_strided逆转NumPy数组

如果索引不存在,pandas系列将通过索引获取值,并填充值

当密钥是复合且唯一时,Pandas合并抱怨标签不唯一

如何使用symy打印方程?

比较2 PD.数组的令人惊讶的结果

抓取rotowire MLB球员新闻并使用Python形成表格

对于一个给定的数字,找出一个整数的最小和最大可能的和

Python库:可选地支持numpy类型,而不依赖于numpy

用Python解密Java加密文件

使用@ guardlasses. guardlass和注释的Python继承

Python—从np.array中 Select 复杂的列子集

梯度下降:简化要素集的运行时间比原始要素集长

如何在图中标记平均点?

当我try 在django中更新模型时,模型表单数据不可见

计算分布的标准差

如何使用Numpy. stracards重新编写滚动和?

如何按row_id/row_number过滤数据帧