Trying get a live plot for a GUI with PyQt5

故事扮演 提交于 2019-12-11 07:30:08

问题


Right now through reading and asking questions I have gotten to a point where I can display the numerical values on LCDs, but now would like to make a graph.

In the Picture below there is a picture that I am going to have as a backdrop for the graph. For a Dyno the important information that is gathered is Torque and HorsePower. These I have being calculated with my Python 3.5 Code and the data is being gathered by using an arduino.

For my graph I actually want to plot two lines at the same time as the data comes in. I would like to plot both the Torque and the HorsePower at the same time. Both of those vs the time that the Dyno is being used. This however might be hard since they need to be plotted with different y-axis. From what I have been reading using pyqtGraph is the best option for the job but due to my in experience with this kind of work I really don't know how to do it.

Below is my code that I have tried to run based on some of the things I have found. Running it does not error out my code, however It also does not interact with the graph area. I tried to get it to work in a similar fashion that the LCDs work in, but even still I don't have anything working.

"""
SCSU DYNO GUI PROGRAM

created 10/20/2017
"""


import sys
import time
import csv
import numpy as np
import warnings
import serial
import serial.tools.list_ports
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtCore import QThread,QTimer, pyqtSignal
from PyQt5.QtWidgets import QMessageBox,QWidget, QApplication
from pyqtgraph.Qt import QtGui, QtCore
import pyqtgraph as pg
import random
from DynoTest1 import Ui_DynoTest1


__author__ = 'Matt Munn'

class GetData(QThread):
    dataChanged = pyqtSignal(float, float, float, float, float, float, float, float)

    #Distance = 0.5 #This is dependent on the lever arm.

    def __init__(self, parent=None):
        QThread.__init__(self, parent)

        arduino_ports = [  # automatically searches for an Arduino and selects the port it's on
            p.device
            for p in serial.tools.list_ports.comports()
            if 'Arduino' in p.description
        ]

        if not arduino_ports:
            raise IOError("No Arduino found - is it plugged in? If so, restart computer.")
        if len(arduino_ports) > 1:
            warnings.warn('Multiple Arduinos found - using the first')
        self.Arduino = serial.Serial(arduino_ports[0], 9600, timeout=1)

    def __del__(self):  # part of the standard format of a QThread
        self.wait()

    def run(self):  # also a required QThread function, the working part
        self.Arduino.close()
        self.Arduino.open()

        self.Arduino.flush()
        self.Arduino.reset_input_buffer()
        start_time = time.time()

        Distance = 0.5 #This is dependent on the lever arm.
        Max_RPM = 0
        Max_HorsePower = 0
        Max_Torque = 0

        while True:
            while self.Arduino.inWaiting() == 0:
                pass
            try:
                data = self.Arduino.readline()
                dataarray = data.decode().rstrip().split(',')
                self.Arduino.reset_input_buffer()
                Force = round(float(dataarray[0]), 3)
                RPM = round(float(dataarray[1]), 3)
                if Max_RPM < RPM:
                    Max_RPM = RPM
                Torque = round(Force * Distance, 3)
                if Max_Torque < Torque:
                    Max_Torque = Torque
                HorsePower = round(Torque * RPM / 5252, 3)
                if Max_HorsePower < HorsePower:
                    Max_HorsePower = HorsePower
                Run_Time = round(time.time() - start_time, 3)
                print(Force, 'Grams', ",", RPM, 'RPMs', ",", Torque, "ft-lbs", ",", HorsePower, "hp", Run_Time,
                      "Time Elasped")
                self.dataChanged.emit(Force, RPM, Max_RPM, Torque, Max_Torque, HorsePower, Max_HorsePower, Run_Time)
            except (KeyboardInterrupt, SystemExit, IndexError, ValueError):
                pass
