class Plotter(QtGui.QWidget): update_plot_xy_signal = pyqtSignal(object, object) def __init__(self, title='PLOTTER', x_label='X', y_label='Y'): QtGui.QWidget.__init__(self) self.gridLayout = QtGui.QGridLayout(self) self.setWindowTitle(title) #graph graphSetOptions(antialias=True) self.graph = PlotWidget() self.graph.setTitle(title) self.graph.setLabel('left', y_label) self.graph.setLabel('bottom', x_label) self.graph.showGrid(x=True, y=True) self.graph.setBackground((235, 236, 237)) self.pen = mkPen(color=(46, 142, 226), width=3, style=QtCore.Qt.DashLine) self.gridLayout.addWidget(self.graph, 0, 1, 10, 10) self.update_plot_xy_signal.connect(self.update_graph_with_value) self.x_vect = [] self.y_vect = [] self.__x_range_was_set = False def set_max_x(self, value): self.graph.setXRange(0, value) self.__x_range_was_set = True def get_max(self): max_y = max(self.y_vect) x = self.x_vect[self.y_vect.index(max_y)] return x, max_y def get_min(self): min_y = min(self.y_vect) x = self.x_vect[self.y_vect.index(min_y)] return x, min_y def update_graph_with_value(self, x, y): self.x_vect.append(x) self.y_vect.append(y) y_max = 0 y_min = 0 x_max = 0 for x_val in self.x_vect: y_val = self.y_vect[self.x_vect.index(x_val)] if y_val > y_max: y_max = y_val if y_val < y_min: y_min = y_val if x_val > x_max: x_max = x_val self.graph.clear() self.graph.setYRange(y_min - float(y_min) / 10, y_max + float(y_max) / 10) if self.__x_range_was_set is False: self.graph.setXRange(0, x_max + float(x_max) / 10) self.graph.plot(self.x_vect, self.y_vect, symbol='o', pen=self.pen)
class SensirionSBPlot(QWidget): def __init__(self, plot_title, color, bufferSize): super().__init__() masterLayout = QVBoxLayout() self.pen = mkPen(color, width=1.25) layout = QVBoxLayout() self.group = QGroupBox(plot_title) self.plot = PlotWidget() self.plot.getPlotItem().showGrid(x=True, y=True, alpha=1) if "qdarkstyle" in sys.modules: self.plot.setBackground((25, 35, 45)) self.buffer = RingBuffer(capacity=bufferSize, dtype=float) self.group.setLayout(layout) layout.addWidget(self.plot) masterLayout.addWidget(self.group) self.setLayout(masterLayout) def change_capacity(self, value): if value > len(self.buffer): newBuf = RingBuffer(capacity=value, dtype=float) newBuf.extend(self.buffer) self.buffer = newBuf elif value < len(self.buffer): newBuf = RingBuffer(capacity=value, dtype=float) newBuf.extend(self.buffer[:-value]) self.buffer = newBuf def update_plot(self, sample): self.plot.clear() self.buffer.append(sample) self.plot.plot(self.buffer, pen=self.pen, symbolPen=self.pen, symbol='o', symbolSize=5, name="symbol ='o'")
class PyQtGraphDataPlot(QWidget): _colors = [ Qt.red, Qt.blue, Qt.magenta, Qt.cyan, Qt.green, Qt.darkYellow, Qt.black, Qt.darkRed, Qt.gray, Qt.darkCyan ] def __init__(self, parent=None): super(PyQtGraphDataPlot, self).__init__(parent) self._plot_widget = PlotWidget() self._plot_widget.setBackground((255, 255, 255)) self._plot_widget.setXRange(0, 10, padding=0) self.legend = self._plot_widget.addLegend() vbox = QVBoxLayout() vbox.addWidget(self._plot_widget) self.setLayout(vbox) self._color_index = 0 self._curves = {} def add_curve(self, curve_id, curve_name, data_x, data_y): color = QColor(self._colors[self._color_index % len(self._colors)]) self._color_index += 1 pen = mkPen(color, width=1) plot = self._plot_widget.plot(name=curve_name, pen=pen) data_x = numpy.array(data_x) data_y = numpy.array(data_y) self._curves[curve_id] = {'x': data_x, 'y': data_y, 'plot': plot} self._update_legend() def remove_curve(self, curve_id): curve_id = str(curve_id) if curve_id in self._curves: self._plot_widget.removeItem(self._curves[curve_id]['plot']) del self._curves[curve_id] self._update_legend() def _update_legend(self): # TODO Figure this out pass @Slot(str, list, list) def update_values(self, curve_id, x, y): curve = self._curves[curve_id] curve['x'] = numpy.append(curve['x'], x) curve['y'] = numpy.append(curve['y'], y) def redraw(self): # Set axis bounds x_range, _ = self._plot_widget.viewRange() x_delta = x_range[1] - x_range[0] x_max = 0 for curve in self._curves.values(): if len(curve['x']) == 0: continue x_max = max(x_max, curve['x'][-1]) curve['plot'].setData(curve['x'], curve['y']) self._plot_widget.setXRange(x_max - x_delta, x_max, padding=0)
class RealtimePlotWidget(QWidget): COLORS = [ Qt.red, Qt.blue, Qt.green, Qt.magenta, Qt.cyan, Qt.darkRed, Qt.darkBlue, Qt.darkGreen, Qt.darkYellow, Qt.gray ] def __init__(self, parent=None): super(RealtimePlotWidget, self).__init__(parent) self._plot_widget = PlotWidget() self._plot_widget.setBackground((0, 0, 0)) self._plot_widget.addLegend() self._plot_widget.showButtons() self._plot_widget.enableAutoRange() self._plot_widget.showGrid(x=True, y=True, alpha=0.2) vbox = QVBoxLayout() vbox.addWidget(self._plot_widget) self.setLayout(vbox) self._color_index = 0 self._curves = {} def add_curve(self, curve_id, curve_name, data_x=[], data_y=[]): color = QColor(self.COLORS[self._color_index % len(self.COLORS)]) self._color_index += 1 pen = mkPen(color, width=1) plot = self._plot_widget.plot(name=curve_name, pen=pen) data_x = numpy.array(data_x) data_y = numpy.array(data_y) self._curves[curve_id] = {'x': data_x, 'y': data_y, 'plot': plot} def remove_curve(self, curve_id): curve_id = str(curve_id) if curve_id in self._curves: self._plot_widget.removeItem(self._curves[curve_id]['plot']) del self._curves[curve_id] def set_x_range(self, left, right): self._plot_widget.setRange(xRange=(left, right)) def update_values(self, curve_id, x, y): curve = self._curves[curve_id] curve['x'] = numpy.append(curve['x'], x) curve['y'] = numpy.append(curve['y'], y) def redraw(self): for curve in self._curves.values(): if len(curve['x']): curve['plot'].setData(curve['x'], curve['y']) def lazy_redraw(self, period): timestamp = time.time() if not hasattr(self, '_prev_lazy_redraw'): self._prev_lazy_redraw = 0.0 if timestamp - self._prev_lazy_redraw > period: self._prev_lazy_redraw = timestamp self.redraw()
class RealtimePlotWidget(QWidget): COLORS = [Qt.red, Qt.blue, Qt.green, Qt.magenta, Qt.cyan, Qt.darkRed, Qt.darkBlue, Qt.darkGreen, Qt.darkYellow, Qt.gray] def __init__(self, parent=None): super(RealtimePlotWidget, self).__init__(parent) self._plot_widget = PlotWidget() self._plot_widget.setBackground((0, 0, 0)) self._plot_widget.addLegend() self._plot_widget.showButtons() self._plot_widget.enableAutoRange() self._plot_widget.showGrid(x=True, y=True, alpha=0.2) vbox = QVBoxLayout() vbox.addWidget(self._plot_widget) self.setLayout(vbox) self._color_index = 0 self._curves = {} def add_curve(self, curve_id, curve_name, data_x=[], data_y=[]): color = QColor(self.COLORS[self._color_index % len(self.COLORS)]) self._color_index += 1 pen = mkPen(color, width=1) plot = self._plot_widget.plot(name=curve_name, pen=pen) data_x = numpy.array(data_x) data_y = numpy.array(data_y) self._curves[curve_id] = {'x': data_x, 'y': data_y, 'plot': plot} def remove_curve(self, curve_id): curve_id = str(curve_id) if curve_id in self._curves: self._plot_widget.removeItem(self._curves[curve_id]['plot']) del self._curves[curve_id] def set_x_range(self, left, right): self._plot_widget.setRange(xRange=(left, right)) def update_values(self, curve_id, x, y): curve = self._curves[curve_id] curve['x'] = numpy.append(curve['x'], x) curve['y'] = numpy.append(curve['y'], y) def redraw(self): for curve in self._curves.values(): if len(curve['x']): curve['plot'].setData(curve['x'], curve['y']) def lazy_redraw(self, period): timestamp = time.time() if not hasattr(self, '_prev_lazy_redraw'): self._prev_lazy_redraw = 0.0 if timestamp - self._prev_lazy_redraw > period: self._prev_lazy_redraw = timestamp self.redraw()
class LookupTableWithGraph(QtGui.QWidget): def __init__(self, name='LOOKPUP TABLE', init_table={}): QtGui.QWidget.__init__(self) self.gridLayout = QtGui.QGridLayout(self) self.name = name #table self.table = LookupTable(init_table) #self.table.add_row() self.table.values_updated_signal.connect(self.values_updated_slot) #graph graphSetOptions(antialias=True) self.graph = PlotWidget() self.graph.setTitle(self.name) self.graph.setLabel('left', 'OUTPUT') self.graph.setLabel('bottom', 'INPUT') self.graph.showGrid(x=True, y=True) self.graph.setBackground((235, 236, 237)) self.pen = mkPen(color=(46, 142, 226), width=3, style=QtCore.Qt.DashLine) self.gridLayout.addWidget(self.table, 0, 0) self.gridLayout.addWidget(self.graph, 0, 1) self.values_updated_slot() def values_updated_slot(self): x_vect = [] y_vect = [] y_max = 0 y_min = 0 x_max = 0 for x_val in self.table.lookup_table: y_val = self.table.lookup_table[x_val] x_vect.append(x_val) y_vect.append(y_val) if y_val > y_max: y_max = y_val if y_val < y_min: y_min = y_val if x_val > x_max: x_max = x_val self.graph.clear() self.graph.setYRange(y_min - float(y_min) / 10, y_max + float(y_max) / 10) self.graph.setXRange(0, x_max + float(x_max) / 10) self.graph.plot(x_vect, y_vect, symbol='o', pen=self.pen) def get_table(self): return self.table.get_table()
class SimpleTestResultsDialog(QMainWindow): def __init__(self, parent=None, methods=None): super(SimpleTestResultsDialog, self).__init__(parent) self.setWindowTitle("Grismo - Wyniki dla prostego testu") self.setMinimumWidth(500) self.results_count = 0 self.all_results = [] self.methods = methods central = QWidget() self.setCentralWidget(central) result_dialog_layout = QVBoxLayout() central.setLayout(result_dialog_layout) self.results_table = QTableWidget() result_dialog_layout.addWidget(self.results_table) self.results_table.setRowCount(len(methods)) self.results_table.setColumnCount(3) self.results_table.setColumnWidth(2, 200) self.results_table.setHorizontalHeaderLabels(["Metoda", "Wynik", "Czas [s]"]) for i in range(len(methods)): self.results_table.setItem(i, 0, QTableWidgetItem(methods[i])) # plot box x_axis_dict = dict(enumerate(methods)) x_axis = AxisItem(orientation='bottom') x_axis.setTicks([x_axis_dict.items()]) self.results_plot = PlotWidget(axisItems={'bottom': x_axis}) self.results_plot.setBackground('w') self.results_plot.setTitle("Porównanie metod dla wskazanych grafów") self.results_plot.setLabel('left', 'Czas obliczeń [s]', color='k', size=10) self.results_plot.setLabel('bottom', 'Metody ', color='k', size=10) self.results_plot.setMaximumWidth(600) self.results_plot.showGrid(y=True) result_dialog_layout.addWidget(self.results_plot) # prepare plot data pen = mkPen(color='k', width=2) self.plot_data = self.results_plot.plot([], [], pen=pen, symbol='+', symbolSize=10, symbolBrush='k') def add_result(self, result): for i in range(len(result)): self.results_table.setItem(self.results_count, i, QTableWidgetItem(str(result[i]))) self.results_count = self.results_count + 1 self.all_results.append(result[-1]) self.plot_data.setData(range(len(self.all_results)), self.all_results)
class Ui_MainWindow(object): def setupUi(self, MainWindow): MainWindow.setObjectName("Signal Viewer") MainWindow.resize(900, 700) self.centralwidget = QtWidgets.QWidget(MainWindow) self.centralwidget.setObjectName("centralwidget") #The Graph Area self.graphicsView = PlotWidget(self.centralwidget) self.graphicsView.setGeometry(QtCore.QRect(20, 30, 761, 500)) self.graphicsView.setObjectName("graphicsView") self.graphicsView.setBackground('#e1f5f3') MainWindow.setCentralWidget(self.centralwidget) self.statusbar = QtWidgets.QStatusBar(MainWindow) self.statusbar.setObjectName("statusbar") MainWindow.setStatusBar(self.statusbar)
class Ui_Dialog(object): def __init__(self) : self.c = 1 self.dx = 0.1 self.n = 1 def setupUi(self, Dialog): Dialog.setObjectName("Equation de transport") Dialog.resize(996, 388) Dialog.setWindowIcon(QtGui.QIcon(r'D:\Cours\Aero2\GP\Transport\Numerix.jpg')) Dialog.setFixedSize(996,388) font = QtGui.QFont() font.setFamily("CMU Bright") font.setPointSize(10) Dialog.setFont(font) self.frame = QtWidgets.QFrame(Dialog) self.frame.setGeometry(QtCore.QRect(20, 10, 361, 81)) self.frame.setFrameShape(QtWidgets.QFrame.StyledPanel) self.frame.setFrameShadow(QtWidgets.QFrame.Raised) self.frame.setObjectName("frame") self.label = QtWidgets.QLabel(self.frame) self.label.setGeometry(QtCore.QRect(10, 10, 181, 16)) self.label.setObjectName("label") self.label_2 = QtWidgets.QLabel(self.frame) self.label_2.setGeometry(QtCore.QRect(200, 10, 161, 16)) self.label_2.setCursor(QtGui.QCursor(QtCore.Qt.ArrowCursor)) self.label_2.setMouseTracking(False) self.label_2.setObjectName("label_2") self.L = QtWidgets.QLineEdit(self.frame) self.L.setGeometry(QtCore.QRect(10, 40, 113, 22)) self.L.setObjectName("L") self.tmax = QtWidgets.QLineEdit(self.frame) self.tmax.setGeometry(QtCore.QRect(200, 40, 113, 22)) self.tmax.setObjectName("tmax") self.frame_2 = QtWidgets.QFrame(Dialog) self.frame_2.setGeometry(QtCore.QRect(20, 110, 361, 221)) font = QtGui.QFont() font.setFamily("CMU Serif") font.setPointSize(10) self.frame_2.setFont(font) self.frame_2.setFrameShape(QtWidgets.QFrame.StyledPanel) self.frame_2.setFrameShadow(QtWidgets.QFrame.Raised) self.frame_2.setObjectName("frame_2") self.label_3 = QtWidgets.QLabel(self.frame_2) self.label_3.setGeometry(QtCore.QRect(10, 10, 171, 16)) self.label_3.setObjectName("label_3") self.CI = QtWidgets.QComboBox(self.frame_2) self.CI.setGeometry(QtCore.QRect(10, 50, 91, 22)) font = QtGui.QFont() font.setFamily("CMU Serif") font.setPointSize(10) font.setBold(False) font.setItalic(False) font.setWeight(50) self.CI.setFont(font) self.CI.setStyleSheet("") self.CI.setObjectName("CI") self.CI.addItem("sin(x)") self.CI.addItem("exp(-x^2)") self.CI.addItem("0") self.label_4 = QtWidgets.QLabel(self.frame_2) self.label_4.setGeometry(QtCore.QRect(180, 10, 201, 16)) self.label_4.setObjectName("label_4") self.frame_3 = QtWidgets.QFrame(self.frame_2) self.frame_3.setGeometry(QtCore.QRect(170, 0, 191, 181)) self.frame_3.setFrameShape(QtWidgets.QFrame.StyledPanel) self.frame_3.setFrameShadow(QtWidgets.QFrame.Raised) self.frame_3.setObjectName("frame_3") self.label_5 = QtWidgets.QLabel(self.frame_3) self.label_5.setGeometry(QtCore.QRect(20, 40, 71, 16)) self.label_5.setObjectName("label_5") self.Cl_0 = QtWidgets.QComboBox(self.frame_3) self.Cl_0.setGeometry(QtCore.QRect(20, 70, 90, 22)) self.Cl_0.setObjectName("Cl_0") self.Cl_0.addItem("0") self.Cl_0.addItem("sin(t)") self.label_6 = QtWidgets.QLabel(self.frame_3) self.label_6.setGeometry(QtCore.QRect(20, 110, 71, 16)) self.label_6.setObjectName("label_6") self.Cl_L = QtWidgets.QComboBox(self.frame_3) self.Cl_L.setGeometry(QtCore.QRect(20, 140, 90, 22)) self.Cl_L.setObjectName("Cl_L") self.Cl_L.addItem("0") self.Cl_L.addItem("sin(t)") self.Cl_L.addItem("Aucune") self.label_7 = QtWidgets.QLabel(self.frame_2) self.label_7.setGeometry(QtCore.QRect(10, 100, 151, 16)) self.label_7.setObjectName("label_7") self.Vitesse = QtWidgets.QLineEdit(self.frame_2) self.Vitesse.setGeometry(QtCore.QRect(10, 140, 113, 22)) self.Vitesse.setObjectName("Vitesse") self.Animation = QtWidgets.QCheckBox(Dialog) self.Animation.setGeometry(QtCore.QRect(30, 340, 101, 20)) self.Animation.setObjectName("Animation") self.Plot_btn = QtWidgets.QPushButton(Dialog) self.Plot_btn.setGeometry(QtCore.QRect(220, 340, 93, 28)) self.Plot_btn.setObjectName("Plot_btn") self.Graph = PlotWidget(Dialog) self.Graph.setGeometry(QtCore.QRect(389, 9, 591, 361)) self.Graph.setObjectName("Graph") self.retranslateUi(Dialog) QtCore.QMetaObject.connectSlotsByName(Dialog) Dialog.setTabOrder(self.CI, self.Vitesse) Dialog.setTabOrder(self.Vitesse,self.Cl_0) Dialog.setTabOrder(self.Cl_0, self.Cl_L) Dialog.setTabOrder(self.Cl_L, self.Animation) Dialog.setTabOrder(self.Animation, self.Plot_btn) setConfigOptions(antialias=True) self.Plot_btn.clicked.connect(self.plotter) self.Graph.setBackground('w') self.Graph.setLabel('left','y(x,tmax)') self.Graph.setLabel('bottom','x') self.timer = QtCore.QTimer() self.timer.timeout.connect(self.animplotter) def retranslateUi(self, Dialog): _translate = QtCore.QCoreApplication.translate Dialog.setWindowTitle(_translate("Dialog", "Equation de transport")) self.label.setText(_translate("Dialog", "Longueur de l\'espace :")) self.label_2.setText(_translate("Dialog", "Temps maximum :")) self.label_3.setText(_translate("Dialog", "Conditions initiales :")) self.CI.setItemText(0, _translate("Dialog", "sin(x)")) self.CI.setItemText(1, _translate("Dialog", "exp(-x^2)")) self.CI.setItemText(2, _translate("Dialog", "0")) self.label_4.setText(_translate("Dialog", "Conditions aux limites :")) self.label_5.setText(_translate("Dialog", "En x = 0 :")) self.Cl_0.setItemText(0, _translate("Dialog", "0")) self.Cl_0.setItemText(1, _translate("Dialog", "sin(t)")) self.label_6.setText(_translate("Dialog", "En x = L :")) self.Cl_L.setItemText(0, _translate("Dialog", "0")) self.Cl_L.setItemText(1, _translate("Dialog", "sin(t)")) self.Animation.setText(_translate("Dialog", "Animation")) self.Plot_btn.setText(_translate("Dialog", "Plot !")) self.label_6.setText(_translate("Dialog", "En x = L :")) self.Cl_L.setItemText(0, _translate("Dialog", "0")) self.Cl_L.setItemText(1, _translate("Dialog", "sin(t)")) self.Cl_L.setItemText(2, _translate("Dialog", "Aucune")) self.Animation.setText(_translate("Dialog", "Animation")) self.Plot_btn.setText(_translate("Dialog", "Plot !")) self.label_7.setText(_translate("Dialog", "Vitesse de l\'onde :")) def solve(self) : self.C = self.c*self.dt/self.dx self.Fi = init = self.Finit() self.sol = [] self.solutions = [0 for t in self.T] for t in range(len(self.T)) : for x in range(len(self.Fi)) : self.sol.append( init[x] - self.C*(init[x] - init[x-1]) ) if self.Cl_0.currentText() == 'sin(t)' : self.sol[0] = np.sin(self.T[t]*self.c) elif self.Cl_0.currentText() == '0' : self.sol[0] = 0 if self.Cl_L.currentText() == 'sin(t)' : self.sol[-1] = np.sin(self.T[t]) elif self.Cl_L.currentText() == '0' : self.sol[-1] = 0 init = self.sol self.sol = [] self.solutions[t] = init self.sol = init return self.sol def plotter(self) : self.c = float(self.Vitesse.text()) self.tmaxv = float(self.tmax.text()) self.dt = self.dx/self.c self.Graph.clear() self.X = np.arange(0,float(self.L.text()),self.dx).tolist() self.T = np.arange(0,self.tmaxv,self.dt).tolist() Solution = self.solve() self.Graph.setXRange(0,float(self.L.text())) self.Graph.setYRange(min(Solution)-self.dx,1.1) self.timer.setInterval(self.tmaxv/len(self.T)*10**3) #self.timer.setInterval(50) if self.Animation.isChecked() : self.n = 1 self.my_line = self.Graph.plot(self.X,self.Finit(),name ='t=0', pen = mkPen(color = 'k') ) self.timer.start() else : self.Graph.plot(self.X,self.Finit(),name ='t=0', pen = mkPen(color = 'b') ) self.Graph.plot(self.X,Solution,name ='t=tmax', pen = mkPen(color = 'k') ) def Finit(self) : X = np.arange(0,float(self.L.text()),self.dx) if self.CI.currentText() == 'exp(-x^2)' : return np.exp(-(X-float(self.L.text())/2)**2) elif self.CI.currentText() == 'sin(x)' : return np.sin(X) elif self.CI.currentText() == '0' : return [0 for x in X] def animplotter(self) : try : self.my_line.setData(self.X,self.solutions[self.n]) self.n += 1 except : self.timer.stop()
class Ui_MainWindow(object): def setupUi(self, MainWindow): MainWindow.setObjectName("MainWindow") MainWindow.resize(1326, 755) self.centralwidget = QtWidgets.QWidget(MainWindow) self.centralwidget.setObjectName("centralwidget") self.layoutWidget = QtWidgets.QWidget(self.centralwidget) self.layoutWidget.setGeometry(QtCore.QRect(0, 0, 1290, 702)) self.layoutWidget.setObjectName("layoutWidget") self.horizontalLayout = QtWidgets.QHBoxLayout(self.layoutWidget) self.horizontalLayout.setContentsMargins(0, 0, 0, 0) self.horizontalLayout.setObjectName("horizontalLayout") self.verticalLayout = QtWidgets.QVBoxLayout() self.verticalLayout.setObjectName("verticalLayout") self.formLayout = QtWidgets.QFormLayout() self.formLayout.setObjectName("formLayout") self.label = QtWidgets.QLabel(self.layoutWidget) font = QtGui.QFont() font.setPointSize(12) self.label.setFont(font) self.label.setObjectName("label") self.formLayout.setWidget(0, QtWidgets.QFormLayout.LabelRole, self.label) self.doubleSpinBoxR = QtWidgets.QDoubleSpinBox(self.layoutWidget) self.doubleSpinBoxR.setMinimumSize(QtCore.QSize(100, 30)) self.doubleSpinBoxR.setObjectName("doubleSpinBoxR") self.formLayout.setWidget(0, QtWidgets.QFormLayout.FieldRole, self.doubleSpinBoxR) self.label_2 = QtWidgets.QLabel(self.layoutWidget) font = QtGui.QFont() font.setPointSize(12) self.label_2.setFont(font) self.label_2.setObjectName("label_2") self.formLayout.setWidget(1, QtWidgets.QFormLayout.LabelRole, self.label_2) self.doubleSpinBoxk = QtWidgets.QDoubleSpinBox(self.layoutWidget) self.doubleSpinBoxk.setMinimumSize(QtCore.QSize(100, 30)) self.doubleSpinBoxk.setObjectName("doubleSpinBoxk") self.formLayout.setWidget(1, QtWidgets.QFormLayout.FieldRole, self.doubleSpinBoxk) self.label_3 = QtWidgets.QLabel(self.layoutWidget) font = QtGui.QFont() font.setPointSize(12) self.label_3.setFont(font) self.label_3.setObjectName("label_3") self.formLayout.setWidget(2, QtWidgets.QFormLayout.LabelRole, self.label_3) self.doubleSpinBoxC = QtWidgets.QDoubleSpinBox(self.layoutWidget) self.doubleSpinBoxC.setMinimumSize(QtCore.QSize(100, 30)) self.doubleSpinBoxC.setObjectName("doubleSpinBoxC") self.formLayout.setWidget(2, QtWidgets.QFormLayout.FieldRole, self.doubleSpinBoxC) self.label_4 = QtWidgets.QLabel(self.layoutWidget) font = QtGui.QFont() font.setPointSize(12) self.label_4.setFont(font) self.label_4.setObjectName("label_4") self.formLayout.setWidget(3, QtWidgets.QFormLayout.LabelRole, self.label_4) self.doubleSpinBoxT = QtWidgets.QDoubleSpinBox(self.layoutWidget) self.doubleSpinBoxT.setMinimumSize(QtCore.QSize(100, 30)) self.doubleSpinBoxT.setMaximum(10.0) self.doubleSpinBoxT.setObjectName("doubleSpinBoxT") self.formLayout.setWidget(3, QtWidgets.QFormLayout.FieldRole, self.doubleSpinBoxT) self.label_5 = QtWidgets.QLabel(self.layoutWidget) font = QtGui.QFont() font.setPointSize(12) self.label_5.setFont(font) self.label_5.setObjectName("label_5") self.formLayout.setWidget(4, QtWidgets.QFormLayout.LabelRole, self.label_5) self.spinBoxI = QtWidgets.QSpinBox(self.layoutWidget) self.spinBoxI.setMinimumSize(QtCore.QSize(100, 30)) self.spinBoxI.setMaximum(10000) self.spinBoxI.setObjectName("spinBoxI") self.formLayout.setWidget(4, QtWidgets.QFormLayout.FieldRole, self.spinBoxI) self.label_6 = QtWidgets.QLabel(self.layoutWidget) font = QtGui.QFont() font.setPointSize(12) self.label_6.setFont(font) self.label_6.setObjectName("label_6") self.formLayout.setWidget(6, QtWidgets.QFormLayout.LabelRole, self.label_6) self.spinBoxK = QtWidgets.QSpinBox(self.layoutWidget) self.spinBoxK.setMinimumSize(QtCore.QSize(100, 30)) self.spinBoxK.setMaximum(10000) self.spinBoxK.setObjectName("spinBoxK") self.formLayout.setWidget(6, QtWidgets.QFormLayout.FieldRole, self.spinBoxK) self.label_7 = QtWidgets.QLabel(self.layoutWidget) font = QtGui.QFont() font.setPointSize(12) self.label_7.setFont(font) self.label_7.setObjectName("label_7") self.formLayout.setWidget(7, QtWidgets.QFormLayout.LabelRole, self.label_7) self.label_8 = QtWidgets.QLabel(self.layoutWidget) font = QtGui.QFont() font.setPointSize(12) self.label_8.setFont(font) self.label_8.setObjectName("label_8") self.formLayout.setWidget(8, QtWidgets.QFormLayout.LabelRole, self.label_8) self.resultch = QtWidgets.QLabel(self.layoutWidget) font = QtGui.QFont() font.setPointSize(12) font.setBold(True) font.setWeight(75) self.resultch.setFont(font) self.resultch.setText("") self.resultch.setObjectName("resultch") self.formLayout.setWidget(7, QtWidgets.QFormLayout.FieldRole, self.resultch) self.resultanal = QtWidgets.QLabel(self.layoutWidget) font = QtGui.QFont() font.setPointSize(12) font.setBold(True) font.setWeight(75) self.resultanal.setFont(font) self.resultanal.setText("") self.resultanal.setObjectName("resultanal") self.formLayout.setWidget(8, QtWidgets.QFormLayout.FieldRole, self.resultanal) self.verticalLayout.addLayout(self.formLayout) self.result = QtWidgets.QLabel(self.layoutWidget) self.result.setText("") self.result.setObjectName("result") self.verticalLayout.addWidget(self.result) self.pushButton = QtWidgets.QPushButton(self.layoutWidget) self.pushButton.setMinimumSize(QtCore.QSize(200, 30)) self.pushButton.setMaximumSize(QtCore.QSize(200, 30)) self.pushButton.setSizeIncrement(QtCore.QSize(10, 10)) self.pushButton.setBaseSize(QtCore.QSize(10, 10)) self.pushButton.setLayoutDirection(QtCore.Qt.LeftToRight) self.pushButton.setObjectName("pushButton") self.verticalLayout.addWidget(self.pushButton, 0, QtCore.Qt.AlignHCenter) self.horizontalLayout.addLayout(self.verticalLayout) self.graphicsView = PlotWidget(self.layoutWidget) self.graphicsView.setObjectName("graphicsView") self.graphicsView.setBackground('w') self.horizontalLayout.addWidget(self.graphicsView) self.graphicsView.plotItem.setLabel(axis='left', text="u(θ,t)") self.graphicsView.plotItem.showGrid(x=True, y=True, alpha=1.0) self.graphicsView.plotItem.setLabel(axis='bottom', text="θ") MainWindow.setCentralWidget(self.centralwidget) self.menubar = QtWidgets.QMenuBar(MainWindow) self.menubar.setGeometry(QtCore.QRect(0, 0, 1326, 26)) self.menubar.setObjectName("menubar") MainWindow.setMenuBar(self.menubar) self.statusbar = QtWidgets.QStatusBar(MainWindow) self.statusbar.setObjectName("statusbar") MainWindow.setStatusBar(self.statusbar) self.retranslateUi(MainWindow) QtCore.QMetaObject.connectSlotsByName(MainWindow) def retranslateUi(self, MainWindow): _translate = QtCore.QCoreApplication.translate MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow")) self.label.setText(_translate("MainWindow", "Радиус, R ")) self.label_2.setText( _translate("MainWindow", "Коэффициент теплопроводности, k")) self.label_3.setText( _translate("MainWindow", "Коэффициент объёмной теплоёмкости, с")) self.label_4.setText( _translate("MainWindow", "Временной промежуток 0 < t < T, t")) self.label_5.setText(_translate("MainWindow", "Параметр сетки по θ, I")) self.label_6.setText(_translate("MainWindow", "Параметр сетки по t, K")) self.label_7.setText(_translate("MainWindow", "Численое решение")) self.label_8.setText(_translate("MainWindow", "Аналитическое решение")) self.pushButton.setText(_translate("MainWindow", "Построить график"))
class PyQtGraphDataPlot(QWidget): _colors = [ Qt.red, Qt.blue, Qt.magenta, Qt.cyan, Qt.green, Qt.darkYellow, Qt.black, Qt.darkRed, Qt.gray, Qt.darkCyan ] def __init__(self, parent=None): super(PyQtGraphDataPlot, self).__init__(parent) self._plot_widget = PlotWidget() self._plot_widget.getPlotItem().addLegend() self._plot_widget.setBackground((255, 255, 255)) self._plot_widget.setXRange(0, 10, padding=0) vbox = QVBoxLayout() vbox.addWidget(self._plot_widget) self.setLayout(vbox) self._autoscroll = False self._color_index = 0 self._curves = {} def add_curve(self, curve_id, curve_name, data_x, data_y): color = QColor(self._colors[self._color_index % len(self._colors)]) self._color_index += 1 pen = mkPen(color, width=2) # this adds the item to the plot and legend plot = self._plot_widget.plot(name=curve_name, pen=pen) data_x = numpy.array(data_x) data_y = numpy.array(data_y) self._curves[curve_id] = {'x': data_x, 'y': data_y, 'plot': plot} def remove_curve(self, curve_id): curve_id = str(curve_id) if curve_id in self._curves: self._plot_widget.getPlotItem().removeItem( self._curves[curve_id]['plot']) del self._curves[curve_id] self._update_legend() def _update_legend(self): # clear and rebuild legend (there is no remove item method for the legend...) self._plot_widget.getPlotItem().clear() self._plot_widget.getPlotItem().legend.items = [] for curve in self._curves.values(): self._plot_widget.getPlotItem().addItem(curve['plot']) @Slot(str, list, list) def update_values(self, curve_id, x, y): curve = self._curves[curve_id] curve['x'] = numpy.append(curve['x'], x) curve['y'] = numpy.append(curve['y'], y) def autoscroll(self, enabled=True): self._autoscroll = enabled def redraw(self): for curve in self._curves.values(): curve['plot'].setData(curve['x'], curve['y']) if self._autoscroll: # Set axis bounds x_range, _ = self._plot_widget.viewRange() x_delta = x_range[1] - x_range[0] x_max = 0 for curve in self._curves.values(): if len(curve['x']) == 0: continue x_max = max(x_max, curve['x'][-1]) self._plot_widget.setXRange(x_max - x_delta, x_max, padding=0)
class Plotter(QWidget): MAX_DATA_POINTS_PER_CURVE = 200000 COLORS = [Qt.red, Qt.green, Qt.blue, # RGB - http://ux.stackexchange.com/questions/79561 Qt.yellow, Qt.cyan, Qt.magenta, # Close to RGB Qt.darkRed, Qt.darkGreen, Qt.darkBlue, # Darker RGB Qt.darkYellow, Qt.darkCyan, Qt.darkMagenta, # Close to RGB Qt.gray, Qt.darkGray] # Leftovers INITIAL_X_RANGE = 60 def __init__(self, parent=None): # Parent super(Plotter, self).__init__(parent) self.setWindowTitle('UAVCAN Plotter') self.setWindowIcon(APP_ICON) # Redraw timer self._update_timer = QTimer() self._update_timer.timeout.connect(self._update) self._update_timer.setSingleShot(False) self._update_timer.start(30) # PyQtGraph self._plot_widget = PlotWidget() self._plot_widget.setBackground((0, 0, 0)) self._legend = self._plot_widget.addLegend() self._plot_widget.setRange(xRange=(0, self.INITIAL_X_RANGE), padding=0) self._plot_widget.showButtons() self._plot_widget.enableAutoRange() self._plot_widget.showGrid(x=True, y=True, alpha=0.4) # Controls # https://specifications.freedesktop.org/icon-naming-spec/icon-naming-spec-latest.html button_add_matcher = QtGui.QPushButton('New matcher', self) button_add_matcher.setIcon(QtGui.QIcon.fromTheme('list-add')) button_add_matcher.setToolTip('Add new curve matcher') button_add_matcher.clicked.connect( lambda: NewCurveMatcherWindow(self, lambda: sorted(self._active_messages), self._add_curve_matcher).show()) button_clear_plots = QtGui.QPushButton('Clear plots', self) button_clear_plots.setIcon(QtGui.QIcon.fromTheme('edit-clear')) button_clear_plots.setToolTip('Clear the plotting area') button_clear_plots.clicked.connect(lambda: self._remove_all_curves()) def delete_all_matchers(): self._curve_matchers = [] for i in reversed(range(self._curve_matcher_container.count())): self._curve_matcher_container.itemAt(i).widget().deleteLater() self._remove_all_curves() button_delete_all_matchers = QtGui.QPushButton('Delete matchers', self) button_delete_all_matchers.setIcon(QtGui.QIcon.fromTheme('edit-delete')) button_delete_all_matchers.setToolTip('Delete all matchers') button_delete_all_matchers.clicked.connect(delete_all_matchers) self._autoscroll = QtGui.QCheckBox('Autoscroll', self) self._autoscroll.setChecked(True) self._max_x = self.INITIAL_X_RANGE # Layout control_panel = QHBoxLayout() control_panel.addWidget(button_add_matcher) control_panel.addWidget(button_clear_plots) control_panel.addWidget(self._autoscroll) control_panel.addStretch() control_panel.addWidget(button_delete_all_matchers) self._curve_matcher_container = QVBoxLayout() layout = QVBoxLayout() layout.addWidget(self._plot_widget, 1) layout.addLayout(control_panel) layout.addLayout(self._curve_matcher_container) self.setLayout(layout) # Logic self._color_index = 0 self._curves = {} self._message_queue = multiprocessing.Queue() self._active_messages = set() # set(data type name) self._curve_matchers = [] # Defaults self._add_curve_matcher(CurveMatcher('uavcan.protocol.debug.KeyValue', 'value', [('key', None)])) def _add_curve_matcher(self, matcher): self._curve_matchers.append(matcher) view = CurveMatcherView(matcher, self) def remove(): self._curve_matchers.remove(matcher) self._curve_matcher_container.removeWidget(view) view.setParent(None) view.deleteLater() view.on_remove = remove self._curve_matcher_container.addWidget(view) def _update(self): # Processing messages while True: try: m = self._message_queue.get_nowait() self._process_message(m) except queue.Empty: break # Updating curves for curve in self._curves.values(): if len(curve['x']): if len(curve['x']) > self.MAX_DATA_POINTS_PER_CURVE: curve['x'] = curve['x'][-self.MAX_DATA_POINTS_PER_CURVE:] curve['y'] = curve['y'][-self.MAX_DATA_POINTS_PER_CURVE:] assert len(curve['x']) == len(curve['y']) curve['plot'].setData(curve['x'], curve['y']) self._max_x = max(self._max_x, curve['x'][-1]) # Updating view range if self._autoscroll.checkState(): (xmin, xmax), _ = self._plot_widget.viewRange() diff = xmax - xmin xmax = self._max_x xmin = self._max_x - diff self._plot_widget.setRange(xRange=(xmin, xmax), padding=0) def _process_message(self, m): self._active_messages.add(m.data_type_name) for matcher in self._curve_matchers: if matcher.match(m): name, x, y = matcher.extract_curve_name_x_y(m) self._draw_curve(name, x, y) def _remove_all_curves(self): for curve in self._curves.values(): self._plot_widget.removeItem(curve['plot']) self._plot_widget.clear() self._curves = {} self._color_index = 0 self._legend.scene().removeItem(self._legend) self._legend = self._plot_widget.addLegend() def _draw_curve(self, name, x, y): if name not in self._curves: logging.info('Adding curve %r', name) color = self.COLORS[self._color_index % len(self.COLORS)] self._color_index += 1 pen = mkPen(QColor(color), width=1) plot = self._plot_widget.plot(name=name, pen=pen) self._curves[name] = {'x': numpy.array([]), 'y': numpy.array([]), 'plot': plot} curve = self._curves[name] curve['x'] = numpy.append(curve['x'], [x] if isinstance(x, (float, int)) else x) curve['y'] = numpy.append(curve['y'], [y] if isinstance(y, (float, int)) else y) assert len(curve['x']) == len(curve['y']) def push_received_message(self, msg): self._message_queue.put_nowait(msg)
class MesCourbes(): def __init__(self): self.plot_widget = PlotWidget() self.plot_widget.showGrid(x=True, y=True) # self.plot_widget.getPlotItem().addLegend() self.plot_widget.setBackground((0, 0, 0)) # dictionary with all the curve and their data # curve 0 is dedicated to the live/acquisition plot self.curves = {} def add_curve(self, curve_id, curve_color, markers_on=False): curve_name = curve_id pen = pg.mkPen(curve_color, width=3) symbol = "o" symbolPen = pg.mkPen(0, 0, 0) symbolBrush = curve_color symbolSize = 8 # this adds the item to the plot and legend if markers_on: plot = self.plot_widget.plot(name=curve_name, pen=pen, symbol=symbol, symbolPen=symbolPen, symbolBrush=symbolBrush, symbolSize=symbolSize) else: plot = self.plot_widget.plot(name=curve_name, pen=pen) self.curves[curve_id] = { 'plot': plot, 'data': { 'X': [], 'Y': [], 'R': [], 'Phi': [] } } def clear_data(self, curve_id): for k in ['Time', 'X', 'Y', 'R', 'Phi']: self.curves[curve_id]['data'][k] = [] # def display(self,curve_id,what): # X = self.curves[curve_id]['data']['Freq'] # Y = self.curves[curve_id]['data'][what] # # during acquisition freq is longer than the others datas # # so it is useful to reduce it # if len(X) != len(Y): # X = self.curves[curve_id]['data']['Freq'][0:len(Y)] # self.set_values(curve_id,X,Y) def remove_curve(self, curve_id): curve_id = str(curve_id) if curve_id in self.curves: self.plot_widget.removeItem(self.curves[curve_id]['plot']) del self.curves[curve_id] def set_values(self, curve_id, data_x, data_y): curve = self.curves[curve_id]['plot'] curve.setData(data_x, data_y) def update_X_Y_R_Phi(self, curve_id, A): self.curves[curve_id]['data']['X'] = np.append( self.curves[curve_id]['data']['X'], A[0]) self.curves[curve_id]['data']['Y'] = np.append( self.curves[curve_id]['data']['Y'], A[1]) self.curves[curve_id]['data']['R'] = np.append( self.curves[curve_id]['data']['R'], A[2]) self.curves[curve_id]['data']['Phi'] = np.append( self.curves[curve_id]['data']['Phi'], A[3])
class Ui_MainWindow(object): def setupUi(self, MainWindow): MainWindow.setObjectName(_fromUtf8("MainWindow")) self.resize(1920, 1080) self.status = False self.setAutoFillBackground(False) self.setDocumentMode(False) self.centralwidget = QtGui.QWidget(MainWindow) self.centralwidget.setObjectName(_fromUtf8("centralwidget")) self.exitAct = QAction(QIcon('exit.png'), '&Exit', self) self.exitAct.setShortcut('Ctrl+Q') self.exitAct.setStatusTip('Exit application') self.exitAct.triggered.connect(qApp.quit) self.loadAct = QAction(QIcon('exit.png'), '&Import Unfolding', self) self.loadAct.setShortcut('Ctrl+L') self.loadAct.setStatusTip('Import Unfolding') self.loadAct.triggered.connect(self.openFileNameDialog) self.exportAct = QAction(QIcon('exit.png'), '&Export Unfolding', self) self.exportAct.setShortcut('Ctrl+E') self.exportAct.setStatusTip('Export Unfolding') self.exportAct.triggered.connect(self.exportUnfolding) self.writeNPAct = QAction(QIcon('exit.png'), '&Write coordinates as np file', self) self.writeNPAct.setShortcut('Ctrl+W') self.writeNPAct.setStatusTip('Write coordinates') self.writeNPAct.triggered.connect(self.writeNP_file) self.loadGeometryAct = QAction(QIcon('exit.png'), '&Load geometry from .log file', self) #self.loadGeometry.setShortcut('Ctrl+W') self.loadGeometryAct.setStatusTip('Load geometry') self.loadGeometryAct.triggered.connect(self.loadGeometry) self.select_directoryAct = QAction( QIcon('exit.png'), '&Select a directory to generate hdf5 files from', self) self.select_directoryAct.setStatusTip('Select directory') self.select_directoryAct.triggered.connect(self.select_directory) self.load_HDF5Act = QAction(QIcon('exit.png'), '&Select a hdf5 files for the DFT data', self) self.load_HDF5Act.setStatusTip('Select HDF5') self.load_HDF5Act.triggered.connect(self.load_hdf5_scan) self.statusBar() self.menubar = self.menuBar() self.fileMenu = self.menubar.addMenu('&File') self.fileMenu.addAction(self.exitAct) self.fileMenu.addAction(self.loadAct) self.fileMenu.addAction(self.exportAct) self.fileMenu.addAction(self.writeNPAct) self.fileMenu.addAction(self.loadGeometryAct) self.fileMenu.addAction(self.select_directoryAct) self.fileMenu.addAction(self.load_HDF5Act) self.horizontalLayout = QHBoxLayout(self.centralwidget) self.horizontalLayout.setSpacing(10) self.verticalLayout = QVBoxLayout() ### Containing the integration buttons self.horizontalLayout_2 = QHBoxLayout() ### Containing the inital/final position show self.finalPositionLayout = QHBoxLayout() self.gl_widget = gl.GLViewWidget() self.gl_widget.setCameraPosition(distance=20, elevation=40) self.gl_widget.setGeometry(0, 110, 1920, 1080) self.energy_Plot = PlotWidget() self.energy_Plot.setObjectName(_fromUtf8("energyPlot")) self.energy_Plot.setBackground('k') # set properties of the label for y axis self.energy_Plot.setLabel('left', 'E(B3LYP)', units='H') # set properties of the label for x axis self.energy_Plot.setLabel('bottom', 'CC-distance', units='A') # adding legend self.energy_Plot.addLegend() self.horizontalLayout.addWidget(self.gl_widget, 4) ### Push button for sinle integration self.btnUp = QPushButton() self.btnUp.setObjectName(_fromUtf8("btnUp")) ### Check box for continous integration self.chkIntegrate = QCheckBox() self.chkIntegrate.setObjectName(_fromUtf8("chkIntegrate")) ### SpinBox to set the size of the integration step self.spinStep = QSpinBox() self.spinStep.setMinimum(0) self.spinStep.setMaximum(10000) self.spinStep.setObjectName(_fromUtf8("spinStep")) ### final position button self.btnFin = QPushButton() self.btnFin.setObjectName(_fromUtf8("btnFin")) ### initial position button self.btnInit = QPushButton() self.btnInit.setObjectName(_fromUtf8("btnPos")) ### select hinges button self.btnSelHinge = QPushButton() self.btnSelHinge.setObjectName(_fromUtf8("btnSelHinge")) ### close unfolding button self.btnClose = QPushButton() self.btnClose.setObjectName(_fromUtf8("btnClose")) ### add the buttons to the integration layout self.horizontalLayout_2.addWidget(self.spinStep) self.horizontalLayout_2.addWidget(self.btnUp) self.horizontalLayout_2.addWidget(self.chkIntegrate) ## add final position button to layout self.finalPositionLayout.addWidget(self.btnInit) self.finalPositionLayout.addWidget(self.btnFin) self.finalPositionLayout.addWidget(self.btnSelHinge) self.finalPositionLayout.addWidget(self.btnClose) ### add integration and final position layout and plot widget to right side layout self.verticalLayout.addLayout(self.horizontalLayout_2, 1) self.verticalLayout.addLayout(self.finalPositionLayout, 1) self.verticalLayout.addWidget(self.energy_Plot, 6) self.horizontalLayout.addLayout(self.verticalLayout, 1) self.widget = QWidget() self.widget.setLayout(self.horizontalLayout) self.setCentralWidget(self.widget) self.retranslateUi(MainWindow) QtCore.QMetaObject.connectSlotsByName(MainWindow) self.setWindowTitle('Fullerene Unfolding') def retranslateUi(self, MainWindow): MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow", None)) self.btnUp.setText("Integrate") self.chkIntegrate.setText("Keep integrating") self.btnFin.setText("Final position") self.btnInit.setText("Initial position") self.btnClose.setText("Close unfolding") self.btnSelHinge.setText("Select Hinges")
class Ui_MainWindow(QDialog): def setupUi(self, MainWindow): MainWindow.setObjectName("MainWindow") MainWindow.resize(926, 645) self.centralwidget = QtWidgets.QWidget(MainWindow) self.centralwidget.setObjectName("centralwidget") self.widget = PlotWidget(self.centralwidget) self.widget.setGeometry(QtCore.QRect(20, 30, 611, 381)) self.widget.setObjectName("widget") self.widget.setBackground('w') self.pushButton = QtWidgets.QPushButton(self.centralwidget) self.pushButton.setGeometry(QtCore.QRect(660, 430, 112, 34)) self.pushButton.setObjectName("pushButton") self.pushButton.clicked.connect(self.browsefiles) #click function self.buttonclear = QtWidgets.QPushButton(self.centralwidget) self.buttonclear.setGeometry(QtCore.QRect(500, 450, 112, 34)) self.buttonclear.setObjectName("clearbutton") self.buttonclear.clicked.connect(self.cleargraph) #click function self.horizontalScrollBar = QtWidgets.QScrollBar(self.centralwidget) self.horizontalScrollBar.setGeometry(QtCore.QRect(10, 430, 621, 20)) self.horizontalScrollBar.setOrientation(QtCore.Qt.Horizontal) self.horizontalScrollBar.setObjectName("horizontalScrollBar") self.verticalScrollBar = QtWidgets.QScrollBar(self.centralwidget) self.verticalScrollBar.setGeometry(QtCore.QRect(640, 40, 20, 381)) self.verticalScrollBar.setOrientation(QtCore.Qt.Vertical) self.verticalScrollBar.setObjectName("verticalScrollBar") self.verticalLayoutWidget = QtWidgets.QWidget(self.centralwidget) self.verticalLayoutWidget.setGeometry(QtCore.QRect(689, 19, 181, 401)) self.verticalLayoutWidget.setObjectName("verticalLayoutWidget") self.verticalLayout = QtWidgets.QVBoxLayout(self.verticalLayoutWidget) self.verticalLayout.setContentsMargins(0, 0, 0, 0) self.verticalLayout.setObjectName("verticalLayout") self.checkBoxTemp = QtWidgets.QCheckBox(self.verticalLayoutWidget) self.checkBoxTemp.setEnabled(True) self.checkBoxTemp.setObjectName("checkBoxTemp") self.checkBoxTemp.stateChanged.connect(self.checked_item) self.verticalLayout.addWidget(self.checkBoxTemp) self.checkBoxPres = QtWidgets.QCheckBox(self.verticalLayoutWidget) self.checkBoxPres.setObjectName("checkBoxPres") self.checkBoxPres.stateChanged.connect(self.checked_item) self.verticalLayout.addWidget(self.checkBoxPres) self.checkBoxPH = QtWidgets.QCheckBox(self.verticalLayoutWidget) self.checkBoxPH.setObjectName("checkBoxPH") self.checkBoxPH.stateChanged.connect(self.checked_item) self.verticalLayout.addWidget(self.checkBoxPH) self.checkBoxDO2 = QtWidgets.QCheckBox(self.verticalLayoutWidget) self.checkBoxDO2.setObjectName("checkBoxDO2") self.checkBoxDO2.stateChanged.connect(self.checked_item) self.verticalLayout.addWidget(self.checkBoxDO2) self.checkBoxAIR = QtWidgets.QCheckBox(self.verticalLayoutWidget) self.checkBoxAIR.setObjectName("checkBoxAIR") self.checkBoxAIR.stateChanged.connect(self.checked_item) self.verticalLayout.addWidget(self.checkBoxAIR) self.checkBoxO2 = QtWidgets.QCheckBox(self.verticalLayoutWidget) self.checkBoxO2.setObjectName("checkBoxO2") self.checkBoxO2.stateChanged.connect(self.checked_item) self.verticalLayout.addWidget(self.checkBoxO2) self.checkBoxCO2 = QtWidgets.QCheckBox(self.verticalLayoutWidget) self.checkBoxCO2.setObjectName("checkBoxCO2") self.checkBoxCO2.stateChanged.connect(self.checked_item) self.verticalLayout.addWidget(self.checkBoxCO2) MainWindow.setCentralWidget(self.centralwidget) self.menubar = QtWidgets.QMenuBar(MainWindow) self.menubar.setGeometry(QtCore.QRect(0, 0, 926, 31)) self.menubar.setObjectName("menubar") self.menuCharts = QtWidgets.QMenu(self.menubar) self.menuCharts.setObjectName("menuCharts") MainWindow.setMenuBar(self.menubar) self.statusbar = QtWidgets.QStatusBar(MainWindow) self.statusbar.setObjectName("statusbar") MainWindow.setStatusBar(self.statusbar) self.menubar.addAction(self.menuCharts.menuAction()) self.retranslateUi(MainWindow) QtCore.QMetaObject.connectSlotsByName(MainWindow) def retranslateUi(self, MainWindow): _translate = QtCore.QCoreApplication.translate MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow")) self.pushButton.setText(_translate("MainWindow", "Export")) self.buttonclear.setText(_translate("MainWindow", "Clear")) self.checkBoxTemp.setText(_translate("MainWindow", "Temperature - Red")) self.checkBoxPres.setText(_translate("MainWindow", "Pressure - Orange")) self.checkBoxPH.setText(_translate("MainWindow", "pH - Yellow")) self.checkBoxDO2.setText(_translate("MainWindow", "dO2 - Green")) self.checkBoxAIR.setText(_translate("MainWindow", "Airflow - Blue")) self.checkBoxO2.setText(_translate("MainWindow", "O2 Flow - Purple")) self.checkBoxCO2.setText(_translate("MainWindow", "CO2 Flow - Pink")) self.menuCharts.setTitle(_translate("MainWindow", "Charts")) def browsefiles(self): fname = QFileDialog.getSaveFileName(self, 'Open File', 'D:\Documents') def cleargraph(self): if self.checkBoxTemp.isChecked(): self.checkBoxTemp.setCheckState(0) self.widget.clear() if self.checkBoxPres.isChecked(): self.checkBoxPres.setCheckState(0) self.widget.clear() if self.checkBoxPH.isChecked(): self.checkBoxPH.setCheckState(0) self.widget.clear() if self.checkBoxDO2.isChecked(): self.checkBoxDO2.setCheckState(0) self.widget.clear() if self.checkBoxAIR.isChecked(): self.checkBoxAIR.setCheckState(0) self.widget.clear() if self.checkBoxO2.isChecked(): self.checkBoxO2.setCheckState(0) self.widget.clear() if self.checkBoxCO2.isChecked(): self.checkBoxCO2.setCheckState(0) self.widget.clear() def checked_item(self): if self.checkBoxTemp.isChecked(): x = [1, 2, 3] y = [2, 3, 4] pen = pg.mkPen(color=(255, 0, 0), width=3) self.widget.plot(x, y, pen=pen) if self.checkBoxPres.isChecked(): x = [2, 3, 4] y = [2, 3, 4] pen = pg.mkPen(color=(255, 155, 55), width=3) self.widget.plot(x, y, pen=pen) if self.checkBoxPH.isChecked(): x = [3, 4, 5] y = [2, 3, 4] pen = pg.mkPen(color=(255, 255, 0), width=3) self.widget.plot(x, y, pen=pen) if self.checkBoxDO2.isChecked(): x = [4, 5, 6] y = [2, 3, 4] pen = pg.mkPen(color=(100, 200, 50), width=3) self.widget.plot(x, y, pen=pen) if self.checkBoxAIR.isChecked(): x = [5, 6, 7] y = [2, 3, 4] pen = pg.mkPen(color=(0, 0, 255), width=3) self.widget.plot(x, y, pen=pen) if self.checkBoxO2.isChecked(): x = [6, 7, 8] y = [2, 3, 4] pen = pg.mkPen(color=(200, 0, 255), width=3) self.widget.plot(x, y, pen=pen) if self.checkBoxCO2.isChecked(): x = [7, 8, 9] y = [2, 3, 4] pen = pg.mkPen(color=(248, 24, 148), width=3) self.widget.plot(x, y, pen=pen)
class Window(QWidget): def __init__(self, *args, **kwargs): super(Window, self).__init__(*args, **kwargs) self.title = "Motor Control" self.setWindowTitle(self.title) #Application Size self.left = 100 self.top = 100 self.width = 1000 self.height = 700 self.setGeometry(self.left, self.top, self.width, self.height) self.initUI() def initUI(self): self.setStyleSheet(qdarkstyle.load_stylesheet()) self.horizontalLayout = QHBoxLayout() self.verticalLayout = QVBoxLayout() self.verticalLayout.setSizeConstraint(QLayout.SetDefaultConstraint) self.verticalLayout.setSpacing(6) self.gridLayout = QGridLayout() self.imageLabel = QLabel() sizePolicy = QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth( self.imageLabel.sizePolicy().hasHeightForWidth()) self.imageLabel.setSizePolicy(sizePolicy) self.imageLabel.setMinimumSize(QSize(200, 130)) self.imageLabel.setMaximumSize(QSize(200, 130)) self.imageLabel.setPixmap( QPixmap("./Arduino/logo/CUAtHomeLogo-Horz.png").scaled( 200, 130, Qt.KeepAspectRatio, Qt.FastTransformation)) self.verticalLayout.addWidget(self.imageLabel) self.startbutton = QPushButton("Start", self) self.startbutton.setCheckable(False) self.startbutton.clicked.connect(self.startbutton_pushed) self.startbutton.setMaximumSize(QSize(100, 20)) self.gridLayout.addWidget(self.startbutton, 0, 0, 1, 1) self.stopbutton = QPushButton("Stop", self) self.stopbutton.setCheckable(False) self.stopbutton.clicked.connect(self.stopbutton_pushed) sizePolicy = QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth( self.stopbutton.sizePolicy().hasHeightForWidth()) self.stopbutton.setSizePolicy(sizePolicy) self.stopbutton.setMaximumSize(QSize(100, 20)) self.gridLayout.addWidget(self.stopbutton, 0, 1, 1, 1) self.clearbutton = QPushButton("Clear", self) self.clearbutton.setCheckable(False) self.clearbutton.clicked.connect(self.clearbutton_pushed) self.clearbutton.setMaximumSize(QSize(100, 20)) self.gridLayout.addWidget(self.clearbutton, 1, 0, 1, 1) self.savebutton = QPushButton("Save", self) self.savebutton.setCheckable(False) self.savebutton.clicked.connect(self.savebutton_pushed) sizePolicy = QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth( self.savebutton.sizePolicy().hasHeightForWidth()) self.savebutton.setSizePolicy(sizePolicy) self.savebutton.setMaximumSize(QSize(100, 20)) self.gridLayout.addWidget(self.savebutton, 1, 1, 1, 1) self.settings = QPushButton("Settings", self) self.settings.clicked.connect(self.settingsMenu) self.settings.setMaximumSize(QSize(300, 20)) self.gridLayout.addWidget(self.settings, 2, 0, 1, 2) self.checkBoxShowAll = QCheckBox("Show All Plots", self) self.checkBoxShowAll.setMaximumSize(QSize(100, 20)) self.checkBoxShowAll.setChecked(True) self.checkBoxShowAll.toggled.connect(self.visibilityAll) self.gridLayout.addWidget(self.checkBoxShowAll, 3, 0, 1, 1) self.checkBoxHideAll = QCheckBox("Hide All Plots", self) self.checkBoxHideAll.setChecked(False) self.checkBoxHideAll.toggled.connect(self.hideAll) sizePolicy = QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth( self.checkBoxHideAll.sizePolicy().hasHeightForWidth()) self.checkBoxHideAll.setSizePolicy(sizePolicy) self.checkBoxHideAll.setMaximumSize(QSize(100, 20)) self.gridLayout.addWidget(self.checkBoxHideAll, 3, 1, 1, 1) self.checkBoxPlot1 = QCheckBox("Plot 1", self) self.checkBoxPlot1.toggled.connect(self.visibility1) self.checkBoxPlot1.setMaximumSize(QSize(100, 20)) self.gridLayout.addWidget(self.checkBoxPlot1, 4, 0, 1, 1) self.checkBoxPlot2 = QCheckBox("Plot 2", self) self.checkBoxPlot2.toggled.connect(self.visibility2) sizePolicy = QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth( self.checkBoxPlot2.sizePolicy().hasHeightForWidth()) self.checkBoxPlot2.setSizePolicy(sizePolicy) self.checkBoxPlot2.setMaximumSize(QSize(100, 20)) self.gridLayout.addWidget(self.checkBoxPlot2, 4, 1, 1, 1) self.checkBoxShowAll.stateChanged.connect(self.checkbox_logic) self.checkBoxHideAll.stateChanged.connect(self.checkbox_logic) self.checkBoxPlot1.stateChanged.connect(self.checkbox_logic) self.checkBoxPlot2.stateChanged.connect(self.checkbox_logic) self.PowerScalingLabel = QLabel("Power Scaling (%)", self) self.PowerScalingLabel.setMinimumSize(QSize(100, 20)) self.PowerScalingLabel.setMaximumSize(QSize(100, 20)) self.gridLayout.addWidget(self.PowerScalingLabel, 7, 0, 1, 1) self.PowerScalingInput = QLineEdit("", self) sizePolicy = QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth( self.PowerScalingInput.sizePolicy().hasHeightForWidth()) self.PowerScalingInput.setSizePolicy(sizePolicy) self.PowerScalingInput.setMaximumSize(QSize(100, 20)) #self.PowerScalingInput.setValidator(QRegExpValidator(QRegExp("^[0-9][0-9]?$|^100$"))) #0-1 as a float FIX THIS self.gridLayout.addWidget(self.PowerScalingInput, 7, 1, 1, 1) self.FrequencyLabel = QLabel("Frequency (Hz)", self) self.FrequencyLabel.setMinimumSize(QSize(100, 20)) self.FrequencyLabel.setMaximumSize(QSize(100, 20)) self.gridLayout.addWidget(self.FrequencyLabel, 8, 0, 1, 1) self.FrequencyInput = QLineEdit("", self) sizePolicy = QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth( self.FrequencyInput.sizePolicy().hasHeightForWidth()) self.FrequencyInput.setSizePolicy(sizePolicy) self.FrequencyInput.setMaximumSize(QSize(100, 20)) self.FrequencyInput.setValidator(QDoubleValidator()) self.gridLayout.addWidget(self.FrequencyInput, 8, 1, 1, 1) PID_validator = QDoubleValidator( 0.0000, 50.000, 4, notation=QDoubleValidator.StandardNotation) self.PCheckBox = QCheckBox("P", self) self.PCheckBox.setMaximumSize(QSize(100, 20)) self.PCheckBox.setChecked(True) self.PCheckBox.toggled.connect(self.PCheckBoxLogic) self.gridLayout.addWidget(self.PCheckBox, 9, 0, 1, 1) self.PInput = QLineEdit("", self) sizePolicy = QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth( self.PInput.sizePolicy().hasHeightForWidth()) self.PInput.setSizePolicy(sizePolicy) self.PInput.setMaximumSize(QSize(100, 20)) self.PInput.setValidator(PID_validator) self.gridLayout.addWidget(self.PInput, 9, 1, 1, 1) self.ICheckBox = QCheckBox("I", self) self.ICheckBox.setMaximumSize(QSize(100, 20)) self.ICheckBox.setChecked(True) self.ICheckBox.toggled.connect(self.ICheckBoxLogic) self.gridLayout.addWidget(self.ICheckBox, 10, 0, 1, 1) self.IInput = QLineEdit("", self) sizePolicy = QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth( self.IInput.sizePolicy().hasHeightForWidth()) self.IInput.setSizePolicy(sizePolicy) self.IInput.setMaximumSize(QSize(100, 20)) self.IInput.setValidator(PID_validator) self.gridLayout.addWidget(self.IInput, 10, 1, 1, 1) self.DCheckBox = QCheckBox("D", self) self.DCheckBox.setMaximumSize(QSize(100, 20)) self.DCheckBox.setChecked(True) self.DCheckBox.toggled.connect(self.DCheckBoxLogic) self.gridLayout.addWidget(self.DCheckBox, 11, 0, 1, 1) self.DInput = QLineEdit("", self) sizePolicy = QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth( self.DInput.sizePolicy().hasHeightForWidth()) self.DInput.setSizePolicy(sizePolicy) self.DInput.setMaximumSize(QSize(100, 20)) self.DInput.setValidator(PID_validator) self.gridLayout.addWidget(self.DInput, 11, 1, 1, 1) self.LabType = QComboBox() self.LabType.addItems(["Position", "Speed"]) #self.LabType.activated.connect(self.getLabType) sizePolicy = QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth( self.LabType.sizePolicy().hasHeightForWidth()) self.LabType.setSizePolicy(sizePolicy) self.LabType.setMaximumSize(QSize(100, 20)) self.gridLayout.addWidget(self.LabType, 5, 1, 1, 1) self.LabLabel = QLabel("Lab Type") self.LabLabel.setMaximumSize(QSize(100, 20)) self.gridLayout.addWidget(self.LabLabel, 5, 0, 1, 1) self.inputForms = QComboBox() self.inputForms.addItems(["Sine", "Step"]) self.inputForms.activated.connect(self.getInput) sizePolicy = QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth( self.inputForms.sizePolicy().hasHeightForWidth()) self.inputForms.setSizePolicy(sizePolicy) self.inputForms.setMaximumSize(QSize(100, 20)) self.gridLayout.addWidget(self.inputForms, 6, 1, 1, 1) self.inputType = QLabel("Input Type") self.inputType.setMaximumSize(QSize(100, 20)) self.gridLayout.addWidget(self.inputType, 6, 0, 1, 1) self.verticalLayout.addLayout(self.gridLayout) spacerItem = QSpacerItem(20, 80, QSizePolicy.Minimum, QSizePolicy.Fixed) self.verticalLayout.addItem(spacerItem) #What is this? self.label = QLabel() self.label.setMaximumSize(QSize(200, 130)) self.label.setText("") self.verticalLayout.addWidget(self.label) self.horizontalLayout.addLayout(self.verticalLayout) self.rightVerticalLayout = QVBoxLayout() self.graphWidgetOutput = PlotWidget() self.graphWidgetInput = PlotWidget() #Adds grid lines self.graphWidgetOutput.showGrid(x=True, y=True, alpha=None) self.graphWidgetInput.showGrid(x=True, y=True, alpha=None) #self.graphWidget.setXRange(0, 100, padding=0) #Doesn't move with the plot. Can drag around #self.graphWidget.setLimits(xMin=0, xMax=100)#, yMin=c, yMax=d) #Doesn't move with the plot. Cannot drag around #self.graphWidget.setYRange(0, 4, padding=0) self.graphWidgetOutput.setYRange(-11, 11, padding=0) self.graphWidgetOutput.enableAutoRange() self.graphWidgetInput.setYRange(-11, 11, padding=0) self.graphWidgetInput.enableAutoRange() #Changes background color of graph self.graphWidgetOutput.setBackground((0, 0, 0)) self.graphWidgetInput.setBackground((0, 0, 0)) #Adds a legend after data starts to plot NOT before self.graphWidgetOutput.addLegend() #Adds title to graphs self.graphWidgetOutput.setTitle("Response", color="w", size="12pt") self.graphWidgetInput.setTitle("PWM Actuation Signal", color="w", size="12pt") self.rightVerticalLayout.addWidget(self.graphWidgetOutput) self.rightVerticalLayout.addWidget(self.graphWidgetInput) self.horizontalLayout.addLayout(self.rightVerticalLayout) self.setLayout(self.horizontalLayout) #Plot time update settings self.timer = QTimer() self.timer.setInterval( 50 ) #Changes the plot speed. Defaulted to 50. Can be placed in startbutton_pushed() method self.initialState() time.sleep(2) try: self.timer.timeout.connect(self.update) except: raise Exception("Not Connected") #self.show() #Checkbox logic def checkbox_logic(self, state): # checking if state is checked if state == Qt.Checked: if self.sender() == self.checkBoxShowAll: self.checkBoxHideAll.setChecked(False) self.checkBoxPlot1.setChecked(False) self.checkBoxPlot2.setChecked(False) #self.checkBoxShow.stateChanged.disconnect(self.uncheck) elif self.sender() == self.checkBoxHideAll: #self.checkBoxShow.stateChanged.connect(self.uncheck) self.checkBoxShowAll.setChecked(False) self.checkBoxPlot1.setChecked(False) self.checkBoxPlot2.setChecked(False) elif self.sender() == self.checkBoxPlot1: self.checkBoxShowAll.setChecked(False) self.checkBoxHideAll.setChecked(False) self.checkBoxPlot2.setChecked(False) elif self.sender() == self.checkBoxPlot2: self.checkBoxShowAll.setChecked(False) self.checkBoxHideAll.setChecked(False) self.checkBoxPlot1.setChecked(False) #Resets data arrays and establishes serial communcation. Disables itself after clicking def startbutton_pushed(self): self.initialState( ) #Reinitializes arrays in case you have to retake data self.size = self.serial_values[3] #Value from settings. Windows data #self.buffersize = self.serial_values[4] #Value from settings. Restricts buffer data ''' self.ser = serial.Serial(port = self.serial_values[0], baudrate = self.serial_values[1], timeout = self.serial_values[2]) self.ser.flushInput() self.ser.write(b'A') time.sleep(2) print("Recording Data") self.timer.start() #self.timer.setInterval(50) self.curve() self.startbutton.clicked.disconnect(self.startbutton_pushed) ''' self.serialInstance = SerialComm(self.serial_values[0], self.serial_values[1], self.serial_values[2]) self.serialInstance.serialOpen() time.sleep(2) print("Recording Data") self.timer.start() self.curve() self.startbutton.clicked.disconnect(self.startbutton_pushed) #Stops timer and ends serial communication def stopbutton_pushed(self): self.timer.stop() #self.ser.close() self.serialInstance.serialClose() ''' print("y1 zeros:", self.y1_zeros) print("y2 zeros:", self.y2_zeros) print("y1 full:", self.y1) print("y2 full:", self.y2) ''' #Resets both plotting windows and reenables Start Button def clearbutton_pushed(self): self.graphWidgetOutput.clear() self.graphWidgetInput.clear() self.graphWidgetOutput.enableAutoRange(axis=None, enable=True, x=None, y=None) self.startbutton.clicked.connect(self.startbutton_pushed) #Dumps data into a csv file to a selected path def savebutton_pushed(self): self.createCSV() path = QFileDialog.getSaveFileName(self, 'Save CSV', os.getenv('HOME'), 'CSV(*.csv)') if path[0] != '': with open(path[0], 'w', newline='') as csvfile: csvwriter = csv.writer(csvfile) csvwriter.writerow(self.header) csvwriter.writerows(self.data_set) #Creates csv data def createCSV(self): self.header = ['time', 'y1', 'y2'] self.data_set = zip(self.time, self.y1, self.y2) #Initilizes lists/arrays def initialState(self): self.buffersize = 500 #np array size that is used to plot data self.step = 0 #Used for repositioning data in plot window to the left #Data buffers. What is being plotted in the 2 windows self.time_zeros = np.zeros(self.buffersize + 1, float) self.y1_zeros = np.zeros(self.buffersize + 1, float) self.y2_zeros = np.zeros(self.buffersize + 1, float) self.y3_zeros = np.zeros(self.buffersize + 1, float) #Complete data. What will be written to the csv file self.time = list() self.y1 = list() self.y2 = list() self.y3 = list() self.getLabType() ''' def readValues(self): arduinoData = self.ser.readline().decode().replace('\r\n','').split(",") return arduinoData ''' #Initializes data# to have specific attributes def curve(self): pen1 = pg.mkPen(color=(255, 0, 0), width=1) pen2 = pg.mkPen(color=(0, 255, 0), width=1) pen3 = pg.mkPen(color=(0, 0, 255), width=1) self.data1 = self.graphWidgetOutput.plot(pen=pen1, name="Data 1") #Response self.data2 = self.graphWidgetOutput.plot(pen=pen2, name="Data 2") #Setpoint self.data3 = self.graphWidgetInput.plot( pen=pen3, name="Data 3") #PWM Actuation Signal #Connected to timer to update plot. Incoming data is in the form of timestamp,data1,data2... def update(self): #fulldata = self.readValues() #print(fulldata) fulldata = self.serialInstance.readValues() self.step = self.step + 1 time_index = int(self.time_zeros[self.buffersize]) self.time_zeros[time_index] = self.time_zeros[time_index + self.size] = float( fulldata[0]) self.time_zeros[self.buffersize] = time_index = (time_index + 1) % self.size self.time.append(fulldata[0]) i = int(self.y1_zeros[self.buffersize]) self.y1_zeros[i] = self.y1_zeros[i + self.size] = float(fulldata[1]) self.y1_zeros[self.buffersize] = i = (i + 1) % self.size self.y1.append(fulldata[1]) j = int(self.y2_zeros[self.buffersize]) self.y2_zeros[j] = self.y2_zeros[j + self.size] = float(fulldata[2]) self.y2_zeros[self.buffersize] = j = (j + 1) % self.size self.y2.append(fulldata[2]) k = int(self.y3_zeros[self.buffersize]) self.y3_zeros[k] = self.y3_zeros[k + self.size] = float(fulldata[3]) self.y3_zeros[self.buffersize] = k = (k + 1) % self.size self.y3.append(fulldata[3]) self.data1.setData(self.time_zeros[time_index:time_index + self.size], self.y1_zeros[i:i + self.size]) self.data1.setPos(self.step, 0) self.data2.setData(self.time_zeros[time_index:time_index + self.size], self.y2_zeros[j:j + self.size]) self.data2.setPos(self.step, 0) self.data3.setData(self.time_zeros[time_index:time_index + self.size], self.y3_zeros[k:k + self.size]) self.data3.setPos(self.step, 0) #Below 4 change visibility of data# in the curves() method def visibilityAll(self): showall = self.sender() if showall.isChecked() == True: self.data1.setVisible(True) self.data2.setVisible(True) def hideAll(self): disappearall = self.sender() if disappearall.isChecked() == True: self.data1.setVisible(False) self.data2.setVisible(False) def visibility1(self): test1 = self.sender() if test1.isChecked() == True: self.data1.setVisible(True) self.data2.setVisible(False) def visibility2(self): test2 = self.sender() if test2.isChecked() == True: self.data2.setVisible(True) self.data1.setVisible(False) #Class instance of settings menu. Creates a dialog (popup) def settingsMenu(self): self.settingsPopUp = Dialog1() self.settingsPopUp.show() #self.settingsPopUp.exec() self.serial_values = self.settingsPopUp.getDialogValues() def PCheckBoxLogic(self): test1 = self.sender() if test1.isChecked() == True: self.PInput.setEnabled(True) elif test1.isChecked() == False: self.PInput.setEnabled(False) def ICheckBoxLogic(self): test1 = self.sender() if test1.isChecked() == True: self.IInput.setEnabled(True) elif test1.isChecked() == False: self.IInput.setEnabled(False) def DCheckBoxLogic(self): test1 = self.sender() if test1.isChecked() == True: self.DInput.setEnabled(True) elif test1.isChecked() == False: self.DInput.setEnabled(False) def PIDInput(self): if self.PInput.text() == "" or self.PCheckBox.checkState() == False: self.Pvalue = 0 else: self.Pvalue = self.PInput.text() if self.IInput.text() == "" or self.ICheckBox.checkState() == False: self.Ivalue = 0 else: self.Ivalue = self.IInput.text() if self.DInput.text() == "" or self.DCheckBox.checkState() == False: self.Dvalue = 0 else: self.Dvalue = self.DInput.text() return ([self.Pvalue, self.Ivalue, self.Dvalue]) #Function that connects output pyqtgraph widget, and the combobox def getInput(self): self.inputType = str(self.inputForms.currentText()) pen_input = pg.mkPen(color=(255, 0, 0), width=1) if self.inputType == "Sine": print("Sine") self.graphWidgetInput.clear() self.x_input = np.arange(0, 10, 0.1) self.y_input = np.sin(self.x_input) self.data_input = self.graphWidgetInput.plot(self.x_input, self.y_input, pen=pen_input) self.data_input.setData(self.x_input, self.y_input) self.graphWidgetInput.setYRange(-2, 2, padding=0) elif self.inputType == "Step": print("Step") self.graphWidgetInput.clear() self.x_input = np.arange(0, 10, 0.1) self.y_input = np.heaviside(self.x_input, 1) self.data_input = self.graphWidgetInput.plot(self.x_input, self.y_input, pen=pen_input) self.data_input.setData(self.x_input, self.y_input) self.graphWidgetInput.setYRange(-2, 2, padding=0) def getLabType(self): self.inputType = str(self.LabType.currentText()) if self.inputType == "Position": print("Lab: Position") return ( self.graphWidgetOutput.setLabel( 'left', "<span style=\"color:white;font-size:16px\">θ (°)</span>" ), self.graphWidgetInput.setLabel( 'left', "<span style=\"color:white;font-size:16px\">Voltage</span>" ), self.graphWidgetOutput.setLabel( 'bottom', "<span style=\"color:white;font-size:16px\">Time (s)</span>" ), self.graphWidgetInput.setLabel( 'bottom', "<span style=\"color:white;font-size:16px\">Time (s)</span>" )) elif self.inputType == "Speed": print("Lab: Speed") return ( self.graphWidgetOutput.setLabel( 'left', "<span style=\"color:white;font-size:16px\">ω (°/s)</span>" ), self.graphWidgetInput.setLabel( 'left', "<span style=\"color:white;font-size:16px\">Voltage</span>" ), self.graphWidgetOutput.setLabel( 'bottom', "<span style=\"color:white;font-size:16px\">Time (s)</span>" ), self.graphWidgetInput.setLabel( 'bottom', "<span style=\"color:white;font-size:16px\">Time (s)</span>" ), )
class widget_mfi_lin_plot(QWidget): #----------------------------------------------------------------------- # DEFINE THE INITIALIZATION FUNCTION. #----------------------------------------------------------------------- def __init__(self, core): # Inherit all attributes of an instance of "QWidget". super(widget_mfi_lin_plot, self).__init__() # Store the Janus core. self.core = core # Prepare to respond to signals received from the core. self.connect(self.core, SIGNAL('janus_rset'), self.resp_rset) self.connect(self.core, SIGNAL('janus_chng_mfi'), self.resp_chng_mfi) # Initialize this widget's instance of "PlotWidget", which will # contain the plot of MFI magnetic field data. # Note. The "QGridLayout" object given to this widget as its # layout is essentially a dummy. I could have just had # this class inherit "PlotWidget", but I think that this # gives me a bit more control (and a similar structure # "janus_widget_fc_cup"). self.setLayout(QGridLayout()) self.plt = PlotWidget() self.layout().addWidget(self.plt) self.layout().setContentsMargins(0, 0, 0, 0) # Extract the individual elements of the "PlotWidget" object # (e.g., it's axes) for more convenient access later. self.vbx = self.plt.getViewBox() self.axs_x = self.plt.getAxis('bottom') self.axs_y = self.plt.getAxis('left') self.ptm = self.plt.getPlotItem() # Initialize and store the pens and fonts. self.pen_vbx = mkPen(color='k') self.pen_crv_m = mkPen(color='k') self.pen_crv_n = mkPen(color='k') self.pen_crv_x = mkPen(color='r') self.pen_crv_y = mkPen(color='g') self.pen_crv_z = mkPen(color='b') self.fnt = self.core.app.font() # Configure the plot: disable automatic adjustments and # adjustments made by the user, change the background and # foreground colors, enable grid lines for both axes, label the # axes, adjust the tick font size, adjust the "AxisItem" sizes, # and add a margin around the entire plot. self.plt.disableAutoRange() self.plt.setMouseEnabled(False, False) self.plt.setMenuEnabled(False) self.plt.hideButtons() self.plt.setBackground('w') setConfigOption('foreground', 'k') #####self.plt.showGrid( True, True ) labelStyle = {'color': 'k'} self.axs_x.setLabel('Time [s]', **labelStyle) self.axs_y.setLabel('Magnetic Field [nT]', **labelStyle) self.axs_x.label.setFont(self.fnt) self.axs_y.label.setFont(self.fnt) self.axs_x.setTickFont(self.fnt) self.axs_y.setTickFont(self.fnt) self.axs_x.setHeight(35) self.axs_y.setWidth(40) self.vbx.border = self.pen_vbx self.ptm.setContentsMargins(5, 5, 5, 5) # Initialize the curves that will be added to this plot. self.crv_m = None self.crv_n = None self.crv_x = None self.crv_y = None self.crv_z = None self.pl = [] # Populate this plot and adjust it's settings. self.make_plt() #----------------------------------------------------------------------- # DEFINE THE FUNCTION FOR POPULATING THE PLOT. #----------------------------------------------------------------------- def make_plt(self): # Reset the plot (i.e., remove all plot elements). self.rset_plt() # Establish the ranges of its time and magnetic field values. # If the core contains no data or only a single datum, # improvise (for the purpose of later establishing axis limits). if (self.core.n_mfi >= 1): # Establish the domain of the plot. t_min = min(amin(self.core.mfi_s), 0.) t_max = max(amax(self.core.mfi_s), self.core.fc_spec['dur']) # Establish the range of the plot. As part of this, # ensure that the range satisfies a minimum size and has # sufficient padding. b_max = amax(self.core.mfi_b) b_min = -b_max d_t_0 = t_max - t_min d_b_0 = b_max - b_min d_t = max(1.5 + d_t_0, 3.) d_b = max(1.2 * d_b_0, 5.) t_max = t_min + d_t b_min = b_min - (d_b - d_b_0) / 2. b_max = b_max + (d_b - d_b_0) / 2. else: t_min = 0.001 t_max = 3.500 b_min = -2.5 b_max = 2.5 # Set the range of the axis of each plot. self.plt.setXRange(t_min, t_max, padding=0.0) self.plt.setYRange(b_min, b_max, padding=0.0) # Set the PESA-L pen with a width corresponding to one rotation # Note: For some reason, the lines are not wide enough unless 5 # is added to the scaled width of the rotation time rot = 3.05 * self.axs_x.width() / (t_max - t_min) + 5 self.pen_pl = mkPen(color=(245, 245, 245), width=rot) # If the core contains no Wind/MFI magnetic field data, return. if (self.core.n_mfi <= 0): return # Generate and display each curve for the plot. self.crv_m = PlotDataItem(self.core.mfi_s, self.core.mfi_b, pen=self.pen_crv_m) self.crv_n = PlotDataItem(self.core.mfi_s, [-b for b in self.core.mfi_b], pen=self.pen_crv_n) self.crv_x = PlotDataItem(self.core.mfi_s, self.core.mfi_b_x, pen=self.pen_crv_x) self.crv_y = PlotDataItem(self.core.mfi_s, self.core.mfi_b_y, pen=self.pen_crv_y) self.crv_z = PlotDataItem(self.core.mfi_s, self.core.mfi_b_z, pen=self.pen_crv_z) # If PESA-L spectra were loaded, add the vertical indicators # showing their time relative to the start of the FC spectrum for n in range(len(self.core.pl_spec_arr)): time = self.core.pl_spec_arr[n]['time'][0] t_0 = self.core.fc_spec['time'] delta_t = (time - t_0).total_seconds() self.pl += [ InfiniteLine(delta_t + self.core.fc_spec['rot'] / 2., pen=self.pen_pl) ] for i in range(len(self.pl)): self.plt.addItem(self.pl[i]) self.plt.addItem(self.crv_m) self.plt.addItem(self.crv_n) self.plt.addItem(self.crv_x) self.plt.addItem(self.crv_y) self.plt.addItem(self.crv_z) #----------------------------------------------------------------------- # DEFINE THE FUNCTION FOR RESETTING THIS PLOT (CLEARING ALL ELEMENTS). #----------------------------------------------------------------------- def rset_plt(self): # Hide and remove each of this plot's elements. if (self.crv_m is not None): self.plt.removeItem(self.crv_m) if (self.crv_n is not None): self.plt.removeItem(self.crv_n) if (self.crv_x is not None): self.plt.removeItem(self.crv_x) if (self.crv_y is not None): self.plt.removeItem(self.crv_y) if (self.crv_z is not None): self.plt.removeItem(self.crv_z) if (self.pl != []): for i in range(len(self.pl)): self.plt.removeItem(self.pl[i]) # if ( self.crv_colat is not None ) : # self.plt.removeItem( self.crv_colat ) # if ( self.crv_lon is not None ) : # self.plt.removeItem( self.crv_lon ) # Permanently delete this plot's elements by setting each of the # variables that store them to "None". self.crv_m = None self.crv_n = None self.crv_x = None self.crv_y = None self.crv_z = None self.pl = [] #----------------------------------------------------------------------- # DEFINE THE FUNCTION FOR RESPONDING TO THE "rset" SIGNAL. #----------------------------------------------------------------------- def resp_rset(self): # Reset the plot. self.rset_plt() #----------------------------------------------------------------------- # DEFINE THE FUNCTION FOR RESPONDING TO THE "chng_mfi" SIGNAL. #----------------------------------------------------------------------- def resp_chng_mfi(self): # Regenerate the plot. self.make_plt()
class DirectDriveWindow(QWidget): virtual_controller = None # will hold an instance of the VirtualController-class motor_controller = None # will hold an instance of the MotorController-class game_interfacer = None # will hold an instance of the GameInterfacer-class # Variables that will be shared between multiple processes raw_force_signal_global = Value( 'f', 0.0) # raw force-feedback value coming from the game game_status_playing_global = Value( 'b', False) # game status (playing/not-playing) motor_pause_mode = Value( 'b', False) # if the motor should be idle when game is paused data_reconstruction = Value( 'b', False) # if the data-reconstruction feature should be used data_smoothing_level = Value( 'i', 0) # if the temproal smoothing feature should be used friction_global = Value('f', 0.0) # strength of the friction effect damping_global = Value('f', 0.0) # strength of the damping effect inertia_global = Value('f', 0.0) # strength of the inertia effect encoder_pos_global = Value( 'f', 0.0) # holds the wheel position in encoder counts wheel_position_deg_global = Value( 'f', 0.0) # holds the wheel position in degrees lock_to_lock_global = Value( 'f', 900.0 ) # holds the digital limit of the wheel (used by the virtual controller) bump_to_bump_global = Value( 'f', 900.0 ) # holds the physical limit of the wheel (used by the motor controller) motor_current_global = Value( 'f', 0.0 ) # holds the current(Ampere) that is applied to the motor at any moment actual_max_force_global = Value( 'f', 0.0 ) # sets the actual maximum torque(Nm) the motor should be limited to invert_force_global = Value( 'b', False) # if the raw force-feedback value should be inverted motor_connected_global = Value( 'b', False) # motor status (connected/not-connected) motor_controller_due_for_restart_global = Value( 'b', False) # is set to true when connection to odrive board is lost motor_control_rate = Value( 'f', 0.0) # target refresh rate for the motor-control process profiles = [] # holds all loaded and newly created profiles selected_profile_index = 0 # holds the index of the currently selected profile graph_sample_rate = 60 # update-rate(Hz) for the motor-current graph graph_history_time_sec = 2 # time-window of the motor-current graph def __init__(self): super().__init__() self.setGeometry(100, 100, 1700, 575) self.setWindowTitle('DIY Direct Drive Wheel') #self.updater = LiveGuiUpdater() #self.updater.ticked.connect(self.LiveGuiTick) #self.updater.start() self.timer = QTimer() self.timer.timeout.connect(self.graph_update) self.timer.setInterval(int(1000 / self.graph_sample_rate)) self.timer.start() self.gui_timer = QTimer() self.gui_timer.timeout.connect(self.LiveGuiTick) self.gui_timer.setInterval(int(1000 / 60)) self.gui_timer.start() self.virtual_controller = VirtualController() self.virtual_controller.set_frequency(180) self.virtual_controller.steering_value_deg = self.wheel_position_deg_global self.virtual_controller.lock_to_lock = self.lock_to_lock_global self.virtual_controller.start() self.game_interfacer = GameInterfacer() self.game_interfacer.set_frequency(180) self.game_interfacer.wheel_force = self.raw_force_signal_global self.game_interfacer.invert_force = self.invert_force_global self.game_interfacer.game_status_playing = self.game_status_playing_global self.motor_controller = MotorController() self.motor_controller.set_frequency(360) self.motor_controller.signal_in = self.raw_force_signal_global self.motor_controller.game_status_playing = self.game_status_playing_global self.motor_controller.motor_pause_mode = self.motor_pause_mode self.motor_controller.data_reconstruction = self.data_reconstruction self.motor_controller.data_smoothing_level = self.data_smoothing_level self.motor_controller.friction = self.friction_global self.motor_controller.damping = self.damping_global self.motor_controller.inertia = self.inertia_global self.motor_controller.encoder_pos = self.encoder_pos_global self.motor_controller.wheel_pos_deg = self.wheel_position_deg_global self.motor_controller.bump_to_bump = self.bump_to_bump_global self.motor_controller.motor_current = self.motor_current_global self.motor_controller.actual_max_force = self.actual_max_force_global self.motor_controller.motor_connected = self.motor_connected_global self.motor_controller.due_for_restart = self.motor_controller_due_for_restart_global self.motor_controller.achieved_freq = self.motor_control_rate self.motor_controller.start() self.lblMotorRate = QLabel('motor control rate:', self) self.lblMotorRate.setFont(QFont("Times", 24, QFont.Normal)) self.lblMotorRate.move(675, 25) self.lblMotorRateHz = QLabel('0.00 Hz', self) self.lblMotorRateHz.setFont(QFont("Times", 24, QFont.Normal)) self.lblMotorRateHz.adjustSize() self.lblMotorRateHz.move(1125 - self.lblMotorRateHz.width(), 25) self.force_graph = PlotWidget(self) self.force_graph.move(675, 75) self.force_graph.resize(1000, 475) self.force_graph.setYRange(-15.0, 15.0) self.force_graph.setBackground((255, 255, 255)) self.force_graph.showGrid(x=False, y=True) self.force_graph.addLegend() pen_ffb = pg.mkPen(color=(0, 0, 255)) self.ffb_curve = self.force_graph.getPlotItem().plot( pen=pen_ffb, name='Game FFB (Nm)') pen_current = pg.mkPen(color=(0, 255, 0)) self.current_curve = self.force_graph.getPlotItem().plot( pen=pen_current, name='Motor Torque (Nm)') self.ffb_history = [ 0 ] * self.graph_sample_rate * self.graph_history_time_sec self.current_history = [ 0 ] * self.graph_sample_rate * self.graph_history_time_sec self.load_profiles_from_file() self.build_gui() self.select_profile(0) # updates the graph showing the raw ffb and the motor torque def graph_update(self): # adding the latest raw game-ffb value(scaled to the actual torque value) to a list storing a history of this value self.ffb_history.append(self.raw_force_signal_global.value / self.actual_max_force_global.value) if len(self.ffb_history ) >= self.graph_history_time_sec * self.graph_sample_rate: self.ffb_history.pop(0) self.ffb_curve.setData(self.ffb_history) # adding the latest final motor torque value to a list storing a history of this value self.current_history.append( self.motor_current_global.value / (self.actual_max_force_global.value * 2.75)) if len(self.current_history ) >= self.graph_history_time_sec * self.graph_sample_rate: self.current_history.pop(0) self.current_curve.setData(self.current_history) # displaying the actually achieved refresh rate of the motor-control process self.lblMotorRateHz.setText( str(int(self.motor_control_rate.value * 100) / 100) + ' Hz') if self.motor_control_rate.value >= 360.0: self.lblMotorRateHz.setStyleSheet( 'QLabel { color: rgb(0,155,0); }') else: self.lblMotorRateHz.setStyleSheet( 'QLabel { color: rgb(155,0,0); }') # initializes and configures all the GUI-elements def build_gui(self): # WHEEL POSITION DATA AND SETTINGS # current bar self.lblCurrent = QLabel(self) self.lblCurrent.move(25 + 128, 25) self.lblCurrent.resize(0, 25) self.lblCurrent.setAutoFillBackground(True) self.lblCurrent.setStyleSheet( 'QLabel { background-color: rgb(0,255,0); }') self.lblCurrentDivider = QLabel(self) self.lblCurrentDivider.move(25 + 128 - 1, 20) self.lblCurrentDivider.resize(2, 35) self.lblCurrentDivider.setAutoFillBackground(True) self.lblCurrentDivider.setStyleSheet( 'QLabel { background-color: rgb(0,0,0); }') # wheel image self.lblWheelImage = QLabel(self) self.wheel_image = QImage('wheel_image.png') self.wheel_image_discon = QImage('wheel_image_disconnect.png') self.wheel_pixmap = QPixmap.fromImage(self.wheel_image) self.lblWheelImage.setPixmap(self.wheel_pixmap) self.lblWheelImage.resize(self.wheel_pixmap.width(), self.wheel_pixmap.height()) self.lblWheelImage.move(25, 75) # motor status label self.lblMotorStatus_1 = QLabel('Motor Status:', self) self.lblMotorStatus_1.move(15, 60) self.lblMotorStatus_2 = QLabel('Not Connected', self) self.lblMotorStatus_2.move(15, 75) self.lblMotorStatus_2.setStyleSheet('QLabel { color: rgb(155,0,0); }') # wheel position self.lblWheelPos = QLabel('0.0°', self) self.lblWheelPos.move(25 + 150 + 25, 75 + 256 + 10) self.lblWheelPos.resize(200, 50) self.lblWheelPos.setFont(QFont("Times", 24, QFont.Normal)) # center button center_pos = [25, 75 + 256 + 22, 150, 30] self.btnCenter = QPushButton('center Wheel', self) self.btnCenter.move(center_pos[0], center_pos[1]) self.btnCenter.resize(center_pos[2], center_pos[3]) self.btnCenter.clicked.connect(self.center_wheel) # lock-to-lock slider self.locklock_pos = [25, 425, 250, 0] self.lblLock = QLabel('Lock to Lock:', self) self.lblLock.move(self.locklock_pos[0], self.locklock_pos[1]) self.sliLock = QSlider(Qt.Horizontal, self) self.sliLock.setTickPosition(QSlider.TicksAbove) self.sliLock.setTickInterval(10) self.sliLock.setMinimum(10) self.sliLock.setMaximum(120) self.sliLock.setValue(90) self.sliLock.setSingleStep(1) self.sliLock.move(self.locklock_pos[0], self.locklock_pos[1] + 20) self.sliLock.resize(self.locklock_pos[2], 25) self.sliLock.valueChanged.connect(self.change_lock) self.lblLockVal = QLabel('900°', self) self.lblLockVal.adjustSize() self.lblLockVal.move( self.locklock_pos[0] + self.locklock_pos[2] - self.lblLockVal.width(), self.locklock_pos[1]) # bump_to_bump slider self.bumpbump_pos = [25, 500, 250, 0] self.lblBump = QLabel('Bump to Bump:', self) self.lblBump.move(self.bumpbump_pos[0], self.bumpbump_pos[1]) self.sliBump = QSlider(Qt.Horizontal, self) self.sliBump.setTickPosition(QSlider.TicksAbove) self.sliBump.setTickInterval(10) self.sliBump.setMinimum(10) self.sliBump.setMaximum(120) self.sliBump.setValue(90) self.sliBump.setSingleStep(1) self.sliBump.move(self.bumpbump_pos[0], self.bumpbump_pos[1] + 20) self.sliBump.resize(self.bumpbump_pos[2], 25) self.sliBump.valueChanged.connect(self.change_bump) self.lblBumpVal = QLabel('900°', self) self.lblBumpVal.adjustSize() self.lblBumpVal.move( self.bumpbump_pos[0] + self.bumpbump_pos[2] - self.lblBumpVal.width(), self.bumpbump_pos[1]) # WHEEL FORCE AND BEHAVIOR SETTINGS # game select combobox gameselect_pos = [325, 25, 250, 25] self.cbxGame = QComboBox(self) self.cbxGame.move(gameselect_pos[0], gameselect_pos[1]) self.cbxGame.resize(gameselect_pos[2], gameselect_pos[3]) for game in self.game_interfacer.games_available: self.cbxGame.addItem(game) self.cbxGame.activated.connect(self.select_game) # invert force checkbox invert_pos = [325, 55] self.cbInvert = QCheckBox('Invert Force Feedback', self) self.cbInvert.move(invert_pos[0], invert_pos[1]) self.cbInvert.stateChanged.connect(self.toggle_invert) # motor pause mode checkbox motorpause_pos = [325, 85] self.cbMotorPause = QCheckBox('pause motor when game is paused', self) self.cbMotorPause.move(motorpause_pos[0], motorpause_pos[1]) self.cbMotorPause.stateChanged.connect(self.toggle_motor_pause_mode) self.cbMotorPause.toggle() # maximum force slider self.max_force_pos = [325, 125, 250, 0] self.lblMaxForce = QLabel('Maximum Force in Nm:', self) self.lblMaxForce.move(self.max_force_pos[0], self.max_force_pos[1]) self.sliMaxForce = QSlider(Qt.Horizontal, self) self.sliMaxForce.setTickPosition(QSlider.TicksAbove) self.sliMaxForce.setTickInterval(10) self.sliMaxForce.setMinimum(1) self.sliMaxForce.setMaximum(150) self.sliMaxForce.setValue(0) self.sliMaxForce.setSingleStep(1) self.sliMaxForce.move(self.max_force_pos[0], self.max_force_pos[1] + 20) self.sliMaxForce.resize(self.max_force_pos[2], 25) self.sliMaxForce.valueChanged.connect(self.change_max_force) self.lblMaxForceVal = QLabel('0.0 Nm - (0.0 Amp)', self) self.lblMaxForceVal.adjustSize() self.lblMaxForceVal.move( self.max_force_pos[0] + self.max_force_pos[2] - self.lblMaxForceVal.width(), self.max_force_pos[1]) # reconstruction checkbox reconst_pos = [325, 175 + 3] self.cbReconst = QCheckBox('Use Data Reconstruction', self) self.cbReconst.move(reconst_pos[0], reconst_pos[1]) self.cbReconst.stateChanged.connect(self.toggle_reconstruction) self.cbReconst.setEnabled(False) # smoothing level combobox smoothing_pos = [475, 175, 100, 25] self.cbxSmoothing = QComboBox(self) self.cbxSmoothing.move(smoothing_pos[0], smoothing_pos[1]) self.cbxSmoothing.resize(smoothing_pos[2], smoothing_pos[3]) self.cbxSmoothing.addItem('no Smoothing') self.cbxSmoothing.addItem('1') self.cbxSmoothing.addItem('2') self.cbxSmoothing.addItem('3') self.cbxSmoothing.addItem('4') self.cbxSmoothing.addItem('5') self.cbxSmoothing.addItem('6') self.cbxSmoothing.addItem('7') self.cbxSmoothing.addItem('8') self.cbxSmoothing.addItem('9') self.cbxSmoothing.activated.connect(self.change_smoothing) self.cbxSmoothing.setEnabled(False) # friction slider self.friction_pos = [325, 215, 250, 0] self.lblFriction = QLabel('Friction:', self) self.lblFriction.move(self.friction_pos[0], self.friction_pos[1]) self.sliFriction = QSlider(Qt.Horizontal, self) self.sliFriction.setTickPosition(QSlider.TicksAbove) self.sliFriction.setTickInterval(10) self.sliFriction.setMinimum(0) self.sliFriction.setMaximum(100) self.sliFriction.setValue(0) self.sliFriction.setSingleStep(1) self.sliFriction.move(self.friction_pos[0], self.friction_pos[1] + 20) self.sliFriction.resize(self.friction_pos[2], 25) self.sliFriction.valueChanged.connect(self.change_friction) self.lblFrictionVal = QLabel('0 %', self) self.lblFrictionVal.adjustSize() self.lblFrictionVal.move( self.friction_pos[0] + self.friction_pos[2] - self.lblFrictionVal.width(), self.friction_pos[1]) # damping slider self.damping_pos = [325, 275, 250, 0] self.lblDamping = QLabel('Damping:', self) self.lblDamping.move(self.damping_pos[0], self.damping_pos[1]) self.sliDamping = QSlider(Qt.Horizontal, self) self.sliDamping.setTickPosition(QSlider.TicksAbove) self.sliDamping.setTickInterval(10) self.sliDamping.setMinimum(0) self.sliDamping.setMaximum(100) self.sliDamping.setValue(0) self.sliDamping.setSingleStep(1) self.sliDamping.move(self.damping_pos[0], self.damping_pos[1] + 20) self.sliDamping.resize(self.damping_pos[2], 25) self.sliDamping.valueChanged.connect(self.change_damping) self.lblDampingVal = QLabel('0 %', self) self.lblDampingVal.adjustSize() self.lblDampingVal.move( self.damping_pos[0] + self.damping_pos[2] - self.lblDampingVal.width(), self.damping_pos[1]) # inertia slider self.inertia_pos = [325, 335, 250, 0] self.lblInertia = QLabel('Inertia:', self) self.lblInertia.move(self.inertia_pos[0], self.inertia_pos[1]) self.sliInertia = QSlider(Qt.Horizontal, self) self.sliInertia.setTickPosition(QSlider.TicksAbove) self.sliInertia.setTickInterval(10) self.sliInertia.setMinimum(0) self.sliInertia.setMaximum(100) self.sliInertia.setValue(0) self.sliInertia.setSingleStep(1) self.sliInertia.move(self.inertia_pos[0], self.inertia_pos[1] + 20) self.sliInertia.resize(self.inertia_pos[2], 25) self.sliInertia.valueChanged.connect(self.change_inertia) self.lblInertiaVal = QLabel('0 %', self) self.lblInertiaVal.adjustSize() self.lblInertiaVal.move( self.inertia_pos[0] + self.inertia_pos[2] - self.lblInertiaVal.width(), self.inertia_pos[1]) # profile select combobox profileselect_pos = [325, 430, 250, 25] self.cbxProfiles = QComboBox(self) self.cbxProfiles.move(profileselect_pos[0], profileselect_pos[1]) self.cbxProfiles.resize(profileselect_pos[2], profileselect_pos[3]) for profile in self.profiles: self.cbxProfiles.addItem(profile.name) self.cbxProfiles.activated.connect(self.select_profile) # create profile button profilecreate_pos = [325, 460, 250, 25] self.btnCreate = QPushButton('create new profile', self) self.btnCreate.move(profilecreate_pos[0], profilecreate_pos[1]) self.btnCreate.resize(profilecreate_pos[2], profilecreate_pos[3]) self.btnCreate.clicked.connect(self.create_profile) # rename profile button profilerename_pos = [325, 490, 250, 25] self.btnRename = QPushButton('rename profile', self) self.btnRename.move(profilerename_pos[0], profilerename_pos[1]) self.btnRename.resize(profilerename_pos[2], profilerename_pos[3]) self.btnRename.clicked.connect(self.rename_profile) # cancel rename button cancelrename_pos = [325 + 200, 490, 50, 25] self.btnCancelRename = QPushButton('cancel', self) self.btnCancelRename.move(cancelrename_pos[0], cancelrename_pos[1]) self.btnCancelRename.resize(cancelrename_pos[2], cancelrename_pos[3]) self.btnCancelRename.clicked.connect(self.cancel_rename) self.btnCancelRename.setVisible(False) # rename textbox self.txtRename = QLineEdit(self) self.txtRename.move(profilerename_pos[0], profilerename_pos[1]) self.txtRename.resize(profilerename_pos[2] - 35 - 55, profilerename_pos[3]) self.txtRename.setVisible(False) self.txtRename.textChanged.connect(self.check_name_validity) # save profile button profilesave_pos = [325, 520, 120, 25] self.btnSave = QPushButton('save profile', self) self.btnSave.move(profilesave_pos[0], profilesave_pos[1]) self.btnSave.resize(profilesave_pos[2], profilesave_pos[3]) self.btnSave.clicked.connect(self.save_current_profile_internally) # delete profile button profiledelete_pos = [325 + 130, 520, 120, 25] self.btnDelete = QPushButton('delete profile', self) self.btnDelete.move(profiledelete_pos[0], profiledelete_pos[1]) self.btnDelete.resize(profiledelete_pos[2], profiledelete_pos[3]) self.btnDelete.clicked.connect(self.delete_current_profile) # updates the GUI-elements that indicate the status of the motor (connected/not-connected) def LiveGuiTick(self): self.lblWheelPos.setText( str(int(self.wheel_position_deg_global.value * 10) / 10) + '°') self.lblCurrent.resize( int( np.abs(self.motor_current_global.value / (self.actual_max_force_global.value * 2.75) * 128)), 25) if self.motor_current_global.value < 0.0: self.lblCurrent.move( 25 + 128 - np.abs(self.motor_current_global.value / (self.actual_max_force_global.value * 2.75) * 128), 25) tf = QTransform() tf.rotate(self.wheel_position_deg_global.value) if self.motor_connected_global.value: self.lblMotorStatus_2.setText('Connected') self.lblMotorStatus_2.setStyleSheet( 'QLabel { color: rgb(0,155,0); }') img_rot = self.wheel_image.transformed(tf) self.btnCenter.setEnabled(True) self.lblWheelPos.setStyleSheet('QLabel { color: rgb(0,0,0); }') else: self.lblMotorStatus_2.setText('Not Connected') self.lblMotorStatus_2.setStyleSheet( 'QLabel { color: rgb(155,0,0); }') img_rot = self.wheel_image_discon.transformed(tf) self.btnCenter.setEnabled(False) self.lblWheelPos.setStyleSheet( 'QLabel { color: rgb(155,155,155); }') diagonal_overlength = (np.sqrt(np.square(256) * 2) - 256) / 2 shift = int( np.abs( np.sin(np.deg2rad(self.wheel_position_deg_global.value * 2)) * diagonal_overlength)) crop_rect = QRect(shift, shift, 256, 256) self.wheel_pixmap = QPixmap.fromImage(img_rot).copy(crop_rect) self.lblWheelImage.setPixmap(self.wheel_pixmap) if self.motor_controller_due_for_restart_global.value: self.motor_controller_due_for_restart_global.value = False print('restarting motor...') try: self.motor_controller.motor_control_process.terminate() except: pass self.motor_controller.start() # helper function to get the index of a profile with a certain name from the profile-list def get_profile_index(self, name): for i in range(len(self.profiles)): if self.profiles[i].name == name: return i # WHEEL POSITION SETTING FUNCTIONS def center_wheel(self): print('centering wheel') self.motor_controller.set_encoder_offset() def change_lock(self): val = int(self.sender().value() * 10) self.lblLockVal.setText(str(val) + '°') self.lock_to_lock_global.value = val self.lblLockVal.adjustSize() self.lblLockVal.move( self.locklock_pos[0] + self.locklock_pos[2] - self.lblLockVal.width(), self.locklock_pos[1]) def change_bump(self): val = int(self.sender().value() * 10) self.lblBumpVal.setText(str(val) + '°') self.bump_to_bump_global.value = val self.lblBumpVal.adjustSize() self.lblBumpVal.move( self.bumpbump_pos[0] + self.bumpbump_pos[2] - self.lblBumpVal.width(), self.bumpbump_pos[1]) # WHEEL FORCE SETTING FUNCTIONS def select_game(self, item_index): print('selecting', item_index) self.game_interfacer.terminate() time.sleep(1) self.game_interfacer.start(item_index) def toggle_invert(self, state): if state == Qt.Checked: self.invert_force_global.value = True else: self.invert_force_global.value = False def toggle_motor_pause_mode(self, state): if state == Qt.Checked: self.motor_pause_mode.value = True else: self.motor_pause_mode.value = False def change_max_force(self): val = self.sender().value() / 10 self.lblMaxForceVal.setText( str(val) + ' Nm - (' + str(int(val * 2.75 * 100) / 100) + ' Amp)') self.actual_max_force_global.value = val self.lblMaxForceVal.adjustSize() self.lblMaxForceVal.move( self.max_force_pos[0] + self.max_force_pos[2] - self.lblMaxForceVal.width(), self.max_force_pos[1]) self.force_graph.setYRange(-val, val) def change_friction(self): val = self.sender().value() / 100 self.lblFrictionVal.setText(str(int(val * 100)) + ' %') self.friction_global.value = val self.lblFrictionVal.adjustSize() self.lblFrictionVal.move( self.friction_pos[0] + self.friction_pos[2] - self.lblFrictionVal.width(), self.friction_pos[1]) def change_damping(self): val = self.sender().value() / 100 self.lblDampingVal.setText(str(int(val * 100)) + ' %') self.damping_global.value = val self.lblDampingVal.adjustSize() self.lblDampingVal.move( self.damping_pos[0] + self.damping_pos[2] - self.lblDampingVal.width(), self.damping_pos[1]) def change_inertia(self): val = self.sender().value() / 100 self.lblInertiaVal.setText(str(int(val * 100)) + ' %') self.inertia_global.value = val self.lblInertiaVal.adjustSize() self.lblInertiaVal.move( self.inertia_pos[0] + self.inertia_pos[2] - self.lblInertiaVal.width(), self.inertia_pos[1]) def toggle_reconstruction(self, state): if state == Qt.Checked: self.data_reconstruction.value = True else: self.data_reconstruction.value = False def change_smoothing(self, item_index): self.data_smoothing_level.value = item_index def select_profile(self, selected_profile): self.sliLock.setValue( int(self.profiles[selected_profile].lock_to_lock / 10)) self.sliBump.setValue( int(self.profiles[selected_profile].bump_to_bump / 10)) self.cbInvert.setChecked( bool(self.profiles[selected_profile].invert_force)) self.sliMaxForce.setValue( int(self.profiles[selected_profile].max_force * 10)) self.cbReconst.setChecked( bool(self.profiles[selected_profile].use_reconstruction)) self.cbxSmoothing.setCurrentIndex( int(self.profiles[selected_profile].smoothing_level)) self.sliFriction.setValue( int(self.profiles[selected_profile].friction * 100)) self.sliDamping.setValue( int(self.profiles[selected_profile].damping * 100)) self.sliInertia.setValue( int(self.profiles[selected_profile].inertia * 100)) def save_current_profile_internally(self): current_index = self.cbxProfiles.currentIndex() self.profiles[ current_index].lock_to_lock = self.lock_to_lock_global.value self.profiles[ current_index].bump_to_bump = self.bump_to_bump_global.value self.profiles[ current_index].invert_force = self.invert_force_global.value self.profiles[ current_index].max_force = self.actual_max_force_global.value self.profiles[ current_index].use_reconstruction = self.data_reconstruction.value self.profiles[ current_index].smoothing_level = self.data_smoothing_level.value self.profiles[current_index].friction = self.friction_global.value self.profiles[current_index].damping = self.damping_global.value self.profiles[current_index].inertia = self.inertia_global.value self.save_profiles_to_file() def save_profiles_to_file(self): root = ET.Element('profiles') for profile in self.profiles: prof_elem = ET.SubElement(root, 'profile', name=profile.name) ET.SubElement(prof_elem, 'lock_to_lock').text = str(profile.lock_to_lock) ET.SubElement(prof_elem, 'bump_to_bump').text = str(profile.bump_to_bump) ET.SubElement(prof_elem, 'invert_force').text = str( bool(profile.invert_force)) ET.SubElement(prof_elem, 'max_force').text = str(profile.max_force) ET.SubElement(prof_elem, 'use_reconstruction').text = str( bool(profile.use_reconstruction)) ET.SubElement(prof_elem, 'smoothing_level').text = str( profile.smoothing_level) ET.SubElement(prof_elem, 'friction').text = str(profile.friction) ET.SubElement(prof_elem, 'damping').text = str(profile.damping) ET.SubElement(prof_elem, 'inertia').text = str(profile.inertia) tree = ET.ElementTree(root) tree.write("profiles.xml") def load_profiles_from_file(self): self.profiles.clear() tree = ET.parse('profiles.xml') root = tree.getroot() for prof in root: profile = Profile(prof.attrib['name']) profile.lock_to_lock = float(prof[0].text) profile.bump_to_bump = float(prof[1].text) profile.invert_force = bool(prof[2].text == 'True') profile.max_force = float(prof[3].text) profile.use_reconstruction = bool(prof[4].text == 'True') profile.smoothing_level = int(prof[5].text) profile.friction = float(prof[6].text) profile.damping = float(prof[7].text) profile.inertia = float(prof[8].text) self.profiles.append(profile) def delete_current_profile(self): current_index = self.cbxProfiles.currentIndex() print('deleting profile at index:', current_index) self.profiles.pop(current_index) self.cbxProfiles.clear() for profile in self.profiles: self.cbxProfiles.addItem(profile.name) self.cbxProfiles.setCurrentIndex(0) self.select_profile(0) self.save_current_profile_internally() if len(self.profiles) == 1: self.btnDelete.setEnabled(False) def create_profile(self): new_profile = Profile('profile #' + str(len(self.profiles) + 1)) current_index = self.cbxProfiles.currentIndex() new_profile.lock_to_lock = self.profiles[current_index].lock_to_lock new_profile.bump_to_bump = self.profiles[current_index].bump_to_bump new_profile.invert_force = self.profiles[current_index].invert_force new_profile.max_force = self.profiles[current_index].max_force new_profile.use_reconstruction = self.profiles[ current_index].use_reconstruction new_profile.smoothing_level = self.profiles[ current_index].smoothing_level new_profile.friction = self.profiles[current_index].friction new_profile.damping = self.profiles[current_index].damping new_profile.inertia = self.profiles[current_index].inertia self.profiles.append(new_profile) self.cbxProfiles.clear() for profile in self.profiles: self.cbxProfiles.addItem(profile.name) self.cbxProfiles.setCurrentIndex(len(self.profiles) - 1) self.select_profile(len(self.profiles) - 1) self.save_current_profile_internally() if len(self.profiles) > 1: self.btnDelete.setEnabled(True) def rename_profile(self): rename_pos = [325, 490, 250, 25] if self.sender().text() == 'rename profile': self.sender().setText('OK') self.sender().move(rename_pos[0] + 220 - 55, rename_pos[1]) self.sender().resize(rename_pos[2] - 220, rename_pos[3]) self.cbxProfiles.setEnabled(False) self.btnCreate.setEnabled(False) self.btnSave.setEnabled(False) self.btnDelete.setEnabled(False) self.btnCancelRename.setVisible(True) self.txtRename.setVisible(True) current_index = self.cbxProfiles.currentIndex() self.txtRename.setText(self.profiles[current_index].name) else: self.sender().setText('rename profile') self.sender().move(rename_pos[0], rename_pos[1]) self.sender().resize(rename_pos[2], rename_pos[3]) self.cbxProfiles.setEnabled(True) self.btnCreate.setEnabled(True) self.btnSave.setEnabled(True) self.btnDelete.setEnabled(True) self.btnCancelRename.setVisible(False) self.txtRename.setVisible(False) current_index = self.cbxProfiles.currentIndex() self.profiles[current_index].name = self.txtRename.text() self.cbxProfiles.clear() for profile in self.profiles: self.cbxProfiles.addItem(profile.name) self.cbxProfiles.setCurrentIndex(current_index) self.select_profile(current_index) self.save_current_profile_internally() def cancel_rename(self): rename_pos = [325, 490, 250, 25] self.btnRename.setText('rename profile') self.btnRename.move(rename_pos[0], rename_pos[1]) self.btnRename.resize(rename_pos[2], rename_pos[3]) self.cbxProfiles.setEnabled(True) self.btnCreate.setEnabled(True) self.btnSave.setEnabled(True) self.btnDelete.setEnabled(True) self.btnCancelRename.setVisible(False) self.txtRename.setVisible(False) def check_name_validity(self, text): if text == '': self.btnRename.setEnabled(False) else: self.btnRename.setEnabled(True)
class Plotter(QWidget): MAX_DATA_POINTS_PER_CURVE = 200000 COLORS = [ Qt.red, Qt.green, Qt.blue, # RGB - http://ux.stackexchange.com/questions/79561 Qt.yellow, Qt.cyan, Qt.magenta, # Close to RGB Qt.darkRed, Qt.darkGreen, Qt.darkBlue, # Darker RGB Qt.darkYellow, Qt.darkCyan, Qt.darkMagenta, # Close to RGB Qt.gray, Qt.darkGray ] # Leftovers INITIAL_X_RANGE = 60 def __init__(self, parent=None): # Parent super(Plotter, self).__init__(parent) self.setWindowTitle('UAVCAN Plotter') self.setWindowIcon(APP_ICON) # Redraw timer self._update_timer = QTimer() self._update_timer.timeout.connect(self._update) self._update_timer.setSingleShot(False) self._update_timer.start(30) # PyQtGraph self._plot_widget = PlotWidget() self._plot_widget.setBackground((0, 0, 0)) self._legend = self._plot_widget.addLegend() self._plot_widget.setRange(xRange=(0, self.INITIAL_X_RANGE), padding=0) self._plot_widget.showButtons() self._plot_widget.enableAutoRange() self._plot_widget.showGrid(x=True, y=True, alpha=0.4) # Controls # https://specifications.freedesktop.org/icon-naming-spec/icon-naming-spec-latest.html button_add_matcher = QtGui.QPushButton('New matcher', self) button_add_matcher.setIcon(QtGui.QIcon.fromTheme('list-add')) button_add_matcher.setToolTip('Add new curve matcher') button_add_matcher.clicked.connect(lambda: NewCurveMatcherWindow( self, lambda: sorted(self._active_messages), self. _add_curve_matcher).show()) button_clear_plots = QtGui.QPushButton('Clear plots', self) button_clear_plots.setIcon(QtGui.QIcon.fromTheme('edit-clear')) button_clear_plots.setToolTip('Clear the plotting area') button_clear_plots.clicked.connect(lambda: self._remove_all_curves()) def delete_all_matchers(): self._curve_matchers = [] for i in reversed(range(self._curve_matcher_container.count())): self._curve_matcher_container.itemAt(i).widget().deleteLater() self._remove_all_curves() button_delete_all_matchers = QtGui.QPushButton('Delete matchers', self) button_delete_all_matchers.setIcon( QtGui.QIcon.fromTheme('edit-delete')) button_delete_all_matchers.setToolTip('Delete all matchers') button_delete_all_matchers.clicked.connect(delete_all_matchers) self._autoscroll = QtGui.QCheckBox('Autoscroll', self) self._autoscroll.setChecked(True) self._max_x = self.INITIAL_X_RANGE # Layout control_panel = QHBoxLayout() control_panel.addWidget(button_add_matcher) control_panel.addWidget(button_clear_plots) control_panel.addWidget(self._autoscroll) control_panel.addStretch() control_panel.addWidget(button_delete_all_matchers) self._curve_matcher_container = QVBoxLayout() layout = QVBoxLayout() layout.addWidget(self._plot_widget, 1) layout.addLayout(control_panel) layout.addLayout(self._curve_matcher_container) self.setLayout(layout) # Logic self._color_index = 0 self._curves = {} self._message_queue = multiprocessing.Queue() self._active_messages = set() # set(data type name) self._curve_matchers = [] # Defaults self._add_curve_matcher( CurveMatcher('uavcan.protocol.debug.KeyValue', 'value', [('key', None)])) def _add_curve_matcher(self, matcher): self._curve_matchers.append(matcher) view = CurveMatcherView(matcher, self) def remove(): self._curve_matchers.remove(matcher) self._curve_matcher_container.removeWidget(view) view.setParent(None) view.deleteLater() view.on_remove = remove self._curve_matcher_container.addWidget(view) def _update(self): # Processing messages while True: try: m = self._message_queue.get_nowait() self._process_message(m) except queue.Empty: break # Updating curves for curve in self._curves.values(): if len(curve['x']): if len(curve['x']) > self.MAX_DATA_POINTS_PER_CURVE: curve['x'] = curve['x'][-self.MAX_DATA_POINTS_PER_CURVE:] curve['y'] = curve['y'][-self.MAX_DATA_POINTS_PER_CURVE:] assert len(curve['x']) == len(curve['y']) curve['plot'].setData(curve['x'], curve['y']) self._max_x = max(self._max_x, curve['x'][-1]) # Updating view range if self._autoscroll.checkState(): (xmin, xmax), _ = self._plot_widget.viewRange() diff = xmax - xmin xmax = self._max_x xmin = self._max_x - diff self._plot_widget.setRange(xRange=(xmin, xmax), padding=0) def _process_message(self, m): self._active_messages.add(m.data_type_name) for matcher in self._curve_matchers: if matcher.match(m): name, x, y = matcher.extract_curve_name_x_y(m) self._draw_curve(name, x, y) def _remove_all_curves(self): for curve in self._curves.values(): self._plot_widget.removeItem(curve['plot']) self._plot_widget.clear() self._curves = {} self._color_index = 0 self._legend.scene().removeItem(self._legend) self._legend = self._plot_widget.addLegend() def _draw_curve(self, name, x, y): if name not in self._curves: logging.info('Adding curve %r', name) color = self.COLORS[self._color_index % len(self.COLORS)] self._color_index += 1 pen = mkPen(QColor(color), width=1) plot = self._plot_widget.plot(name=name, pen=pen) self._curves[name] = { 'x': numpy.array([]), 'y': numpy.array([]), 'plot': plot } curve = self._curves[name] curve['x'] = numpy.append(curve['x'], [x] if isinstance(x, (float, int)) else x) curve['y'] = numpy.append(curve['y'], [y] if isinstance(y, (float, int)) else y) assert len(curve['x']) == len(curve['y']) def push_received_message(self, msg): self._message_queue.put_nowait(msg)
def __init__(self): super(MainWindow, self).__init__() self.resize(1080, 600) self.setMinimumSize(QSize(1080, 600)) self.setMaximumSize(QSize(1366, 745)) self.setWindowTitle("GPCO - General Power Converter Optimizer") main_widget = QWidget() self.component_selection_buttons = {} main_layout = QHBoxLayout() main_splitter = QSplitter(Qt.Horizontal, self) left_frame = QFrame(main_splitter) left_frame.setFrameShape(QFrame.Box) left_frame.setMaximumWidth(250) left_frame.setMinimumWidth(220) right_frame = QFrame(main_splitter) right_frame.setFrameShape(QFrame.Box) main_splitter.addWidget(left_frame) main_splitter.addWidget(right_frame) converter_config_layout = QVBoxLayout() visualize_information_layout = QVBoxLayout() right_splitter = QSplitter(Qt.Vertical) visualize_information_layout.addWidget(right_splitter) top_right_frame = QFrame(right_splitter) bottom_right_frame = QFrame(right_splitter) right_splitter.addWidget(top_right_frame) right_splitter.addWidget(bottom_right_frame) top_right_layout = QHBoxLayout() self.converter_result_edit = QTextBrowser() self.optimizer_graph = PlotWidget() self.optimizer_graph.setBackground('w') aux_frame = QFrame() aux_frame.setMaximumWidth(450) aux_layout = QHBoxLayout() aux_layout.addWidget(self.optimizer_graph) aux_frame.setLayout(aux_layout) top_right_layout.addWidget(self.converter_result_edit) top_right_layout.addWidget(aux_frame) bottom_right_layout = QHBoxLayout() analysis_graph_1 = QTextBrowser() analysis_graph_2 = PlotWidget() analysis_graph_2.setBackground('w') aux_frame2 = QFrame() aux_frame2.setMaximumWidth(450) aux_layout2 = QHBoxLayout() aux_layout2.addWidget(analysis_graph_2) aux_frame2.setLayout(aux_layout2) bottom_right_layout.addWidget(analysis_graph_1) bottom_right_layout.addWidget(aux_frame2) top_right_frame.setLayout(top_right_layout) bottom_right_frame.setLayout(bottom_right_layout) # Adiciona tudo que vai no Layout do Conversor configuration_label = QLabel( "<html><head/><body><p><span style=\" font-size:12pt;\">Configuração do Conversor</span></p></body></html>" ) configuration_label.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Minimum) configuration_label.setAlignment(Qt.AlignCenter) converter_config_layout.addWidget(configuration_label) topology_label = QLabel( "<html><head/><body><p><span style=\" font-size:10pt;\">Topologia</span></p></body></html>" ) topology_label.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Minimum) topology_label.setAlignment(Qt.AlignCenter) converter_config_layout.addItem( QSpacerItem(10, 10, QSizePolicy.Minimum, QSizePolicy.Minimum)) converter_config_layout.addWidget(topology_label) converter_config_layout.addItem( QSpacerItem(10, 10, QSizePolicy.Minimum, QSizePolicy.Minimum)) converter_selector = QComboBox() converter_selector.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Minimum) converter_selector.addItem("Boost Half Bridge") converter_config_layout.addLayout(CenteredWidget(converter_selector)) parameters_label = QLabel( "<html><head/><body><p><span style=\" font-size:10pt;\">Parâmetros de Projeto</span></p></body></html>" ) parameters_label.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Minimum) parameters_label.setAlignment(Qt.AlignCenter) converter_config_layout.addItem( QSpacerItem(20, 10, QSizePolicy.Minimum, QSizePolicy.Fixed)) converter_config_layout.addWidget(parameters_label) converter_config_layout.addItem( QSpacerItem(20, 10, QSizePolicy.Minimum, QSizePolicy.Fixed)) self.design_features_inputs = { 'Vi': LabeledInput('Tensão de Entrada (V)'), 'Vo': LabeledInput('Tensão de Saída (V)'), 'Po': LabeledInput('Potência de Saída (W)'), 'dIin_max': LabeledInput('DeltaIinMax (%)'), 'dVo_max': LabeledInput('DeltaVoMax (%)'), } for key in self.design_features_inputs: converter_config_layout.addLayout(self.design_features_inputs[key]) converter_config_layout.addItem( QSpacerItem(20, 10, QSizePolicy.Minimum, QSizePolicy.Fixed)) select_components_label = QLabel( "<html><head/><body><p><span style=\" font-size:10pt;\">Selecione os Componentes</span></p></body></html>" ) select_components_label.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Minimum) select_components_label.setAlignment(Qt.AlignCenter) converter_config_layout.addWidget(select_components_label) self.select_components_tab = QTabWidget() complete_optimization_components_tab = QFrame() continuous_optimization_components_tab = QFrame() complete_optimization_components_tab.setSizePolicy( QSizePolicy.Minimum, QSizePolicy.Expanding) continuous_optimization_components_tab.setSizePolicy( QSizePolicy.Minimum, QSizePolicy.Expanding) continuous_optimization_components_layout = QVBoxLayout() complete_optimization_components_layout = QVBoxLayout() self.complete_component_selection_buttons = {} self.continuous_component_selection_buttons = {} for component in COMPLETE: self.complete_component_selection_buttons[component] = QPushButton( component) for component in CONTINUOUS: self.continuous_component_selection_buttons[ component] = QPushButton(component) complete_optimization_components_layout.addLayout( SpacedWidget( [self.complete_component_selection_buttons['Capacitors']])) complete_optimization_components_layout.addLayout( SpacedWidget([ self.complete_component_selection_buttons['Diodes'], self.complete_component_selection_buttons['Switches'] ])) complete_optimization_components_layout.addLayout( SpacedWidget([ self.complete_component_selection_buttons['Cores'], self.complete_component_selection_buttons['Cables'] ])) complete_optimization_components_layout.addItem( QSpacerItem(0, 0, QSizePolicy.Minimum, QSizePolicy.Expanding)) complete_optimization_components_tab.setLayout( complete_optimization_components_layout) continuous_optimization_components_layout.addLayout( SpacedWidget([ self.continuous_component_selection_buttons['C1'], self.continuous_component_selection_buttons['C2'] ])) continuous_optimization_components_layout.addLayout( SpacedWidget([ self.continuous_component_selection_buttons['C3'], self.continuous_component_selection_buttons['C4'] ])) continuous_optimization_components_layout.addLayout( SpacedWidget([ self.continuous_component_selection_buttons['S1'], self.continuous_component_selection_buttons['S2'] ])) continuous_optimization_components_layout.addLayout( SpacedWidget([ self.continuous_component_selection_buttons['D3'], self.continuous_component_selection_buttons['D4'] ])) continuous_optimization_components_layout.addLayout( SpacedWidget([ self.continuous_component_selection_buttons['Li'], self.continuous_component_selection_buttons['Lk'] ])) continuous_optimization_components_layout.addLayout( SpacedWidget([self.continuous_component_selection_buttons['Tr']])) continuous_optimization_components_layout.addItem( QSpacerItem(0, 0, QSizePolicy.Minimum, QSizePolicy.Expanding)) continuous_optimization_components_tab.setLayout( continuous_optimization_components_layout) self.select_components_tab.addTab(complete_optimization_components_tab, "Completa") self.select_components_tab.addTab( continuous_optimization_components_tab, "Contínua") converter_config_layout.addWidget(self.select_components_tab) left_frame.setLayout(converter_config_layout) right_frame.setLayout(visualize_information_layout) main_layout.addWidget(main_splitter) main_widget.setLayout(main_layout) self.setCentralWidget(main_widget) # Create all action menus. self.menu_bar = QMenuBar(self) self.file_menu = QMenu(self.menu_bar) self.run_menu = QMenu(self.menu_bar) self.components_menu = QMenu(self.menu_bar) self.add_component_menu = QMenu(self.components_menu) self.settings_menu = QMenu(self.menu_bar) self.help_menu = QMenu(self.menu_bar) self.setMenuBar(self.menu_bar) self.status_bar = QStatusBar(self) self.setStatusBar(self.status_bar) self.optimization_progress_bar = QProgressBar(self) self.optimization_progress_bar.setMaximumWidth(250) self.status_bar_text_edit = QLabel("") self.status_bar.addPermanentWidget(self.optimization_progress_bar, 1) self.status_bar.addPermanentWidget(self.status_bar_text_edit, 1) self.actionNew = QAction(self) self.actionNew.setIcon(QIcon("GUI/Icons/document--add.svg")) self.actionOpen = QAction(self) self.actionOpen.setIcon(QIcon("GUI/Icons/folder.svg")) self.actionSave = QAction(self) self.actionSave.setIcon(QIcon("GUI/Icons/save.svg")) self.actionSaveAs = QAction(self) self.actionSaveAs.setIcon(QIcon("GUI/Icons/save.svg")) self.actionSwitch = QAction(self) self.actionDiode = QAction(self) self.actionCapacitor = QAction(self) self.actionCable = QAction(self) self.actionCore = QAction(self) self.actionConfigOptimizer = QAction(self) self.actionConfigSecurity = QAction(self) self.actionTransformer = QAction(self) self.actionInductor = QAction(self) self.actionHowItWorks = QAction(self) self.actionHowToUse = QAction(self) self.actionLoadFile = QAction(self) self.action_run_optimizer = QAction(self) self.action_run_optimizer.setIcon( QIcon("GUI/Icons/play--filled--alt.svg")) self.action_stop_optimizer = QAction(self) self.action_stop_optimizer.setIcon( QIcon("GUI/Icons/stop--filled--alt.svg")) self.actionComponents = QAction(self) self.file_menu.addAction(self.actionNew) self.file_menu.addAction(self.actionOpen) self.file_menu.addAction(self.actionSave) self.file_menu.addAction(self.actionSaveAs) self.add_component_menu.addAction(self.actionSwitch) self.add_component_menu.addAction(self.actionDiode) self.add_component_menu.addAction(self.actionCapacitor) self.add_component_menu.addAction(self.actionCable) self.add_component_menu.addAction(self.actionCore) self.add_component_menu.addAction(self.actionTransformer) self.add_component_menu.addAction(self.actionInductor) self.run_menu.addAction(self.action_run_optimizer) self.run_menu.addAction(self.action_stop_optimizer) self.components_menu.addAction(self.add_component_menu.menuAction()) self.components_menu.addAction(self.actionLoadFile) self.settings_menu.addAction(self.actionConfigOptimizer) self.settings_menu.addAction(self.actionConfigSecurity) self.help_menu.addAction(self.actionHowItWorks) self.help_menu.addAction(self.actionHowToUse) self.menu_bar.addAction(self.file_menu.menuAction()) self.menu_bar.addAction(self.run_menu.menuAction()) self.menu_bar.addAction(self.components_menu.menuAction()) self.menu_bar.addAction(self.settings_menu.menuAction()) self.menu_bar.addAction(self.help_menu.menuAction()) _translate = QCoreApplication.translate self.file_menu.setTitle(_translate("MainWindow", "Arquivo")) self.components_menu.setTitle(_translate("MainWindow", "Biblioteca")) self.help_menu.setTitle(_translate("MainWindow", "Ajuda")) self.settings_menu.setTitle(_translate("MainWindow", "Configurações")) self.run_menu.setTitle(_translate("MainWindow", "Rodar")) self.add_component_menu.setTitle( _translate("MainWindow", "Adicionar Componente")) self.actionNew.setText(_translate("MainWindow", "Novo Arquivo")) self.actionNew.setShortcut(_translate("MainWindow", "Ctrl+N")) self.actionOpen.setText(_translate("MainWindow", "Carregar Arquivo")) self.actionOpen.setShortcut(_translate("MainWindow", "Ctrl+O")) self.actionSave.setText(_translate("MainWindow", "Salvar")) self.actionSave.setShortcut(_translate("MainWindow", "Ctrl+S")) self.actionSaveAs.setText(_translate("MainWindow", "Salvar Como")) self.actionSaveAs.setShortcut(_translate("MainWindow", "Ctrl+Shift+S")) self.actionSwitch.setText(_translate("MainWindow", "Chave")) self.actionDiode.setText(_translate("MainWindow", "Diodo")) self.actionCapacitor.setText(_translate("MainWindow", "Capacitor")) self.actionCable.setText(_translate("MainWindow", "Fio")) self.actionCore.setText(_translate("MainWindow", "Núcleo Magnético")) self.actionConfigOptimizer.setText( _translate("MainWindow", "Otimizador")) self.actionConfigSecurity.setText( _translate("MainWindow", "Fatores de Segurança")) self.actionTransformer.setText( _translate("MainWindow", "Transformador")) self.actionInductor.setText(_translate("MainWindow", "Indutor")) self.actionHowItWorks.setText( _translate("MainWindow", "Como funciona o otimizador?")) self.actionHowToUse.setText( _translate("MainWindow", "Como utilizar o otimizador?")) self.actionLoadFile.setText( _translate("MainWindow", "Carregar Arquivo")) self.actionComponents.setText(_translate("MainWindow", "Componentes")) self.action_run_optimizer.setText( _translate("MainWindow", "Rodar Otimizador")) self.action_run_optimizer.setShortcut(_translate("MainWindow", "F5")) self.action_stop_optimizer.setText( _translate("MainWindow", "Parar Otimizador")) self.action_stop_optimizer.setShortcut(_translate("MainWindow", "F9")) # Execution Toolbar execution_toolbar = QToolBar("Run", self) execution_toolbar.addAction(self.actionNew) execution_toolbar.addAction(self.actionSave) execution_toolbar.addAction(self.actionOpen) execution_toolbar.addAction(self.action_run_optimizer) execution_toolbar.addAction(self.action_stop_optimizer) execution_toolbar.setFixedHeight(36) execution_toolbar.setIconSize(QSize(12, 12)) self.addToolBar(execution_toolbar)
class Ui_MainWindow(object): def setupUi(self, MainWindow): MainWindow.setObjectName("MainWindow") MainWindow.resize(882, 605) self.centralwidget = QtWidgets.QWidget(MainWindow) self.centralwidget.setObjectName("centralwidget") self.gridLayout = QtWidgets.QGridLayout(self.centralwidget) self.gridLayout.setObjectName("gridLayout") self.labelHKLS = QtWidgets.QLabel(self.centralwidget) font = QtGui.QFont() font.setPointSize(10) font.setBold(True) font.setWeight(75) self.labelHKLS.setFont(font) self.labelHKLS.setObjectName("labelHKLS") self.gridLayout.addWidget(self.labelHKLS, 13, 0, 1, 4) self.label_19 = QtWidgets.QLabel(self.centralwidget) font = QtGui.QFont() font.setPointSize(10) self.label_19.setFont(font) self.label_19.setObjectName("label_19") self.gridLayout.addWidget(self.label_19, 15, 6, 1, 1) self.labelSimpara = QtWidgets.QLabel(self.centralwidget) font = QtGui.QFont() font.setPointSize(10) font.setBold(True) font.setWeight(75) self.labelSimpara.setFont(font) self.labelSimpara.setObjectName("labelSimpara") self.gridLayout.addWidget(self.labelSimpara, 0, 0, 1, 2) self.labelHKLS_2 = QtWidgets.QLabel(self.centralwidget) font = QtGui.QFont() font.setPointSize(10) font.setBold(True) font.setWeight(75) self.labelHKLS_2.setFont(font) self.labelHKLS_2.setObjectName("labelHKLS_2") self.gridLayout.addWidget(self.labelHKLS_2, 13, 4, 1, 3) self.label_17 = QtWidgets.QLabel(self.centralwidget) font = QtGui.QFont() font.setPointSize(10) self.label_17.setFont(font) self.label_17.setObjectName("label_17") self.gridLayout.addWidget(self.label_17, 14, 4, 1, 1) self.idealLueftenInput = QtWidgets.QLineEdit(self.centralwidget) font = QtGui.QFont() font.setPointSize(10) self.idealLueftenInput.setFont(font) self.idealLueftenInput.setObjectName("idealLueftenInput") self.gridLayout.addWidget(self.idealLueftenInput, 14, 1, 1, 2) self.textEditCalcInfo = QtWidgets.QTextEdit(self.centralwidget) self.textEditCalcInfo.setMaximumSize(QtCore.QSize(16777215, 61)) self.textEditCalcInfo.setObjectName("textEditCalcInfo") self.gridLayout.addWidget(self.textEditCalcInfo, 21, 0, 1, 7) self.CustomLueftenInput = QtWidgets.QLineEdit(self.centralwidget) font = QtGui.QFont() font.setPointSize(10) self.CustomLueftenInput.setFont(font) self.CustomLueftenInput.setObjectName("CustomLueftenInput") self.gridLayout.addWidget(self.CustomLueftenInput, 14, 5, 1, 1) self.CustomInnereLastenInput = QtWidgets.QLineEdit(self.centralwidget) font = QtGui.QFont() font.setPointSize(10) self.CustomInnereLastenInput.setFont(font) self.CustomInnereLastenInput.setObjectName("CustomInnereLastenInput") self.gridLayout.addWidget(self.CustomInnereLastenInput, 16, 5, 1, 1) self.NatLueftenInput = QtWidgets.QLineEdit(self.centralwidget) font = QtGui.QFont() font.setPointSize(10) self.NatLueftenInput.setFont(font) self.NatLueftenInput.setObjectName("NatLueftenInput") self.gridLayout.addWidget(self.NatLueftenInput, 18, 1, 1, 2) self.label_20 = QtWidgets.QLabel(self.centralwidget) font = QtGui.QFont() font.setPointSize(10) self.label_20.setFont(font) self.label_20.setObjectName("label_20") self.gridLayout.addWidget(self.label_20, 15, 4, 1, 1) self.NachtlueftenInput = QtWidgets.QLineEdit(self.centralwidget) font = QtGui.QFont() font.setPointSize(10) self.NachtlueftenInput.setFont(font) self.NachtlueftenInput.setObjectName("NachtlueftenInput") self.gridLayout.addWidget(self.NachtlueftenInput, 15, 1, 1, 2) self.TaglueftenInput = QtWidgets.QLineEdit(self.centralwidget) font = QtGui.QFont() font.setPointSize(10) self.TaglueftenInput.setFont(font) self.TaglueftenInput.setObjectName("TaglueftenInput") self.gridLayout.addWidget(self.TaglueftenInput, 16, 1, 1, 2) self.label_14 = QtWidgets.QLabel(self.centralwidget) font = QtGui.QFont() font.setPointSize(10) self.label_14.setFont(font) self.label_14.setObjectName("label_14") self.gridLayout.addWidget(self.label_14, 19, 3, 1, 1) self.label_4 = QtWidgets.QLabel(self.centralwidget) font = QtGui.QFont() font.setPointSize(10) self.label_4.setFont(font) self.label_4.setObjectName("label_4") self.gridLayout.addWidget(self.label_4, 14, 3, 1, 1) self.label_23 = QtWidgets.QLabel(self.centralwidget) font = QtGui.QFont() font.setPointSize(10) self.label_23.setFont(font) self.label_23.setObjectName("label_23") self.gridLayout.addWidget(self.label_23, 16, 4, 1, 1) self.label_2 = QtWidgets.QLabel(self.centralwidget) self.label_2.setMaximumSize(QtCore.QSize(14, 22)) font = QtGui.QFont() font.setPointSize(10) self.label_2.setFont(font) self.label_2.setObjectName("label_2") self.gridLayout.addWidget(self.label_2, 1, 2, 1, 1) self.label_8 = QtWidgets.QLabel(self.centralwidget) font = QtGui.QFont() font.setPointSize(10) self.label_8.setFont(font) self.label_8.setObjectName("label_8") self.gridLayout.addWidget(self.label_8, 17, 0, 1, 1) self.label_12 = QtWidgets.QLabel(self.centralwidget) font = QtGui.QFont() font.setPointSize(10) self.label_12.setFont(font) self.label_12.setObjectName("label_12") self.gridLayout.addWidget(self.label_12, 18, 0, 1, 1) self.label = QtWidgets.QLabel(self.centralwidget) font = QtGui.QFont() font.setPointSize(10) self.label.setFont(font) self.label.setObjectName("label") self.gridLayout.addWidget(self.label, 1, 0, 1, 1) self.label_3 = QtWidgets.QLabel(self.centralwidget) self.label_3.setMinimumSize(QtCore.QSize(121, 0)) font = QtGui.QFont() font.setPointSize(10) self.label_3.setFont(font) self.label_3.setObjectName("label_3") self.gridLayout.addWidget(self.label_3, 14, 0, 1, 1) self.label_18 = QtWidgets.QLabel(self.centralwidget) font = QtGui.QFont() font.setPointSize(10) self.label_18.setFont(font) self.label_18.setObjectName("label_18") self.gridLayout.addWidget(self.label_18, 14, 6, 1, 1) self.SonnenschutzInput = QtWidgets.QLineEdit(self.centralwidget) font = QtGui.QFont() font.setPointSize(10) self.SonnenschutzInput.setFont(font) self.SonnenschutzInput.setObjectName("SonnenschutzInput") self.gridLayout.addWidget(self.SonnenschutzInput, 17, 1, 1, 2) self.startTempInput = QtWidgets.QLineEdit(self.centralwidget) self.startTempInput.setMaximumSize(QtCore.QSize(100, 16777215)) font = QtGui.QFont() font.setPointSize(10) self.startTempInput.setFont(font) self.startTempInput.setObjectName("startTempInput") self.gridLayout.addWidget(self.startTempInput, 3, 1, 1, 1) self.MechLueftenInput = QtWidgets.QLineEdit(self.centralwidget) font = QtGui.QFont() font.setPointSize(10) self.MechLueftenInput.setFont(font) self.MechLueftenInput.setObjectName("MechLueftenInput") self.gridLayout.addWidget(self.MechLueftenInput, 19, 1, 1, 2) self.startSimulation = QtWidgets.QPushButton(self.centralwidget) font = QtGui.QFont() font.setPointSize(10) self.startSimulation.setFont(font) self.startSimulation.setObjectName("startSimulation") self.gridLayout.addWidget(self.startSimulation, 20, 4, 1, 2) self.label_16 = QtWidgets.QLabel(self.centralwidget) font = QtGui.QFont() font.setPointSize(10) self.label_16.setFont(font) self.label_16.setObjectName("label_16") self.gridLayout.addWidget(self.label_16, 16, 0, 1, 1) self.label_11 = QtWidgets.QLabel(self.centralwidget) font = QtGui.QFont() font.setPointSize(10) self.label_11.setFont(font) self.label_11.setObjectName("label_11") self.gridLayout.addWidget(self.label_11, 18, 3, 1, 1) self.label_6 = QtWidgets.QLabel(self.centralwidget) font = QtGui.QFont() font.setPointSize(10) self.label_6.setFont(font) self.label_6.setObjectName("label_6") self.gridLayout.addWidget(self.label_6, 15, 0, 1, 1) self.CustomSonnenschutzInput = QtWidgets.QLineEdit(self.centralwidget) font = QtGui.QFont() font.setPointSize(10) self.CustomSonnenschutzInput.setFont(font) self.CustomSonnenschutzInput.setObjectName("CustomSonnenschutzInput") self.gridLayout.addWidget(self.CustomSonnenschutzInput, 15, 5, 1, 1) self.label_13 = QtWidgets.QLabel(self.centralwidget) font = QtGui.QFont() font.setPointSize(10) self.label_13.setFont(font) self.label_13.setObjectName("label_13") self.gridLayout.addWidget(self.label_13, 19, 0, 1, 1) self.progressBar = QtWidgets.QProgressBar(self.centralwidget) self.progressBar.setMinimumSize(QtCore.QSize(0, 0)) font = QtGui.QFont() font.setPointSize(10) self.progressBar.setFont(font) self.progressBar.setProperty("value", 24) self.progressBar.setObjectName("progressBar") self.gridLayout.addWidget(self.progressBar, 20, 0, 1, 4) self.label_10 = QtWidgets.QLabel(self.centralwidget) font = QtGui.QFont() font.setPointSize(10) self.label_10.setFont(font) self.label_10.setObjectName("label_10") self.gridLayout.addWidget(self.label_10, 11, 0, 1, 1) self.label_15 = QtWidgets.QLabel(self.centralwidget) font = QtGui.QFont() font.setPointSize(10) self.label_15.setFont(font) self.label_15.setObjectName("label_15") self.gridLayout.addWidget(self.label_15, 16, 3, 1, 1) self.labelStandort = QtWidgets.QLabel(self.centralwidget) font = QtGui.QFont() font.setPointSize(10) font.setBold(True) font.setWeight(75) self.labelStandort.setFont(font) self.labelStandort.setObjectName("labelStandort") self.gridLayout.addWidget(self.labelStandort, 10, 0, 1, 2) self.label_24 = QtWidgets.QLabel(self.centralwidget) font = QtGui.QFont() font.setPointSize(10) self.label_24.setFont(font) self.label_24.setObjectName("label_24") self.gridLayout.addWidget(self.label_24, 16, 6, 1, 1) self.zeitschrittInput = QtWidgets.QLineEdit(self.centralwidget) self.zeitschrittInput.setMaximumSize(QtCore.QSize(100, 16777215)) font = QtGui.QFont() font.setPointSize(10) self.zeitschrittInput.setFont(font) self.zeitschrittInput.setObjectName("zeitschrittInput") self.gridLayout.addWidget(self.zeitschrittInput, 1, 1, 1, 1) self.label_5 = QtWidgets.QLabel(self.centralwidget) font = QtGui.QFont() font.setPointSize(10) self.label_5.setFont(font) self.label_5.setObjectName("label_5") self.gridLayout.addWidget(self.label_5, 15, 3, 1, 1) self.label_21 = QtWidgets.QLabel(self.centralwidget) self.label_21.setText("") self.label_21.setObjectName("label_21") self.gridLayout.addWidget(self.label_21, 6, 1, 1, 1) self.label_7 = QtWidgets.QLabel(self.centralwidget) font = QtGui.QFont() font.setPointSize(10) self.label_7.setFont(font) self.label_7.setObjectName("label_7") self.gridLayout.addWidget(self.label_7, 17, 3, 1, 1) self.stopSimulation = QtWidgets.QPushButton(self.centralwidget) font = QtGui.QFont() font.setPointSize(10) self.stopSimulation.setFont(font) self.stopSimulation.setObjectName("stopSimulation") self.gridLayout.addWidget(self.stopSimulation, 20, 6, 1, 1) self.label_22 = QtWidgets.QLabel(self.centralwidget) font = QtGui.QFont() font.setPointSize(10) self.label_22.setFont(font) self.label_22.setObjectName("label_22") self.gridLayout.addWidget(self.label_22, 2, 0, 1, 1) self.genauigkeitInput = QtWidgets.QLineEdit(self.centralwidget) self.genauigkeitInput.setMaximumSize(QtCore.QSize(100, 16777215)) font = QtGui.QFont() font.setPointSize(10) self.genauigkeitInput.setFont(font) self.genauigkeitInput.setObjectName("genauigkeitInput") self.gridLayout.addWidget(self.genauigkeitInput, 2, 1, 1, 1) self.label_26 = QtWidgets.QLabel(self.centralwidget) font = QtGui.QFont() font.setPointSize(10) self.label_26.setFont(font) self.label_26.setObjectName("label_26") self.gridLayout.addWidget(self.label_26, 3, 0, 1, 1) self.label_25 = QtWidgets.QLabel(self.centralwidget) font = QtGui.QFont() font.setPointSize(10) self.label_25.setFont(font) self.label_25.setObjectName("label_25") self.gridLayout.addWidget(self.label_25, 3, 2, 1, 1) self.label_9 = QtWidgets.QLabel(self.centralwidget) self.label_9.setMaximumSize(QtCore.QSize(14, 22)) font = QtGui.QFont() font.setPointSize(10) self.label_9.setFont(font) self.label_9.setObjectName("label_9") self.gridLayout.addWidget(self.label_9, 11, 2, 1, 1) self.SeehoeheInput = QtWidgets.QLineEdit(self.centralwidget) self.SeehoeheInput.setMaximumSize(QtCore.QSize(100, 16777215)) font = QtGui.QFont() font.setPointSize(10) self.SeehoeheInput.setFont(font) self.SeehoeheInput.setObjectName("SeehoeheInput") self.gridLayout.addWidget(self.SeehoeheInput, 11, 1, 1, 1) self.graphWidget = PlotWidget(self.centralwidget) self.graphWidget.setMinimumSize(QtCore.QSize(0, 0)) self.graphWidget.setObjectName("graphWidget") self.gridLayout.addWidget(self.graphWidget, 1, 3, 11, 4) MainWindow.setCentralWidget(self.centralwidget) self.statusbar = QtWidgets.QStatusBar(MainWindow) self.statusbar.setObjectName("statusbar") MainWindow.setStatusBar(self.statusbar) self.retranslateUi(MainWindow) QtCore.QMetaObject.connectSlotsByName(MainWindow) # to here '-------------------Multithreading------------------------' self.threadpool = QThreadPool() print("Multithreading with maximum %d threads" % self.threadpool.maxThreadCount()) '-------------------Events--------------------------------' #Hier werden alle Events von Buttons verwaltet self.startSimulation.clicked.connect(self.Simulation) self.stopSimulation.clicked.connect(self.Stop) self.x = list(range(96)) # initializing plot x axis self.y = [float(self.startTempInput.text())] * 96 # initializing plot y axis self.graphWidget.setBackground('w') pen = pg.mkPen(color=(51, 51, 255)) self.data_line = self.graphWidget.plot(self.x, self.y, pen=pen) self.graphWidget.getPlotItem().hideAxis('bottom') self.timer = QtCore.QTimer() self.timer.setInterval(200) self.timer.timeout.connect(self.update_plot_data) self.timer.start() self.line = 0 self.progress = 0 self.progressLimit = 100 def update_plot_data(self): abbruchTxt = open('Abbruch.txt', 'r') if abbruchTxt.read() == 'False' and self.progress < self.progressLimit: #Umrechnung des Simulationsfortschrittes in Prozent indexTxt = open('index.txt', 'r') indexTxtLines = indexTxt.readlines() for i in range(len(indexTxtLines)): indexTxtLines[i] = indexTxtLines[i].replace('\n', '') self.progress = float(indexTxtLines[len(indexTxtLines) - 1]) * float(self.zeitschrittInput.text()) / 86400 * 100 self.progressBar.setProperty("value", self.progress) self.textEditCalcInfo.setText(open('time.txt', 'r').read()) else: self.progressBar.setProperty("value", 0) self.progress = 0 #Dynamic graph plot update for Qtimer filename = 'graphTop.txt' if os.stat(filename).st_size != 0: if self.line == 0: time.sleep(0.2) file = open(filename) fileLines = file.readlines() for i in range(len(fileLines)): fileLines[i] = fileLines[i].replace('\n', '') self.x = self.x[1:] # Remove the first y element. self.x.append(self.x[-1] + 1) # Add a new value 1 higher than the last. self.y = self.y[1:] # Remove the first self.y.append(float(fileLines[self.line])) # Add a new value. self.data_line.setData(self.x, self.y) # Update the data. file.close() self.line += 1 #self.counter += 1 if self.line == len(fileLines): self.line = 0 else: print('No Data') self.x = self.x[1:] # Remove the first x element. self.x.append(self.x[-1] + 1) # Add a new value 1 higher than the last. self.y = self.y[1:] # Remove the first self.y.append(float(self.startTempInput.text())) # Add a new value. self.data_line.setData(self.x, self.y) #here the functions for the workers are defined def SUe3_fn_worker(self, progress_callback): open('graphTop.txt', 'w').close() SUe3(float(self.zeitschrittInput.text()), float(self.genauigkeitInput.text()), float(self.startTempInput.text()), bool(int(self.idealLueftenInput.text())), bool(int(self.NachtlueftenInput.text())), bool(int(self.TaglueftenInput.text())), bool(int(self.SonnenschutzInput.text())), bool(int(self.NatLueftenInput.text())), bool(int(self.MechLueftenInput.text())), float(self.SeehoeheInput.text()), bool(int(self.CustomLueftenInput.text())), bool(int(self.CustomSonnenschutzInput.text())), bool(int(self.CustomInnereLastenInput.text()))) '------------------Functions by PyQt5--------------------' #copy after changes in .ui by Designer from here def retranslateUi(self, MainWindow): _translate = QtCore.QCoreApplication.translate MainWindow.setWindowTitle(_translate("MainWindow", "SUe-Thermischer Komfort")) self.labelHKLS.setText(_translate("MainWindow", "HKLS-Steuerung (automatisch)")) self.label_19.setText(_translate("MainWindow", "1 = Ja // 0 = Nein")) self.labelSimpara.setText(_translate("MainWindow", "Simulationsparameter")) self.labelHKLS_2.setText(_translate("MainWindow", "HKLS-Steuerung (aus Input Datei)")) self.label_17.setText(_translate("MainWindow", "Lüften")) self.idealLueftenInput.setText(_translate("MainWindow", "1")) self.textEditCalcInfo.setHtml(_translate("MainWindow", "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0//EN\" \"http://www.w3.org/TR/REC-html40/strict.dtd\">\n" "<html><head><meta name=\"qrichtext\" content=\"1\" /><style type=\"text/css\">\n" "p, li { white-space: pre-wrap; }\n" "</style></head><body style=\" font-family:\'MS Shell Dlg 2\'; font-size:8.25pt; font-weight:400; font-style:normal;\">\n" "<p style=\"-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\"><br /></p></body></html>")) self.CustomLueftenInput.setText(_translate("MainWindow", "0")) self.CustomInnereLastenInput.setText(_translate("MainWindow", "1")) self.NatLueftenInput.setText(_translate("MainWindow", "1")) self.label_20.setText(_translate("MainWindow", "Sonnenschutz")) self.NachtlueftenInput.setText(_translate("MainWindow", "0")) self.TaglueftenInput.setText(_translate("MainWindow", "1")) self.label_14.setText(_translate("MainWindow", "1 = Ja // 0 = Nein")) self.label_4.setText(_translate("MainWindow", "1 = Ja // 0 = Nein")) self.label_23.setText(_translate("MainWindow", "Innere Lasten")) self.label_2.setText(_translate("MainWindow", "s")) self.label_8.setText(_translate("MainWindow", "Sonnenschutz")) self.label_12.setText(_translate("MainWindow", "Nat. Lüftung")) self.label.setText(_translate("MainWindow", "Zeitschritt")) self.label_3.setText(_translate("MainWindow", "ideal Lüften")) self.label_18.setText(_translate("MainWindow", "1 = Ja // 0 = Nein")) self.SonnenschutzInput.setText(_translate("MainWindow", "0")) self.startTempInput.setText(_translate("MainWindow", "30")) self.MechLueftenInput.setText(_translate("MainWindow", "0")) self.startSimulation.setText(_translate("MainWindow", "Start")) self.label_16.setText(_translate("MainWindow", "Taglüften")) self.label_11.setText(_translate("MainWindow", "1 = Ja // 0 = Nein")) self.label_6.setText(_translate("MainWindow", "Nachtlüften")) self.CustomSonnenschutzInput.setText(_translate("MainWindow", "0")) self.label_13.setText(_translate("MainWindow", "Mech. Lüftung")) self.label_10.setText(_translate("MainWindow", "Seehöhe")) self.SeehoeheInput.setText(_translate("MainWindow", "172")) self.label_15.setText(_translate("MainWindow", "1 = Ja // 0 = Nein")) self.labelStandort.setText(_translate("MainWindow", "Standort")) self.label_24.setText(_translate("MainWindow", "1 = Ja // 0 = Nein")) self.zeitschrittInput.setText(_translate("MainWindow", "10")) self.label_5.setText(_translate("MainWindow", "1 = Ja // 0 = Nein")) self.label_7.setText(_translate("MainWindow", "1 = Ja // 0 = Nein")) self.stopSimulation.setText(_translate("MainWindow", "Stop")) self.label_22.setText(_translate("MainWindow", "Genauigkeit")) self.genauigkeitInput.setText(_translate("MainWindow", "1e-3")) self.label_26.setText(_translate("MainWindow", "Starttemperatur")) self.label_25.setText(_translate("MainWindow", "°C")) self.label_9.setText(_translate("MainWindow", "m")) #to here '----------------------Funktionen----------------------------' #Hier finden sich alle selbst geschriebenen Funktionen zu den Events def Simulation(self): file = open('Abbruch.txt', 'w') file.write('False') self.line = 0 open('graphTop.txt', 'w').close() open('time.txt', 'w').close() #SUe3(float(self.zeitschrittInput.text()), float(self.genauigkeitInput.text()), float(self.startTempInput.text()), bool(int(self.idealLueftenInput.text())), bool(int(self.NachtlueftenInput.text())), # bool(int(self.TaglueftenInput.text())), bool(int(self.SonnenschutzInput.text())), bool(int(self.NatLueftenInput.text())), bool(int(self.MechLueftenInput.text())), # float(self.SeehoeheInput.text()), bool(int(self.CustomLueftenInput.text())), bool(int(self.CustomSonnenschutzInput.text())), bool(int(self.CustomInnereLastenInput.text()))) worker1 = Worker(self.SUe3_fn_worker) # any other args, kwargs are passed to the run function # execute self.threadpool.start(worker1) def Stop(self): file = open('Abbruch.txt', 'w') file.write('True') self.line = 0 open('graphTop.txt', 'w').close() open('time.txt', 'w').close()
class MesCourbes(): def __init__(self): self.plot_widget = PlotWidget() self.plot_widget.showGrid(x=True,y=True) # self.plot_widget.getPlotItem().addLegend() self.plot_widget.setBackground((0, 0, 0)) # dictionary with all the curve and their data # curve 0 is dedicated to the live/acquisition plot self.curves = {} def add_curve(self, curve_id, curve_color, markers_on=False): curve_name = curve_id pen = pg.mkPen(curve_color, width=3) symbol = "o" symbolPen = pg.mkPen(0,0,0) symbolBrush = curve_color symbolSize = 8 # this adds the item to the plot and legend if markers_on: plot = self.plot_widget.plot( name=curve_name, pen=pen, symbol=symbol, symbolPen=symbolPen, symbolBrush=symbolBrush, symbolSize=symbolSize ) else: plot = self.plot_widget.plot(name=curve_name, pen=pen) self.curves[curve_id] = { 'plot':plot, 'data':{'Current':[],'X':[],'Y':[],'R':[],'Phi':[]} } def average(self,curve_id,param_tree): current_min = param_tree.give('Laser Driver','current min') current_max = param_tree.give('Laser Driver','current max') nbr_pts = param_tree.give('Laser Driver','nbr pts') nbr_seqs = param_tree.give('Laser Driver','nbr seqs') current_list = np.linspace(current_min,current_max,nbr_pts) self.curves[curve_id]['data']['Current'] = current_list for k in ['X','Y','R','Phi']: temp = self.curves[curve_id]['data'][k] self.curves[curve_id]['data'][k] = toolbox.function.average(temp,nbr_seqs) def clear_data(self,curve_id): for k in ['Current','X','Y','R','Phi']: self.curves[curve_id]['data'][k] = [] def create_current_list(self,curve_id,param_tree): ''' Create a array with all the frequency use for the frequency sweep It take into account if many sequences have been asked ''' current_min = param_tree.give('Laser Driver','current min') current_max = param_tree.give('Laser Driver','current max') nbr_pts = param_tree.give('Laser Driver','nbr pts') nbr_seqs = param_tree.give('Laser Driver','nbr seqs') current_list = np.linspace(current_min,current_max,nbr_pts) if nbr_seqs > 1: temp = current_list i=0 while i < int(nbr_seqs)-1: i+=1 current_list = np.append(current_list,temp[::(-1)**i]) self.curves[curve_id]['data']['Current'] = current_list def display(self,curve_id,what): X = self.curves[curve_id]['data']['Current'] Y = self.curves[curve_id]['data'][what] # during acquisition freq is longer than the others datas # so it is useful to reduce it if len(X) != len(Y): X = self.curves[curve_id]['data']['Current'][0:len(Y)] self.set_values(curve_id,X,Y) def remove_curve(self, curve_id): curve_id = str(curve_id) if curve_id in self.curves: self.plot_widget.removeItem(self.curves[curve_id]['plot']) del self.curves[curve_id] def set_values(self, curve_id, data_x, data_y): curve = self.curves[curve_id]['plot'] curve.setData(data_x, data_y) def update_X_Y_R_Phi(self,curve_id,A): self.curves[curve_id]['data']['X'] = np.append(self.curves[curve_id]['data']['X'],A[0]) self.curves[curve_id]['data']['Y'] = np.append(self.curves[curve_id]['data']['Y'],A[1]) self.curves[curve_id]['data']['R'] = np.append(self.curves[curve_id]['data']['R'],A[2]) self.curves[curve_id]['data']['Phi'] = np.append(self.curves[curve_id]['data']['Phi'],A[3])
class PyQtGraphDataPlot(QWidget): limits_changed = Signal() def __init__(self, parent=None): super(PyQtGraphDataPlot, self).__init__(parent) self._plot_widget = PlotWidget() self._plot_widget.getPlotItem().addLegend() self._plot_widget.setBackground((255, 255, 255)) self._plot_widget.setXRange(0, 10, padding=0) vbox = QVBoxLayout() vbox.addWidget(self._plot_widget) self.setLayout(vbox) self._plot_widget.getPlotItem().sigRangeChanged.connect( self.limits_changed) self._curves = {} self._current_vline = None def add_curve(self, curve_id, curve_name, curve_color=QColor(Qt.blue), markers_on=False): pen = mkPen(curve_color, width=1) symbol = "o" symbolPen = mkPen(QColor(Qt.black)) symbolBrush = mkBrush(curve_color) # this adds the item to the plot and legend if markers_on: plot = self._plot_widget.plot(name=curve_name, pen=pen, symbol=symbol, symbolPen=symbolPen, symbolBrush=symbolBrush, symbolSize=4) else: plot = self._plot_widget.plot(name=curve_name, pen=pen) self._curves[curve_id] = plot def remove_curve(self, curve_id): curve_id = str(curve_id) if curve_id in self._curves: self._plot_widget.removeItem(self._curves[curve_id]) del self._curves[curve_id] self._update_legend() def _update_legend(self): # clear and rebuild legend (there is no remove item method for the legend...) self._plot_widget.clear() self._plot_widget.getPlotItem().legend.items = [] for curve in self._curves.values(): self._plot_widget.addItem(curve) if self._current_vline: self._plot_widget.addItem(self._current_vline) def redraw(self): pass def set_values(self, curve_id, data_x, data_y): curve = self._curves[curve_id] curve.setData(data_x, data_y) def vline(self, x, color): if self._current_vline: self._plot_widget.removeItem(self._current_vline) self._current_vline = self._plot_widget.addLine(x=x, pen=color) def set_xlim(self, limits): # TODO: this doesn't seem to handle fast updates well self._plot_widget.setXRange(limits[0], limits[1], padding=0) def set_ylim(self, limits): self._plot_widget.setYRange(limits[0], limits[1], padding=0) def get_xlim(self): x_range, _ = self._plot_widget.viewRange() return x_range def get_ylim(self): _, y_range = self._plot_widget.viewRange() return y_range
class FindPeak(QWidget): def __init__(self, parent, x_data, y_data): super(FindPeak, self).__init__() self.parent = parent self.x = x_data self.y = y_data self.lower = np.min(x_data) self.upper = np.max(x_data) self.range = self.upper - self.lower self.renderWindow() self.initPlotView() self.drawCurve() self.setUpProcessUI() self.bindEvents() self.integral(x_data, y_data, self.lower, self.upper) def bindEvents(self): self.bindBoundEvent() self.bindAlgorithmEvent() self.bindFindEvent() def bindBoundEvent(self): def leftBoundEvent(x): self.lower = x upper = self.upper self.plotRegion.setRegion([x, upper]) self.rightBound.setMinimum(x) self.peakCenter.setMinimum(x) self.peakCenter.setValue((x + upper) / 2) self.integral(self.x, self.y, x, upper) def rightBoundEvent(x): self.upper = x lower = self.lower self.plotRegion.setRegion([lower, x]) self.leftBound.setMaximum(x) self.peakCenter.setMaximum(x) self.peakCenter.setValue((x + lower) / 2) self.integral(self.x, self.y, lower, x) def regionChangeEvent(): lower, upper = self.plotRegion.getRegion() self.lower = lower self.upper = upper self.leftBound.setValue(lower) self.leftBound.setMaximum(upper) self.rightBound.setValue(upper) self.rightBound.setMinimum(lower) self.peakCenter.setMinimum(lower) self.peakCenter.setMaximum(upper) self.peakCenter.setValue((lower + upper) / 2) self.integral(self.x, self.y, lower, upper) self.leftBound.valueChanged.connect(leftBoundEvent) self.rightBound.valueChanged.connect(rightBoundEvent) self.plotRegion.sigRegionChanged.connect(regionChangeEvent) def bindAlgorithmEvent(self): def updateInput(a, b, c, d, e, f): self.peakWidth.setEnabled(a) self.detectDis.setEnabled(b) self.noisePrt.setEnabled(c) self.amplitude.setEnabled(d) self.threshold.setEnabled(e) self.findBtn.setEnabled(f) def changeAlgorithm(algorithm): if algorithm == "Extremum": updateInput(False, False, False, False, False, True) pass elif algorithm == "Matlab Like": updateInput(True, True, False, True, True, True) pass elif algorithm == "Gaussian": updateInput(False, False, False, False, False, False) pass elif algorithm == "Lorentzian": updateInput(False, False, False, False, False, False) pass elif algorithm == "Pseudo-Voigt": updateInput(False, False, False, False, False, False) pass elif algorithm == "Wavelet Transform": updateInput(True, True, True, False, False, False) pass self.algorithm.currentTextChanged.connect(changeAlgorithm) updateInput(False, False, False, False, False, True) def integral(self, x_data, y_data, lower, upper): idx = np.where((x_data >= lower) & (x_data <= upper)) x = x_data[idx] y = y_data[idx] self.integralArea.setValue(simps(y, x)) def bindFindEvent(self): x_data = self.x y_data = self.y def findPeak(): region = np.where((x_data >= self.lower) & (x_data <= self.upper)) sub_data = y_data[region] sub_region = x_data[region] algorithm = self.algorithm.currentText() shape = self.shape.currentText() if shape == "Peak": const = 1 else: const = -1 sub_data = sub_data * const if algorithm == "Extremum": peak = np.max(sub_data) idx = np.where(sub_data == peak) x = sub_region[idx][0] y = sub_data[idx][0] * const self.peakCenter.setValue(x) return self.renderPeakPoint([x, y]) elif algorithm == "Matlab Like": indexes = find_peaks( sub_data, height=self.amplitude.value(), #低于指定高度忽略 threshold=self.threshold.value(), #相邻两点高度差 distance=self.detectDis.value(), #两峰间距 width=self.peakWidth.value() #峰宽 )[0] if np.size(indexes) == 0: return idx = np.where(sub_data == np.max(sub_data[indexes])) x = sub_region[idx][0] y = sub_data[idx][0] * const self.peakCenter.setValue(x) return self.renderPeakPoint([x, y]) elif algorithm == "Wavelet Transform": indexes = find_peaks_cwt( sub_data, widths=self.peakWidth.value(), #峰宽 max_distances=self.detectDis.value(), #两峰间距 noise_perc=self.noisePrt.value())[0] if np.size(indexes) == 0: return idx = np.where(sub_data == np.max(sub_data[indexes])) x = sub_region[idx][0] y = sub_data[idx][0] * const self.peakCenter.setValue(x) return self.renderPeakPoint([x, y]) self.noisePrt pass self.findBtn.clicked.connect(findPeak) def renderPeakPoint(self, pos): self.peakPoint.clear() self.peakPoint.addPoints([{'pos': pos, 'data': 1}]) def renderWindow(self): #边框结构 self.setGeometry(80, 80, 800, 420) size = self.geometry() screen = QDesktopWidget().screenGeometry() posX = (screen.width() - size.width()) / 2 posY = (screen.height() - size.height()) / 2 self.move(posX, posY) #标题 self.setWindowTitle('Find Peak') self.setWindowIcon(QIcon('resource/curve.ico')) #布局 layout = QGridLayout() self.graphicsView = QGridLayout() layout.addLayout(self.graphicsView, 0, 0, 1, 1) self.Process_Box = QGroupBox() self.Process_Box.setMinimumSize(200, 420) self.Process_Box.setFlat(True) layout.addWidget(self.Process_Box, 0, 1, 1, 1) self.setLayout(layout) def setUpProcessUI(self): layout = QGridLayout() layout.setContentsMargins(10, 10, 10, 10) layout.setSpacing(10) self.Process_Box.setLayout(layout) layout.addWidget(QLabel(self.translate('Left Boundary')), 0, 0, 1, 1) layout.addWidget(QLabel(self.translate('Right Boundary')), 1, 0, 1, 1) layout.addWidget(QLabel(self.translate("Integral Area")), 2, 0, 1, 1) layout.addWidget(QLabel(self.translate('Peak Center')), 3, 0, 1, 1) layout.addWidget(QLabel(self.translate('Peak Shape')), 4, 0, 1, 1) layout.addWidget(QLabel(self.translate('Find Peak Algorithm')), 5, 0, 1, 1) layout.addWidget(QLabel(self.translate('Minimum Peak Width')), 6, 0, 1, 1) layout.addWidget(QLabel(self.translate('Minimum Detect Distance')), 7, 0, 1, 1) layout.addWidget(QLabel(self.translate('Noise Percent')), 8, 0, 1, 1) layout.addWidget(QLabel(self.translate("Minimum Amplitude")), 9, 0, 1, 1) layout.addWidget(QLabel(self.translate("Relative Threshold")), 10, 0, 1, 1) self.leftBound = SpinBox(lower=self.lower, dec=4, val=self.lower) self.rightBound = SpinBox(upper=self.upper, dec=4, val=self.upper) self.peakCenter = SpinBox(lower=self.lower, upper=self.upper, dec=4) self.peakWidth = SpinBox(lower=1, upper=10000, val=5) self.noisePrt = SpinBox(lower=0, upper=100, step=1, val=10) self.detectDis = SpinBox(lower=1, val=3) self.amplitude = SpinBox(lower=-1E5, upper=1E5, dec=4, val=-1) self.threshold = SpinBox(lower=0, upper=100, dec=4, val=0.001) self.integralArea = SpinBox(upper=1E8, dec=4) self.integralArea.setReadOnly(True) self.integralArea.setButtonSymbols(QAbstractSpinBox.NoButtons) self.shape = QComboBox() self.shape.addItems(["Peak", "Valley"]) #self.shape.currentTextChanged.connect() self.algorithm = QComboBox() self.algorithm.addItems([ 'Extremum', 'Matlab Like', 'Wavelet Transform', 'Gaussian', 'Lorentzian', 'Pseudo-Voigt' ]) #self.algorithm.currentTextChanged.connect() #https://docs.scipy.org/doc/scipy/reference/generated/scipy.signal.find_peaks_cwt.html layout.addWidget(self.leftBound, 0, 1, 1, 1) layout.addWidget(self.rightBound, 1, 1, 1, 1) layout.addWidget(self.integralArea, 2, 1, 1, 1) layout.addWidget(self.peakCenter, 3, 1, 1, 1) layout.addWidget(self.shape, 4, 1, 1, 1) layout.addWidget(self.algorithm, 5, 1, 1, 1) layout.addWidget(self.peakWidth, 6, 1, 1, 1) layout.addWidget(self.detectDis, 7, 1, 1, 1) layout.addWidget(self.noisePrt, 8, 1, 1, 1) layout.addWidget(self.amplitude, 9, 1, 1, 1) layout.addWidget(self.threshold, 10, 1, 1, 1) self.findBtn = QPushButton(self.translate('Find Peak')) layout.addWidget(self.findBtn, 11, 0, 1, 2) pass def initPlotView(self): self.plot = PlotWidget(enableAutoRange=True) self.plot.setXRange(self.lower - self.range * 0.05, self.upper + self.range * 0.05) self.plotLegand = self.plot.addLegend() self.graphicsView.addWidget(self.plot) self.plotRegion = LinearRegionItem() self.plotRegion.setZValue(10) self.peakPoint = ScatterPlotItem(size=8, pen=mkPen(color='0000FF', width=2), symbol="+", brush=mkBrush(255, 255, 255, 240)) self.plot.addItem(self.plotRegion, ignoreBounds=True) self.plot.addItem(self.peakPoint) self.setGraphViewStyle() def setGraphViewStyle(self): self.plot.setAutoVisible(y=True) self.plot.setBackground('#ffffff') self.plot.showGrid(x=True, y=True, alpha=0.25) self.plot.getAxis('bottom').setPen(color='#000000', width=1.5) self.plot.getAxis('left').setPen(color='#000000', width=1.5) self.plotRegion.setRegion([self.lower, self.upper]) self.plotRegion.setBounds([self.lower, self.upper]) def drawCurve(self): pen = mkPen(color='FF0000', width=2) self.plot.plot(self.x, self.y, pen=pen) self.plot.show() def translate(self, text): if self.parent: self.langText = self.parent.langText else: self.langText = load(open('SCN.translation', encoding='utf-8')) if text in self.langText: return self.langText[text] return text
class Ui_Op2(object): def setupUi(self, Op2): listChem = Equilibrium() Op2.setObjectName("Op2") Op2.resize(950, 640) Op2.setMinimumSize(QtCore.QSize(950, 640)) Op2.setMaximumSize(QtCore.QSize(950, 640)) Op2.setWindowIcon(QtGui.QIcon('images\Icone.jpg')) Op2.setFocusPolicy(QtCore.Qt.NoFocus) Op2.setToolButtonStyle(QtCore.Qt.ToolButtonIconOnly) self.centralwidget = QtWidgets.QWidget(Op2) self.centralwidget.setObjectName("centralwidget") self.line = QtWidgets.QFrame(self.centralwidget) self.line.setGeometry(QtCore.QRect(0, -1, 951, 16)) self.line.setFrameShape(QtWidgets.QFrame.HLine) self.line.setFrameShadow(QtWidgets.QFrame.Sunken) self.line.setObjectName("line") self.line_2 = QtWidgets.QFrame(self.centralwidget) self.line_2.setGeometry(QtCore.QRect(0, 470, 961, 20)) self.line_2.setFrameShape(QtWidgets.QFrame.HLine) self.line_2.setFrameShadow(QtWidgets.QFrame.Sunken) self.line_2.setObjectName("line_2") self.graphicPlot = QtWidgets.QPushButton(self.centralwidget) self.graphicPlot.setGeometry(QtCore.QRect(480, 520, 161, 51)) font = QtGui.QFont() font.setPointSize(11) font.setBold(True) font.setWeight(75) self.graphicPlot.setFont(font) self.graphicPlot.setObjectName("graphicPlot") self.graphics1 = PlotWidget(self.centralwidget) self.graphics1.setGeometry(QtCore.QRect(10, 10, 461, 401)) self.graphics1.setBackground('w') self.graphics1.showGrid(x=True, y=True) self.graphics1.setObjectName("graphics1") self.graphics2 = PlotWidget(self.centralwidget) self.graphics2.setGeometry(QtCore.QRect(480, 10, 461, 401)) self.graphics2.setBackground('w') self.graphics2.showGrid(x=True, y=True) self.graphics2.setObjectName("graphics2") self.verticalLayoutWidget = QtWidgets.QWidget(self.centralwidget) self.verticalLayoutWidget.setGeometry(QtCore.QRect(310, 520, 171, 51)) self.verticalLayoutWidget.setObjectName("verticalLayoutWidget") self.verticalLayout_2 = QtWidgets.QVBoxLayout( self.verticalLayoutWidget) self.verticalLayout_2.setContentsMargins(0, 0, 0, 0) self.verticalLayout_2.setObjectName("verticalLayout_2") self.pconst = QtWidgets.QRadioButton(self.verticalLayoutWidget) self.pconst.setEnabled(True) self.pconst.setCheckable(True) self.pconst.setChecked(False) self.pconst.setObjectName("pconst") self.verticalLayout_2.addWidget(self.pconst) self.tconst = QtWidgets.QRadioButton(self.verticalLayoutWidget) self.tconst.setChecked(True) self.tconst.setObjectName("tconst") self.verticalLayout_2.addWidget(self.tconst) self.horizontalLayoutWidget = QtWidgets.QWidget(self.centralwidget) self.horizontalLayoutWidget.setGeometry(QtCore.QRect( 310, 490, 331, 31)) self.horizontalLayoutWidget.setObjectName("horizontalLayoutWidget") self.horizontalLayout = QtWidgets.QHBoxLayout( self.horizontalLayoutWidget) self.horizontalLayout.setContentsMargins(0, 0, 0, 0) self.horizontalLayout.setObjectName("horizontalLayout") spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) self.horizontalLayout.addItem(spacerItem) self.changeTextVar = QtWidgets.QLabel(self.horizontalLayoutWidget) font = QtGui.QFont() font.setPointSize(11) font.setBold(True) font.setWeight(75) self.changeTextVar.setFont(font) self.changeTextVar.setObjectName("changeTextVar") self.horizontalLayout.addWidget(self.changeTextVar) self.databox = QtWidgets.QLineEdit(self.horizontalLayoutWidget) font = QtGui.QFont() font.setPointSize(10) self.databox.setFont(font) self.databox.setValidator(QtGui.QDoubleValidator()) self.databox.setCursor(QtGui.QCursor(QtCore.Qt.IBeamCursor)) self.databox.setToolTipDuration(1) self.databox.setObjectName("databox") self.horizontalLayout.addWidget(self.databox) self.changeTextUni = QtWidgets.QLabel(self.horizontalLayoutWidget) font = QtGui.QFont() font.setPointSize(11) font.setBold(True) font.setWeight(75) self.changeTextUni.setFont(font) self.changeTextUni.setObjectName("changeTextUni") self.horizontalLayout.addWidget(self.changeTextUni) spacerItem1 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) self.horizontalLayout.addItem(spacerItem1) self.gridLayoutWidget = QtWidgets.QWidget(self.centralwidget) self.gridLayoutWidget.setGeometry(QtCore.QRect(260, 420, 431, 53)) self.gridLayoutWidget.setObjectName("gridLayoutWidget") self.gridLayout_2 = QtWidgets.QGridLayout(self.gridLayoutWidget) self.gridLayout_2.setContentsMargins(0, 0, 0, 0) self.gridLayout_2.setObjectName("gridLayout_2") self.label_2 = QtWidgets.QLabel(self.gridLayoutWidget) font = QtGui.QFont() font.setPointSize(10) font.setBold(True) font.setWeight(75) self.label_2.setFont(font) self.label_2.setAlignment(QtCore.Qt.AlignCenter) self.label_2.setObjectName("label_2") self.gridLayout_2.addWidget(self.label_2, 0, 1, 1, 1) self.label = QtWidgets.QLabel(self.gridLayoutWidget) font = QtGui.QFont() font.setPointSize(10) font.setBold(True) font.setWeight(75) self.label.setFont(font) self.label.setAlignment(QtCore.Qt.AlignCenter) self.label.setObjectName("label") self.gridLayout_2.addWidget(self.label, 0, 0, 1, 1) self.comp2 = QtWidgets.QComboBox(self.gridLayoutWidget) font = QtGui.QFont() self.comp2.addItems(listChem.chemComp()) font.setPointSize(9) self.comp2.setFont(font) self.comp2.setObjectName("comp2") self.gridLayout_2.addWidget(self.comp2, 1, 1, 1, 1) self.comp1 = QtWidgets.QComboBox(self.gridLayoutWidget) font = QtGui.QFont() self.comp1.addItems(listChem.chemComp()) font.setPointSize(9) self.comp1.setFont(font) self.comp1.setObjectName("comp1") self.gridLayout_2.addWidget(self.comp1, 1, 0, 1, 1) Op2.setCentralWidget(self.centralwidget) self.menubar = QtWidgets.QMenuBar(Op2) self.menubar.setGeometry(QtCore.QRect(0, 0, 950, 21)) self.menubar.setObjectName("menubar") self.menuTools = QtWidgets.QMenu(self.menubar) self.menuTools.setObjectName("menuTools") self.menuAbout = QtWidgets.QMenu(self.menubar) self.menuAbout.setObjectName("menuAbout") Op2.setMenuBar(self.menubar) self.statusbar = QtWidgets.QStatusBar(Op2) self.statusbar.setObjectName("statusbar") Op2.setStatusBar(self.statusbar) self.actionsave2Excel = QtWidgets.QAction(Op2) self.actionsave2Excel.setObjectName("actionsave2Excel") #self.actionsavePlot = QtWidgets.QAction(Op2) #self.actionsavePlot.setObjectName("actionsavePlot") #self.addElement = QtWidgets.QAction(Op2) #self.addElement.setObjectName("addElement") self.about = QtWidgets.QAction(Op2) self.about.setObjectName("about") #self.removeElement = QtWidgets.QAction(Op2) #self.removeElement.setObjectName("removeElement") self.menuTools.addAction(self.actionsave2Excel) #self.menuTools.addAction(self.actionsavePlot) self.menuTools.addSeparator() #self.menuTools.addAction(self.addElement) #self.menuTools.addAction(self.removeElement) self.menuAbout.addAction(self.about) self.menubar.addAction(self.menuTools.menuAction()) self.menubar.addAction(self.menuAbout.menuAction()) self.retranslateUi(Op2) QtCore.QMetaObject.connectSlotsByName(Op2) self.pconst.toggled.connect(lambda: self.selected(self.pconst) ) #Selection RadioButton Pressão Constante self.tconst.toggled.connect(lambda: self.selected( self.tconst)) #Selection RadioButton Temperatura Constante self.graphicPlot.clicked.connect( lambda: self.call(float(self.databox.text( )), self.changeTextUni.text())) #Call the plot function self.actionsave2Excel.triggered.connect(lambda: self.saveData()) self.about.triggered.connect(lambda: self.aboutMsg()) def retranslateUi(self, Op2): _translate = QtCore.QCoreApplication.translate Op2.setWindowTitle(_translate("Op2", "Op_2 App")) self.graphicPlot.setText(_translate("Op2", "Plot")) self.pconst.setText(_translate("Op2", "Constant pressure ")) self.tconst.setText(_translate("Op2", "Constant temperature ")) self.changeTextVar.setText(_translate("Op2", "Temperature")) self.changeTextUni.setText(_translate("Op2", "K")) self.label_2.setText(_translate("Op2", "Substance 2")) self.label.setText(_translate("Op2", "Substance 1")) self.menuTools.setTitle(_translate("Op2", "Tools")) self.menuAbout.setTitle(_translate("Op2", "About")) self.actionsave2Excel.setText(_translate("Op2", "Save data to Excel")) #self.actionsavePlot.setText(_translate("Op2", "Salvar gráficos")) #self.addElement.setText(_translate("Op2", "Adicionar Elemento")) self.about.setText(_translate("Op2", "about")) #self.removeElement.setText(_translate("Op2", "Remover Elemento")) def selected(self, b): if b.text() == "Constant pressure ": if b.isChecked() == True: self.changeTextVar.setText('Pressure') self.changeTextUni.setText("bar") elif b.text() == "Constant temperature ": if b.isChecked() == True: self.changeTextVar.setText('Temperature') self.changeTextUni.setText("K") def call(self, data, signal, n=1000): self.graphics1.clear(), self.graphics2.clear() x = np.arange(0, 1.0 + (1 / n), (1 / n)) y, P, T = np.zeros(np.size(x)), np.zeros(np.size(x)), np.zeros( np.size(x)) if signal == "bar": #Erase float_files if os.path.exists('float_files\\pconstdata.txt'): os.remove('float_files\\pconstdata.txt') try: data = open('float_files\\pconstdata.txt', 'a') newData = Equilibrium( lchem=[self.comp1.currentText(), self.comp2.currentText()], p=float(self.databox.text())) self.A, self.B, self.C, self.Tmax, self.Tmin, self.DG = newData.compData( ) Tsat = ( self.B / (self.A - np.log10(float(self.databox.text())))) - self.C data.write('Temperature [K], x, y\n') for i in range(np.size(x)): T0 = np.sum(np.asarray([x[i], 1 - x[i]]) * Tsat) while (True): a12 = 10**(self.A[0] - self.A[1] - (self.B[0] / (T0 + self.C[0])) + (self.B[1] / (T0 + self.C[1]))) coef = UNIFAC(T=T0, xs=[x[i], 1 - x[i]], chemgroups=self.DG) P2sat = (float(self.databox.text()) / (x[i] * coef[0] * a12 + (1 - x[i]) * coef[1])) Tn = (self.B[1] / (self.A[1] - np.log10(P2sat))) - self.C[1] if (abs(Tn - T0) < 0.001): break T0 = Tn T[i] = T0 y[i] = 1 - ((1 - x[i]) * coef[1] * P2sat) / (float( self.databox.text())) data.write( str(round(T[i], 4)) + ', ' + str(round(x[i], 4)) + ', ' + str(round(y[i], 4))) data.write('\n') self.graphics1.plot(x, y, pen='r') self.graphics1.plot(x, x, pen='r') self.graphics1.setLabel('left', 'Gas composition of ' + self.comp1.currentText(), color='r', size=20) self.graphics1.setLabel('bottom', 'Liquid composition of ' + self.comp1.currentText(), color='b', size=20) self.graphics2.plot(x, T, pen='g') self.graphics2.plot(y, T, pen='k') self.graphics2.setLabel('left', 'Temperature of ' + self.comp1.currentText() + ' [K]', color='r', size=20) self.graphics2.setLabel('bottom', 'Composition of ' + self.comp1.currentText(), color='b', size=20) data.close() except: print('error') elif signal == "K": #Erase float_files if os.path.exists('float_files\\tconstdata.txt'): os.remove('float_files\\tconstdata.txt') try: data = open('float_files\\tconstdata.txt', 'a') newData = Equilibrium( lchem=[self.comp1.currentText(), self.comp2.currentText()], t=float(self.databox.text())) self.A, self.B, self.C, self.Tmax, self.Tmin, self.DG = newData.compData( ) Pvap = 10**(self.A - (self.B / (float(self.databox.text()) + self.C))) data.write('Pressure [bar], x, y\n') for i in range(np.size(x)): actCoef = UNIFAC(T=float(self.databox.text()), xs=[x[i], 1 - x[i]], chemgroups=self.DG) P[i] = np.sum(Pvap * np.asarray(actCoef) * np.asarray([x[i], 1 - x[i]])) y[i] = ((x[i] * actCoef[0] * Pvap[0])) / P[i] data.write( str(round(P[i], 4)) + ', ' + str(round(x[i], 4)) + ', ' + str(round(y[i], 4))) data.write('\n') self.graphics1.plot(x, y, pen='r') self.graphics1.plot(x, x, pen='r') self.graphics1.setLabel('left', 'Gas composition of ' + self.comp1.currentText(), color='r', size=20) self.graphics1.setLabel('bottom', 'Liquid composition of ' + self.comp1.currentText(), color='b', size=20) self.graphics2.plot(x, P, pen='b') self.graphics2.plot(y, P, pen='r') self.graphics2.setLabel('left', 'Pressure of ' + self.comp1.currentText() + ' [bar]', color='r', size=20) self.graphics2.setLabel('bottom', 'Composition of ' + self.comp1.currentText(), color='b', size=20) data.close() except: print('Error!') def saveData(self): if self.changeTextUni.text() == 'bar': try: filename = QtWidgets.QFileDialog.getSaveFileName( caption='Salvar arquivo', directory='c:\\', filter='(*.xlsx)', initialFilter='') data = pd.read_csv('float_files\\pconstdata.txt', sep=', ') data.to_excel(excel_writer=filename[0]) os.remove('float_files\\pconstdata.txt') except: pass elif self.changeTextUni.text() == 'K': try: filename = QtWidgets.QFileDialog.getSaveFileName( caption='Salvar arquivo', directory='c:\\', filter='(*.xlsx)', initialFilter='') data = pd.read_csv('float_files\\tconstdata.txt', sep=', ') data.to_excel(excel_writer=filename[0]) os.remove('float_files\\tconstdata.txt') except: pass def aboutMsg(self): msg = QtWidgets.QMessageBox() msg.setWindowTitle('Sobre') msg.setWindowIcon(QtGui.QIcon('images\Icone.jpg')) msg.setText( 'Programa desenvolvido para calcular o equilíbrio de fase líquido-vapor de um sistema binário com fase vapor ideal e fase liquída não ideal cujo' + ' coeficiente de atividade é obtido por meio do método UNIFAC') x = msg.exec_()
class ControllerGUITab(QWidget): LEFT_COLUMN_MAX_WIDTH = 400 # This signal tells the global tab if is not possible to start dosing for this tab # False is sent out when the dosing vectors are incorrect or when the process is already started dosingSignal = pyqtSignal(bool) # This just signals if saving was enabled/disabled by the user in the tab, so the global tab can update itself savingSignal = pyqtSignal(bool) # Signal when a sample is ready for the combined plot sampleReady = pyqtSignal(int, np.float16) def __init__(self, controller: Controller): super().__init__() # Create the master layout outerLayout = QHBoxLayout() self.graph = None self.controller = controller self.temperatureController = None self.tempControllerGroup = None self.sensor1 = None self.sensor2 = None self.sensor1Group = None self.sensor2Group = None self.vorNormalButton = None self.vorClosedButton = None self.vorOpenButton = None self.gasFactorEdit = None self.pvFullScaleEdit = None self.pvSigtypeDropdown = None self.spFullScaleEdit = None self.spSigtypeDropdown = None self.spSourceDropdown = None self.decimalDropdown = None self.measureUnitsDropdown = None self.timebaseDropdown = None self.bufferSizeEdit = None self.intervalEdit = None self.setpointEdit = None self.setpointUnitsLabel = None self.saveCsvButton = None self.sensor1Timer = None self.sensor1SampleIntervalEdit = None self.sensor1BufferSizeEdit = None self.sensor2Timer = None self.sensor2SampleIntervalEdit = None self.sensor2BufferSizeEdit = None self.temperatureSlider = None self.temperatureLabel = None self.tempReadoutLabel = None self.rangeLowEdit = None self.rangeHighEdit = None self.rampingCheckbox = None self.gradientEdit = None self.tempControlButton = None self.dosingTimesEdit = None self.dosingTimes = None self.dosingValuesEdit = None self.dosingValues = None self.dosingUnitsLabel = None self.dosingLabel = None self.dosingVorStateLabel = None self.dosingControlButton = None self.dosingEnabled = False # Data buffers self.sampleBufferSize = 64 self.samplesPV = RingBuffer(capacity=self.sampleBufferSize, dtype=np.float16) self.samplesTotalizer = RingBuffer(capacity=self.sampleBufferSize, dtype=np.float32) self.sampleTimestamps = RingBuffer(capacity=self.sampleBufferSize, dtype=datetime) # Nest the inner layouts into the outer layout outerLayout.addLayout(self.create_left_column()) outerLayout.addLayout(self.create_right_column()) # Set the window's main layout self.setLayout(outerLayout) # Generic timer that calls generic_update every second # Used to update a few labels self.genericTimer = QTimer() self.genericTimer.timeout.connect(self.update_generic) self.genericTimer.start(1000) self.graphTimer = QTimer() self.graphTimer.timeout.connect(self.update_plot) self.graphTimer.start(int(60 * 1000 * float(self.intervalEdit.text()))) self.dosingValue = None self.dosingTimer = QTimer() self.dosingTimer.timeout.connect(self.dosing_process) self.csvFile = None self.csvIterator = 1 self.defaultStyleSheet = QLineEdit().styleSheet() # Current dosing value, used to set the setpoint edit # text correctly after a process shutdown self.spValue = 1.0 # Get initial dosing values from the text inside self.dosingValues = [ float(x) for x in self.dosingValuesEdit.text().split(sep=',') if x.strip() != '' ] self.dosingTimes = [ float(x) * 60 * 1000 for x in self.dosingTimesEdit.text().split(sep=',') if x.strip() != '' ] self.dosingValues.reverse() self.dosingTimes.reverse() def get_measurement(self): # Proper implementation that gets the data from the device over serial current, total, timestamp = self.controller.get_measurements() if total is not None: self.samplesTotalizer.append(total) self.samplesPV.append(current) self.sampleTimestamps.append(timestamp) self.sampleReady.emit(self.controller.channel, current) # Save samples to a csv file, named after the current time and controller number it is coming from # After this function saving is continued by update_plot function, which calls append_to_csv def save_to_csv_start(self): # If saving is invoked from global tab while it is already enabled, close the old file, # so no sensor data will be lost and it will be closed properly if self.csvFile is not None: self.save_to_csv_stop() filename = datetime.now().strftime( f"controller{self.controller.channel}_%Y-%m-%d_%H-%M-%S.csv") self.csvFile = open(filename, 'w') self.csvFile.write( f"Gas factor:{self.controller.get_gas()}\tDecimal point:{self.controller.get_decimal_point()},\tUnits:{self.controller.get_measurement_units()}/{self.controller.get_time_base()}\n" ) self.csvFile.write("{:<15} {:^18} {:>19}\n".format( "Measurement", "Totalizer", "Time of measurement")) for i in range(0, len(self.samplesPV) - 1): self.csvFile.write("{:<15},{:^18},{:>19}\n".format( self.samplesPV[len(self.samplesPV) - 1], self.samplesTotalizer[len(self.samplesPV) - 1], self.sampleTimestamps[len(self.samplesPV) - 1].strftime("%Y/%m/%d,%H:%M:%S"))) self.saveCsvButton.clicked.disconnect() self.saveCsvButton.clicked.connect(self.save_to_csv_stop) self.saveCsvButton.setText("Stop saving to CSV") self.savingSignal.emit(True) def append_to_csv(self): # check if file is bigger than ~8MB if self.csvFile.tell() > 8192000: name = re.sub( r"(|_[0-9]+).csv", f"_{self.csvIterator}.csv", self.csvFile.name.split("\\")[ len(self.csvFile.name.split("\\")) - 1]) self.csvIterator += 1 self.append_sensor() self.csvFile.close() self.csvFile = open(name, 'w') self.csvFile.write("{:<15},{:^18},{:>19}\n".format( self.samplesPV[len(self.samplesPV) - 1], self.samplesTotalizer[len(self.samplesPV) - 1], self.sampleTimestamps[len(self.samplesPV) - 1].strftime("%Y/%m/%d,%H:%M:%S"))) def save_to_csv_stop(self): self.append_sensor() self.csvFile.close() self.csvFile = None self.saveCsvButton.clicked.disconnect() self.saveCsvButton.clicked.connect(self.save_to_csv_start) self.saveCsvButton.setText("Start saving to CSV") self.csvIterator = 1 self.savingSignal.emit(False) def append_sensor(self): # if available, append data from sensors if self.sensor1 is not None and len(self.sensor1.buffer) > 0: self.csvFile.write(f"Sensor 1 header: {self.sensor1.header}\n") for i in range(0, len(self.sensor1.buffer)): self.csvFile.write(str(self.sensor1.buffer[i])) self.sensor1.buffer.clear() self.csvFile.write('\n') if self.sensor2 is not None and len(self.sensor2.buffer) > 0: self.csvFile.write(f"Sensor 2 header: {self.sensor2.header}\n") for i in range(0, len(self.sensor2.buffer)): self.csvFile.write(str(self.sensor2.buffer[i])) self.sensor2.buffer.clear() # Handler functions for UI elements # TODO: react to returned value from functions def update_vor_normal(self): if self.vorNormalButton.isChecked(): # disable other buttons to clarify which VOR state is active self.vorClosedButton.setChecked(False) self.vorOpenButton.setChecked(False) self.controller.set_valve_override(Controller.VOR_OPTION_NORMAL) self.dosingVorStateLabel.setText("VOR is normal") self.dosingVorStateLabel.setStyleSheet("color: green;") def update_vor_closed(self): if self.vorClosedButton.isChecked(): self.vorNormalButton.setChecked(False) self.vorOpenButton.setChecked(False) self.controller.set_valve_override(Controller.VOR_OPTION_CLOSED) self.dosingVorStateLabel.setText("VOR is closed") self.dosingVorStateLabel.setStyleSheet("color: red;") def update_vor_open(self): if self.vorOpenButton.isChecked(): self.vorClosedButton.setChecked(False) self.vorNormalButton.setChecked(False) self.controller.set_valve_override(Controller.VOR_OPTION_OPEN) self.dosingVorStateLabel.setText("VOR is open") self.dosingVorStateLabel.setStyleSheet("color: red;") def update_gas_factor(self): self.controller.set_gas_factor(float(self.gasFactorEdit.text())) def update_pv_full_scale(self): self.controller.set_pv_full_scale(float(self.pvFullScaleEdit.text())) def update_pv_signal_type(self): self.controller.set_pv_signal_type( self.pvSigtypeDropdown.currentText()) def update_sp_full_scale(self): self.controller.set_sp_full_scale(float(self.spFullScaleEdit.text())) def update_sp_signal_type(self): self.controller.set_sp_signal_type( self.spSigtypeDropdown.currentText()) def update_source(self): self.controller.set_source(self.spSourceDropdown.currentText()) def update_decimal_point(self): self.controller.set_decimal_point(self.decimalDropdown.currentText()) def update_measure_units(self): if self.dosingUnitsLabel is not None: self.dosingUnitsLabel.setText( f"{self.measureUnitsDropdown.currentText()}/{self.timebaseDropdown.currentText()}" ) if self.setpointUnitsLabel is not None: self.setpointUnitsLabel.setText( f"{self.measureUnitsDropdown.currentText()}/{self.timebaseDropdown.currentText()}" ) self.controller.set_measurement_units( self.measureUnitsDropdown.currentText()) def update_time_base(self): if self.dosingUnitsLabel is not None: self.dosingUnitsLabel.setText( f"{self.measureUnitsDropdown.currentText()}/{self.timebaseDropdown.currentText()}" ) if self.setpointUnitsLabel is not None: self.setpointUnitsLabel.setText( f"{self.measureUnitsDropdown.currentText()}/{self.timebaseDropdown.currentText()}" ) self.controller.set_time_base(self.timebaseDropdown.currentText()) def update_buffer_size(self): self.change_buffer_size(int(self.bufferSizeEdit.text())) self.sampleBufferSize = int(self.bufferSizeEdit.text()) def update_graph_timer(self): self.graphTimer.setInterval( float(self.intervalEdit.text()) * 60 * 1000) def update_setpoint(self): value = float(self.setpointEdit.text()) self.controller.set_setpoint(value) def update_sensor1_timer(self): self.sensor1Timer.setInterval( float(self.sensor1SampleIntervalEdit.text()) * 60 * 1000) def update_sensor1_buffer(self): self.sensor1.change_buffer_size(int(self.sensor1BufferSizeEdit.text())) def update_sensor2_timer(self): self.sensor2Timer.setInterval( float(self.sensor2SampleIntervalEdit.text()) * 60 * 1000) def update_sensor2_buffer(self): self.sensor2.change_buffer_size(int(self.sensor2BufferSizeEdit.text())) def update_temperature(self): self.temperatureController.set_temperature( float(self.temperatureSlider.value())) self.temperatureLabel.setText(self.temperatureSlider.value()) def update_range_low(self): newTemp = self.temperatureController.set_range_low( float(self.rangeLowEdit.text())) self.temperatureSlider.setMinimum(float(self.rangeLowEdit.text())) self.temperatureSlider.setValue(newTemp) def update_range_high(self): newTemp = self.temperatureController.set_range_high( float(self.rangeHighEdit.text())) self.temperatureSlider.setMaximum(float(self.rangeHighEdit.text())) self.temperatureSlider.setValue(newTemp) def update_ramping_enable(self): if self.rampingCheckbox.isChecked(): self.temperatureController.ramping_on() else: self.temperatureController.ramping_off() def update_gradient(self): self.temperatureController.set_gradient(float()) def update_temp_control_enable(self): if self.tempControlButton.isChecked(): self.temperatureController.ramping_on() self.tempControlButton.setText("Disable output") else: self.temperatureController.ramping_off() self.tempControlButton.setText("Enable output") def update_dosing_vectors(self): self.dosingValues = [ float(x) for x in self.dosingValuesEdit.text().split(sep=',') if x.strip() != '' ] self.dosingTimes = [ float(x) * 1000 * 60 for x in self.dosingTimesEdit.text().split(sep=',') if x.strip() != '' ] # Since we will be using pop() to get the next values, we reverse the arrays self.dosingValues.reverse() self.dosingTimes.reverse() if len(self.dosingTimes) != len(self.dosingValues) or len( self.dosingTimes) * len(self.dosingValues) == 0: self.dosingTimesEdit.setStyleSheet("color: red;") self.dosingValuesEdit.setStyleSheet("color: red;") self.dosingControlButton.setEnabled(False) self.dosingSignal.emit(True) else: self.dosingTimesEdit.setStyleSheet(self.defaultStyleSheet) self.dosingValuesEdit.setStyleSheet(self.defaultStyleSheet) self.dosingControlButton.setEnabled(True) self.dosingSignal.emit(False) def update_dosing_state(self): if self.dosingControlButton.isChecked(): self.dosingValuesEdit.setEnabled(False) self.dosingValuesEdit.setStyleSheet("color: grey") self.dosingTimesEdit.setEnabled(False) self.dosingTimesEdit.setStyleSheet("color: grey") self.dosingControlButton.setText("Disable dosing") self.setpointEdit.setEnabled(False) self.dosingEnabled = True self.dosingSignal.emit(True) # Set VOR to normal for dosing self.vorNormalButton.setChecked(True) self.update_vor_normal() self.dosing_process() else: self.dosingValuesEdit.setEnabled(True) self.dosingValuesEdit.setStyleSheet(self.defaultStyleSheet) self.dosingTimesEdit.setEnabled(True) self.dosingTimesEdit.setStyleSheet(self.defaultStyleSheet) self.dosingControlButton.setText("Enable dosing") self.setpointEdit.setEnabled(True) self.dosingEnabled = False self.end_dosing_process() # This function sets the setpoint to those values that were set when "Enable dosing" was pressed # and iterates over them def dosing_process(self): self.spValue = self.dosingValues.pop() spTime = self.dosingTimes.pop() self.setpointEdit.setText(f"{str(self.spValue)} - dosing is enabled") self.controller.set_setpoint(self.spValue) if len(self.dosingTimes) == 0: self.dosingTimer.timeout.disconnect() self.dosingTimer.singleShot(spTime, self.end_dosing_process) self.dosingTimer.setInterval(spTime) self.dosingTimer.start() def update_generic(self): if self.dosingTimer.isActive() and len(self.dosingValues) > 0: if self.dosingTimer.remainingTime() / 1000 > 60: self.dosingLabel.setText( f"{int(self.dosingTimer.remainingTime() / (1000 * 60))} minutes {int(self.dosingTimer.remainingTime() / 1000) % 60} seconds until next dosing value: {self.dosingValues[-1]}" ) else: self.dosingLabel.setText( f"{int(self.dosingTimer.remainingTime() / 1000)} seconds until next dosing value: {self.dosingValues[-1]}" ) elif self.dosingTimer.isActive() and len(self.dosingValues) == 0: self.dosingLabel.setText( f"{int(self.dosingTimer.remainingTime() / 1000)} seconds until end of process" ) else: self.dosingLabel.setText("Dosing disabled") if self.temperatureController is not None: self.tempReadoutLabel.setText( f"Readout: {self.temperatureController.read_temperature()} ℃") else: self.tempReadoutLabel.setText("Readout: None ℃") def end_dosing_process(self): self.dosingControlButton.setChecked(False) self.dosingControlButton.setText("Enable dosing") self.dosingLabel.setText("Dosing disabled") self.dosingTimer.stop() # Since all the values have been popped and the text is unchanged, we fill the vectors again self.dosingValues = [ float(x) for x in self.dosingValuesEdit.text().split(sep=',') if x.strip() != '' ] self.dosingTimes = [ float(x) * 60 * 1000 for x in self.dosingTimesEdit.text().split(sep=',') if x.strip() != '' ] self.dosingValues.reverse() self.dosingTimes.reverse() # Remove the string portion from setpoint field self.setpointEdit.setText(str(self.spValue)) # Unlock the setpoint and dosing values/times fields self.setpointEdit.setEnabled(True) self.dosingValuesEdit.setEnabled(True) self.dosingTimesEdit.setEnabled(True) # Return to normal stylesheet self.dosingValuesEdit.setStyleSheet(self.defaultStyleSheet) self.dosingTimesEdit.setStyleSheet(self.defaultStyleSheet) # reconnect the dosing_process function to the timer self.dosingTimer.timeout.connect(self.dosing_process) # Set the setpoint to 0 and close valve at the end self.controller.set_setpoint(0) self.setpointEdit.setText("0") self.vorClosedButton.setChecked(True) self.dosingSignal.emit(False) self.update_vor_closed() def update_plot(self): self.graph.clear() self.get_measurement() self.graph.plot(self.samplesPV, pen=pyqtgraph.mkPen((255, 127, 0), width=1.25), symbolBrush=(255, 127, 0), symbolPen=pyqtgraph.mkPen((255, 127, 0)), symbol='o', symbolSize=5, name="symbol ='o'") if self.csvFile is not None: self.append_to_csv() def update_sensor1_group(self): if self.sensor1Group.isChecked(): dg = SensorConfigDialog() dg.accepted.connect(self.connect_sensor1) # if unsuccessful, disable the temperature controller group if dg.exec_() == 0: self.sensor1Group.setChecked(False) else: self.sensor1.close() self.sensor1Timer.stop() self.sensor1 = None # connect to sensor instance 1 using values returned by the dialog def connect_sensor1(self, values): self.sensor1 = Sensor(comport=values['port'], baudrate=values['baudrate'], databits=values['databits'], parity=values['paritybits'], stopbits=values['stopbits'], dataHeader=values['header']) self.sensor1Timer = QTimer() self.sensor1Timer.setInterval( float(self.sensor1SampleIntervalEdit.text()) * 1000 * 60) self.sensor1Timer.timeout.connect(self.sensor1_get_data) self.sensor1Timer.start() # Wrapper function to handle exceptions from GUI level def sensor1_get_data(self): try: self.sensor1.getData() except SerialException as se: dg = QErrorMessage() dg.setWindowIcon(QIcon(':/icon.png')) dg.setWindowTitle("Sensor 1 Exception") filename = datetime.now().strftime("sensor1_%Y-%m-%d_%H-%M-%S.csv") dumpFile = open(filename, 'w') dumpFile.write(f"Sensor 1 header: {self.sensor1.header}\n") for i in range(0, len(self.sensor1.buffer)): self.csvFile.write(str(self.sensor1.buffer[i])) dumpFile.close() self.sensor1Group.setChecked(False) self.update_sensor1_group() dg.showMessage(f"Sensor 1 has encountered an exception: {se}") dg.exec_() def update_sensor2_group(self): if self.sensor2Group.isChecked(): dg = SensorConfigDialog() dg.accepted.connect(self.connect_sensor2) # if unsuccessful, disable the temperature controller group if dg.exec_() == 0: self.sensor2Group.setChecked(False) else: self.sensor2.close() self.sensor2Timer.stop() self.sensor2 = None # connect to sensor instance 2 using values returned by the dialog def connect_sensor2(self, values): self.sensor2 = Sensor(comport=values['port'], baudrate=values['baudrate'], databits=values['databits'], parity=values['paritybits'], stopbits=values['stopbits'], dataHeader=values['header']) self.sensor2Timer = QTimer() self.sensor2Timer.setInterval( float(self.sensor2SampleIntervalEdit.text()) * 1000 * 60) self.sensor2Timer.timeout.connect(self.sensor2_get_data) self.sensor2Timer.start() # Wrapper function to handle exceptions from GUI level def sensor2_get_data(self): try: self.sensor2.getData() except SerialException as se: dg = QErrorMessage() dg.setWindowIcon(QIcon(':/icon.png')) dg.setWindowTitle("Sensor 2 Exception") filename = datetime.now().strftime("sensor2_%Y-%m-%d_%H-%M-%S.csv") dumpFile = open(filename, 'w') dumpFile.write(f"Sensor 2 header: {self.sensor2.header}\n") for i in range(0, len(self.sensor2.buffer)): self.csvFile.write(str(self.sensor2.buffer[i])) dumpFile.close() self.sensor2Group.setChecked(False) self.update_sensor2_group() dg.showMessage(f"Sensor 2 has encountered an exception: {se}") dg.exec_() def update_temperature_group(self): if self.tempControllerGroup.isChecked(): dg = AR6X2ConfigDialog() dg.accepted.connect(self.connect_temp_controller) # if unsuccessful, disable the temperature controller group if dg.exec_() == 0: self.tempControllerGroup.setChecked(False) else: self.temperatureController = None self.tempControlButton.setText("Enable output") # Connect to the AR6X2 controller using given parameters def connect_temp_controller(self, values): self.temperatureController = AR6X2(port=values['port'], address=values['address']) def create_left_column(self): # Create a vertical layout for the left column leftColumnLayout = QVBoxLayout() # Valve override group vorGroup = QGroupBox("Valve override") vorLayout = QHBoxLayout() self.vorNormalButton = QPushButton("Normal") self.vorNormalButton.setMinimumWidth(50) self.vorNormalButton.setFixedHeight(75) self.vorNormalButton.setCheckable(True) self.vorNormalButton.clicked.connect(self.update_vor_normal) self.vorClosedButton = QPushButton("Closed") self.vorClosedButton.setMinimumWidth(50) self.vorClosedButton.setFixedHeight(75) self.vorClosedButton.setCheckable(True) self.vorClosedButton.clicked.connect(self.update_vor_closed) self.vorOpenButton = QPushButton("Open") self.vorOpenButton.setMinimumWidth(50) self.vorOpenButton.setFixedHeight(75) self.vorOpenButton.setCheckable(True) self.vorOpenButton.clicked.connect(self.update_vor_open) vorState = self.controller.get_valve_override() if vorState == "Normal": self.vorNormalButton.setChecked(True) self.vorClosedButton.setChecked(False) self.vorOpenButton.setChecked(False) elif vorState == "Closed": self.vorNormalButton.setChecked(False) self.vorClosedButton.setChecked(True) self.vorOpenButton.setChecked(False) elif vorState == "Open": self.vorNormalButton.setChecked(False) self.vorClosedButton.setChecked(False) self.vorOpenButton.setChecked(True) else: raise ValueError(f"Unexpected vor state: {vorState}") vorLayout.addWidget(self.vorNormalButton) vorLayout.addWidget(self.vorClosedButton) vorLayout.addWidget(self.vorOpenButton) vorGroup.setLayout(vorLayout) vorGroup.setMaximumWidth(ControllerGUITab.LEFT_COLUMN_MAX_WIDTH) leftColumnLayout.addWidget(vorGroup, alignment=Qt.AlignTop) # Process configuration group processGroup = QGroupBox("Process configuration") processLayout = QFormLayout() self.gasFactorEdit = QLineEdit() self.gasFactorEdit.setValidator( QRegExpValidator(QRegExp("[0-9]{1,3}(|\\.[0-9]{1,3})"))) self.gasFactorEdit.editingFinished.connect(self.update_gas_factor) self.gasFactorEdit.setText("{:.5f}".format(self.controller.get_gas())) self.pvFullScaleEdit = QLineEdit() self.pvFullScaleEdit.setValidator( QRegExpValidator(QRegExp("(-|)[0-9]{1,3}(|\\.[0-9]{1,3})"))) self.pvFullScaleEdit.editingFinished.connect(self.update_pv_full_scale) self.pvFullScaleEdit.setText(str(self.controller.get_pv_full_scale())) self.pvSigtypeDropdown = QComboBox() self.pvSigtypeDropdown.addItems(Controller.INPUT_PORT_TYPES.keys()) self.pvSigtypeDropdown.currentTextChanged.connect( self.update_pv_signal_type) self.pvSigtypeDropdown.setCurrentText( str(self.controller.get_pv_signal_type())) self.spFullScaleEdit = QLineEdit() self.spFullScaleEdit.setValidator( QRegExpValidator(QRegExp("(-|)[0-9]{1,3}(|\\.[0-9]{1,3})"))) self.spFullScaleEdit.editingFinished.connect(self.update_sp_full_scale) self.spFullScaleEdit.setText(str(self.controller.get_sp_full_scale())) self.spSigtypeDropdown = QComboBox() self.spSigtypeDropdown.addItems(Controller.OUTPUT_PORT_TYPES.keys()) self.spSigtypeDropdown.currentTextChanged.connect( self.update_sp_signal_type) self.spSigtypeDropdown.setCurrentText( str(self.controller.get_sp_signal_type())) self.spSourceDropdown = QComboBox() self.spSourceDropdown.addItems(Controller.SP_SOURCES.keys()) self.spSourceDropdown.currentTextChanged.connect(self.update_source) self.spSourceDropdown.setCurrentText(str(self.controller.get_source())) self.decimalDropdown = QComboBox() self.decimalDropdown.addItems(Controller.DECIMAL_POINTS.keys()) self.decimalDropdown.currentTextChanged.connect( self.update_decimal_point) self.decimalDropdown.setCurrentText( str(self.controller.get_decimal_point())) self.measureUnitsDropdown = QComboBox() self.measureUnitsDropdown.addItems(Controller.MEASUREMENT_UNITS.keys()) self.measureUnitsDropdown.currentTextChanged.connect( self.update_measure_units) self.measureUnitsDropdown.setCurrentText( str(self.controller.get_measurement_units())) self.timebaseDropdown = QComboBox() self.timebaseDropdown.addItems(Controller.RATE_TIME_BASE.keys()) self.timebaseDropdown.currentTextChanged.connect(self.update_time_base) self.timebaseDropdown.setCurrentText( str(self.controller.get_time_base())) processLayout.addRow(QLabel("Gas factor"), self.gasFactorEdit) processLayout.addRow(QLabel("PV Full Scale"), self.pvFullScaleEdit) processLayout.addRow(QLabel("PV Signal Type"), self.pvSigtypeDropdown) processLayout.addRow(QLabel("SP Full Scale"), self.spFullScaleEdit) processLayout.addRow(QLabel("SP Signal Type"), self.spSigtypeDropdown) processLayout.addRow(QLabel("Setpoint source"), self.spSourceDropdown) processLayout.addRow(QLabel("Decimal point"), self.decimalDropdown) processLayout.addRow(QLabel("Measurement units"), self.measureUnitsDropdown) processLayout.addRow(QLabel("Time base"), self.timebaseDropdown) processGroup.setLayout(processLayout) processGroup.setMaximumWidth(ControllerGUITab.LEFT_COLUMN_MAX_WIDTH) leftColumnLayout.addWidget(processGroup, alignment=Qt.AlignTop) leftColumnLayout.setStretch(1, 100) runtimeGroup = QGroupBox("Runtime options") runtimeLayout = QVBoxLayout() layout = QHBoxLayout() self.bufferSizeEdit = QLineEdit() self.bufferSizeEdit.setText("64") self.bufferSizeEdit.setValidator(QIntValidator()) self.bufferSizeEdit.editingFinished.connect(self.update_buffer_size) layout.addWidget(QLabel("Sample buffer size")) layout.addWidget(self.bufferSizeEdit) layout.addWidget(QLabel("samples")) runtimeLayout.addLayout(layout) layout = QHBoxLayout() self.intervalEdit = QLineEdit() self.intervalEdit.setText("1") self.intervalEdit.setValidator( QRegExpValidator(QRegExp("[0-9]*(|\\.[0-9]*)"))) self.intervalEdit.editingFinished.connect(self.update_graph_timer) layout.addWidget(QLabel("Data update interval")) layout.addWidget(self.intervalEdit) layout.addWidget(QLabel("minutes")) runtimeLayout.addLayout(layout) layout = QHBoxLayout() self.setpointEdit = QLineEdit() self.setpointEdit.setValidator( QRegExpValidator(QRegExp("[0-9]*(|\\.[0-9]*)"))) self.setpointEdit.editingFinished.connect(self.update_setpoint) self.setpointEdit.setText(str(self.controller.get_setpoint())) self.setpointUnitsLabel = QLabel( f"{self.measureUnitsDropdown.currentText()}/{self.timebaseDropdown.currentText()}" ) layout.addWidget(QLabel("Setpoint")) layout.addWidget(self.setpointEdit) layout.addWidget(self.setpointUnitsLabel) runtimeLayout.addLayout(layout) layout = QHBoxLayout() manualMeasureButton = QPushButton("Get measurement") manualMeasureButton.clicked.connect(self.update_plot) self.saveCsvButton = QPushButton("Start saving to CSV") self.saveCsvButton.clicked.connect(self.save_to_csv_start) layout.addWidget(manualMeasureButton) layout.addWidget(self.saveCsvButton) runtimeLayout.addLayout(layout) runtimeGroup.setLayout(runtimeLayout) runtimeGroup.setMaximumWidth(ControllerGUITab.LEFT_COLUMN_MAX_WIDTH) runtimeGroup.setFixedHeight(150) leftColumnLayout.addWidget(runtimeGroup, alignment=Qt.AlignBottom) return leftColumnLayout def create_right_column(self): # Create layouts and elements for the right column, including graph and sensor/temperature control/dosing groups rightColumnLayout = QVBoxLayout() rightInnerGrid = QGridLayout() # Creation of sensor 1 and sub-elements self.sensor1Group = QGroupBox("Sensor 1") self.sensor1Group.setCheckable(True) self.sensor1Group.setChecked(False) self.sensor1Group.clicked.connect(self.update_sensor1_group) sensor1Layout = QVBoxLayout() layout = QHBoxLayout() self.sensor1SampleIntervalEdit = QLineEdit() self.sensor1SampleIntervalEdit.setValidator( QRegExpValidator(QRegExp("[0-9]*(|\\.[0-9]*)"))) self.sensor1SampleIntervalEdit.setFixedWidth(100) self.sensor1SampleIntervalEdit.editingFinished.connect( self.update_sensor1_timer) self.sensor1SampleIntervalEdit.setText("1") label = QLabel('Sampling interval') label.setFixedWidth(90) layout.addWidget(label) layout.addWidget(self.sensor1SampleIntervalEdit) layout.addWidget(QLabel('minutes')) layout.setStretch(2, 10) sensor1Layout.addLayout(layout) layout = QHBoxLayout() self.sensor1BufferSizeEdit = QLineEdit() self.sensor1BufferSizeEdit.setValidator(QIntValidator()) self.sensor1BufferSizeEdit.setFixedWidth(100) self.sensor1BufferSizeEdit.editingFinished.connect( self.update_sensor1_buffer) self.sensor1BufferSizeEdit.setText("64") label = QLabel('Buffer size') label.setFixedWidth(90) layout.addWidget(label) layout.addWidget(self.sensor1BufferSizeEdit) layout.addWidget(QLabel('samples')) layout.setStretch(2, 10) sensor1Layout.addLayout(layout) self.sensor1Group.setLayout(sensor1Layout) # Creation of sensor 2 and sub-elements self.sensor2Group = QGroupBox("Sensor 2") self.sensor2Group.setCheckable(True) self.sensor2Group.setChecked(False) self.sensor2Group.clicked.connect(self.update_sensor2_group) sensor2Layout = QVBoxLayout() layout = QHBoxLayout() self.sensor2SampleIntervalEdit = QLineEdit() self.sensor2SampleIntervalEdit.setValidator( QRegExpValidator(QRegExp("[0-9]*(|\\.[0-9]*)"))) self.sensor2SampleIntervalEdit.setFixedWidth(100) self.sensor2SampleIntervalEdit.editingFinished.connect( self.update_sensor2_timer) self.sensor2SampleIntervalEdit.setText("1") label = QLabel('Sampling interval') label.setFixedWidth(90) layout.addWidget(label) layout.addWidget(self.sensor2SampleIntervalEdit) layout.addWidget(QLabel('minutes')) layout.setStretch(2, 10) sensor2Layout.addLayout(layout) layout = QHBoxLayout() self.sensor2BufferSizeEdit = QLineEdit() self.sensor2BufferSizeEdit.setValidator(QIntValidator()) self.sensor2BufferSizeEdit.setFixedWidth(100) self.sensor2BufferSizeEdit.editingFinished.connect( self.update_sensor2_buffer) self.sensor2BufferSizeEdit.setText("64") label = QLabel('Buffer size') label.setFixedWidth(90) layout.addWidget(label) layout.addWidget(self.sensor2BufferSizeEdit) layout.addWidget(QLabel('samples')) layout.setStretch(2, 10) sensor2Layout.addLayout(layout) self.sensor2Group.setLayout(sensor2Layout) self.tempControllerGroup = QGroupBox("Temperature controller") self.tempControllerGroup.setCheckable(True) self.tempControllerGroup.setEnabled( False) # Disabled functionality as it is untested self.tempControllerGroup.setChecked(False) self.tempControllerGroup.clicked.connect(self.update_temperature_group) tempControllerLayout = QVBoxLayout() layout = QHBoxLayout() self.temperatureSlider = QSlider(Qt.Horizontal) self.temperatureSlider.setMinimumWidth(95) self.temperatureSlider.setMaximumWidth(1000) self.temperatureSlider.setMinimum(-199.9) self.temperatureSlider.setMaximum(850.0) self.temperatureSlider.setValue(100) self.temperatureSlider.sliderMoved.connect(self.update_temperature) self.temperatureLabel = QLabel("100") layout.addWidget(QLabel("Temperature"), alignment=Qt.AlignLeft) layout.addWidget(self.temperatureSlider, alignment=Qt.AlignLeft) layout.addWidget(self.temperatureLabel, alignment=Qt.AlignLeft) layout.addWidget(QLabel("℃"), alignment=Qt.AlignLeft) layout.setStretch(3, 200) tempControllerLayout.addLayout(layout) # these edits have validators, but input still has to be capped layout = QHBoxLayout() self.rangeLowEdit = QLineEdit() self.rangeLowEdit.setMinimumWidth(30) self.rangeLowEdit.setMaximumWidth(60) self.rangeLowEdit.setText("-199.9") self.rangeLowEdit.setValidator( QRegExpValidator( QRegExp("(-[0-9]{1,3}\\.[0-9]|[0-9]{1,3}\\.[0-9|[0-9]{1,4})"))) self.rangeLowEdit.editingFinished.connect(self.update_range_low) self.rangeHighEdit = QLineEdit() self.rangeHighEdit.setMinimumWidth(30) self.rangeHighEdit.setMaximumWidth(60) self.rangeHighEdit.setText("850.0") self.rangeHighEdit.setValidator( QRegExpValidator( QRegExp("(-[0-9]{1,3}\\.[0-9]|[0-9]{1,3}\\.[0-9|[0-9]{1,4})"))) self.rangeHighEdit.editingFinished.connect(self.update_range_high) layout.addWidget(QLabel("Range")) layout.addWidget(self.rangeLowEdit, alignment=Qt.AlignLeft) layout.addWidget(self.rangeHighEdit, alignment=Qt.AlignLeft) layout.addWidget(QLabel("℃")) layout.setStretch(3, 10) tempControllerLayout.addLayout(layout) self.rampingCheckbox = QCheckBox() self.rampingCheckbox.stateChanged.connect(self.update_ramping_enable) self.tempReadoutLabel = QLabel("Readout: None ℃") layout = QHBoxLayout() layout.addWidget(QLabel("Ramping"), alignment=Qt.AlignLeft) layout.addWidget(self.rampingCheckbox, alignment=Qt.AlignLeft) layout.addWidget(self.tempReadoutLabel, alignment=Qt.AlignBottom) layout.setStretch(1, 10) tempControllerLayout.addLayout(layout) layout = QHBoxLayout() self.gradientEdit = QLineEdit() self.gradientEdit.setMinimumWidth(30) self.gradientEdit.setMaximumWidth(60) self.gradientEdit.setText("0.1") # default value from the datasheet self.gradientEdit.editingFinished.connect(self.update_gradient) self.tempControlButton = QPushButton("Enable output") self.tempControlButton.setCheckable(True) self.tempControlButton.clicked.connect(self.update_temp_control_enable) layout.addWidget(QLabel("Gradient"), alignment=Qt.AlignLeft) layout.addWidget(self.gradientEdit, alignment=Qt.AlignLeft) layout.addWidget(QLabel("℃/min")) layout.addWidget(self.tempControlButton, alignment=Qt.AlignBottom) layout.setStretch(2, 10) tempControllerLayout.addLayout(layout) self.tempControllerGroup.setLayout(tempControllerLayout) self.tempControllerGroup.setMinimumWidth(200) self.tempControllerGroup.setFixedHeight(150) dosingGroup = QGroupBox("Dosing control") dosingGroup.setCheckable(False) dosingLayout = QVBoxLayout() layout = QHBoxLayout() self.dosingTimesEdit = QLineEdit() self.dosingTimesEdit.setMinimumWidth(160) self.dosingTimesEdit.setText("1, 1, 1.5") self.dosingTimesEdit.setValidator( QRegExpValidator(QRegExp("(([0-9]+|[0-9]+\\.[0-9]+),(| ))+"))) self.dosingTimesEdit.textChanged.connect(self.update_dosing_vectors) label = QLabel("Times") label.setFixedWidth(55) layout.addWidget(label) layout.addWidget(self.dosingTimesEdit) layout.addWidget(QLabel("minutes")) dosingLayout.addLayout(layout) layout = QHBoxLayout() self.dosingValuesEdit = QLineEdit() self.dosingValuesEdit.setMinimumWidth(160) self.dosingValuesEdit.setText("1.0, 2.0, 5.0") self.dosingValuesEdit.setValidator( QRegExpValidator(QRegExp("(([0-9]+|[0-9]+\\.[0-9]+),(| ))+"))) self.dosingValuesEdit.textChanged.connect(self.update_dosing_vectors) label = QLabel("Setpoints") label.setFixedWidth(55) self.dosingUnitsLabel = QLabel( f"{self.measureUnitsDropdown.currentText()}/{self.timebaseDropdown.currentText()}" ) layout.addWidget(label) layout.addWidget(self.dosingValuesEdit) layout.addWidget(self.dosingUnitsLabel) dosingLayout.addLayout(layout) self.dosingLabel = QLabel("Dosing disabled") self.dosingVorStateLabel = QLabel( f"VOR is {self.controller.get_valve_override().lower()}") if "normal" in self.dosingVorStateLabel.text(): self.dosingVorStateLabel.setStyleSheet("color: green") else: self.dosingVorStateLabel.setStyleSheet("color: red") self.dosingControlButton = QPushButton("Start dosing") self.dosingControlButton.setCheckable(True) self.dosingControlButton.clicked.connect(self.update_dosing_state) dosingLayout.addWidget(self.dosingLabel, alignment=Qt.AlignLeft) layout = QHBoxLayout() layout.addWidget(self.dosingVorStateLabel, alignment=Qt.AlignLeft) layout.addWidget(self.dosingControlButton, alignment=Qt.AlignRight) dosingLayout.addLayout(layout) # finally, assign the layout to the group dosingGroup.setLayout(dosingLayout) dosingGroup.setMinimumWidth(200) dosingGroup.setFixedHeight(150) rightInnerGrid.addWidget(self.sensor1Group, 0, 0) rightInnerGrid.addWidget(self.sensor2Group, 0, 1) rightInnerGrid.addWidget(self.tempControllerGroup, 1, 0) rightInnerGrid.addWidget(dosingGroup, 1, 1) rightInnerGrid.setColumnStretch(0, 100) rightInnerGrid.setColumnStretch(1, 100) self.graph = PlotWidget() self.graph.getPlotItem().showGrid(x=True, y=True, alpha=1) if "qdarkstyle" in sys.modules: self.graph.setBackground((25, 35, 45)) rightColumnLayout.addWidget(self.graph) rightColumnLayout.addLayout(rightInnerGrid) return rightColumnLayout # function to change the amount of stored samples without losing previously gathered samples def change_buffer_size(self, value): if value > self.sampleBufferSize: newBufPV = RingBuffer(capacity=value, dtype=np.float16) newBufTotal = RingBuffer(capacity=value, dtype=np.float32) newTimestampBuf = RingBuffer(capacity=value, dtype=datetime) newBufPV.extend(self.samplesPV) newBufTotal.extend(self.samplesTotalizer) newTimestampBuf.extend(self.sampleTimestamps) self.samplesPV = newBufPV self.samplesTotalizer = newBufTotal self.sampleTimestamps = newTimestampBuf elif value < self.sampleBufferSize: newBufPV = RingBuffer(capacity=value, dtype=np.float16) newBufTotal = RingBuffer(capacity=value, dtype=np.float32) newTimestampBuf = RingBuffer(capacity=value, dtype=datetime) newBufPV.extend(self.samplesPV[:-value]) newBufTotal.extend(self.samplesTotalizer[:-value]) newTimestampBuf.extend(self.sampleTimestamps[:-value]) self.samplesPV = newBufPV self.samplesTotalizer = newBufTotal self.sampleTimestamps = newTimestampBuf
class widget_mfi_lon_plot(QWidget): #----------------------------------------------------------------------- # DEFINE THE INITIALIZATION FUNCTION. #----------------------------------------------------------------------- def __init__(self, core): # Inherit all attributes of an instance of "QWidget". super(widget_mfi_lon_plot, self).__init__() # Store the Janus core. self.core = core # Prepare to respond to signals received from the core. self.connect(self.core, SIGNAL('janus_rset'), self.resp_rset) self.connect(self.core, SIGNAL('janus_chng_mfi'), self.resp_chng_mfi) # Initialize this widget's instance of "PlotWidget", which will # contain the plot of MFI magnetic field data. # Note. The "QGridLayout" object given to this widget as its # layout is essentially a dummy. I could have just had # this class inherit "PlotWidget", but I think that this # gives me a bit more control (and a similar structure # "janus_widget_fc_cup"). self.setLayout(QGridLayout()) self.plt = PlotWidget() self.layout().addWidget(self.plt) self.layout().setContentsMargins(0, 0, 0, 0) # Extract the individual elements of the "PlotWidget" object # (e.g., it's axes) for more convenient access later. self.vbx = self.plt.getViewBox() self.axs_x = self.plt.getAxis('bottom') self.axs_y = self.plt.getAxis('left') self.ptm = self.plt.getPlotItem() # Initialize and store the pens and fonts. self.pen_vbx = mkPen(color='k') self.pen_crv_lon = mkPen(color='#FFD700') self.fnt = self.core.app.font() # Configure the plot: disable automatic adjustments and # adjustments made by the user, change the background and # foreground colors, enable grid lines for both axes, label the # axes, adjust the tick font size, adjust the "AxisItem" sizes, # and add a margin around the entire plot. self.plt.disableAutoRange() self.plt.setMouseEnabled(False, False) self.plt.setMenuEnabled(False) self.plt.hideButtons() self.plt.setBackground('w') setConfigOption('foreground', 'k') #####self.plt.showGrid( True, True ) labelStyle = {'color': 'k'} self.axs_x.setLabel('Time [s]', **labelStyle) self.axs_y.setLabel('Azim. [deg]', **labelStyle) self.axs_x.label.setFont(self.fnt) self.axs_y.label.setFont(self.fnt) self.axs_x.setTickFont(self.fnt) self.axs_y.setTickFont(self.fnt) self.axs_x.setHeight(35) self.axs_y.setWidth(40) self.vbx.border = self.pen_vbx self.ptm.setContentsMargins(5, 5, 5, 5) # Initialize the curves that will be added to this plot. self.crv_lon = None # Populate this plot and adjust it's settings. self.make_plt() #----------------------------------------------------------------------- # DEFINE THE FUNCTION FOR POPULATING THE PLOT. #----------------------------------------------------------------------- def make_plt(self): # Reset the plot (i.e., remove all plot elements). self.rset_plt() # Establish the ranges of its time and magnetic field values. # If the core contains no data or only a single datum, # improvise (for the purpose of later establishing axis limits). if (self.core.n_mfi >= 1): # Establish the domain of the plot. t_min = min(amin(self.core.mfi_s), 0.) t_max = max(amax(self.core.mfi_s), self.core.fc_spec['dur']) # Establish the range of the plot. As part of this, # ensure that the range satisfies a minimum size and has # sufficient padding. ang_max = max(self.core.mfi_b_lon) ang_min = min(self.core.mfi_b_lon) ang_max = 5. + ang_max ang_min = -5. + ang_min d_t_0 = t_max - t_min d_t = max(1.5 + d_t_0, 3.) t_max = t_min + d_t else: t_min = 0.001 t_max = 3.500 ang_min = -360 ang_max = 360 # Set the range of the axis of each plot. self.plt.setXRange(t_min, t_max, padding=0.0) self.plt.setYRange(ang_min, ang_max, padding=0.0) # If the core contains no Wind/MFI magnetic field data, return. if (self.core.n_mfi <= 0): return # Generate and display each curve for the plot. self.crv_lon = PlotDataItem(self.core.mfi_s, self.core.mfi_b_lon, pen=self.pen_crv_lon) self.plt.addItem(self.crv_lon) #----------------------------------------------------------------------- # DEFINE THE FUNCTION FOR RESETTING THIS PLOT (CLEARING ALL ELEMENTS). #----------------------------------------------------------------------- def rset_plt(self): # Hide and remove each of this plot's elements. if (self.crv_lon is not None): self.plt.removeItem(self.crv_lon) # Permanently delete this plot's elements by setting each of the # variables that store them to "None". self.crv_lon = None #----------------------------------------------------------------------- # DEFINE THE FUNCTION FOR RESPONDING TO THE "rset" SIGNAL. #----------------------------------------------------------------------- def resp_rset(self): # Reset the plot. self.rset_plt() #----------------------------------------------------------------------- # DEFINE THE FUNCTION FOR RESPONDING TO THE "chng_mfi" SIGNAL. #----------------------------------------------------------------------- def resp_chng_mfi(self): # Regenerate the plot. self.make_plt()
class Ui_MainWindow(object): def setupUi(self, MainWindow): MainWindow.setObjectName("MainWindow") MainWindow.resize(1103, 561) self.centralwidget = QtWidgets.QWidget(MainWindow) self.centralwidget.setObjectName("centralwidget") self.Connect_box = QtWidgets.QGroupBox(self.centralwidget) self.Connect_box.setGeometry(QtCore.QRect(10, 10, 191, 121)) font = QtGui.QFont() font.setPointSize(10) font.setBold(True) font.setWeight(75) self.Connect_box.setFont(font) self.Connect_box.setObjectName("Connect_box") self.COM = QtWidgets.QComboBox(self.Connect_box) self.COM.setGeometry(QtCore.QRect(50, 30, 131, 22)) font = QtGui.QFont() font.setPointSize(8) font.setBold(False) font.setWeight(50) self.COM.setFont(font) self.COM.setLayoutDirection(QtCore.Qt.LeftToRight) self.COM.setObjectName("COM") self.COM.addItem("") self.COM.addItem("") self.COM.addItem("") self.COM.addItem("") self.COM.addItem("") self.COM.addItem("") self.connect = QtWidgets.QPushButton(self.Connect_box) self.connect.setGeometry(QtCore.QRect(20, 70, 151, 41)) font = QtGui.QFont() font.setPointSize(9) font.setBold(False) font.setWeight(50) self.connect.setFont(font) self.connect.setObjectName("connect") self.label = QtWidgets.QLabel(self.Connect_box) self.label.setGeometry(QtCore.QRect(10, 30, 31, 21)) font = QtGui.QFont() font.setPointSize(8) font.setBold(False) font.setWeight(50) self.label.setFont(font) self.label.setObjectName("label") self.Mode_box = QtWidgets.QGroupBox(self.centralwidget) self.Mode_box.setGeometry(QtCore.QRect(200, 10, 481, 121)) font = QtGui.QFont() font.setPointSize(10) font.setBold(True) font.setWeight(75) self.Mode_box.setFont(font) self.Mode_box.setObjectName("Mode_box") self.Start = QtWidgets.QPushButton(self.Mode_box) self.Start.setGeometry(QtCore.QRect(10, 40, 101, 51)) font = QtGui.QFont() font.setPointSize(9) font.setBold(False) font.setWeight(50) self.Start.setFont(font) self.Start.setObjectName("Start") self.Stop = QtWidgets.QPushButton(self.Mode_box) self.Stop.setGeometry(QtCore.QRect(130, 40, 101, 51)) font = QtGui.QFont() font.setPointSize(9) font.setBold(False) font.setWeight(50) self.Stop.setFont(font) self.Stop.setObjectName("Stop") self.Reset = QtWidgets.QPushButton(self.Mode_box) self.Reset.setGeometry(QtCore.QRect(250, 40, 101, 51)) font = QtGui.QFont() font.setPointSize(9) font.setBold(False) font.setWeight(50) self.Reset.setFont(font) self.Reset.setObjectName("Reset") self.draw_graph = QtWidgets.QPushButton(self.Mode_box) self.draw_graph.setGeometry(QtCore.QRect(370, 40, 101, 51)) font = QtGui.QFont() font.setPointSize(10) font.setBold(False) font.setWeight(50) self.draw_graph.setFont(font) self.draw_graph.setObjectName("draw_graph") self.PIDStatus_box = QtWidgets.QGroupBox(self.centralwidget) self.PIDStatus_box.setGeometry(QtCore.QRect(680, 10, 411, 121)) font = QtGui.QFont() font.setPointSize(10) font.setBold(True) font.setWeight(75) self.PIDStatus_box.setFont(font) self.PIDStatus_box.setObjectName("PIDStatus_box") self.label_6 = QtWidgets.QLabel(self.PIDStatus_box) self.label_6.setGeometry(QtCore.QRect(20, 30, 31, 31)) font = QtGui.QFont() font.setFamily("MS Shell Dlg 2") font.setPointSize(10) font.setBold(False) font.setWeight(50) self.label_6.setFont(font) self.label_6.setObjectName("label_6") self.Kp_data = QtWidgets.QTextEdit(self.PIDStatus_box) self.Kp_data.setGeometry(QtCore.QRect(60, 30, 71, 31)) font = QtGui.QFont() font.setBold(False) font.setWeight(50) self.Kp_data.setFont(font) self.Kp_data.setObjectName("Kp_data") self.label_7 = QtWidgets.QLabel(self.PIDStatus_box) self.label_7.setGeometry(QtCore.QRect(20, 80, 31, 31)) font = QtGui.QFont() font.setFamily("MS Shell Dlg 2") font.setPointSize(10) font.setBold(False) font.setWeight(50) self.label_7.setFont(font) self.label_7.setObjectName("label_7") self.Ki_data = QtWidgets.QTextEdit(self.PIDStatus_box) self.Ki_data.setGeometry(QtCore.QRect(60, 80, 71, 31)) font = QtGui.QFont() font.setBold(False) font.setWeight(50) self.Ki_data.setFont(font) self.Ki_data.setObjectName("Ki_data") self.label_8 = QtWidgets.QLabel(self.PIDStatus_box) self.label_8.setGeometry(QtCore.QRect(190, 30, 31, 31)) font = QtGui.QFont() font.setFamily("MS Shell Dlg 2") font.setPointSize(10) font.setBold(False) font.setWeight(50) self.label_8.setFont(font) self.label_8.setObjectName("label_8") self.Kd_data = QtWidgets.QTextEdit(self.PIDStatus_box) self.Kd_data.setGeometry(QtCore.QRect(230, 30, 71, 31)) font = QtGui.QFont() font.setBold(False) font.setWeight(50) self.Kd_data.setFont(font) self.Kd_data.setObjectName("Kd_data") self.label_9 = QtWidgets.QLabel(self.PIDStatus_box) self.label_9.setGeometry(QtCore.QRect(160, 80, 71, 31)) font = QtGui.QFont() font.setFamily("MS Shell Dlg 2") font.setPointSize(10) font.setBold(False) font.setWeight(50) self.label_9.setFont(font) self.label_9.setObjectName("label_9") self.Setpoint_data = QtWidgets.QTextEdit(self.PIDStatus_box) self.Setpoint_data.setGeometry(QtCore.QRect(230, 80, 71, 31)) font = QtGui.QFont() font.setBold(False) font.setWeight(50) self.Setpoint_data.setFont(font) self.Setpoint_data.setObjectName("Setpoint_data") self.send_PID = QtWidgets.QPushButton(self.PIDStatus_box) self.send_PID.setGeometry(QtCore.QRect(320, 80, 81, 31)) font = QtGui.QFont() font.setPointSize(8) font.setBold(False) font.setWeight(50) self.send_PID.setFont(font) self.send_PID.setObjectName("send_PID") self.get_PID = QtWidgets.QPushButton(self.PIDStatus_box) self.get_PID.setGeometry(QtCore.QRect(320, 30, 81, 31)) font = QtGui.QFont() font.setPointSize(8) font.setBold(False) font.setWeight(50) self.get_PID.setFont(font) self.get_PID.setObjectName("get_PID") self.Graph_box = QtWidgets.QGroupBox(self.centralwidget) self.Graph_box.setGeometry(QtCore.QRect(10, 130, 761, 401)) font = QtGui.QFont() font.setPointSize(10) font.setBold(True) font.setWeight(75) self.Graph_box.setFont(font) self.Graph_box.setObjectName("Graph_box") self.tabWidget = QtWidgets.QTabWidget(self.Graph_box) self.tabWidget.setGeometry(QtCore.QRect(0, 20, 761, 381)) self.tabWidget.setObjectName("tabWidget") self.Velocity_tab = QtWidgets.QWidget() self.Velocity_tab.setObjectName("Velocity_tab") self.Velocity_graph = PlotWidget(self.Velocity_tab) self.Velocity_graph.setGeometry(QtCore.QRect(10, 10, 741, 331)) sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth( self.Velocity_graph.sizePolicy().hasHeightForWidth()) self.Velocity_graph.setSizePolicy(sizePolicy) self.Velocity_graph.setObjectName("Velocity_graph") self.tabWidget.addTab(self.Velocity_tab, "") self.Position_tab = QtWidgets.QWidget() self.Position_tab.setObjectName("Position_tab") self.Position_graph = PlotWidget(self.Position_tab) self.Position_graph.setGeometry(QtCore.QRect(10, 10, 741, 331)) sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth( self.Position_graph.sizePolicy().hasHeightForWidth()) self.Position_graph.setSizePolicy(sizePolicy) self.Position_graph.setObjectName("Position_graph") self.tabWidget.addTab(self.Position_tab, "") self.groupBox_10 = QtWidgets.QGroupBox(self.centralwidget) self.groupBox_10.setGeometry(QtCore.QRect(770, 130, 321, 311)) font = QtGui.QFont() font.setFamily("MS Shell Dlg 2") font.setPointSize(10) font.setBold(True) font.setWeight(75) self.groupBox_10.setFont(font) self.groupBox_10.setObjectName("groupBox_10") self.re_se_data = QtWidgets.QTextBrowser(self.groupBox_10) self.re_se_data.setEnabled(True) self.re_se_data.setGeometry(QtCore.QRect(10, 20, 301, 241)) sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth( self.re_se_data.sizePolicy().hasHeightForWidth()) self.re_se_data.setSizePolicy(sizePolicy) font = QtGui.QFont() font.setPointSize(8) font.setBold(False) font.setWeight(50) self.re_se_data.setFont(font) self.re_se_data.setObjectName("re_se_data") self.testsend = QtWidgets.QTextEdit(self.groupBox_10) self.testsend.setGeometry(QtCore.QRect(10, 270, 231, 31)) font = QtGui.QFont() font.setPointSize(8) font.setBold(False) font.setWeight(50) self.testsend.setFont(font) self.testsend.setObjectName("testsend") self.send = QtWidgets.QPushButton(self.groupBox_10) self.send.setGeometry(QtCore.QRect(250, 270, 61, 31)) font = QtGui.QFont() font.setPointSize(8) font.setBold(False) font.setWeight(50) self.send.setFont(font) self.send.setObjectName("send") MainWindow.setCentralWidget(self.centralwidget) self.statusbar = QtWidgets.QStatusBar(MainWindow) self.statusbar.setObjectName("statusbar") MainWindow.setStatusBar(self.statusbar) self.ser = serial.Serial() self.retranslateUi(MainWindow) self.tabWidget.setCurrentIndex(0) #connect serial self.connect.clicked.connect(self.clickedCONNECT) #enter mode self.Start.clicked.connect(self.clickedStart) self.Stop.clicked.connect(self.clickedStop) self.Reset.clicked.connect(self.clickedReset) #draw graph self.draw_graph.clicked.connect(self.clickeddrawgraph) #set up Position_graph self.Position_graph.setBackground('w') self.Position_graph.showGrid(x=True, y=True) self.Position_graph.setYRange(Y_min, Y_max, padding=0) self.Position_graph.setMouseEnabled(x=False, y=False) #set up Velocity_graph self.Velocity_graph.setBackground('w') self.Velocity_graph.showGrid(x=True, y=True) self.Velocity_graph.setYRange(Y_min, Y_max, padding=0) self.Velocity_graph.setMouseEnabled(x=False, y=False) #get PID status self.get_PID.clicked.connect(self.clickedgetPID) #transmit data # self.send.clicked.connect(self.clickedSEND) self.send_PID.clicked.connect(self.clickedsendPID) #set time for recive function self.timer_getdata = QtCore.QTimer() self.timer_getdata.setInterval(100) self.timer_getdata.timeout.connect(self.recive) #set time run system self.timer_run = QtCore.QTimer() self.timer_run.setInterval(1500) self.timer_run.timeout.connect(self.clickedCONNECT) QtCore.QMetaObject.connectSlotsByName(MainWindow) def retranslateUi(self, MainWindow): _translate = QtCore.QCoreApplication.translate MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow")) self.Connect_box.setTitle(_translate("MainWindow", "Connect")) self.COM.setCurrentText(_translate("MainWindow", "COM1")) self.COM.setItemText(0, _translate("MainWindow", "COM1")) self.COM.setItemText(1, _translate("MainWindow", "COM2")) self.COM.setItemText(2, _translate("MainWindow", "COM3")) self.COM.setItemText(3, _translate("MainWindow", "COM4")) self.COM.setItemText(4, _translate("MainWindow", "COM5")) self.COM.setItemText(5, _translate("MainWindow", "COM6")) self.connect.setText(_translate("MainWindow", "CONNECT")) self.label.setText(_translate("MainWindow", "COM:")) self.Mode_box.setTitle(_translate("MainWindow", "Mode")) self.Start.setText(_translate("MainWindow", "START")) self.Stop.setText(_translate("MainWindow", "STOP")) self.Reset.setText(_translate("MainWindow", "RESET")) self.draw_graph.setText(_translate("MainWindow", "DRAW")) self.PIDStatus_box.setTitle(_translate("MainWindow", "PID Status")) self.label_6.setText(_translate("MainWindow", "Kp:")) self.Kp_data.setHtml( _translate( "MainWindow", "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0//EN\" \"http://www.w3.org/TR/REC-html40/strict.dtd\">\n" "<html><head><meta name=\"qrichtext\" content=\"1\" /><style type=\"text/css\">\n" "p, li { white-space: pre-wrap; }\n" "</style></head><body style=\" font-family:\'MS Shell Dlg 2\'; font-size:10pt; font-weight:400; font-style:normal;\">\n" "<p align=\"center\" style=\"-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-weight:600;\"><br /></p></body></html>" )) self.label_7.setText(_translate("MainWindow", "Ki:")) self.Ki_data.setHtml( _translate( "MainWindow", "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0//EN\" \"http://www.w3.org/TR/REC-html40/strict.dtd\">\n" "<html><head><meta name=\"qrichtext\" content=\"1\" /><style type=\"text/css\">\n" "p, li { white-space: pre-wrap; }\n" "</style></head><body style=\" font-family:\'MS Shell Dlg 2\'; font-size:10pt; font-weight:400; font-style:normal;\">\n" "<p align=\"center\" style=\"-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-weight:600;\"><br /></p></body></html>" )) self.label_8.setText(_translate("MainWindow", "Kd:")) self.Kd_data.setHtml( _translate( "MainWindow", "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0//EN\" \"http://www.w3.org/TR/REC-html40/strict.dtd\">\n" "<html><head><meta name=\"qrichtext\" content=\"1\" /><style type=\"text/css\">\n" "p, li { white-space: pre-wrap; }\n" "</style></head><body style=\" font-family:\'MS Shell Dlg 2\'; font-size:10pt; font-weight:400; font-style:normal;\">\n" "<p align=\"center\" style=\"-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-weight:600;\"><br /></p></body></html>" )) self.label_9.setText(_translate("MainWindow", "Setpoint:")) self.Setpoint_data.setHtml( _translate( "MainWindow", "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0//EN\" \"http://www.w3.org/TR/REC-html40/strict.dtd\">\n" "<html><head><meta name=\"qrichtext\" content=\"1\" /><style type=\"text/css\">\n" "p, li { white-space: pre-wrap; }\n" "</style></head><body style=\" font-family:\'MS Shell Dlg 2\'; font-size:10pt; font-weight:400; font-style:normal;\">\n" "<p align=\"center\" style=\"-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-weight:600;\"><br /></p></body></html>" )) self.send_PID.setText(_translate("MainWindow", "Send PID")) self.get_PID.setText(_translate("MainWindow", "Get PID")) self.Graph_box.setTitle(_translate("MainWindow", "Graph")) self.tabWidget.setTabText(self.tabWidget.indexOf(self.Velocity_tab), _translate("MainWindow", "Velocity")) self.tabWidget.setTabText(self.tabWidget.indexOf(self.Position_tab), _translate("MainWindow", "Position")) self.groupBox_10.setTitle( _translate("MainWindow", "Received/Send data")) self.re_se_data.setHtml( _translate( "MainWindow", "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0//EN\" \"http://www.w3.org/TR/REC-html40/strict.dtd\">\n" "<html><head><meta name=\"qrichtext\" content=\"1\" /><style type=\"text/css\">\n" "p, li { white-space: pre-wrap; }\n" "</style></head><body style=\" font-family:\'MS Shell Dlg 2\'; font-size:8pt; font-weight:400; font-style:normal;\">\n" "<p style=\"-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:8.25pt;\"><br /></p></body></html>" )) self.send.setText(_translate("MainWindow", "SEND")) #disable button, box self.Start.setEnabled(False) self.Stop.setEnabled(False) self.Reset.setEnabled(False) self.testsend.setEnabled(False) self.send.setEnabled(False) self.re_se_data.setEnabled(False) self.send_PID.setEnabled(False) # self.draw_graph.setEnabled(False) def clickedCONNECT(self): global comconnect, ser, i NameCOM = self.COM.currentText() try: if (comconnect == False): self.ser = serial.Serial(NameCOM, 115200, timeout=2.5) self.COM.setEnabled(False) self.Start.setEnabled(True) self.Stop.setEnabled(True) self.Reset.setEnabled(True) self.re_se_data.setEnabled(True) self.testsend.setEnabled(True) self.send.setEnabled(True) self.send_PID.setEnabled(True) self.draw_graph.setEnabled(False) self.connect.setText('DISCONNECT') self.connect.setStyleSheet('QPushButton {color: red;}') self.re_se_data.append('Serial port ' + NameCOM + ' opened') self.timer_getdata.start() comconnect = True else: self.COM.setEnabled(True) self.ser.close() self.Start.setEnabled(False) self.Stop.setEnabled(False) self.Reset.setEnabled(False) self.re_se_data.setEnabled(False) self.testsend.setEnabled(False) self.send.setEnabled(False) self.send_PID.setEnabled(False) self.draw_graph.setEnabled(True) self.connect.setText('CONNECT') self.connect.setStyleSheet('QPushButton {color: green;}') self.re_se_data.append('Serial port ' + NameCOM + ' closed') self.timer_getdata.stop() self.timer_run.stop() comconnect = False i = 0 except IOError: if (comconnect == False): self.re_se_data.append('Serial port ' + NameCOM + ' opening error') else: self.re_se_data.append('Serial port ' + NameCOM + ' closing error') def clickedStart(self): self.re_se_data.append('Motor is runing') strs_tmp = ['0', '0', '\n'] Startdata_send = ' '.join(strs_tmp) self.ser.write(Startdata_send.encode()) #self.timer_run.start() def clickedStop(self): self.re_se_data.append('Motor stopped') strs_tmp = ['0', '1', '\n'] Stopdata_send = ' '.join(strs_tmp) self.ser.write(Stopdata_send.encode()) def clickedReset(self): global i, axis self.Position_graph.clear() self.Velocity_graph.clear() i = 1 axis = [] self.re_se_data.append('System reseted') strs_tmp = ['0', '2', '\n'] Resetdata_send = ' '.join(strs_tmp) self.ser.write(Resetdata_send.encode()) # def clickedSEND(self): # datasend = self.testsend.toPlainText() # self.re_se_data.append(datasend) # self.ser.write('2'.encode()) #recognize the data test # self.ser.write(datasend.encode()) def clickedgetPID(self): global Kp_send, Ki_send, Kd_send, Setpoint_send, PID_send Kp_send = self.Kp_data.toPlainText() Ki_send = self.Ki_data.toPlainText() Kd_send = self.Kd_data.toPlainText() Setpoint_send = self.Setpoint_data.toPlainText() strs_tmp = ['1', Kp_send, Ki_send, Kd_send, Setpoint_send, '\n'] PID_send = ' '.join(strs_tmp) def clickedsendPID(self): global Kp_send, Ki_send, Kd_send, Setpoint_send, PID_send self.ser.write(PID_send.encode()) def recive(self): global axis, ser, i bytetoread = self.ser.inWaiting() try: if bytetoread > 0: receive_data = self.ser.read(bytetoread) axis = receive_data.split() axis_Velocity[i] = int(str(axis[0], 'UTF-8')) axis_Position[i] = int(str(axis[1], 'UTF-8')) self.re_se_data.append(str(axis[0], 'UTF-8')) self.re_se_data.append(str(axis[1], 'UTF-8')) i += 1 except: self.re_se_data.append('bug roi con ga') def clickeddrawgraph(self): global axis_Position, axis_Velocity pen = pg.mkPen(color=(255, 0, 0), width=3) self.Velocity_graph.plot(time, axis_Velocity, pen=pen) self.Position_graph.plot(time, axis_Position, pen=pen)
class PyQtGraphDataPlot(QWidget): limits_changed = Signal() def __init__(self, parent=None): super(PyQtGraphDataPlot, self).__init__(parent) self._plot_widget = PlotWidget() self._plot_widget.getPlotItem().addLegend() self._plot_widget.setBackground((255, 255, 255)) self._plot_widget.setXRange(0, 10, padding=0) vbox = QVBoxLayout() vbox.addWidget(self._plot_widget) self.setLayout(vbox) self._plot_widget.getPlotItem().sigRangeChanged.connect(self.limits_changed) self._curves = {} self._current_vline = None def add_curve(self, curve_id, curve_name, curve_color=QColor(Qt.blue), markers_on=False): pen = mkPen(curve_color, width=1) symbol = "o" symbolPen = mkPen(QColor(Qt.black)) symbolBrush = mkBrush(curve_color) # this adds the item to the plot and legend if markers_on: plot = self._plot_widget.plot(name=curve_name, pen=pen, symbol=symbol, symbolPen=symbolPen, symbolBrush=symbolBrush, symbolSize=4) else: plot = self._plot_widget.plot(name=curve_name, pen=pen) self._curves[curve_id] = plot def remove_curve(self, curve_id): curve_id = str(curve_id) if curve_id in self._curves: self._plot_widget.removeItem(self._curves[curve_id]) del self._curves[curve_id] self._update_legend() def _update_legend(self): # clear and rebuild legend (there is no remove item method for the legend...) self._plot_widget.clear() self._plot_widget.getPlotItem().legend.items = [] for curve in self._curves.values(): self._plot_widget.addItem(curve) if self._current_vline: self._plot_widget.addItem(self._current_vline) def redraw(self): pass def set_values(self, curve_id, data_x, data_y): curve = self._curves[curve_id] curve.setData(data_x, data_y) def vline(self, x, color): if self._current_vline: self._plot_widget.removeItem(self._current_vline) self._current_vline = self._plot_widget.addLine(x=x, pen=color) def set_xlim(self, limits): # TODO: this doesn't seem to handle fast updates well self._plot_widget.setXRange(limits[0], limits[1], padding=0) def set_ylim(self, limits): self._plot_widget.setYRange(limits[0], limits[1], padding=0) def get_xlim(self): x_range, _ = self._plot_widget.viewRange() return x_range def get_ylim(self): _, y_range = self._plot_widget.viewRange() return y_range
class Ui_StateWise(object): def setupUi(self, StateWise): QtGui.QFontDatabase.addApplicationFont( resource_path("Pictures/BankGothic Md BT.ttf")) StateWise.setObjectName("StateWise") StateWise.resize(546, 539) StateWise.setFixedSize(StateWise.size()) self.centralwidget = QtWidgets.QWidget(StateWise) self.centralwidget.setObjectName("centralwidget") self.label = QtWidgets.QLabel(self.centralwidget) self.label.setGeometry(QtCore.QRect(0, 0, 546, 60)) font = QtGui.QFont() font.setFamily("BankGothic Md BT") font.setPointSize(18) font.setBold(False) font.setWeight(50) self.label.setFont(font) self.label.setObjectName("label") self.label_2 = QtWidgets.QLabel(self.centralwidget) self.label_2.setGeometry(QtCore.QRect(20, 100, 300, 41)) font = QtGui.QFont() font.setFamily("BankGothic Md BT") font.setPointSize(14) font.setBold(False) font.setWeight(50) self.label_2.setFont(font) self.label_2.setObjectName("label_2") self.comboBox = QtWidgets.QComboBox(self.centralwidget) self.comboBox.setGeometry(QtCore.QRect(360, 110, 161, 22)) self.comboBox.setObjectName("comboBox") self.label_3 = QtWidgets.QLabel(self.centralwidget) self.label_3.setGeometry(QtCore.QRect(20, 150, 126, 60)) font = QtGui.QFont() font.setFamily("BankGothic Md BT") font.setPointSize(11) font.setBold(True) font.setWeight(100) self.label_3.setFont(font) self.label_3.setObjectName("label_3") self.label_4 = QtWidgets.QLabel(self.centralwidget) self.label_4.setGeometry(QtCore.QRect(145, 150, 126, 60)) font = QtGui.QFont() font.setFamily("BankGothic Md BT") font.setPointSize(11) font.setBold(True) font.setWeight(100) self.label_4.setFont(font) self.label_4.setObjectName("label_4") self.label_5 = QtWidgets.QLabel(self.centralwidget) self.label_5.setGeometry(QtCore.QRect(270, 150, 126, 60)) font = QtGui.QFont() font.setFamily("BankGothic Md BT") font.setPointSize(11) font.setBold(True) font.setWeight(100) self.label_5.setFont(font) self.label_5.setObjectName("label_5") self.label_6 = QtWidgets.QLabel(self.centralwidget) self.label_6.setGeometry(QtCore.QRect(395, 150, 126, 60)) font = QtGui.QFont() font.setFamily("BankGothic Md BT") font.setPointSize(11) font.setBold(True) font.setWeight(100) self.label_6.setFont(font) self.label_6.setObjectName("label_6") self.graphWidget = PlotWidget(self.centralwidget) self.graphWidget.setGeometry(QtCore.QRect(20, 230, 501, 251)) self.graphWidget.setObjectName("graphWidget") StateWise.setCentralWidget(self.centralwidget) self.menubar = QtWidgets.QMenuBar(StateWise) self.menubar.setGeometry(QtCore.QRect(0, 0, 546, 26)) self.menubar.setObjectName("menubar") StateWise.setMenuBar(self.menubar) self.statusbar = QtWidgets.QStatusBar(StateWise) self.statusbar.setObjectName("statusbar") StateWise.setStatusBar(self.statusbar) self.comboBox.currentIndexChanged.connect(self.updates) StateWise.setStyleSheet("background-color:#fff9ea") self.comboBox_2 = QtWidgets.QComboBox(self.centralwidget) self.comboBox_2.setGeometry(QtCore.QRect(360, 485, 161, 22)) self.comboBox_2.setObjectName("comboBox_2") self.comboBox_2.currentIndexChanged.connect(self.updateGraph) self.retranslateUi(StateWise) QtCore.QMetaObject.connectSlotsByName(StateWise) def updateGraph(self): val = self.comboBox.currentText() stateCode = stateDict[val] stateDC = statedaily.loc[statedaily["Status"] == "Confirmed"] stateDR = statedaily.loc[statedaily["Status"] == "Recovered"] stateDD = statedaily.loc[statedaily["Status"] == "Deceased"] stateDCVal = list(stateDC[stateCode]) stateDRVal = list(stateDR[stateCode]) stateDDVal = list(stateDD[stateCode]) stateDates = list(stateDC["Date"]) tmp = self.comboBox_2.currentText() if (tmp == "Confirmed"): self.plot(stateDates, stateDCVal) if (tmp == "Recovered"): self.plot(stateDates, stateDRVal, c1='#C0E5C8', c2='#E4F4E8', c3='#29A746') if (tmp == "Deceased"): self.plot(stateDates, stateDDVal, c1='#706CC3', c2='#E3E2F3', c3='#3D37AD') def updates(self): _translate = QtCore.QCoreApplication.translate val = self.comboBox.currentText() state = statewise.loc[statewise['State'] == val] confirmed = int(state['Confirmed']) recovered = int(state['Recovered']) deaths = int(state['Deaths']) active = int(state['Active']) self.label_3.setText( _translate("StateWise", "Confirmed:" + "\n" + str(confirmed))) self.label_4.setText( _translate("StateWise", "Active:" + "\n" + str(active))) self.label_5.setText( _translate("StateWise", "Recovered:" + "\n" + str(recovered))) self.label_6.setText( _translate("StateWise", "Deceased:" + "\n" + str(deaths))) stateCode = stateDict[val] stateDC = statedaily.loc[statedaily["Status"] == "Confirmed"] stateDR = statedaily.loc[statedaily["Status"] == "Recovered"] stateDD = statedaily.loc[statedaily["Status"] == "Deceased"] stateDCVal = list(stateDC[stateCode]) stateDRVal = list(stateDR[stateCode]) stateDDVal = list(stateDD[stateCode]) stateDates = list(stateDC["Date"]) self.plot(stateDates, stateDCVal) self.updateGraph() def plot(self, x, y, c1="#FF6282", c2="#FFE0E6", c3="#FF083B"): xdict = dict(enumerate(x)) xax = self.graphWidget.getAxis('bottom') xax.setTicks([xdict.items()]) pen = pg.mkPen( color=c1, width=5, ) self.graphWidget.clear() #self.graphWidget.setLabel('left', "<span style=\"color:#017CFF;font-size:20px;background-color:#EFF7FF\"> Active </span>") #self.graphWidget.setLabel('bottom',"<span style=\"color:#29A746;font-size:20px;background-color:#E4F4E8\"> Recovered </span>") self.data_line = self.graphWidget.plot(list(xdict), y, pen=pen, symbol='o', symbolSize=10, symbolBrush=(c3)) self.graphWidget.setBackground(c2) def retranslateUi(self, StateWise): _translate = QtCore.QCoreApplication.translate StateWise.setWindowTitle(_translate("StateWise", "Statewise Analysis")) self.label.setText(_translate("StateWise", "Statewise Analysis")) self.label.setStyleSheet( 'color: #FD7F15;background-color: #FFF3D0;background-image:url("");qproperty-alignment: AlignCenter;' ) self.label_2.setText(_translate("StateWise", " Select a State/U.T :")) self.label_2.setStyleSheet( 'color: #FC9274;background-color: #FEE5D9;background-image:url("");' ) self.label_3.setStyleSheet( 'color: #FF2D58;background-color: #F8CCCA;background-image:url("");qproperty-alignment: AlignCenter;' ) self.label_4.setStyleSheet( 'color: #017CFF;background-color: #EFF7FF;background-image:url("");qproperty-alignment: AlignCenter;' ) self.label_5.setStyleSheet( 'color:#29A746;background-color: #E4F4E8;background-image:url("");qproperty-alignment: AlignCenter;' ) self.label_6.setStyleSheet( 'color:#767E85;background-color: #F6F6F7;background-image:url("");qproperty-alignment: AlignCenter;' ) self.comboBox.addItems(StateList) self.comboBox_2.addItems(["Confirmed", "Recovered", "Deceased"]) self.comboBox_2.setStyleSheet("background-color:white")
class PyQtGraphDataPlot(QWidget): limits_changed = Signal() def __init__(self, parent=None): super(PyQtGraphDataPlot, self).__init__(parent) self._plot_widget = PlotWidget() self._plot_widget.getPlotItem().addLegend() self._plot_widget.setBackground((255, 255, 255)) self._plot_widget.setXRange(0, 10, padding=0) vbox = QVBoxLayout() vbox.addWidget(self._plot_widget) self.setLayout(vbox) self._plot_widget.getPlotItem().sigRangeChanged.connect( self.limits_changed) self.bins = 10 self.window = 100 self._curves = {} self._current_vline = None def add_curve(self, curve_id, curve_name, curve_color=QColor(Qt.blue), markers_on=False): pen = mkPen(curve_color, width=1) # this adds the item to the plot and legend plot = self._plot_widget.plot(stepMode=True, fillLevel=0, brush=(0, 0, 255, 150)) self._curves[curve_id] = plot def remove_curve(self, curve_id): curve_id = str(curve_id) if curve_id in self._curves: self._plot_widget.removeItem(self._curves[curve_id]) del self._curves[curve_id] self._update_legend() def _update_legend(self): # clear and rebuild legend (there is no remove item method for the legend...) self._plot_widget.clear() self._plot_widget.getPlotItem().legend.items = [] for curve in self._curves.values(): self._plot_widget.addItem(curve) if self._current_vline: self._plot_widget.addItem(self._current_vline) def redraw(self): pass def set_values(self, curve_id, data_x, data_y): curve = self._curves[curve_id] if len(data_y) > 0: y, x = numpy.histogram(data_y[-self.window:], self.bins) curve.setData(x, y) else: curve.clear() self._plot_widget.autoRange() def vline(self, x, color): if self._current_vline: self._plot_widget.removeItem(self._current_vline) self._current_vline = self._plot_widget.addLine(x=x, pen=color) def set_xlim(self, limits): # TODO: this doesn't seem to handle fast updates well self._plot_widget.setXRange(limits[0], limits[1], padding=0) def set_ylim(self, limits): self._plot_widget.setYRange(limits[0], limits[1], padding=0) def get_xlim(self): x_range, _ = self._plot_widget.viewRange() return x_range def get_ylim(self): _, y_range = self._plot_widget.viewRange() return y_range
class ComplicatedTestResultsDialog(QMainWindow): def __init__(self, parent=None, methods=None, vertices_amounts=None, samples_amount=None, name_1=None, name_2=None): super(ComplicatedTestResultsDialog, self).__init__(parent) self.parent_window = parent self.setWindowTitle("Grismo - Wyniki dla testu wpływu liczby " + name_1) self.setMinimumWidth(630) self.setMinimumHeight(800) self.setMaximumHeight(900) self.methods = methods self.results_count = 0 self.start_vertices = vertices_amounts[0] self.all_vertices_amount = len(vertices_amounts) self.samples_amount = samples_amount # store all results to calculate means self.all_results = [] central = QWidget() self.setCentralWidget(central) central_layout = QVBoxLayout() central.setLayout(central_layout) # plot box plot_label = QLabel("Wykres dla wszystkich testów:") central_layout.addWidget(plot_label) self.plot_log_mode = False self.results_plot = PlotWidget() self.results_plot.setLogMode(False, self.plot_log_mode) self.results_plot.setBackground('w') self.results_plot.setTitle("Badanie wpływu liczby " + name_1 + " na czas testu") self.results_plot.setLabel('left', 'Czas obliczeń [s]', color='k', size=10) self.results_plot.setLabel('bottom', 'Liczba ' + name_1, color='k', size=10) self.results_plot.setXRange(self.start_vertices, vertices_amounts[-1]) self.results_plot.setMaximumWidth(600) self.results_plot.showGrid(y=True) central_layout.addWidget(self.results_plot) switch_plot_log_button = QPushButton("Zmień skalę osi Y (logarytmiczna/liniowa)") switch_plot_log_button.setCheckable(False) switch_plot_log_button.clicked.connect(self.switch_plot_log) central_layout.addWidget(switch_plot_log_button) # prepare plot lines self.plot_data = [] method_colors = ['k', 'b', 'g', 'r', 'y'] self.results_plot.plot([], [], name="") self.results_plot.addLegend() for method_index in range(len(self.methods)): method_name = self.methods[method_index] method_color = method_colors[method_index] pen = mkPen(color=method_color, width=2) self.plot_data.append(self.results_plot.plot([], [], name=method_name, pen=pen, symbol='+', symbolSize=10, symbolBrush=method_color)) self.results_plot.addLegend() # tables box tables_box = QScrollArea(self) tables_box.setWidgetResizable(True) tables_box_content = QWidget(tables_box) tables_box_layout = QVBoxLayout(tables_box_content) tables_box_content.setLayout(tables_box_layout) tables_box.setWidget(tables_box_content) central_layout.addWidget(tables_box) # for each vertices_amount prepare table: label -> table -> label -> progress_bar self.results_tables = [] self.results_progress_bars = [] bold_font = QFont() bold_font.setBold(True) for i in vertices_amounts: vertices_label = QLabel("Wyniki dla grafów o " + str(i) + " " + name_2 + ":") vertices_label.setFont(bold_font) results_table = QTableWidget() results_table.setRowCount(len(methods)) results_table.setColumnCount(4) results_table.setColumnWidth(1, 150) results_table.setColumnWidth(2, 150) results_table.setMinimumHeight((len(methods) + 1) * 30) results_table.setHorizontalHeaderLabels(["Metoda", "Wyniki pozytywne", "Wyniki negatywne", "Średni czas [s]"]) progress_label = QLabel("Postęp:") results_progress_bar = QProgressBar() results_progress_bar.setValue(0) self.results_tables.append(results_table) self.results_progress_bars.append(results_progress_bar) tables_box_layout.addWidget(vertices_label) tables_box_layout.addWidget(results_table) tables_box_layout.addWidget(progress_label) tables_box_layout.addWidget(results_progress_bar) self.all_results.append([]) for method_index in range(len(methods)): method_title = methods[method_index] results_table.setItem(method_index, 0, QTableWidgetItem(method_title)) self.all_results[-1].append([]) def add_result(self, result, vertices_amount, sample_number): # result: [method, decision, time] # vertices table index table_index = vertices_amount - self.start_vertices # method index method_index = self.methods.index(result[0]) # add result to all stored results self.all_results[table_index][method_index].append(result) # positive and negatives # firstly extract 2nd column from results matrix new_positives = sum([row[1] for row in self.all_results[table_index][method_index]]) new_negatives = len(self.all_results[table_index][method_index]) - new_positives self.results_tables[table_index].setItem(method_index, 1, QTableWidgetItem(str(new_positives))) self.results_tables[table_index].setItem(method_index, 2, QTableWidgetItem(str(new_negatives))) # mean new_mean = mean([row[2] for row in self.all_results[table_index][method_index]]) self.results_tables[table_index].setItem(method_index, 3, QTableWidgetItem(str(new_mean))) # progress_bar self.results_progress_bars[table_index].setValue(sample_number / self.samples_amount * 100) self.results_count = self.results_count + 1 # update plot self.update_plot() def update_plot(self): for method_index in range(len(self.methods)): # for this method find all mean values x = [] y = [] for vertices_index in range(self.all_vertices_amount): vertices_amount = vertices_index + self.start_vertices if len(self.all_results[vertices_index][method_index]): x.append(vertices_amount) y.append(mean([row[2] for row in self.all_results[vertices_index][method_index]])) self.plot_data[method_index].setData(x, y) def switch_plot_log(self): self.plot_log_mode = not self.plot_log_mode self.results_plot.setLogMode(False, self.plot_log_mode) def closeEvent(self, event): self.parent_window.stop_test = True
class Ui_MainWindow(QtWidgets.QMainWindow): def setupUi(self, MainWindow): MainWindow.setObjectName("MainWindow") MainWindow.setFixedSize(800, 618) MainWindow.setStyleSheet('background:#e8e8e8') #here starts widget setup, mostly just assigning locations and various properties self.centralwidget = QtWidgets.QWidget(MainWindow) self.centralwidget.setObjectName("centralwidget") self.topDisplayDivider = QtWidgets.QFrame(self.centralwidget) self.topDisplayDivider.setGeometry(QtCore.QRect(0, 90, 801, 16)) self.topDisplayDivider.setFrameShape(QtWidgets.QFrame.HLine) self.topDisplayDivider.setFrameShadow(QtWidgets.QFrame.Sunken) self.topDisplayDivider.setObjectName("topDisplayDivider") self.menuDivider = QtWidgets.QFrame(self.centralwidget) self.menuDivider.setGeometry(QtCore.QRect(110, 100, 16, 501)) self.menuDivider.setFrameShape(QtWidgets.QFrame.VLine) self.menuDivider.setFrameShadow(QtWidgets.QFrame.Sunken) self.menuDivider.setObjectName("menuDivider") self.pushHistory = QtWidgets.QPushButton(self.centralwidget) self.pushHistory.setGeometry(QtCore.QRect(20, 140, 75, 23)) self.pushHistory.setObjectName("pushHistory") self.pushHistory.setStyleSheet("border: 1px solid grey;") self.pushAnalytics = QtWidgets.QPushButton(self.centralwidget) self.pushAnalytics.setGeometry(QtCore.QRect(20, 210, 75, 23)) self.pushAnalytics.setObjectName("pushAnalytics") self.pushExport = QtWidgets.QPushButton(self.centralwidget) self.pushExport.setGeometry(QtCore.QRect(20, 280, 75, 23)) self.pushExport.setObjectName("pushExport") self.pushOptions = QtWidgets.QPushButton(self.centralwidget) self.pushOptions.setGeometry(QtCore.QRect(20, 350, 75, 23)) self.pushOptions.setObjectName("pushOptions") self.pushLive = QtWidgets.QPushButton(self.centralwidget) self.pushLive.setGeometry(QtCore.QRect(20, 550, 75, 23)) self.pushLive.setObjectName("pushLive") self.pushGraph = QtWidgets.QPushButton(self.centralwidget) self.pushGraph.setGeometry(QtCore.QRect(200, 550, 75, 23)) self.pushGraph.setObjectName("pushGraph") self.pushGraph2 = QtWidgets.QPushButton(self.centralwidget) self.pushGraph2.setGeometry(QtCore.QRect(300, 550, 75, 23)) self.pushGraph2.setObjectName("pushGraph2") self.liveDisplay_1 = QtWidgets.QLabel(self.centralwidget) self.liveDisplay_1.setGeometry(QtCore.QRect(710, 20, 61, 61)) self.liveDisplay_1.setObjectName("liveDisplay_1") self.liveDisplay_1.setStyleSheet("font: 30pt Arial MS") self.liveDisplay_2 = QtWidgets.QLabel(self.centralwidget) self.liveDisplay_2.setGeometry(QtCore.QRect(570, 20, 61, 61)) self.liveDisplay_2.setObjectName("liveDisplay_2") self.liveDisplay_2.setStyleSheet("font: 30pt Arial MS") self.label = QtWidgets.QLabel(self.centralwidget) self.label.setGeometry(QtCore.QRect(500, 20, 61, 61)) self.label.setText("") self.label.setPixmap(QtGui.QPixmap("heart.png")) self.label.setScaledContents(True) self.label.setObjectName("label") self.label_2 = QtWidgets.QLabel(self.centralwidget) self.label_2.setGeometry(QtCore.QRect(640, 20, 61, 61)) self.label_2.setText("") self.label_2.setPixmap(QtGui.QPixmap("o2.png")) self.label_2.setScaledContents(True) self.label_2.setObjectName("label_2") self.groupBox = QtWidgets.QGroupBox(self.centralwidget) self.groupBox.setGeometry(QtCore.QRect(140, 120, 631, 311)) self.groupBox.setObjectName("groupBox") self.label_3 = QtWidgets.QLabel(self.groupBox) self.label_3.setGeometry(QtCore.QRect(210, 110, 151, 31)) self.label_3.setObjectName("label_3") self.dateTimeEdit = QtWidgets.QDateEdit(self.centralwidget) self.dateTimeEdit.setGeometry(QtCore.QRect(190, 490, 194, 22)) self.dateTimeEdit.setObjectName("dateTimeEdit") self.dateTimeEdit.setDate(QDate.currentDate()) self.label_6 = QtWidgets.QLabel(self.centralwidget) self.label_6.setGeometry(QtCore.QRect(40, 20, 251, 41)) font = QtGui.QFont() font.setPointSize(19) self.label_6.setFont(font) self.label_6.setObjectName("label_6") MainWindow.setCentralWidget(self.centralwidget) self.menubar = QtWidgets.QMenuBar(MainWindow) self.menubar.setGeometry(QtCore.QRect(0, 0, 800, 21)) self.menubar.setObjectName("menubar") MainWindow.setMenuBar(self.menubar) self.statusbar = QtWidgets.QStatusBar(MainWindow) self.statusbar.setObjectName("statusbar") MainWindow.setStatusBar(self.statusbar) #creating graphs self.graphWidgetLive = PlotWidget(self.centralwidget) self.graphWidgetLive.setGeometry(QtCore.QRect(40, 10, 400, 70)) self.graphWidgetLive.setObjectName("graphWidgetLive") self.graphWidgetLive.getPlotItem().hideAxis('bottom') self.graphWidgetLive.setMouseEnabled(x=False, y=False) self.graphWidgetLive.setYRange(0, 150, padding=0.2) self.graphWidgetLive.getPlotItem().hideAxis('bottom') self.graphWidgetMain = PlotWidget(self.centralwidget) self.graphWidgetMain.setGeometry(QtCore.QRect(150, 140, 600, 275)) self.graphWidgetMain.setObjectName("graphWidgetLive") self.graphWidgetMain.setMouseEnabled(x=True, y=False) self.graphWidgetMain.setYRange(50, 150, padding=0) self.graphWidgetMain.getPlotItem().hideAxis('bottom') self.graphWidgetLive.setBackground('w') pen = pg.mkPen(color=(255, 0, 0), width=2) pen2 = pg.mkPen(color=(0, 0, 255), width=2) time = [1, 2, 3, 4] heartRate = [90, 87, 88, 85] oxygenLevel = [100, 99, 99, 98] self.graphWidgetMain.setBackground('w') self.graphWidgetMain.plot(time, heartRate, pen=pen) self.graphWidgetMain.plot(time, oxygenLevel, pen=pen2) #these two values can be changed in options and are parameters for the windows notifications self.notifThresh = [120, 95] self.notifCooldown = 25 self.serialInput = False self.retranslateUi(MainWindow) QtCore.QMetaObject.connectSlotsByName(MainWindow) #connecting buttons self.pushAnalytics.clicked.connect(self.show_Analysis) self.pushExport.clicked.connect(self.show_export) self.pushOptions.clicked.connect(self.show_popOptions) self.pushLive.setCheckable(True) self.pushLive.clicked.connect(self.show_graphLive) self.pushGraph.clicked.connect(self.fromFile) self.pushGraph2.clicked.connect(self.fromDate) def update_plot_data(self): #this is used to update the live graph by reading from serial or the debugging simulator self.timeLive = self.timeLive[1:] # Remove the first y element. self.timeLive.append(self.timeLive[-1] + 1) # Add a new value 1 higher than the last. if self.serialInput == True: serialData = serial_connection.getSerial() else: serialData = (singleGenerate(79, 3), singleGenerate(97, 1)) if serialData[0] != 0: self.liveHR = self.liveHR[1:] # Remove the first self.liveHR.append(serialData[0]) self.liveDisplay_2.setText(str(self.liveHR[99])) if serialData[1] != 0: self.liveO2 = self.liveO2[1:] # Remove the first self.liveO2.append(serialData[1]) self.liveDisplay_1.setText(str(self.liveO2[99])) if not (serialData[0] == 0 & serialData[1] == 0): datasystem.data_store(serialData[0], serialData[1]) a = datetime.datetime.now() b = self.startTime c = a - b print(c.total_seconds()) if c.total_seconds() > self.notifCooldown: if self.notifThresh[0] < serialData[0]: windowsalert.sendNotifH() self.startTime = datetime.datetime.now() if self.notifThresh[1] > serialData[1] & serialData[1] != 0: windowsalert.sendNotifO() self.startTime = datetime.datetime.now() self.data_line_1.setData(self.timeLive, self.liveHR) # Update the data. self.data_line_2.setData(self.timeLive, self.liveO2) # Update the data. def show_export(self): #used to call the zipping function in datasystem.py, and the file dialog options = QFileDialog.Options() | QFileDialog.DontUseNativeDialog fileName = QFileDialog.getSaveFileName(self, "Select an export location", "", "Zip Files (*.zip)", options=options) datasystem.data_zip(fileName[0] + '.zip') def show_graphLive(self): #connects to the button for live, and also controls if the graph/reading is enabled self.timeLive = list(range(100)) # 100 time points self.liveHR = [0] * 100 self.liveO2 = [0] * 100 self.startTime = datetime.datetime.now() - datetime.timedelta( seconds=self.notifCooldown) print(self.startTime) pen = pg.mkPen(color=(255, 0, 0), width=2) pen2 = pg.mkPen(color=(0, 0, 255), width=2) self.liveDisplay_2.setText('0') self.liveDisplay_1.setText('0') if self.pushLive.isChecked(): self.data_line_1 = self.graphWidgetLive.plot(self.timeLive, self.liveHR, pen=pen) self.data_line_2 = self.graphWidgetLive.plot(self.timeLive, self.liveO2, pen=pen2) self.timer = QtCore.QTimer() self.timer.setInterval(250) self.timer.timeout.connect(self.update_plot_data) self.timer.start() self.pushLive.setText('Stop') else: self.timer.stop() self.graphWidgetLive.clear() self.pushLive.setText('Start') def fromDate(self): #used to connect the date picker to the main graph x = self.dateTimeEdit.date().toPyDate() date = 'vitals' + str(x) directory = os.getcwd() foldername = directory + '\\vitalsmouse_userdata' self.importfile = foldername + '\\' + date + '.csv' self.show_graphMain() def fromFile(self): #used to connect the file dialog to the main graph options = QFileDialog.Options() | QFileDialog.DontUseNativeDialog fileName = QFileDialog.getOpenFileName(self, "Select a file to view", "", "CSV Files (*.csv)", options=options) self.importfile = fileName[0] self.show_graphMain() def show_graphMain(self): #loads the data from a file and displays it on the main graph print(self.importfile) self.graphWidgetMain.clear() maindata = datasystem.data_get(self.importfile) mainTime = maindata[0] mainHR = maindata[1] mainO2 = maindata[2] pen = pg.mkPen(color=(255, 0, 0), width=2) pen2 = pg.mkPen(color=(0, 0, 255), width=2) self.graphWidgetMain.setBackground('w') self.graphWidgetMain.plot(mainTime, mainHR, pen=pen) self.graphWidgetMain.plot(mainTime, mainO2, pen=pen2) def show_popOptions(self): #secondary window for options self.Options = QDialog() self.Options.resize(200, 250) self.input_label = QtWidgets.QLabel(self.Options) self.input_label.setGeometry(QtCore.QRect(10, 10, 61, 51)) self.input_label.setObjectName("input_label") self.inputBox = QtWidgets.QComboBox(self.Options) self.inputBox.setGeometry(QtCore.QRect(80, 30, 69, 22)) self.inputBox.setObjectName("inputBox") self.inputBox.addItem('Debug') self.inputBox.addItem('USB') self.notificationsBox = QtWidgets.QGroupBox(self.Options) self.notificationsBox.setGeometry(QtCore.QRect(0, 90, 211, 131)) self.notificationsBox.setObjectName("notificationsBox") self.lineEdit = QtWidgets.QLineEdit(self.notificationsBox) self.lineEdit.setGeometry(QtCore.QRect(130, 30, 61, 20)) self.lineEdit.setObjectName("lineEdit") self.hr_label = QtWidgets.QLabel(self.notificationsBox) self.hr_label.setGeometry(QtCore.QRect(6, 30, 111, 20)) self.hr_label.setObjectName("hr_label") self.lineEdit_2 = QtWidgets.QLineEdit(self.notificationsBox) self.lineEdit_2.setGeometry(QtCore.QRect(130, 60, 61, 20)) self.lineEdit_2.setObjectName("lineEdit_2") self.lineEdit_3 = QtWidgets.QLineEdit(self.notificationsBox) self.lineEdit_3.setGeometry(QtCore.QRect(130, 90, 61, 20)) self.lineEdit_3.setObjectName("lineEdit_3") self.o2_label = QtWidgets.QLabel(self.notificationsBox) self.o2_label.setGeometry(QtCore.QRect(10, 60, 111, 20)) self.o2_label.setObjectName("o2_label") self.cooldown_label = QtWidgets.QLabel(self.notificationsBox) self.cooldown_label.setGeometry(QtCore.QRect(10, 90, 111, 20)) self.cooldown_label.setObjectName("cooldown_label") self.input_label.setText("Input mode") self.notificationsBox.setTitle(("Notifications")) self.lineEdit.setText(("110")) self.hr_label.setText(("Heartrate threshold")) self.lineEdit_2.setText(("95")) self.lineEdit_3.setText(("20")) self.o2_label.setText(("Oxygen threshold")) self.cooldown_label.setText(("Cooldown(seconds)")) self.Options.setWindowTitle("Options") self.Options.exec_() h = self.inputBox.currentText() if h == 'USB': self.serialInput = True else: self.serialInput = False heartThresh = self.lineEdit.text() o2Thresh = self.lineEdit_2.text() cool = self.lineEdit_3.text() self.notifThresh = (int(heartThresh), int(o2Thresh)) self.notifCooldown = int(cool) def show_Analysis(self): #secondary window for analysis self.Analysis = QDialog() self.Analysis.resize(400, 400) self.dailyLine = QtWidgets.QLineEdit(self.Analysis) self.dailyLine.setGeometry(QtCore.QRect(210, 60, 113, 20)) self.dailyLine.setReadOnly(True) self.dailyLine.setObjectName("dailyLine") self.yearly_label = QtWidgets.QLabel(self.Analysis) self.yearly_label.setGeometry(QtCore.QRect(40, 140, 101, 16)) self.yearly_label.setObjectName("yearly_label") self.monthly_label = QtWidgets.QLabel(self.Analysis) self.monthly_label.setGeometry(QtCore.QRect(40, 100, 111, 16)) self.monthly_label.setObjectName("monthly_label") self.monthlyLine = QtWidgets.QLineEdit(self.Analysis) self.monthlyLine.setGeometry(QtCore.QRect(210, 100, 113, 20)) self.monthlyLine.setReadOnly(True) self.monthlyLine.setObjectName("monthlyLine") self.daily_label = QtWidgets.QLabel(self.Analysis) self.daily_label.setGeometry(QtCore.QRect(40, 60, 111, 16)) self.daily_label.setObjectName("daily_label") self.yearlyLine = QtWidgets.QLineEdit(self.Analysis) self.yearlyLine.setGeometry(QtCore.QRect(210, 140, 113, 20)) self.yearlyLine.setReadOnly(True) self.yearlyLine.setObjectName("yearlyLine") self.legend_label = QtWidgets.QLabel(self.Analysis) self.legend_label.setGeometry(QtCore.QRect(220, 20, 113, 20)) self.legend_label.setObjectName("legend_label") self.legend_label.setText("Heartrate, Oxygen") self.graphWidgetAnalysis = PlotWidget(self.Analysis) self.graphWidgetAnalysis.setGeometry(QtCore.QRect(50, 200, 300, 150)) self.graphWidgetAnalysis.setObjectName("graphWidgetLive") self.graphWidgetAnalysis.setMouseEnabled(x=False, y=False) self.graphWidgetAnalysis.setYRange(50, 150, padding=0) self.graphWidgetAnalysis.getPlotItem().hideAxis('bottom') analysis_data = datasystem.data_analysis() pen = pg.mkPen(color=(255, 0, 0), width=2) pen2 = pg.mkPen(color=(0, 0, 255), width=2) heartRate = analysis_data[3][0] oxygenLevel = analysis_data[3][1] length = len(heartRate) time = [int(z) for z in range(length)] self.graphWidgetAnalysis.setBackground('w') self.graphWidgetAnalysis.plot(time, heartRate, pen=pen) self.graphWidgetAnalysis.plot(time, oxygenLevel, pen=pen2) self.dailyLine.setText( str(round(analysis_data[0][0], 2)) + ', ' + str(round(analysis_data[0][1], 2))) self.monthlyLine.setText( str(round(analysis_data[1][0], 2)) + ', ' + str(round(analysis_data[1][1], 2))) self.yearlyLine.setText( str(round(analysis_data[2][0], 2)) + ', ' + str(round(analysis_data[2][1], 2))) self.yearly_label.setText("Yearly Average") self.monthly_label.setText("Monthly Average") self.daily_label.setText("Daily Average") self.Analysis.setWindowTitle("Analysis") self.Analysis.exec_() def retranslateUi(self, MainWindow): #this is a holdover from using pyuic5, not normally used like this _translate = QtCore.QCoreApplication.translate MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow")) self.pushHistory.setText(_translate("MainWindow", "History")) self.pushAnalytics.setText(_translate("MainWindow", "Analytics")) self.pushExport.setText(_translate("MainWindow", "Export")) self.pushOptions.setText(_translate("MainWindow", "Options")) self.pushLive.setText(_translate("MainWindow", "Start")) self.pushGraph.setText(_translate("MainWindow", "From file")) self.pushGraph2.setText(_translate("MainWindow", "From date")) self.liveDisplay_1.setText("##") self.liveDisplay_2.setText("##") self.groupBox.setTitle(_translate("MainWindow", "History"))
class RealtimePlotWidget(QWidget): AUTO_RANGE_FRACTION = 0.99 COLORS = [Qt.red, Qt.blue, Qt.green, Qt.magenta, Qt.cyan, Qt.darkRed, Qt.darkBlue, Qt.darkGreen, Qt.darkYellow, Qt.gray] def __init__(self, display_measurements, parent): super(RealtimePlotWidget, self).__init__(parent) self.setAttribute(Qt.WA_DeleteOnClose) # This is required to stop background timers! self._plot_widget = PlotWidget() self._plot_widget.setBackground((0, 0, 0)) self._legend = self._plot_widget.addLegend() self._plot_widget.showButtons() self._plot_widget.showGrid(x=True, y=True, alpha=0.3) vbox = QVBoxLayout(self) vbox.addWidget(self._plot_widget) self.setLayout(vbox) self._last_update_ts = 0 self._reset_required = False self._update_timer = QTimer(self) self._update_timer.setSingleShot(False) self._update_timer.timeout.connect(self._update) self._update_timer.start(200) self._color_index = 0 self._curves = {} # Crosshair def _render_measurements(cur, ref): text = 'time %.6f sec, y %.6f' % cur if ref is None: return text dt = cur[0] - ref[0] dy = cur[1] - ref[1] if abs(dt) > 1e-12: freq = '%.6f' % abs(1 / dt) else: freq = 'inf' display_measurements(text + ';' + ' ' * 4 + 'dt %.6f sec, freq %s Hz, dy %.6f' % (dt, freq, dy)) display_measurements('Hover to sample Time/Y, click to set new reference') add_crosshair(self._plot_widget, _render_measurements) # Final reset self.reset() def _trigger_auto_reset_if_needed(self): ts = time.monotonic() dt = ts - self._last_update_ts self._last_update_ts = ts if dt > 2: self._reset_required = True def add_curve(self, curve_id, curve_name, data_x=[], data_y=[]): color = QColor(self.COLORS[self._color_index % len(self.COLORS)]) self._color_index += 1 pen = mkPen(color, width=1) plot = self._plot_widget.plot(name=curve_name, pen=pen) data_x = numpy.array(data_x) data_y = numpy.array(data_y) self._curves[curve_id] = {'data': (data_x, data_y), 'plot': plot} self._trigger_auto_reset_if_needed() def update_values(self, curve_id, x, y): curve = self._curves[curve_id] old_x, old_y = curve['data'] curve['data'] = numpy.append(old_x, x), numpy.append(old_y, y) self._trigger_auto_reset_if_needed() def reset(self): for curve in self._curves.keys(): self._plot_widget.removeItem(self._curves[curve]['plot']) self._curves = {} self._color_index = 0 self._plot_widget.enableAutoRange(enable=self.AUTO_RANGE_FRACTION, x=self.AUTO_RANGE_FRACTION, y=self.AUTO_RANGE_FRACTION) self._legend.scene().removeItem(self._legend) self._legend = self._plot_widget.addLegend() def _update(self): if self._reset_required: self.reset() self._reset_required = False for curve in self._curves.values(): if len(curve['data'][0]): curve['plot'].setData(*curve['data'])