pyQtgraph 绘图延迟串行绘图

Posted

技术标签:

【中文标题】pyQtgraph 绘图延迟串行绘图【英文标题】:pyQtgraph plotting is delayed for serial plot 【发布时间】:2019-03-03 08:26:08 【问题描述】:

我正在尝试通过 python 中的 PyQTgraph 框架用我的 MPR121 和 arduino UNO 绘制 12 个通道。

一切都很好,我什至将数据写入 .csv 文件进行分析。但是,当我在 python 中运行代码时,“实时”绘图会延迟。我的代码附在下面。我想知道是否是我设置代码的方式导致了实时可视化的延迟。

# Importing required packages and libraries
import serial
import numpy as np
from pyqtgraph.Qt import QtGui, QtCore
import pyqtgraph as pg
import time
import csv

####################################################################################################################################
# Declaring variables SETUP!
csv_fileName = 'MPR_dataTest_20181909_T6.csv'                                  # File Name
numberOfSamples = 500                                                          # Specify number of samples
interactiveWindow = 100                                                        # Interactive visualization window
numberOfChannels = 12                                                          # Specifiy number of channels
serialPort = 'COM4'                                                            # Choose the Serial Port
baudrate = 19200                                                                # Set the baudrate (bytes/s)
curveColour = 'b'                                                              # Set curve colour
yMin = 50                                                                      # y-axis limit minimum
yMax = 320                                                                     # y-axis limit maximum
####################################################################################################################################
####################################################################################################################################

channelData = []
t = []                                                                         # Time array
sample = []                                                                    # Sample count array   
smpl = 1                                                                       # Sample counter (initialized at 0)
fileHeader = ['Sample','Time (s)','Ch1','Ch2','Ch3','Ch4','Ch5','Ch6','Ch7','Ch8','Ch9','Ch10','Ch11','Ch12', 'Ch13',\
              'Ch14', 'Ch15', 'Ch16', 'Ch17', 'Ch18', 'Ch19', 'Ch20']
fileHeader = fileHeader[0:numberOfChannels+2]

with open(csv_fileName, 'a', newline = '') as f:                               # opens file in directory and appends to that file (does not erase existing data)
    writer = csv.writer(f, delimiter = ',')                       
    # Naming Column Headers
    writer.writerow(fileHeader)

# Serial Port Communication 
# Begin Serial Port Stream
serialData = serial.Serial(port= serialPort)                                   # Open serial port object
serialData.baudrate = baudrate                                                 # Set baudrate
time.sleep(1)                                                                  # Time delay
serialData.reset_input_buffer()                                                # Clears the serial port queue so there's no overlap or erroneous data points
serialData.reset_output_buffer()                                               # Flush output buffer, aborting current output and discard all in buffer

# Interactive Real-Time Plotting
app = QtGui.QApplication([])                                                   # Initialize visulation GUI!
win = pg.GraphicsWindow(title="Signal from serial port")                       # Creates a plotter window
win.resize(1700,900)
pg.setConfigOption('background', 'w')                                          # Switch to using white background and black foreground
pg.setConfigOptions(antialias=True)                                            # Enable antialiasing for prettier plots 
ptr = (-interactiveWindow)*np.ones((numberOfChannels, 1))                      # set first x position

if numberOfChannels >= 1:
    p1 = win.addPlot(title="Channel 1")                                        # Creates empty space for the plot in the window
    curve1 = p1.plot(pen = curveColour)                                        # Create an empty "plot" (a curve to plot)
    p1.setLabel('left', 'Capacitance')                                         # Setting y-axis label                    
    p1.setLabel('bottom', 'samples')                                           # Setting x-axis label 
    p1.setYRange(yMin, yMax, padding=0)                                        # Setting y-axis limits
    ch1 = np.linspace(0,0,interactiveWindow)                                   # create array that will contain the relevant time series    
if numberOfChannels >= 2:
    p2 = win.addPlot(title="Channel 2")                                        
    curve2 = p2.plot(pen = curveColour)                                                
    p2.setLabel('left', 'Capacitance')                                                            
    p2.setLabel('bottom', 'samples')
    p2.setYRange(yMin, yMax, padding=0)                                              
    ch2 = np.linspace(0,0,interactiveWindow)                                                                                       
if numberOfChannels >= 3:
    p3 = win.addPlot(title="Channel 3")                                        
    curve3 = p3.plot(pen = curveColour)                                                
    p3.setLabel('left', 'Capacitance')                                                            
    p3.setLabel('bottom', 'samples')                                              
    p3.setYRange(yMin, yMax, padding=0)
    ch3 = np.linspace(0,0,interactiveWindow) 
if numberOfChannels >= 4:
    p4 = win.addPlot(title="Channel 4")                                        
    curve4 = p4.plot(pen = curveColour)                                                
    p4.setLabel('left', 'Capacitance')                                                            
    p4.setLabel('bottom', 'samples')                                              
    p4.setYRange(yMin, yMax, padding=0)
    ch4 = np.linspace(0,0,interactiveWindow)      
