Hello,
I have been using pyqtgraph with pyqt5 on a number of GUI's at my office. I used to run them all using python 2.7 and didn't have any problems with random crashes. However, now that I've started using python 3.7, everything seem so much less stable. My GUI's will randomly crash with no traceback / error message. The window simply closes, despite wrapping general try/excepts over most functions that should print out the exception. I'm using the anaconda package and IPython console built into Spyder.
The crashing persists
- on multiple different installs on different computers.
- running scripts locally and network based
- All on python 3.7 and Windows 10
- sometimes happens when I click buttons
- sometimes seems to happen due to mouse / hover events
I'm not entirely convinced it's due to the pyqtgraph import but I figured this is a good place to start since my one application that does not use pyqtgraph doesn't seem to have this problem.
I recently got it to be more stable by only running the GUI script once from a specific console instance. My only lead is that it might has something to do with running the GUI from the console multiple times in a row ( I often do this when I'm adjusting pen colors / layouts etc)
My biggest problem is that I get no traceback or clue as to what's going on. It just closes without any message at all.
Here's a few relevant code snippets:
import sys
import time
import traceback
import numpy as np
from functools import partial
from PyQt5 import QtWidgets, QtCore, QtGui
from PyQt5.QtCore import pyqtSignal
import pyqtgraph.exporters
import pyqtgraph as pg
import DB_Control_v002 as DB
import pyqtGraphPresets_v001 as pgPre
class MainWindow(QtWidgets.QMainWindow):
sigCount = pyqtSignal()
def __init__(self, parent=None):
super(self.__class__, self).__init__(parent)
# Allows for statistical anylisis from the SPC table
# if an SPC table is not chosen it is changed to false and no analysis is done
# if the openened database is closed, it is then turned back to True
self.statsEnabled = True
self.statsGraphs = {}
self.check_list = []
"""Create Status Bar"""
self.MainStatus = self.statusBar()
""" Create MainWindow """
self.setObjectName("Data Viewer")
self.resize(1500, 800)
self.setWindowTitle("Data Viewer")
self.setWindowIcon(QtGui.QIcon('line-chart.png'))
graph_color = pg.mkColor(float(.9))
pg.setConfigOption('background', graph_color)
pg.setConfigOption('foreground', 'k')
self.layout = QtWidgets.QGridLayout() #establishes Grid layout style
self.layout.setContentsMargins(20,20,20,20)
self.layout.setHorizontalSpacing(9)
self.layout.setVerticalSpacing(1)
""" Font Creation """
self.font1 = QtGui.QFont("Times New Roman", pointSize=15)
self.font2 = QtGui.QFont("Helvetica",pointSize=12)
""" Graph Pen Creation """
self.magenta_line = pg.mkPen(width=1, color='m')
self.red_line = pg.mkPen(width=1, color='r')
self.green_line = pg.mkPen(width=1, color=(52, 127, 6), style=QtCore.Qt.DashLine)
self.yellow_dash = pg.mkPen(width=2, color=(249, 157, 19), style=QtCore.Qt.DashLine)
self.purp_dash = pg.mkPen(width=1,color=(182, 59, 191), style=QtCore.Qt.DashLine)
self.blank = QtGui.QColor(0,0,0,0)
""" ToolBar Creation """
toolbar_main = QtWidgets.QToolBar(self)
toolbar_main.setWindowTitle("Filter")
toolbar_main.setMovable(False)
toolbar_main.setIconSize(QtCore.QSize(50,50))
self.addToolBar(toolbar_main)
self.but_open = QtWidgets.QAction(QtGui.QIcon("download.png"),"Open new SQL Database",self)
self.but_close = QtWidgets.QAction(QtGui.QIcon("cancel.png"),"Close Database",self)
self.but_spc = QtWidgets.QAction(QtGui.QIcon("fence.png"),"SPC ",self)
self.but_spc.setCheckable(True)
self.but_avg = QtWidgets.QAction(QtGui.QIcon("avg.png"),"Average",self)
self.but_avg.setCheckable(True)
self.but_sigma = QtWidgets.QAction(QtGui.QIcon("sigma.png"),"Control Limits",self)
self.but_sigma.setCheckable(True)
self.but_minmax = QtWidgets.QAction(QtGui.QIcon("min-max.png"),"Min - Max",self)
self.but_minmax.setCheckable(True)
self.but_feed = QtWidgets.QAction(QtGui.QIcon("play_grad.png"),"Start live feed.",self)
self.but_feed.setCheckable(True)
self.stats_but_list = [self.but_spc, self.but_avg, self.but_sigma, self.but_minmax]
spacer_list = [QtGui.QWidget(self) for i in range(3)]
for spacer in spacer_list:
spacer.setSizePolicy(QtGui.QSizePolicy.Minimum,QtGui.QSizePolicy.Minimum)
spacer.setMinimumWidth(40)
toolbar_main.addAction(self.but_open)
toolbar_main.addAction(self.but_close)
toolbar_main.addWidget(spacer_list[0])
toolbar_main.addWidget(spacer_list[1])
toolbar_main.addAction(self.but_spc)
toolbar_main.addAction(self.but_avg)
toolbar_main.addAction(self.but_sigma)
toolbar_main.addAction(self.but_minmax)
toolbar_main.insertSeparator(self.but_spc)
toolbar_main.addWidget(spacer_list[2])
toolbar_main.addAction(self.but_feed)
toolbar_main.insertSeparator(self.but_feed)
""" Create Tab Zone """
self.Tab_zone = QtWidgets.QTabWidget()
self.Tab_zone.tabCloseRequested.connect(self.closeTab)
self.layout.addWidget(self.Tab_zone)
self.setCentralWidget(self.Tab_zone)
self.setLayout(self.layout)
""" Button Connections """
self.but_open.triggered.connect(self.openFile)
self.but_close.triggered.connect(self.closeFile)
self.but_spc.triggered.connect(self.toggleStatLines)
self.but_avg.triggered.connect(self.toggleStatLines)
self.but_sigma.triggered.connect(self.toggleStatLines)
self.but_minmax.triggered.connect(self.toggleStatLines)
self.but_feed.triggered.connect(self.handleFeed)
self.updateStatus(0)
def updateStatus(self, status):
# 0 = no database opened, or database closed
# 1 = database opened
if status == 0:
self.but_open.setEnabled(True)
self.but_close.setEnabled(False)
self.but_feed.setEnabled(False)
for but in self.stats_but_list:
but.setEnabled(False)
if status == 1:
self.but_open.setEnabled(False)
self.but_close.setEnabled(True)
self.but_feed.setEnabled(True)
for but in self.stats_but_list:
but.setEnabled(True)
def openSummaryTab(self):
try:
tab = QtWidgets.QWidget()
layout = QtWidgets.QGridLayout()
param_list = [col for col in self.dataFrame.columns]
row_limit = 25
start_row = 4
for i, param in enumerate(param_list):
col = (i)//row_limit
row = i+start_row - row_limit*col
button = QtWidgets.QCheckBox(param)
button.setSizePolicy(QtWidgets.QSizePolicy.Minimum,QtWidgets.QSizePolicy.Expanding)
button.stateChanged.connect(self.updateSummaryGraph)
button.stateChanged.connect(partial(self.openStatsTab, button))
self.check_list.append(button)
layout.addWidget(button,row,col,1,1)
label_Xaxis = QtWidgets.QLabel('Select X-Axis')
label_Xaxis.setAlignment(QtCore.Qt.AlignCenter)
label_Xaxis.setSizePolicy(QtWidgets.QSizePolicy.Minimum,QtGui.QSizePolicy.Minimum)
label_Xaxis.setFont(self.font1)
self.combo_Xaxis = QtWidgets.QComboBox()
for param in param_list:
self.combo_Xaxis.addItem(param)
self.combo_Xaxis.currentIndexChanged.connect(self.sortTableView)
layout.addWidget(self.combo_Xaxis, 1, 0, 1, layout.columnCount()-1)
self.text_mode = QtWidgets.QCheckBox('Text Mode')
layout.addWidget(self.text_mode, 2, 0, 1, layout.columnCount()-1)
self.text_mode.stateChanged.connect(self.setTextMode)
label_Yaxis = QtWidgets.QLabel('Select Y-Axis')
label_Yaxis.setAlignment(QtCore.Qt.AlignCenter)
label_Yaxis.setSizePolicy(QtWidgets.QSizePolicy.Minimum,QtGui.QSizePolicy.Minimum)
label_Yaxis.setFont(self.font1)
layout.addWidget(label_Xaxis,0,0,1,layout.columnCount())
layout.addWidget(label_Yaxis,3,0,1,layout.columnCount())
self.Xaxis = pgPre.CustomAxis(orientation='bottom')
if self.text_mode.isChecked():
self.Xaxis.setTextMode(True)
self.sumGraph = pg.PlotWidget(axisItems={'bottom': self.Xaxis})
self.sumGraph.showGrid(x=True,y=True)
self.combo_Xaxis.currentIndexChanged.connect(self.updateSummaryGraph)
self.combo_Xaxis.currentIndexChanged.connect(self.updateAllStatsGraph)
self.header.sigUpdate.connect(self.updateSummaryGraph)
self.updateSummaryGraph()
layout.addWidget(self.sumGraph,0,layout.columnCount(),layout.rowCount(),1)
tab.setLayout(layout)
self.Tab_zone.addTab(tab, "Summary")
self.updateStatus(1)
except Exception as ex:
tb = sys.exc_info()[-1]
self.MainStatus.showMessage("openSummaryTab Error : {} | Line : {} | Details : {}".format(type(ex).__name__,tb.tb_lineno,ex.args))
def updateSummaryGraph(self):
try:
y_axis_title_list = []
color_list = ['#0080FF', '#FF0000', '#00FF00','#FF007F',
'#00FFFF', '#FF8000',
'#7F00FF', '#FF00FF', '#FFFF00',
'#E0E0E0', '#606060']
self.sumGraph.plot([],[], clear=True)
x_param = self.combo_Xaxis.currentText()
if self.text_mode.isChecked():
self.Xaxis.x_list = self.getStrings(x_param)
x = list(range(len(self.Xaxis.x_list)))
else:
x = self.getGraphData(x_param)
color=0
for item in self.check_list:
item.setStyleSheet('')
if item.isChecked():
y_param = item.text()
y = self.getGraphData(y_param)
y_axis_title_list.append(y_param)
brush = pg.mkBrush(color=color_list[color], symbol='o')
self.sumGraph.plot(x, y, pen=color_list[color], symbolBrush=brush, symbolPen='k')
item.setStyleSheet("background-color: {}".format(color_list[color]))
color += 1
if color > (len(color_list)-1):
color = 0
self.sumGraph.setLabels(title = 'Summary Graph', left = str(y_axis_title_list), bottom = x_param)
def main():
try:
sys.excepthook = traceback.print_exception
app = 0
app = QtWidgets.QApplication(sys.argv)
app.setQuitOnLastWindowClosed(True)
dlg = MainWindow()
dlg.show()
dlg.raise_()
sys.exit(app.exec_())
except SystemExit as sysEx:
if sysEx.args[0] == 0:
pass
else:
print(sysEx.args)
except Exception as ex:
print(ex)
if __name__ == "__main__":
main()