class GUI(QWidget, Ui_DynoTest1):


    def __init__(self, parent=None):
        QWidget.__init__(self, parent)
        self.setupUi(self)
        self.thread = GetData(self)
        self.thread.dataChanged.connect(self.onDataChanged)
        self.thread.start()
    """
        layout = QtGui.QHBoxLayout()
        self.plot = pg.PlotWidget()
        layout.addWidget(self.plot)
        self.setLayout(layout)

    def plotter(self):

        self.data = [0]
        self.curve = self.plot.getPlotItem().plot()
        self.timer = QtCore.QTimer()
        self.timer.timeout.connect(self.updater)
        self.timer.start(0)

    def updater(self):
        self.data.append(self.data[-1]+0.2*(0.5-random.random()))
        self.curve.setData(self.data)
    """
    def onDataChanged(self, Force, RPM, Max_RPM, Torque,Max_Torque, HorsePower, Max_HorsePower, Run_Time):
        self.lcdNumber.display(Max_RPM)
        self.lcdNumber_2.display(Max_Torque)
        self.lcdNumber_3.display(Max_HorsePower)
        self.lcdNumber_4.display(RPM)
        self.lcdNumber_5.display(Torque)
        self.lcdNumber_6.display(HorsePower)
        self.lcdNumber_7.display(Run_Time)
        #self.graphicsView.display(Tourque,Run_Time)


if __name__ == '__main__':
    import sys
    app = QApplication(sys.argv)
    Dyno = GUI()
    Dyno.show()
    sys.exit(app.exec_())

This is the code generated by the QTDesigner.

# -*- coding: utf-8 -*-

# Form implementation generated from reading ui file 'dynotest1.ui'
#
# Created by: PyQt5 UI code generator 5.9
#
# WARNING! All changes made in this file will be lost!

from PyQt5 import QtCore, QtGui, QtWidgets

