【问题标题】:Animate pyqtgraph in class在课堂上制作 pyqtgraph 动画
【发布时间】:2019-10-22 12:17:09
【问题描述】:

我正在尝试编写一个程序,该程序通过串行从 arduino 获取串行数据,并实时绘制它。我使用 matplotlib 编写了代码,但我希望对结果感到满意,所以我试图让它在 pyqtgraph 上工作(学习如何使用它的资源要少得多)。我的问题是代码显示了一个空图。似乎 _update 只被调用了一次,但是当我把它放在一个循环中时,图表甚至都没有显示。

我已经编写了一些其他代码来执行我想要的操作,即实时绘制数据,并在数据通过阈值后在数据上绘制新线,以显示线性回归。我从这里 (https://github.com/JaFeKl/joystick_real_time_plot_with_pyqtgraph/blob/master/real_time_plot.py) 得到了一个示例,因为我希望我的代码是可调用的(在一个函数中,但我无法让它工作。到目前为止,我正在从 python 中生成数据以简化调试

import sys
import pyqtgraph as pg
import pyqtgraph.exporters
from pyqtgraph.Qt import QtGui, QtCore
import numpy as np

import serial

# test
import math
import time


class Graph(QtGui.QMainWindow):
    def __init__(self, parent=None):
        super(Graph, self).__init__(parent)
        self.n = 3
        self.mainbox = QtGui.QWidget()
        self.setCentralWidget(self.mainbox)
        self.mainbox.setLayout(QtGui.QVBoxLayout())

        self.canvas = pg.GraphicsLayoutWidget()             # create GrpahicsLayoutWidget obejct  
        self.mainbox.layout().addWidget(self.canvas)

        #  Set up plot
        self.analogPlot = self.canvas.addPlot(title='Signal from serial port')
        self.analogPlot.setYRange(-1,1123)                # set axis range
        self.analogPlot.setXRange(-1,1123)
        self.analogPlot.showGrid(x=True, y=True, alpha=0.5) # show Grid
        x_axis = self.analogPlot.getAxis('bottom')
        y_axis = self.analogPlot.getAxis('left')
        font=QtGui.QFont()
        font.setPixelSize(20)
        x_axis.tickFont = font
        y_axis.tickFont = font
        x_axis.setLabel(text='Tensão [V]')              # set axis labels
        y_axis.setLabel(text='Corrente [mA]')

        self.plts = []
        self.intplts = []
        colors = ['r', 'b', 'w', 'y', 'g', 'm', 'c', 'k']
        for i in range(self.n):
            self.plts.append([])
            self.intplts.append([])


        for i in range(self.n):
            if len(self.plts) <= len(colors):
                self.plts[i]=(self.analogPlot.plot(pen= pg.mkPen(colors[i], width=6)))
        for i in range(self.n):
            if len(self.plts) <= len(colors)*2:
                self.intplts.append(self.analogPlot.plot(pen= pg.mkPen(colors[i+3], width=3)))

        #Data
        self.datay = []
        self.datax = []
        for i in range(self.n):
            self.datax.append([])
            self.datay.append([])

        # set up image exporter (necessary to be able to export images)
        QtGui.QApplication.processEvents()
        self.exporter=pg.exporters.ImageExporter(self.canvas.scene())
        self.image_counter = 1


        # start updating
        self.t=0

        self._update()


    def _update(self):
        time.sleep(0.01)
        if self.t<= 30:
            #line = raw.readline()
            #data.append(int(line))
            self.datay[0].append(math.sin(self.t+(math.pi/2)))
            self.datay[1].append(math.sin(self.t+(5*math.pi/4)))
            self.datay[2].append(math.sin(self.t))
            self.datax[0].append(self.t)
            self.datax[1].append(self.t)
            self.datax[2].append(self.t)
            self.t+=0.1
            self.plts[0].setData(self.datax[0], self.datay[0])
            self.plts[1].setData(self.datax[1], self.datay[1])
            self.plts[2].setData(self.datax[2], self.datay[2])

            app.processEvents()
        elif self.t>=30 and self.t<=30.1 :
            self.t+=1

if __name__ == '__main__':

    app = QtGui.QApplication(sys.argv)
    plot = Graph()
    plot.show()
    sys.exit(app.exec_())

我希望得到类似于此代码的结果(仅没有线性回归)

import pyqtgraph as pg
import pyqtgraph.exporters
from pyqtgraph.Qt import QtGui, QtCore
import numpy as np

# linear regression
from scipy import stats

#Arduino
#import find_arduino
#import find_buad
import serial

import math
import time

#port = find_arduino.FindArduino()
#baud = find_buad.FindBaudRate()
ard=None

def Con():
    global ard
    ard = serial.Serial(port,baud,timeout=5)
    time.sleep(2) # wait for Arduino
    ard.close()

# define the data
theTitle = "pyqtgraph plot"
datay = [[],[],[]]
datax = [[],[],[]]
x2 = []
T=[]
t=0

y1L=[]
x1L=[]

# create plot
### START QtApp #####
app = QtGui.QApplication([])            # you MUST do this once (initialize things)
####################
win = pg.GraphicsWindow(title="Signal from serial port") # creates a window
plt = win.addPlot(title="Realtime plot")  # creates empty space for the plot in the window

font=QtGui.QFont()
font.setPixelSize(20)
plt.getAxis("bottom").tickFont = font
plt.getAxis("left").tickFont = font

plt1 = plt.plot(pen=pg.mkPen('r', width=6))
plt2= plt.plot(pen=pg.mkPen('b', width=6))
plt3= plt.plot(pen=pg.mkPen('w', width=6))

plt1I = plt.plot(pen=pg.mkPen('y', width=3))
plt2I = plt.plot(pen=pg.mkPen('g', width=3))
plt3I = plt.plot(pen=pg.mkPen('m', width=3))

plt.showGrid(x=True,y=True)


def update():
    global plt1,plt2,plt3, t, plt1I, plt2I, plt3I
    if t<= 30:
        #line = raw.readline()
        #data.append(int(line))
        datay[0].append(math.sin(t+(math.pi/2)))
        datay[1].append(math.sin(t+(5*math.pi/4)))
        datay[2].append(math.sin(t))
        datax[0].append(t)
        datax[1].append(t)
        datax[2].append(t)
        t+=0.1
        plt1.setData(datax[0],datay[0])
        plt2.setData(datax[1],datay[1])
        plt3.setData(datax[2],datay[2])
        app.processEvents()
        time.sleep(0.01)
    elif t>=30 and t<=30.1 :
        #plt1I.setData([0,1,2],[5,3,1])
        #app.processEvents()
        interp(plt1I, plt2I, plt3I)
        t+=1
    else:
        app.processEvents()

def interp(pt1, pt2, pt3):
    slope, intercept, r_value, p_value, std_err = stats.linregress(datax[0][10:],datay[0][10:])
    x=[]
    y=[]
    print(slope)
    for i in datax[0][10:]:
        x.append(i)
        y.append(intercept+slope*i)
    pt1.setData(x,y)

    slope, intercept, r_value, p_value, std_err = stats.linregress(datax[1][10:],datay[1][10:])
    x=[]
    y=[]
    print(slope)
    for i in datax[0][10:]:
        x.append(i)
        y.append(intercept+slope*i)
    pt2.setData(x, y)

    slope, intercept, r_value, p_value, std_err = stats.linregress(datax[2][10:],datay[2][10:])
    x=[]
    y=[]
    print(slope)
    for i in datax[0][10:]:
        x.append(i)
        y.append(intercept+slope*i)
    pt3.setData(x,y)
    app.processEvents()

timer = QtCore.QTimer()
timer.timeout.connect(update)
timer.start(0)

### MAIN PROGRAM #####    
# this is a brutal infinite loop calling your realtime data plot
# make this interpret the incoming data
#Con()
#Communicate(1)
while True: update()


### END QtApp ####
pg.QtGui.QApplication.exec_() # you MUST put this at the end
##################

【问题讨论】:

    标签: python pyqtgraph


    【解决方案1】:

    我没有连接 Arduino 来从中获取数据,因此在此示例中,我使用随机数据进行绘图。绘制数据时,您要避免使用time.sleep(),因为它会导致 GUI 冻结。相反,使用连接到更新处理程序的QtGui.QTimer() 来绘制数据。同样作为一种优化,您可以使用线程来轮询数据,然后在单独的计时器中更新它。

    from pyqtgraph.Qt import QtCore, QtGui
    from threading import Thread
    import pyqtgraph as pg
    import numpy as np
    import random
    import sys
    import time
    
    """Scrolling Plot Widget Example"""
    
    # Scrolling plot widget with adjustable X-axis and dynamic Y-axis
    class ScrollingPlot(QtGui.QWidget):
        def __init__(self, parent=None):
            super(ScrollingPlot, self).__init__(parent)
    
            # Desired Frequency (Hz) = 1 / self.FREQUENCY
            # USE FOR TIME.SLEEP (s)
            self.FREQUENCY = .004
    
            # Frequency to update plot (ms)
            # USE FOR TIMER.TIMER (ms)
            self.TIMER_FREQUENCY = self.FREQUENCY * 1000
    
            # Set X Axis range. If desired is [-10,0] then set LEFT_X = -10 and RIGHT_X = 0
            self.LEFT_X = -10
            self.RIGHT_X = 0
            self.X_Axis = np.arange(self.LEFT_X, self.RIGHT_X, self.FREQUENCY)
            self.buffer = int((abs(self.LEFT_X) + abs(self.RIGHT_X))/self.FREQUENCY)
            self.data = [] 
    
            # Create Plot Widget 
            self.scrolling_plot_widget = pg.PlotWidget()
    
            # Enable/disable plot squeeze (Fixed axis movement)
            self.scrolling_plot_widget.plotItem.setMouseEnabled(x=False, y=False)
            self.scrolling_plot_widget.setXRange(self.LEFT_X, self.RIGHT_X)
            self.scrolling_plot_widget.setTitle('Scrolling Plot Example')
            self.scrolling_plot_widget.setLabel('left', 'Value')
            self.scrolling_plot_widget.setLabel('bottom', 'Time (s)')
    
            self.scrolling_plot = self.scrolling_plot_widget.plot()
            self.scrolling_plot.setPen(197,235,255)
    
            self.layout = QtGui.QGridLayout()
            self.layout.addWidget(self.scrolling_plot_widget)
    
            self.read_position_thread()
            self.start()
    
        # Update plot
        def start(self):
            self.position_update_timer = QtCore.QTimer()
            self.position_update_timer.timeout.connect(self.plot_updater)
            self.position_update_timer.start(self.get_scrolling_plot_timer_frequency())
    
        # Read in data using a thread
        def read_position_thread(self):
            self.current_position_value = 0
            self.old_current_position_value = 0
            self.position_update_thread = Thread(target=self.read_position, args=())
            self.position_update_thread.daemon = True
            self.position_update_thread.start()
    
        def read_position(self):
            frequency = self.get_scrolling_plot_frequency()
            while True:
                try:
                    # Add data
                    self.current_position_value = random.randint(1,101) 
                    self.old_current_position_value = self.current_position_value
                    time.sleep(frequency)
                except:
                    self.current_position_value = self.old_current_position_value
    
        def plot_updater(self):
            self.dataPoint = float(self.current_position_value)
    
            if len(self.data) >= self.buffer:
                del self.data[:1]
            self.data.append(self.dataPoint)
            self.scrolling_plot.setData(self.X_Axis[len(self.X_Axis) - len(self.data):], self.data)
    
        def clear_scrolling_plot(self):
            self.data[:] = []
    
        def get_scrolling_plot_frequency(self):
            return self.FREQUENCY
    
        def get_scrolling_plot_timer_frequency(self):
            return self.TIMER_FREQUENCY
    
        def get_scrolling_plot_layout(self):
            return self.layout
    
        def get_current_position_value(self):
            return self.current_position_value
    
        def get_scrolling_plot_widget(self):
            return self.scrolling_plot_widget
    
    if __name__ == '__main__':
        # Create main application window
        app = QtGui.QApplication([])
        app.setStyle(QtGui.QStyleFactory.create("Cleanlooks"))
        mw = QtGui.QMainWindow()
        mw.setWindowTitle('Scrolling Plot Example')
    
        # Create scrolling plot
        scrolling_plot_widget = ScrollingPlot()
    
        # Create and set widget layout
        # Main widget container
        cw = QtGui.QWidget()
        ml = QtGui.QGridLayout()
        cw.setLayout(ml)
        mw.setCentralWidget(cw)
    
        # Can use either to add plot to main layout
        #ml.addWidget(scrolling_plot_widget.get_scrolling_plot_widget(),0,0)
        ml.addLayout(scrolling_plot_widget.get_scrolling_plot_layout(),0,0)
        mw.show()
    
        # Start Qt event loop unless running in interactive mode or using pyside
        if (sys.flags.interactive != 1) or not hasattr(QtCore, 'PYQT_VERSION'):
            QtGui.QApplication.instance().exec_()
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-08-03
      • 1970-01-01
      • 2013-05-26
      • 1970-01-01
      相关资源
      最近更新 更多