if numberOfChannels >= 5:
    p5 = win.addPlot(title="Channel 5")                                        
    curve5 = p5.plot(pen = curveColour)                                                
    p5.setLabel('left', 'Capacitance')                                                            
    p5.setLabel('bottom', 'samples')                                              
    p5.setYRange(yMin, yMax, padding=0)
    ch5 = np.linspace(0,0,interactiveWindow)     
if numberOfChannels >= 6:
    win.nextRow()                                                              # New row in visualization plot
    p6 = win.addPlot(title="Channel 6")                                        
    curve6 = p6.plot(pen = curveColour)                                                
    p6.setLabel('left', 'Capacitance')                                                            
    p6.setLabel('bottom', 'samples')                                              
    p6.setYRange(yMin, yMax, padding=0)
    ch6 = np.linspace(0,0,interactiveWindow)
if numberOfChannels >= 7:
    p7 = win.addPlot(title="Channel 7")                                        
    curve7 = p7.plot(pen = curveColour)                                                
    p7.setLabel('left', 'Capacitance')                                                            
    p7.setLabel('bottom', 'samples')                                              
    p7.setYRange(yMin, yMax, padding=0)
    ch7 = np.linspace(0,0,interactiveWindow)
if numberOfChannels >= 8:
    p8 = win.addPlot(title="Channel 8")                                        
    curve8 = p8.plot(pen = curveColour)                                                
    p8.setLabel('left', 'Capacitance')                                                            
    p8.setLabel('bottom', 'samples')                                              
    p8.setYRange(yMin, yMax, padding=0)
    ch8 = np.linspace(0,0,interactiveWindow)    
if numberOfChannels >= 9:
    p9 = win.addPlot(title="Channel 9")                                        
    curve9 = p9.plot(pen = curveColour)                                                
    p9.setLabel('left', 'Capacitance')                                                            
    p9.setLabel('bottom', 'samples')                                              
    p9.setYRange(yMin, yMax, padding=0)
    ch9 = np.linspace(0,0,interactiveWindow)    
if numberOfChannels >= 10:
    p10 = win.addPlot(title="Channel 10")                                        
    curve10 = p10.plot(pen = curveColour)                                                
    p10.setLabel('left', 'Capacitance')                                                            
    p10.setLabel('bottom', 'samples')                                              
    p10.setYRange(yMin, yMax, padding=0)
    ch10 = np.linspace(0,0,interactiveWindow)    
if numberOfChannels >= 11:
    win.nextRow()                                                              # New row in visualization plot
    p11 = win.addPlot(title="Channel 11")                                        
    curve11 = p11.plot(pen = curveColour)                                                
    p11.setLabel('left', 'Capacitance')                                                            
    p11.setLabel('bottom', 'samples')                                              
    p11.setYRange(yMin, yMax, padding=0)
    ch11 = np.linspace(0,0,interactiveWindow)   
if numberOfChannels >= 12:
    p12 = win.addPlot(title="Channel 12")                                        
    curve12 = p12.plot(pen = curveColour)                                                
    p12.setLabel('left', 'Capacitance')                                                            
    p12.setLabel('bottom', 'samples')                                              
    p12.setYRange(yMin, yMax, padding=0)
    ch12 = np.linspace(0,0,interactiveWindow)