class Ui_DynoTest1(object):
    def setupUi(self, DynoTest1):
        DynoTest1.setObjectName("DynoTest1")
        DynoTest1.resize(1001, 695)
        self.verticalLayout_4 = QtWidgets.QVBoxLayout(DynoTest1)
        self.verticalLayout_4.setObjectName("verticalLayout_4")
        self.horizontalLayout_2 = QtWidgets.QHBoxLayout()
        self.horizontalLayout_2.setObjectName("horizontalLayout_2")
        self.horizontalLayout = QtWidgets.QHBoxLayout()
        self.horizontalLayout.setObjectName("horizontalLayout")
        self.verticalLayout_3 = QtWidgets.QVBoxLayout()
        self.verticalLayout_3.setObjectName("verticalLayout_3")
        self.gridLayout = QtWidgets.QGridLayout()
        self.gridLayout.setObjectName("gridLayout")
        self.pushButton_2 = QtWidgets.QPushButton(DynoTest1)
        self.pushButton_2.setObjectName("pushButton_2")
        self.gridLayout.addWidget(self.pushButton_2, 1, 0, 1, 1)
        self.pushButton_4 = QtWidgets.QPushButton(DynoTest1)
        self.pushButton_4.setObjectName("pushButton_4")
        self.gridLayout.addWidget(self.pushButton_4, 1, 1, 1, 1)
        self.pushButton_3 = QtWidgets.QPushButton(DynoTest1)
        self.pushButton_3.setObjectName("pushButton_3")
        self.gridLayout.addWidget(self.pushButton_3, 0, 1, 1, 1)
        self.pushButton = QtWidgets.QPushButton(DynoTest1)
        self.pushButton.setObjectName("pushButton")
        self.gridLayout.addWidget(self.pushButton, 0, 0, 1, 1)
        self.verticalLayout_3.addLayout(self.gridLayout)
        self.label_3 = QtWidgets.QLabel(DynoTest1)
        self.label_3.setObjectName("label_3")
        self.verticalLayout_3.addWidget(self.label_3)
        self.label_2 = QtWidgets.QLabel(DynoTest1)
        self.label_2.setObjectName("label_2")
        self.verticalLayout_3.addWidget(self.label_2)
        self.label = QtWidgets.QLabel(DynoTest1)
        self.label.setObjectName("label")
        self.verticalLayout_3.addWidget(self.label)
        self.horizontalLayout.addLayout(self.verticalLayout_3)
        self.verticalLayout = QtWidgets.QVBoxLayout()
        self.verticalLayout.setObjectName("verticalLayout")
        self.label_5 = QtWidgets.QLabel(DynoTest1)
        self.label_5.setObjectName("label_5")
        self.verticalLayout.addWidget(self.label_5)
        self.lcdNumber_4 = QtWidgets.QLCDNumber(DynoTest1)
        self.lcdNumber_4.setFrameShape(QtWidgets.QFrame.Box)
        self.lcdNumber_4.setFrameShadow(QtWidgets.QFrame.Raised)
        self.lcdNumber_4.setLineWidth(1)
        self.lcdNumber_4.setSmallDecimalPoint(True)
        self.lcdNumber_4.setDigitCount(5)
        self.lcdNumber_4.setMode(QtWidgets.QLCDNumber.Dec)
        self.lcdNumber_4.setSegmentStyle(QtWidgets.QLCDNumber.Filled)
        self.lcdNumber_4.setProperty("value", 0.0)
        self.lcdNumber_4.setObjectName("lcdNumber_4")
        self.verticalLayout.addWidget(self.lcdNumber_4)
        self.lcdNumber_5 = QtWidgets.QLCDNumber(DynoTest1)
        font = QtGui.QFont()
        font.setBold(False)
        font.setWeight(50)
        self.lcdNumber_5.setFont(font)
        self.lcdNumber_5.setSmallDecimalPoint(True)
        self.lcdNumber_5.setObjectName("lcdNumber_5")
        self.verticalLayout.addWidget(self.lcdNumber_5)
        self.lcdNumber_6 = QtWidgets.QLCDNumber(DynoTest1)
        self.lcdNumber_6.setSmallDecimalPoint(True)
        self.lcdNumber_6.setObjectName("lcdNumber_6")
        self.verticalLayout.addWidget(self.lcdNumber_6)
        self.horizontalLayout.addLayout(self.verticalLayout)
        self.verticalLayout_2 = QtWidgets.QVBoxLayout()
        self.verticalLayout_2.setObjectName("verticalLayout_2")
        self.label_6 = QtWidgets.QLabel(DynoTest1)
        self.label_6.setObjectName("label_6")
        self.verticalLayout_2.addWidget(self.label_6)
        self.lcdNumber = QtWidgets.QLCDNumber(DynoTest1)
        self.lcdNumber.setSmallDecimalPoint(True)
        self.lcdNumber.setObjectName("lcdNumber")
        self.verticalLayout_2.addWidget(self.lcdNumber)
        self.lcdNumber_2 = QtWidgets.QLCDNumber(DynoTest1)
        self.lcdNumber_2.setSmallDecimalPoint(True)
        self.lcdNumber_2.setObjectName("lcdNumber_2")
        self.verticalLayout_2.addWidget(self.lcdNumber_2)
        self.lcdNumber_3 = QtWidgets.QLCDNumber(DynoTest1)
        self.lcdNumber_3.setSmallDecimalPoint(True)
        self.lcdNumber_3.setObjectName("lcdNumber_3")
        self.verticalLayout_2.addWidget(self.lcdNumber_3)
        self.horizontalLayout.addLayout(self.verticalLayout_2)
        self.horizontalLayout_2.addLayout(self.horizontalLayout)
        self.verticalLayout_5 = QtWidgets.QVBoxLayout()
        self.verticalLayout_5.setObjectName("verticalLayout_5")
        self.label_7 = QtWidgets.QLabel(DynoTest1)
        self.label_7.setObjectName("label_7")
        self.verticalLayout_5.addWidget(self.label_7)
        self.lcdNumber_7 = QtWidgets.QLCDNumber(DynoTest1)
        self.lcdNumber_7.setObjectName("lcdNumber_7")
        self.verticalLayout_5.addWidget(self.lcdNumber_7)
        self.horizontalLayout_2.addLayout(self.verticalLayout_5)
        self.verticalLayout_4.addLayout(self.horizontalLayout_2)
        self.graphicsView = QtWidgets.QGraphicsView(DynoTest1)
        self.graphicsView.setStyleSheet("border-image: url(:/newPrefix/husky_head5.png);")
        self.graphicsView.setLineWidth(1)
        self.graphicsView.setObjectName("graphicsView")
        self.verticalLayout_4.addWidget(self.graphicsView)

        self.retranslateUi(DynoTest1)
        QtCore.QMetaObject.connectSlotsByName(DynoTest1)

    def retranslateUi(self, DynoTest1):
        _translate = QtCore.QCoreApplication.translate
        DynoTest1.setWindowTitle(_translate("DynoTest1", "DynoTest1"))
        self.pushButton_2.setText(_translate("DynoTest1", "Pause"))
        self.pushButton_4.setText(_translate("DynoTest1", "Print"))
        self.pushButton_3.setText(_translate("DynoTest1", "Stop"))
        self.pushButton.setText(_translate("DynoTest1", "Start"))
        self.label_3.setText(_translate("DynoTest1", "<html><head/><body><p align=\"center\"><span style=\" font-size:18pt; font-weight:600;\">RPMs</span></p></body></html>"))
        self.label_2.setText(_translate("DynoTest1", "<html><head/><body><p align=\"center\"><span style=\" font-size:18pt; font-weight:600;\">Torque (ft-lbs)</span></p></body></html>"))
        self.label.setText(_translate("DynoTest1", "<html><head/><body><p align=\"center\"><span style=\" font-size:18pt; font-weight:600;\">Horse Power</span></p></body></html>"))
        self.label_5.setText(_translate("DynoTest1", "<html><head/><body><p align=\"center\"><span style=\" font-size:18pt; font-weight:600;\">Now</span></p></body></html>"))
        self.label_6.setText(_translate("DynoTest1", "<html><head/><body><p align=\"center\"><span style=\" font-size:18pt; font-weight:600;\">Max</span></p></body></html>"))
        self.label_7.setText(_translate("DynoTest1", "<html><head/><body><p align=\"center\"><span style=\" font-size:18pt; font-weight:600;\">Run Time</span></p><p align=\"center\"><span style=\" font-size:18pt; font-weight:600;\">(Seconds)</span></p></body></html>"))

