我正在尝试编写一个程序,该程序通过串行从arduino获取串行数据,并实时绘制它。我使用matplotlib编写了代码,但我想对结果感到满意,因此我试图使其在pyqtgraph上运行(学习使用方法的资源更少)。我的问题是代码显示一个空图。似乎_update仅被调用一次,但是当我将其放入循环中时,该图甚至无法显示。
我写了一些其他的代码来实现我想要的功能,即实时绘制数据,并在数据超过阈值后在数据上绘制新行,以显示线性回归。我从这里(https://github.com/JaFeKl/joystick_real_time_plot_with_pyqtgraph/blob/master/real_time_plot.py)获得了一个示例,因为我希望我的代码可以被调用(在一个函数中,但是我无法使其正常工作。到目前为止,我正在python中生成数据以简化调试< / p>
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
##################
答案 0 :(得分:3)
我没有连接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_()