首页 > 解决方案 > Python:matplotlib livedata plot with buffer,更有效的方法

问题描述

我尝试编写脚本来绘制真实对象的实时数据,但我需要更有效的方法。我认为问题在于始终存储相同数量的样本来绘制,并同时收集和绘制它。我得到了一些代码,但我对它并不完全满意。

import time
from math import sin, cos
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation

x_value = 0
x_list = []
y1_list = []
y2_list = []

props = dict(boxstyle='round', facecolor='wheat', alpha=0.5)
plt.rcParams['animation.html'] = 'jshtml'
fig, (ax1, ax2) = plt.subplots(2,1)
ax1.set_title("Power supply parameters")
ax1.set(ylabel='Voltage [V]')
ax2.set(xlabel='sample [n]', ylabel='Current [A]')
ax1.set_ylim(-1.5, 1.5)
ax2.set_ylim(-1.5,1.5)
ax1.grid(1)
ax2.grid(1)

box1 = ax1.text(.87, 0.95, str(0), transform=ax1.transAxes, fontsize=14,
        verticalalignment='top', bbox=props)
box2 = ax2.text(0.87, 0.95, str(0), transform=ax2.transAxes, fontsize=14,
        verticalalignment='top', bbox=props)

def annotate(last_y1, last_y2):
    box1.set_text(str(round(last_y1,3)))
    box2.set_text(str(round(last_y2,3)))

def data_gen(x_value):
    x_value += 0.2
    x_value = round(x_value,3)
    total_1 = round(sin(x_value),3)
    total_2 = round(cos(x_value),3)
    time.sleep(0.1)
    return (x_value,total_1,total_2)

def run(i):
    global x_value ,x_list,y1_list, y2_list
    x, y1, y2 = data_gen(x_value)
    x_value += 0.2
    
    if len(x_list) <=20:
        x_list.append(x)
        y1_list.append(y1)
        y2_list.append(y2)
    else:
        x_list.append(x)
        x_list.pop(0)
        y1_list.append(y1)
        y1_list.pop(0)
        y2_list.append(y2)
        y2_list.pop(0)

    ax1.plot(x_list, y1_list, color='b')
    ax2.plot(x_list, y2_list, color='r')  

    ax1.set_xlim(left=max(0, x_list[-1] - 50), right=x_list[-1] + 10)
    ax2.set_xlim(left=max(0, x_list[-1] - 50), right=x_list[-1] + 10)
    
    annotate(y1_list[-1], y2_list[-1])

ani = FuncAnimation(fig, run, interval=10)
plt.show()

我想知道如何memoryview()为样本创建某种缓冲区,导致一遍又一遍地从列表中追加和弹出似乎太慢了,但我不知道如何使用它。

我会很高兴得到建议:)

[编辑] 下面是未来的固定版本:)

import time
from math import sin, cos
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
from matplotlib.lines import Line2D      

x_value = 0
x_list = []
y1_list = []
y2_list = []

props = dict(boxstyle='round', facecolor='wheat', alpha=0.5)
plt.rcParams['animation.html'] = 'jshtml'
fig, (ax1, ax2) = plt.subplots(2,1)
ax1.set_title("Power supply parameters")
ax1.set(ylabel='Voltage [V]')
ax2.set(xlabel='sample [n]', ylabel='Current [A]')
ax1.set_ylim(-1.5, 1.5)
ax2.set_ylim(-1.5,1.5)
ax1.grid(1)
ax2.grid(1)

line1 = Line2D([0],[0.0],color='blue')
ax1.add_line(line1)
line2 = Line2D([0],[0.0],color='red')
ax2.add_line(line2)


box1 = ax1.text(.87, 0.95, str(0), transform=ax1.transAxes, fontsize=14,
        verticalalignment='top', bbox=props)
box2 = ax2.text(0.87, 0.95, str(0), transform=ax2.transAxes, fontsize=14,
        verticalalignment='top', bbox=props)

def annotate(last_y1, last_y2):
    box1.set_text(str(round(last_y1,3)))
    box2.set_text(str(round(last_y2,3)))

def data_gen(x_value):
    x_value = round(x_value,3)
    total_1 = round(sin(x_value),3)
    total_2 = round(cos(x_value),3)
    return (x_value,total_1,total_2)

def run(i):
    global x_value ,x_list,y1_list, y2_list
    x, y1, y2 = data_gen(x_value)
    x_value += 0.2
    
    if len(x_list) <=200:
        x_list.append(x)
        y1_list.append(y1)
        y2_list.append(y2)
    else:
        x_list.append(x)
        x_list.pop(0)
        y1_list.append(y1)
        y1_list.pop(0)
        y2_list.append(y2)
        y2_list.pop(0) 

    ax1.set_xlim(left=max(0, x_list[-1] - 20), right=x_list[-1] + 10)
    ax2.set_xlim(left=max(0, x_list[-1] - 20), right=x_list[-1] + 10)

    line1.set_data(x_list,y1_list)
    line2.set_data(x_list,y2_list)
    annotate(y1_list[-1], y2_list[-1])

ani = FuncAnimation(fig, run, interval=1)
plt.show()

标签: pythonmatplotlibreal-time-data

解决方案


我将冒险并争辩说您存储数据的方式可能是代码中耗时最少的部分。

一个主要问题是您在每次迭代时都创建新行,而您应该创建 2 个 Line2D 对象并更新它们的数据(使用Line2D.set_data())。参见例如https://matplotlib.org/gallery/animation/unchained.html


推荐阅读