簡體   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