import Resource_rc

Picture of the GUI


回答1:


The first thing is to add the PlotWidget to the GUI. For this we use QGraphicsView (in fact any widget can be used), in the QGraphicsView we add a layout, and in this layout we add the PlotWidget.

layout = QHBoxLayout()
self.plot = pg.PlotWidget()
layout.addWidget(self.plot)
self.graphicsView.setLayout(layout)

Then the items are created, and as you wish to have 2 axes and in the same plot we take as an example the code found in the following link.

In the example you wanted to use, use a timer to update the data, but in this case that clock must be reading data for it every time the onDataChanged method is called. To obtain a view, a procedure has been created to only store and display the last 50 elements.

Code:

class GUI(QWidget, Ui_DynoTest1):
    def __init__(self, parent=None):
        [...]
        self.thread.start()
        self.torque = []
        self.horse_power = []

        layout = QHBoxLayout()
        self.plot = pg.PlotWidget()
        layout.addWidget(self.plot)
        self.graphicsView.setLayout(layout)

        self.p1 = self.plot.plotItem
        self.p1.setLabels(left='Torque')
        self.TorqueCurve = self.p1.plot()
        self.TorqueCurve.setPen(pg.mkPen(color="#ff0000", width=2))

        self.p2 = pg.ViewBox()
        self.HorsePowerCurve = pg.PlotCurveItem()
        self.HorsePowerCurve.setPen(pg.mkPen(QColor(0, 255, 0)), width=2)
        self.p2.addItem(self.HorsePowerCurve)
        self.p1.scene().addItem(self.p2)
        self.p1.showAxis('right')
        self.p1.getAxis('right').setLabel('HorsePower', color='#0000ff')
        self.p1.getAxis('right').linkToView(self.p2)
        self.p1.vb.sigResized.connect(self.updateViews)

    def updateViews(self):
        self.p2.setGeometry(self.p1.vb.sceneBoundingRect())
        self.p2.linkedViewChanged(self.p1.vb, self.p2.XAxis)

    def onDataChanged(self, Force, RPM, Max_RPM, Torque, Max_Torque, HorsePower, Max_HorsePower, Run_Time):
        [...]
        if len(self.torque) < 50:
            self.torque.append(Torque)
        else:
            self.torque = self.torque[1:] + [Torque]

        if len(self.horse_power) < 50:
            self.horse_power.append(HorsePower)
        else:
            self.horse_power = self.horse_power[1:] + [HorsePower]
        self.TorqueCurve.setData(self.torque)
        self.HorsePowerCurve.setData(self.horse_power)
        self.updateViews()


来源:https://stackoverflow.com/questions/47044290/trying-get-a-live-plot-for-a-gui-with-pyqt5

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!