# Realtime data plot. Each time this function is called, the data display is updated
def update():
    global ptr, ch1, ch2, ch3, ch4, ch5, ch6, ch7, ch8, ch9, ch10, ch11, ch12, \
    curve1, curve2, curve3, curve4, curve5, curve6, curve7, curve8, curve9, curve10, curve11, curve12

    if numberOfChannels >= 1:
        ch1[:-1] = ch1[1:]                                                     # shift data in the temporal mean 1 sample left
        ch1[-1] = dataArray[0]                                                 # vector containing the instantaneous values          
        curve1.setData(ch1)                                                    # set the curve with this data
        curve1.setPos(ptr[0],0)                                                # set x position in the graph to 0         
        ptr[0] += 1                                                            # update x position for displaying the curve  
    if numberOfChannels >= 2:
        ch2[:-1] = ch2[1:]                                                     
        ch2[-1] = dataArray[1]                                                     
        curve2.setData(ch2)                                                     
        curve2.setPos(ptr[1],0)                                                           
        ptr[1] += 1    
    if numberOfChannels >= 3:
        ch3[:-1] = ch3[1:]                                                     
        ch3[-1] = dataArray[2]                                                     
        curve3.setData(ch3)                                                     
        curve3.setPos(ptr[2],0)                                                           
        ptr[2] += 1                                        
    if numberOfChannels >= 4:
        ch4[:-1] = ch4[1:]                                                     
        ch4[-1] = dataArray[3]                                                     
        curve4.setData(ch4)                                                     
        curve4.setPos(ptr[3],0)                                                           
        ptr[3] += 1                                            
    if numberOfChannels >= 5:
        ch5[:-1] = ch5[1:]                                                     
        ch5[-1] = dataArray[4]                                                     
        curve5.setData(ch5)                                                     
        curve5.setPos(ptr[4],0)                                                           
        ptr[4] += 1                                            
    if numberOfChannels >= 6:
        ch6[:-1] = ch6[1:]                                                     
        ch6[-1] = dataArray[5]                                                     
        curve6.setData(ch6)                                                     
        curve6.setPos(ptr[5],0)                                                           
        ptr[5] += 1          
    if numberOfChannels >= 7:
        ch7[:-1] = ch7[1:]                                                     
        ch7[-1] = dataArray[6]                                                     
        curve7.setData(ch7)                                                     
        curve7.setPos(ptr[6],0)                                                           
        ptr[6] += 1 
    if numberOfChannels >= 8:
        ch8[:-1] = ch8[1:]                                                     
        ch8[-1] = dataArray[7]                                                     
        curve8.setData(ch8)                                                     
        curve8.setPos(ptr[7],0)                                                           
        ptr[7] += 1          
    if numberOfChannels >= 9:
        ch9[:-1] = ch9[1:]                                                     
        ch9[-1] = dataArray[8]                                                     
        curve9.setData(ch9)                                                     
        curve9.setPos(ptr[8],0)                                                           
        ptr[8] += 1               
    if numberOfChannels >= 10:
        ch10[:-1] = ch10[1:]                                                     
        ch10[-1] = dataArray[9]                                                     
        curve10.setData(ch10)                                                     
        curve10.setPos(ptr[9],0)                                                           
        ptr[9] += 1          
    if numberOfChannels >= 11:
        ch11[:-1] = ch11[1:]                                                     
        ch11[-1] = dataArray[10]                                                     
        curve11.setData(ch11)                                                     
        curve11.setPos(ptr[10],0)                                                           
        ptr[10] += 1          
    if numberOfChannels >= 12:
        ch12[:-1] = ch12[1:]                                                     
        ch12[-1] = dataArray[11]                                                     
        curve12.setData(ch12)                                                     
        curve12.setPos(ptr[11],0)                                                           
        ptr[11] += 1          
    QtGui.QApplication.processEvents()   
#################################################################################################################################
#%%
startTime = time.time()                                                        # Start logging time
while smpl <= numberOfSamples:                                                 # Infinite (or set to num. of. samples) While loop
    try:
        while (serialData.inWaiting() == 0):                                   # Waiting for there to be serial data
            pass                                                               # Do nothing if there is no serial information

        if smpl <= numberOfSamples:                                            # If there is serial data

            serialString = serialData.readline()                               # Read serial port line by line     
            decode_String = serialString.decode('utf-8')                       # Decodes the bytes from serial port (give value in b[value]\r\n)                   
            dataStringArray = decode_String.split(' ')                         # Splitting the data 'comma' delimited            
            dataArray = [np.float16(i) for i in dataStringArray[0:numberOfChannels]]# Convert string to floating point number            

            update()                                                           # This is a brutal infinite loop calling the realtime data plot

            print(smpl, dataArray)
            sample.append(smpl)
            t.append(time.time() - startTime)
            channelData.append(dataArray)
            smpl += 1                                                          # Step increment for each good sample

        if smpl > numberOfSamples:                                             # Check for data completion
            print('\n Data collection complete! Check file.')                  # Print check..                             
            serialData.close()                                                 # Close serial port object 

    except:         
        print('\n Keyboard Interrupt!... Stopped Data Acquisition!')        
        serialData.close()                                                     # Close serial port object                                                                 
        break

timeElapsed = str(time.time() - startTime)                                     # Time elapsed check!
print('Time elapsed = ', timeElapsed)

################################################################################
if __name__ == '__main__':
    import sys
    if sys.flags.interactive != 1 or not hasattr(QtCore, 'PYQT_VERSION'):
        pg.QtGui.QApplication.exec_()
################################################################################

sample = np.array(np.reshape(sample, (len(sample), 1)))                        # Converting to array
t = np.array(np.reshape(t, (len(t), 1)))
channelData = np.array(channelData)                                            

channelData = np.hstack((sample, t, channelData))                              # Concatenating desired data
with open(csv_fileName, 'a', newline = '') as f:                               # Opens file in directory and appends to that file (does not erase existing data)
    writer = csv.writer(f, delimiter = ',')                       
    writer.writerows(channelData)          

感谢您的帮助!期待解决这个问题。

【问题讨论】:

通过降低arduino脚本中的采样率解决(延迟从1ms增加到10ms) 【参考方案1】:

通过降低arduino脚本中的采样率来解决(延迟从1ms增加到10ms)

【讨论】:

以上是关于pyQtgraph 绘图延迟串行绘图的主要内容,如果未能解决你的问题,请参考以下文章

重新启动实时绘图时,pyqtgraph实时绘图中断

使用 Python 最大化来自 Teensy 3.2 的实时绘图数据的串行通信速度

在pyqtgraph中实现实时绘图的最简单方法是啥

pyqtgraph绘图安装pyqtgraph

如何在pyqtgraph中缩放绘图

pyqtgraph绘图线条,填充和颜色