I am facing an issue during plotting graph in real-time in pyqt widget application that i made for my ECG hardware. Basically, I am sending my ECG-data in csv format via usb and trying to capture that data in "PyQt Widget application" and after capturing this by QSerial port i tried to plot 14 graphs in real time.
In PyQt Widget application that i made i make 3 tabs 1st tab user intetface to connect microcontroller with PC via USB by selecting COM-PORT and BAUDRATE and, 2nd tab show 8 graphs in realtime & 3rd tab shows 6 graphs in realtime.
Problem: Whenever i tried to plot or update all graph in realtime my GUI is Hanged . I also tried thread method but may be i mistake somewhere because i do know much in this GUI .
Note: data comming at every 450 microSeconds.
I am sharing this code, if anybody can help me out in this please help
import sys
from PyQt5 import QtCore
from PyQt5.QtCore import Qt, pyqtSignal, QTimer
from PyQt5 import QtSerialPort
from PyQt5.QtWidgets import QApplication, QWidget
from PyQt5.QtWidgets import QFormLayout, QVBoxLayout, QHBoxLayout, QGridLayout
from PyQt5.QtWidgets import QFrame, QLabel, QPushButton, QTabWidget, QComboBox
from PyQt5.QtGui import QIcon
####################################
import serial
from serial.tools import list_ports
import time
####################################
import pyqtgraph as pg
from pyqtgraph import PlotWidget
import pyqtgraph.exporters
import numpy as np
import queue
####################################
class Window(QWidget):
# Signal generate to for data receive
# dataReceive = pyqtSignal(list)
dataReceive = pyqtSignal()
# Signal generate for graph plot
displayPlot = pyqtSignal()
def __init__(self, parent = None):
super(Window, self).__init__(parent)
# Default Main Window Size
self.resize(1000,600)
# Main Window Title
self.setWindowTitle("Smart Health Diagnostic Tool")
# Title Bar Icon
self.setWindowIcon(QIcon('C:/tkinter_plot_app/guiLib/images/app_icon.png'))
font = self.font()
font.setPointSize(12)
# component of Smart Health Device Page TAB
##########################################################
self.label_deviceId = QLabel("DEVICE :")
self.label_deviceId.setFont(font)
self.label_deviceId_value = QLabel("ADS1198")
self.label_deviceId_value.setFont(font)
self.label_comPort = QLabel("COM PORT :")
self.label_comPort.setFont(font)
self.comPort_comboBox = QComboBox()
self.comPort_comboBox.setFont(font)
self.comPort_comboBox.activated.connect(self.comPortHandleActivated)
self.label_baudRate = QLabel("BAUDRATE :")
self.label_baudRate.setFont(font)
self.baudRate_comboBox = QComboBox()
self.baudRate_comboBox.setFont(font)
self.baudRate_comboBox.activated.connect(self.baudRateHandleActivated)
self.connect_disconnect_button = QPushButton('Connect', checkable= True, toggled=self.on_toggled)
self.connect_disconnect_button.setFont(font)
#########################################################
# Serial PORT configuration
self.COM_PORT = None
self.BAUDRATE = None
self.comPort_connect_disconnect_status = False
comList = ['']
comList += [port.device for port in list_ports.comports()]
print(comList)
self.comPort_comboBox.addItems(comList)
self.serial = QtSerialPort.QSerialPort(
self.COM_PORT,
baudRate= self.BAUDRATE,
readyRead=self.receive_serial
)
#########################################################
# SCOPE GRAPH Widgets
self.scope_graph1 = pg.PlotWidget(title='V6')
self.scope_graph1.plotItem.setLabel('left', '<h2><b>CHANNEL 1</b></h2>')
self.scope_graph1.plotItem.showGrid(x= True, y=True)
self.scope_graph2 = pg.PlotWidget(title='LEAD I')
self.scope_graph2.plotItem.setLabel('left', '<h2><b>CHANNEL 2</b></h2>')
self.scope_graph2.plotItem.showGrid(x= True, y=True)
self.scope_graph3 = pg.PlotWidget(title='LEAD II')
self.scope_graph3.plotItem.setLabel('left', '<h2><b>CHANNEL 3</b></h2>')
self.scope_graph3.plotItem.showGrid(x= True, y=True)
self.scope_graph4 = pg.PlotWidget(title='V2')
self.scope_graph4.plotItem.setLabel('left', '<h2><b>CHANNEL 4</b></h2>')
self.scope_graph4.plotItem.showGrid(x= True, y=True)
self.scope_graph5 = pg.PlotWidget(title='V3')
self.scope_graph5.plotItem.setLabel('left', '<h2><b>CHANNEL 5</b></h2>')
self.scope_graph5.plotItem.showGrid(x= True, y=True)
self.scope_graph6 = pg.PlotWidget(title='V4')
self.scope_graph6.plotItem.setLabel('left', '<h2><b>CHANNEL 6</b></h2>')
self.scope_graph6.plotItem.showGrid(x= True, y=True)
self.scope_graph7 = pg.PlotWidget(title='V5')
self.scope_graph7.plotItem.setLabel('left', '<h2><b>CHANNEL 7</b></h2>')
self.scope_graph7.plotItem.showGrid(x= True, y=True)
self.scope_graph8 = pg.PlotWidget(title='V1')
self.scope_graph8.plotItem.setLabel('left', '<h2><b>CHANNEL 8</b></h2>')
self.scope_graph8.plotItem.showGrid(x= True, y=True)
self.channelData_1 = np.array([])
self.channelData_2 = np.array([])
self.channelData_3 = np.array([])
self.channelData_4 = np.array([])
self.channelData_5 = np.array([])
self.channelData_6 = np.array([])
self.channelData_7 = np.array([])
self.channelData_8 = np.array([])
self.lead_III = np.array([])
self.avR = np.array([])
self.avL = np.array([])
self.avF = np.array([])
# ECG GRAPH Widgets
self.ecg_graph1 = pg.PlotWidget()
self.ecg_graph1.plotItem.setLabel('left', '<h2><b>LEAD I</b></h2>')
self.ecg_graph1.plotItem.showGrid(x= True, y=True)
self.ecg_graph2 = pg.PlotWidget()
self.ecg_graph2.plotItem.setLabel('left', '<h2><b>LEAD II</b></h2>')
self.ecg_graph2.plotItem.showGrid(x= True, y=True)
self.ecg_graph3 = pg.PlotWidget()
self.ecg_graph3.plotItem.setLabel('left', '<h2><b>LEAD III</b></h2>')
self.ecg_graph3.plotItem.showGrid(x= True, y=True)
self.ecg_graph4 = pg.PlotWidget()
self.ecg_graph4.plotItem.setLabel('left', '<h2><b>aVR</b></h2>')
self.ecg_graph4.plotItem.showGrid(x= True, y=True)
self.ecg_graph5 = pg.PlotWidget()
self.ecg_graph5.plotItem.setLabel('left', '<h2><b>aVL</b></h2>')
self.ecg_graph5.plotItem.showGrid(x= True, y=True)
self.ecg_graph6 = pg.PlotWidget()
self.ecg_graph6.plotItem.setLabel('left', '<h2><b>aVF</b></h2>')
self.ecg_graph6.plotItem.showGrid(x= True, y=True)
#########################################################
self.dataReceive.connect(self.data_processing)
self.displayPlot.connect(self.graph_plot)
self.q = queue.Queue()
self.timer1 = QtCore.QTimer()
self.timer1.timeout.connect(self.data_processing)
self.timer1.start(10)
# self.timer2 = QtCore.QTimer()
# self.timer2.timeout.connect(self.plot1)
# self.timer2.start(10)
# self.timer3 = QtCore.QTimer()
# self.timer3.timeout.connect(self.plot2)
# self.timer3.start(15)
# self.timer4 = QtCore.QTimer()
# self.timer4.timeout.connect(self.plot3)
# self.timer4.start(20)
# self.timer5 = QtCore.QTimer()
# self.timer5.timeout.connect(self.plot4)
# self.timer5.start(25)
# Create a top-level layout
layout = QVBoxLayout()
self.setLayout(layout)
# Create the tab widget with THREE tabs
tabs = QTabWidget()
tabs.setTabPosition(QTabWidget.North)
tabs.addTab(self.smartHealthDeviceTabUI(), QIcon('C:/tkinter_plot_app/guiLib/images/usb_icon.png'),"Smart Health Device")
tabs.addTab(self.scopeTabUI(), QIcon('C:/tkinter_plot_app/guiLib/images/scope_icon.png'), "Scope")
tabs.addTab(self.ecgTabUI(), QIcon('C:/tkinter_plot_app/guiLib/images/ecg_icon.png'), "ECG Display")
layout.addWidget(tabs)
def smartHealthDeviceTabUI(self):
"""Create the Smart Health Device page UI."""
smartHealthDeviceTab = QWidget()
layout = QGridLayout()
label1 = QLabel("")
label2 = QLabel("")
label3 = QLabel("")
label4 = QLabel("")
label5 = QLabel("")
label6 = QLabel("")
label7 = QLabel("")
label8 = QLabel("")
layout.addWidget(label1, 0, 0)
layout.addWidget(label2, 0, 1)
layout.addWidget(label3, 0, 2)
layout.addWidget(label4, 1, 0)
layout.addWidget(label5, 1, 2)
layout.addWidget(label6, 2, 0)
layout.addWidget(label7, 2, 1)
layout.addWidget(label8, 2, 2)
frame = QFrame()
frame.setFrameShape(QFrame.StyledPanel)
frame.setLineWidth(1)
panel = QGridLayout()
label_deviceId = self.label_deviceId
label_deviceId_value = self.label_deviceId_value
label_deviceId.setAlignment(Qt.AlignCenter)
label_deviceId.setFixedHeight(30)
panel.addWidget(label_deviceId, 0, 0)
panel.addWidget(label_deviceId_value, 0, 1)
label_comPort = self.label_comPort
label_comPort.setAlignment(Qt.AlignCenter)
label_comPort.setFixedHeight(30)
comPort_comboBox = self.comPort_comboBox
comPort_comboBox.setFixedHeight(30)
comPort_comboBox.addItems([])
panel.addWidget(label_comPort, 1, 0)
panel.addWidget(comPort_comboBox, 1, 1)
label_baudRate = self.label_baudRate
label_baudRate.setAlignment(Qt.AlignCenter)
label_baudRate.setFixedHeight(30)
baudRate_comboBox = self.baudRate_comboBox
baudRate_comboBox.setFixedHeight(30)
baudRate_comboBox.addItems(['','300', '1200', '2400', '4800','9600', '19200', '38400', '57600', '74800', '115200', '230400', '250000', '500000'])
panel.addWidget(label_baudRate, 2, 0)
panel.addWidget(baudRate_comboBox, 2, 1)
hLayout = QHBoxLayout()
connect_disconnect_button = self.connect_disconnect_button
connect_disconnect_button.setFixedHeight(35)
connect_disconnect_button.setStyleSheet("""QPushButton:hover {background-color: #50AF50;}""")
hLayout.addWidget(connect_disconnect_button)
# hLayout.addWidget(disConnect_button)
panel.addLayout(hLayout, 3, 1)
frame.setLayout(panel)
layout.addWidget(frame, 1, 1)
smartHealthDeviceTab.setLayout(layout)
return smartHealthDeviceTab
def scopeTabUI(self):
"""Create the Scope page UI."""
scopeTab = QWidget()
layout = QGridLayout()
label1 = self.scope_graph1
label2 = self.scope_graph2
label3 = self.scope_graph3
label4 = self.scope_graph4
label5 = self.scope_graph5
label6 = self.scope_graph6
label7 = self.scope_graph7
label8 = self.scope_graph8
layout.addWidget(label1, 0, 0)
layout.addWidget(label2, 0, 1)
layout.addWidget(label3, 1, 0)
layout.addWidget(label4, 1, 1)
layout.addWidget(label5, 2, 0)
layout.addWidget(label6, 2, 1)
layout.addWidget(label7, 3, 0)
layout.addWidget(label8, 3, 1)
scopeTab.setLayout(layout)
return scopeTab
def ecgTabUI(self):
"""Create the ECG page UI."""
ecgTab = QWidget()
layout = QGridLayout()
label1 = self.ecg_graph1
label2 = self.ecg_graph2
label3 = self.ecg_graph3
label4 = self.ecg_graph4
label5 = self.ecg_graph5
label6 = self.ecg_graph6
layout.addWidget(label1, 0, 0)
layout.addWidget(label2, 0, 1)
layout.addWidget(label3, 1, 0)
layout.addWidget(label4, 1, 1)
layout.addWidget(label5, 2, 0)
layout.addWidget(label6, 2, 1)
ecgTab.setLayout(layout)
return ecgTab
@QtCore.pyqtSlot()
def baudRateHandleActivated(self):
self.BAUDRATE = int(self.baudRate_comboBox.currentText())
self.serial.setBaudRate(self.BAUDRATE)
@QtCore.pyqtSlot()
def comPortHandleActivated(self):
self.COM_PORT = self.comPort_comboBox.currentText()
self.serial.setPortName(self.COM_PORT)
@QtCore.pyqtSlot(bool)
def on_toggled(self, checked):
self.connect_disconnect_button.setText("Disconnect" if checked else "Connect")
if checked:
if not self.serial.isOpen():
if not self.serial.open(QtCore.QIODevice.ReadWrite):
self.connect_disconnect_button.setChecked(False)
else:
self.connect_disconnect_button.setStyleSheet("""QPushButton:hover {background-color: #ff4040;}""")
self.comPort_comboBox.setDisabled(True)
self.baudRate_comboBox.setDisabled(True)
else:
self.connect_disconnect_button.setStyleSheet("""QPushButton:hover {background-color: #50AF50;}""")
self.serial.close()
self.comPort_comboBox.setEnabled(True)
self.baudRate_comboBox.setEnabled(True)
@QtCore.pyqtSlot()
def receive_serial(self):
try:
while self.serial.canReadLine():
rxData = self.serial.readLine().data().decode()
rxData = rxData.rstrip('\r\n')
rxData = rxData.split(",")
self.q.put(rxData)
except Exception as e:
print('Receive Serial Method Eception: ' + str(e))
@QtCore.pyqtSlot()
def data_processing(self):
rxData = []
if self.q.empty() != True:
rxData = self.q.get()
if(
len(self.channelData_1) < 300 and
len(self.channelData_2) < 300 and
len(self.channelData_3) < 300 and
len(self.channelData_4) < 300 and
len(self.channelData_5) < 300 and
len(self.channelData_6) < 300 and
len(self.channelData_7) < 300 and
len(self.channelData_8) < 300
):
self.channelData_1,self.channelData_2,self.channelData_3,self.channelData_4 = np.append(self.channelData_1, int(rxData[0])), np.append(self.channelData_2, int(rxData[1])), np.append(self.channelData_3, int(rxData[2])),np.append(self.channelData_4, int(rxData[3]))
self.channelData_5,self.channelData_6,self.channelData_7,self.channelData_8 = np.append(self.channelData_5, int(rxData[4])),np.append(self.channelData_6, int(rxData[5])), np.append(self.channelData_7, int(rxData[6])),np.append(self.channelData_8, int(rxData[7]))
temp_LEAD_III, temp_avR, temp_avL, temp_avF = float(int(rxData[2]) - int(rxData[1])), float((int(rxData[1]) + int(rxData[2]))/2), float(int(rxData[1]) - int(rxData[2])/2), float(int(rxData[2]) - int(rxData[1])/2)
# print(temp_avR)
self.lead_III = np.append(self.lead_III, temp_LEAD_III)
self.avR = np.append(self.avR, temp_avR)
self.avL = np.append(self.avL, temp_avL)
self.avF = np.append(self.avF, temp_avF)
else:
self.scope_graph1.plotItem.clear()
self.scope_graph2.plotItem.clear()
self.scope_graph3.plotItem.clear()
self.scope_graph4.plotItem.clear()
self.scope_graph5.plotItem.clear()
self.scope_graph6.plotItem.clear()
self.scope_graph7.plotItem.clear()
self.scope_graph8.plotItem.clear()
self.ecg_graph1.plotItem.clear()
self.ecg_graph2.plotItem.clear()
self.ecg_graph3.plotItem.clear()
self.ecg_graph4.plotItem.clear()
self.ecg_graph5.plotItem.clear()
self.ecg_graph6.plotItem.clear()
self.channelData_1[0:299], self.channelData_1[299] = self.channelData_1[1:300], int(rxData[0])
self.channelData_2[0:299], self.channelData_2[299] = self.channelData_2[1:300], int(rxData[1])
self.channelData_3[0:299], self.channelData_3[299] = self.channelData_3[1:300], int(rxData[2])
self.channelData_4[0:299], self.channelData_4[299] = self.channelData_4[1:300], int(rxData[3])
self.channelData_5[0:299], self.channelData_5[299] = self.channelData_5[1:300], int(rxData[4])
self.channelData_6[0:299], self.channelData_6[299] = self.channelData_6[1:300], int(rxData[5])
self.channelData_7[0:299], self.channelData_7[299] = self.channelData_7[1:300], int(rxData[6])
self.channelData_8[0:299], self.channelData_8[299] = self.channelData_8[1:300], int(rxData[7])
temp_LEAD_III, temp_avR, temp_avL, temp_avF = float(int(rxData[2]) - int(rxData[1])), float((int(rxData[1]) + int(rxData[2]))/2), float(int(rxData[1]) - int(rxData[2])/2),float(int(rxData[2]) - int(rxData[1])/2)
self.lead_III[0:299], self.lead_III[299] = self.lead_III[1:300], temp_LEAD_III
self.avR[0:299], self.avR[299] = self.avR[1:300], temp_avR
self.avL[0:299], self.avL[299] = self.avL[1:300], temp_avL
self.avF[0:299], self.avF[299] = self.avF[1:300], temp_avF
self.displayPlot.emit()
@QtCore.pyqtSlot()
def graph_plot(self):
self.scope_graph1.plotItem.plot(self.channelData_1, pen=pg.mkPen('y', width=2))
self.scope_graph2.plotItem.plot(self.channelData_2, pen=pg.mkPen('y', width=2))
self.scope_graph3.plotItem.plot(self.channelData_3, pen=pg.mkPen('y', width=2))
self.scope_graph4.plotItem.plot(self.channelData_4, pen=pg.mkPen('y', width=2))
self.scope_graph5.plotItem.plot(self.channelData_5, pen=pg.mkPen('y', width=2))
self.scope_graph6.plotItem.plot(self.channelData_6, pen=pg.mkPen('y', width=2))
self.scope_graph7.plotItem.plot(self.channelData_7, pen=pg.mkPen('y', width=2))
self.scope_graph8.plotItem.plot(self.channelData_8, pen=pg.mkPen('y', width=2))
self.ecg_graph1.plotItem.plot(self.channelData_2, pen=pg.mkPen('y', width=2))
self.ecg_graph2.plotItem.plot(self.channelData_3, pen=pg.mkPen('y', width=2))
self.ecg_graph3.plotItem.plot(self.lead_III, pen=pg.mkPen('y', width=2))
self.ecg_graph4.plotItem.plot(self.avR, pen=pg.mkPen('y', width=2))
self.ecg_graph5.plotItem.plot(self.avL, pen=pg.mkPen('y', width=2))
self.ecg_graph6.plotItem.plot(self.avF, pen=pg.mkPen('y', width=2))
def appRun():
app = QApplication(sys.argv)
win = Window()
win.show()
sys.exit(app.exec_())
if __name__ == '__main__':
try:
appRun()
except Exception as e:
print(e)