繁体   English   中英

Matplotlib在Python中“实时”绘图

[英]Matplotlib “real time” plotting in python

我在python 3.7上。 我正在尝试从串行端口读取数据,这将是7个不同的字节。 然后,我想在不同的子图中绘制每个不同的字节。 我想每500毫秒读取一次串行端口,并且每次读取时都将新数据添加到子图中。 每次读取都会提供一个数据,以便在每个子图上进行绘制。 这基本上是传感器读数。

这是我编写的代码:

从时间导入睡眠导入串行导入matplotlib.pyplot as plt

f=plt.figure(1)
ax=[0 for x in range(7)]
for i in range(0,7):
    ax[i]=f.add_subplot(4,2,1+i)

ser = serial.Serial('COM3', 115200) # Establish the connection on a specific port
counter = 0 
byte=ser.readline() #first line not to be plotted
while True:
    counter +=1
    ser.write(b'9') # send a command to the arduino
    byte=ser.read(7) #read 7 bytes back
    for i in range(0,7):
        ax[i].plot(counter, byte[i]) # Trying to plot the new values to each different subplots
    plt.pause(0.01)
    sleep(.5) # Delay for one half of a second

如图所示,x轴和y轴都适合我要输入的值,但是绘图上根本没有数据。 如果我使用散点图而不是绘图,它可以工作,但是通用性较差,并且我无法绘制想要的图形类型。 我还尝试不使用串行数据而是仅一个接一个地显示列表中的点来重现此问题:

import matplotlib.pyplot as plt
from time import sleep

f=plt.figure()
series=[[4,3,2,1],[8,7,6,5],[12,11,10,9]]
counter=0
ax=[0 for x in range(7)]

for i in range(0,3):
    ax[i]=f.add_subplot(4,2,1+i)


for j in range (0,4):
    counter=counter+1
    for i in range(0,3):
        ax[i].plot(counter,series[i][j])
    plt.pause(0.01)
    sleep(1)

而且它所做的完全相同,我在图上得到的最终图像是: 在此处输入图片说明 该图显示轴已绘制我想要绘制的内容,但未绘制任何内容。 关键是我不想清除全部图并重画所有内容,因为对于数据传感器,我将有大约30天的数据要连续显示。 我编写的代码在做什么错?

编辑:在对ImportanceOfBeingErnest进行评论后,我尝试执行此处给出的答案。 代码如下:

from time import sleep
import serial
import matplotlib.pyplot as plt
import numpy

plt.ion()
f=plt.figure()
ax=[0 for x in range(7)]
lines=[0 for x in range(7)]
for i in range(0,7):
    ax[i]=f.add_subplot(4,2,1+i)
    lines[i]=ax[0].plot([],[])


def update_line(hl, new_datax, new_datay):
    hl.set_xdata(numpy.append(hl.get_xdata(), new_datax))
    hl.set_ydata(numpy.append(hl.get_ydata(), new_datay))
    plt.draw()

ser = serial.Serial('COM3', 115200) # Establish the connection on a specific port
counter = 0 
byte=ser.readline() #first line not to be plotted
while True:
    counter +=1
    ser.write(b'9') # send a command to the arduino
    byte=ser.read(7) #read 7 bytes back
    for i in range(0,7):
        update_line(lines[i][0], counter, byte[i]) # Trying to plot the new values to each different subplots
    plt.pause(0.01)
    sleep(.5) # Delay for one half of a second

但是它仍然没有显示任何东西。 我有点猜想我错过了一个图和/或在某个地方清除,但是尝试了几种选择后却无法正常工作。

作为一个在光学实验室工作的人,努力使Matplotlib进行实时绘图,我感到很痛苦,因此我强烈建议为此选择Matplotlib以外的其他东西(例如 pyqtgraph )。

就是说,我已经让Matplotlib从传感器数据执行一些实时绘图。 我发现它有问题。 这里是一些想法以及使用matplotlib的解决方案:

尽可能使用字典。 为什么? 由于访问字典的速度很快,因此我发现字典键比列表索引更易于使用。

使用列表而不是NumPy数组。 为什么? 因为每次您调整NumPy数组的大小或附加NumPy数组时,都必须将其完全重写为内存中的新对象。 这是非常昂贵的。 列表可以调整大小并附加到可以忽略不计的成本中。

下面的代码使用随机数据来模拟传入的传感器数据并简化故障排除。

1.进口

from time import sleep
import matplotlib.pyplot as plt
import numpy as np
#import serial

2.设置您的matplotlib对象和数据容器

# specify how many points to show on the x-axis
xwidth = 10

# use real-time plotting
plt.ion()

# setup each of the subplots
ax = []
fig, ax[0:7] = plt.subplots(7, 1, sharex=False, sharey=False)

# set up each of the lines/curves to be plotted on their respective subplots
lines = {index: Axes_object.plot([],[])[0] for index, Axes_object in enumerate(ax)}

# cache background of each plot for fast re-drawing, AKA Blit
ax_bgs = {index: fig.canvas.copy_from_bbox(Axes_object.bbox) 
          for index, Axes_object in enumerate(ax)}

# initial drawing of the canvas
fig.canvas.draw()

# setup variable to contain incoming serial port data
y_data = {index:[0] for index in range(len(ax))}
x_data = [-1]

3.编写函数以更新绘图和更新数据容器

def update_data(new_byte, ):
    x_data.append(x_data[-1] + 1)
    for i, val in enumerate(new_byte): 
        y_data[i].append(val)

def update_graph():
    for i in y_data.keys():
        # update each line object
        lines[i].set_data(x_data, y_data[i])

        # try to set new axes limits
        try:
            ax[i].set_xlim([x_data[-1] - xwidth, x_data[-1]])
            if max(y_data[i][-xwidth:]) > ax[i].get_ylim()[1]:
                new_min = min(y_data[i][-xwidth:])
                new_max = max(y_data[i][-xwidth:])
                ax[i].set_ylim([new_min-abs(new_min)*0.2, new_max+abs(new_max)*0.2])
        except:
            continue

    fig.canvas.draw()

4.最后,运行循环

#ser = serial.Serial('COM3', 115200) # Establish the connection on a specific port
#byte=ser.readline() #first line not to be plotted


while x_data[-1] < 30:
    # ser.write(b'9') # send a command to the arduino
    # byte=ser.read(7) #read 7 bytes back
    byte = np.random.rand(7)

    update_data(byte)
    update_graph()

    sleep(.1) # Delay for an arbitrary amount of time

希望对您有所帮助。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM