Matplotlib“实时”在Python中绘图

时间:2019-02-06 15:49:54

标签: python matplotlib plot real-time-data

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

这是我编写的代码:

从时间导入睡眠 导入序列 导入matplotlib.pyplot作为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)

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

编辑: 在对ImportanceOfBeingErnest发表评论后,我尝试实现给定here的答案。代码如下:

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

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

1 个答案:

答案 0 :(得分:0)

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

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

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

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

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

1。导入

pyqtgraph

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

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

3。编写用于更新绘图和更新数据容器的功能

# 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]

4。最后,运行循环

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()

我希望有帮助。

相关问题