def _plot(self): """ Network performance graph """ setConfigOption('background', '#FF000000') _graph = PlotWidget() _graph.setMenuEnabled(enableMenu=False) _graph.setMouseEnabled(x=False, y=False) _graph.hideButtons() self._out_curve = _graph.getPlotItem().plot() self._inc_curve = _graph.getPlotItem().plot() self._legend = LegendItem(offset=(50, 10)) self._legend.setParentItem(_graph.getPlotItem()) self._legend.addItem(self._out_curve, self._lang.NetworkGraphOutgoing) self._legend.addItem(self._inc_curve, self._lang.NetworkGraphIncoming) self._base.net_perf_lyt.addWidget(_graph) self._menu_popup = QMenu() _action = QAction(QIcon('icon/reload.png'), self._lang.PopupReload, self._base.net_perf_box) _action.triggered.connect(self.reload) self._menu_popup.addAction(_action) self._base.net_perf_box.setContextMenuPolicy(Qt.CustomContextMenu) self._base.net_perf_box.customContextMenuRequested.connect( self._popup_show)
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 FFTViewerUi(Frontend): backend: FFTAnalyzer gui = 'gui/image_viewer.ui' def setupUi(self): super().setupUi() self.widget = PlotWidget(parent=self) self.setCentralWidget(self.widget) self.plot_item = self.widget.getPlotItem() self.plot_item.setLabel('left', 'Intensity') self.plot_item.setLabel('bottom', 'Position') self.plot_item.showGrid(x=True, y=True, alpha=0.3) self.plot_item.enableAutoScale() self.plot_data_item = self.plot_item.plot(x=np.zeros((2, )), y=np.zeros((2, ))) def connect_backend(self): super().connect_backend() self.backend.new_data.connect(self.refresh) def refresh(self, fft, timestamp=None): self.plot_data_item.setData(x=fft.x, y=fft.absolute)
def __call__(self) -> PlotWidget: """ Generate an interactive pyqtgraph plot widget from this plotter's data """ graph = PlotWidget() plot = graph.getPlotItem() plot.setLabel("left", "membrane potential (mV)") plot.setLabel("bottom", "time (s)") plot.addLegend() if self.initial is not None: plot.plot(self.time, self.initial, pen=mkPen(color=TEST_PULSE_INIT_COLOR, width=2), name="initial") if self.previous is not None: plot.plot(self.time, self.previous, pen=mkPen(color=TEST_PULSE_PREV_COLOR, width=2), name="previous") plot.plot(self.time, self.voltage, pen=mkPen(color=TEST_PULSE_CURRENT_COLOR, width=2), name=f"sweep {self.sweep_number}") return graph
class SpectraViewerUi(Frontend): backend: SpectraAnalyzer gui = 'gui/image_viewer.ui' def setupUi(self): super().setupUi() self.widget = PlotWidget(parent=self) self.setCentralWidget(self.widget) self.plot_item = self.widget.getPlotItem() self.plot_item.setLabel('left', 'Intensity') self.plot_item.setLabel('bottom', 'Wavelength') self.plot_item.showGrid(x=True, y=True, alpha=0.3) self.plot_item.enableAutoRange() self.plot_data_item = self.plot_item.plot(x=np.zeros((2, )), y=np.zeros((2, ))) def connect_backend(self): super().connect_backend() self.backend.new_data.connect(self.refresh) def refresh(self, spectrum, timestamp=None): self.plot_data_item.setData(x=spectrum.x, y=spectrum.y.flatten())
class rabi_plot(QtGui.QWidget): def __init__(self, parent=None, gage = None, d= None, s =None, NI = None): QtGui.QWidget.__init__(self, parent) self.initGUI() def initGUI(self): self.p_upper = PlotWidget() self.p_lower = PlotWidget() layout = QtGui.QVBoxLayout() layout.addWidget(self.p_upper) layout.addWidget(self.p_lower) self.setLayout(layout) self.p1 = self.p_upper.getPlotItem() self.p2 = self.p_lower.getPlotItem() self.p1.addLegend() self.p1data = self.p1.plot([0],pen = 'r', name = 'averaged') self.p2data = self.p1.plot([0],pen = 'g', name = 'instant') self.p1.setLabel('bottom','Time','ns') self.p2.setLabel('bottom','Freq','kHz') self.p_upper.setTitle('Rabi raw data') self.p_lower.setTitle('Rabi FFT')
class timetraceplots(QtGui.QWidget): def __init__(self, parent=None): QtGui.QWidget.__init__(self, parent) self.initGUI() def initGUI(self): self.plot = PlotWidget() layout = QtGui.QHBoxLayout() layout.addWidget(self.plot) self.setLayout(layout) self.p1 = self.plot.getPlotItem() self.p2 = self.plot.getPlotItem() self.p1.addLegend() self.p1data = self.p1.plot([0],pen = 'r',name = ' ch 1') self.p2data = self.p2.plot([0],pen = 'g', name = ' ch 2') self.vLine5 = pg.InfiniteLine(angle=90, movable=True) self.p1.addItem(self.vLine5, ignoreBounds=True)
def __call__(self) -> PlotWidget: """ Generate an interactive pyqtgraph plot widget from this plotter's data """ graph = PlotWidget() plot = graph.getPlotItem() plot.setLabel("left", "membrane potential (mV)") plot.setLabel("bottom", "time (s)") plot.plot(self.time, self.voltage, pen=mkPen(color=EXP_PULSE_CURRENT_COLOR, width=2)) plot.addLine(y=self.baseline, pen=mkPen(color=EXP_PULSE_BASELINE_COLOR, width=2), label="baseline") return graph
class PlotWindow(QtWidgets.QWidget): """Виджет для рисования графиков""" def __init__(self): super().__init__() self.plot_w = PlotWidget(self) self.plot_w.setGeometry(QtCore.QRect(0, 0, self.width(), self.height())) self.canvas = self.plot_w.getPlotItem() # self.panel = NavigationToolbar2QT(self.canvas, self, (0, 0)) def plot(self, *data, mode='plot', **kwargs): """Рисование графов""" if mode == 'plot': self.canvas.addItem(self.canvas.plot(*data, **kwargs)) return self.canvas def plot_clear(self): """Отчистка графика""" self.canvas.clear()
class RatingView(QtWidgets.QWidget): _ratings_ready = QtCore.pyqtSignal(object, object) _node_ratings_ready = QtCore.pyqtSignal(object) def __init__(self): super().__init__() layout = QtWidgets.QVBoxLayout(self) layout.setContentsMargins(0, 0, 0, 0) self._cubeable_plot = PlotWidget( axisItems={'bottom': TimeAxisItem(orientation='bottom')}) self._nodes_plot = PlotWidget( axisItems={'bottom': TimeAxisItem(orientation='bottom')}) self._splitter = QtWidgets.QSplitter(QtCore.Qt.Vertical) self._splitter.setStretchFactor(0, 1) self._splitter.setStretchFactor(1, 1) layout.addWidget(self._splitter) self._splitter.addWidget(self._cubeable_plot) self._splitter.addWidget(self._nodes_plot) self._display_target: t.Optional[t.Tuple[int, CardboardCubeable]] = None self._ratings_ready.connect(self._set_cubeable_ratings) self._node_ratings_ready.connect(self._set_nodes_ratings) LOGIN_CONTROLLER.login_success.connect(self._on_login) @classmethod def _get_color(cls, n: int = 0) -> QColor: return QColor(100 + (n * 70) % 155, 100 + ((n + 1) * 50) % 155, 100 + ((n + 2) * 40) % 155) @functools.lru_cache(maxsize=128) def _get_rating_points( self, release_id: int, cardboard_cubeable: CardboardCubeable ) -> Promise[t.Sequence[RatingPoint]]: return Context.cube_api_client.rating_history_for_cardboard_cubeable( release_id, cardboard_cubeable, ) @functools.lru_cache(maxsize=256) def _get_node_rating_points( self, release_id: int, node: CardboardNodeChild) -> Promise[t.Sequence[NodeRatingPoint]]: return Context.cube_api_client.rating_history_for_node( release_id, node, ).then(lambda ratings: (node, ratings)) def _on_login(self, *args, **kwargs) -> None: self._get_rating_points.cache_clear() self._get_node_rating_points.cache_clear() def _set_cubeable_ratings(self, cardboard_cubeable: CardboardCubeable, ratings: t.Sequence[RatingPoint]) -> None: self._cubeable_plot.clear() data_item = self._cubeable_plot.plot( [p.rating_map.created_at.timestamp() for p in ratings], [p.rating for p in ratings]) legend = self._cubeable_plot.addLegend(labelTextSize='15pt') legend.addItem( data_item, cardboard_cubeable.name if isinstance( cardboard_cubeable, Cardboard) else cardboard_cubeable.description) self._cubeable_plot.getPlotItem().enableAutoRange() def _set_nodes_ratings( self, ratings: t.Iterable[t.Tuple[CardboardNodeChild, t.Sequence[NodeRatingPoint]]] ) -> None: self._nodes_plot.show() self._nodes_plot.clear() legend = self._nodes_plot.addLegend(labelTextSize='15pt') for idx, (node_child, ratings) in enumerate(ratings): data_item = self._nodes_plot.plot( [p.rating_map.created_at.timestamp() for p in ratings], [p.rating for p in ratings], pen=mkPen(color=self._get_color(idx)), ) legend.addItem( data_item, node_child.name if isinstance(node_child, Cardboard) else node_child.get_minimal_string()) self._nodes_plot.getPlotItem().enableAutoRange() def on_focus_event(self, focus_event: FocusEvent) -> None: if not self.isVisible( ) or not focus_event.release_id or Context.focus_card_frozen: return cardboard_cubeable = focusable_as_cardboards(focus_event.focusable) display_target = (focus_event.release_id, cardboard_cubeable) if display_target == self._display_target: return self._display_target = display_target promise = self._get_rating_points(focus_event.release_id, cardboard_cubeable) if promise.is_pending: promise.then(lambda ratings: self._ratings_ready.emit( cardboard_cubeable, ratings)).catch(logging.warning) elif promise.is_fulfilled: self._set_cubeable_ratings(cardboard_cubeable, promise.get()) if isinstance( cardboard_cubeable, CardboardTrap ) and cardboard_cubeable.intention_type == IntentionType.GARBAGE: promise = Promise.all([ self._get_node_rating_points(focus_event.release_id, node) for node in cardboard_cubeable.node.children.distinct_elements() ]) if promise.is_pending: promise.then(self._node_ratings_ready.emit).catch( logging.warning) elif promise.is_fulfilled: self._set_nodes_ratings(promise.get()) else: self._nodes_plot.hide()
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 CamViewer(Display): # Emitted when the user changes the value. roi_x_signal = Signal(str) roi_y_signal = Signal(str) roi_w_signal = Signal(str) roi_h_signal = Signal(str) def __init__(self, parent=None, args=None): super(CamViewer, self).__init__(parent=parent, args=args) # Set up the list of cameras, and all the PVs test_dict = { "image": "ca://MTEST:Image", "max_width": "ca://MTEST:ImageWidth", "max_height": "ca://MTEST:ImageWidth", "roi_x": None, "roi_y": None, "roi_width": None, "roi_height": None } # self.cameras = { "VCC": vcc_dict, "C-Iris": c_iris_dict, "Test": test_dict } self.cameras = {"Testing IOC Image": test_dict } self._channels = [] self.imageChannel = None # Populate the camera combo box self.ui.cameraComboBox.clear() for camera in self.cameras: self.ui.cameraComboBox.addItem(camera) # When the camera combo box changes, disconnect from PVs, re-initialize, then reconnect. self.ui.cameraComboBox.activated[str].connect(self.cameraChanged) # Set up the color map combo box. self.ui.colorMapComboBox.clear() for key, map_name in cmap_names.items(): self.ui.colorMapComboBox.addItem(map_name, userData=key) self.ui.imageView.colorMap = self.ui.colorMapComboBox.currentData() self.ui.colorMapComboBox.activated[str].connect(self.colorMapChanged) # Set up the color map limit sliders and line edits. # self._color_map_limit_sliders_need_config = True self.ui.colorMapMinSlider.valueChanged.connect(self.setColorMapMin) self.ui.colorMapMaxSlider.valueChanged.connect(self.setColorMapMax) self.ui.colorMapMinLineEdit.returnPressed.connect(self.colorMapMinLineEditChanged) self.ui.colorMapMaxLineEdit.returnPressed.connect(self.colorMapMaxLineEditChanged) # Set up the stuff for single-shot and average modes. self.ui.singleShotRadioButton.setChecked(True) self._average_mode_enabled = False self.ui.singleShotRadioButton.clicked.connect(self.enableSingleShotMode) self.ui.averageRadioButton.clicked.connect(self.enableAverageMode) self.ui.numShotsLineEdit.returnPressed.connect(self.numAverageChanged) # Add a plot for vertical lineouts self.yLineoutPlot = PlotWidget() self.yLineoutPlot.setMaximumWidth(80) self.yLineoutPlot.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Expanding) self.yLineoutPlot.getPlotItem().invertY() self.yLineoutPlot.hideAxis('bottom') # self.yLineoutPlot.setYLink(self.ui.imageView.getView()) self.ui.imageGridLayout.addWidget(self.yLineoutPlot, 0, 0) self.yLineoutPlot.hide() # We do some mangling of the .ui file here and move the imageView over a cell, kind of ugly. self.ui.imageGridLayout.removeWidget(self.ui.imageView) self.ui.imageGridLayout.addWidget(self.ui.imageView, 0, 1) # Add a plot for the horizontal lineouts self.xLineoutPlot = PlotWidget() self.xLineoutPlot.setMaximumHeight(80) self.xLineoutPlot.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Minimum) self.xLineoutPlot.hideAxis('left') # self.xLineoutPlot.setXLink(self.ui.imageView.getView()) self.ui.imageGridLayout.addWidget(self.xLineoutPlot, 1, 1) self.xLineoutPlot.hide() # Update the lineout plot ranges when the image gets panned or zoomed self.ui.imageView.getView().sigRangeChanged.connect(self.updateLineoutRange) # Instantiate markers. self.marker_dict = {1:{}, 2:{}, 3:{}, 4:{}} marker_size = QPointF(20., 20.) self.marker_dict[1]['marker'] = ImageMarker((0, 0), size=marker_size, pen=mkPen((100, 100, 255), width=5)) self.marker_dict[1]['button'] = self.ui.marker1Button self.marker_dict[1]['xlineedit'] = self.ui.marker1XPosLineEdit self.marker_dict[1]['ylineedit'] = self.ui.marker1YPosLineEdit self.marker_dict[2]['marker'] = ImageMarker((0, 0), size=marker_size, pen=mkPen((255, 100, 100), width=5)) self.marker_dict[2]['button'] = self.ui.marker2Button self.marker_dict[2]['xlineedit'] = self.ui.marker2XPosLineEdit self.marker_dict[2]['ylineedit'] = self.ui.marker2YPosLineEdit self.marker_dict[3]['marker'] = ImageMarker((0, 0), size=marker_size, pen=mkPen((60, 255, 60), width=5)) self.marker_dict[3]['button'] = self.ui.marker3Button self.marker_dict[3]['xlineedit'] = self.ui.marker3XPosLineEdit self.marker_dict[3]['ylineedit'] = self.ui.marker3YPosLineEdit self.marker_dict[4]['marker'] = ImageMarker((0, 0), size=marker_size, pen=mkPen((255, 60, 255), width=5)) self.marker_dict[4]['button'] = self.ui.marker4Button self.marker_dict[4]['xlineedit'] = self.ui.marker4XPosLineEdit self.marker_dict[4]['ylineedit'] = self.ui.marker4YPosLineEdit # Disable auto-ranging the image (it feels strange when the zoom changes as you move markers around.) self.ui.imageView.getView().disableAutoRange() for d in self.marker_dict: marker = self.marker_dict[d]['marker'] marker.setZValue(20) marker.hide() marker.sigRegionChanged.connect(self.markerMoved) self.ui.imageView.getView().addItem(marker) self.marker_dict[d]['button'].toggled.connect(self.enableMarker) curvepen = QPen(marker.pen) curvepen.setWidth(1) self.marker_dict[d]['xcurve'] = self.xLineoutPlot.plot(pen=curvepen) self.marker_dict[d]['ycurve'] = self.yLineoutPlot.plot(pen=curvepen) self.marker_dict[d]['xlineedit'].returnPressed.connect(self.markerPositionLineEditChanged) self.marker_dict[d]['ylineedit'].returnPressed.connect(self.markerPositionLineEditChanged) # Set up zoom buttons self.ui.zoomInButton.clicked.connect(self.zoomIn) self.ui.zoomOutButton.clicked.connect(self.zoomOut) self.ui.zoomToActualSizeButton.clicked.connect(self.zoomToActualSize) # Set up ROI buttons self.ui.setROIButton.clicked.connect(self.setROI) self.ui.resetROIButton.clicked.connect(self.resetROI) self.destroyed.connect(functools.partial(widget_destroyed, self.channels)) @Slot() def zoomIn(self): self.ui.imageView.getView().scaleBy((0.5, 0.5)) @Slot() def zoomOut(self): self.ui.imageView.getView().scaleBy((2.0, 2.0)) @Slot() def zoomToActualSize(self): if len(self.image_data) == 0: return self.ui.imageView.getView().setRange(xRange=(0, self.image_data.shape[0]), yRange=(0, self.image_data.shape[1]), padding=0.0) def disable_all_markers(self): for d in self.marker_dict: self.marker_dict[d]['button'].setChecked(False) self.marker_dict[d]['marker'].setPos((0, 0)) @Slot(bool) def enableMarker(self, checked): any_markers_visible = False for d in self.marker_dict: marker = self.marker_dict[d]['marker'] button = self.marker_dict[d]['button'] any_markers_visible = any_markers_visible or button.isChecked() marker.setVisible(button.isChecked()) self.markerMoved(d) self.marker_dict[d]['xcurve'].setVisible(button.isChecked()) self.marker_dict[d]['ycurve'].setVisible(button.isChecked()) self.marker_dict[d]['xlineedit'].setEnabled(button.isChecked()) self.marker_dict[d]['ylineedit'].setEnabled(button.isChecked()) if any_markers_visible: self.xLineoutPlot.show() self.yLineoutPlot.show() else: self.xLineoutPlot.hide() self.yLineoutPlot.hide() @Slot() def markerPositionLineEditChanged(self): for d in self.marker_dict: marker = self.marker_dict[d]['marker'] x_line_edit = self.marker_dict[d]['xlineedit'] y_line_edit = self.marker_dict[d]['ylineedit'] try: new_x = int(x_line_edit.text()) new_y = int(y_line_edit.text()) if new_x <= marker.maxBounds.width() and new_y <= marker.maxBounds.height(): marker.setPos((new_x, new_y)) except: pass coords = marker.getPixelCoords() x_line_edit.setText(str(coords[0])) y_line_edit.setText(str(coords[1])) @Slot(object) def markerMoved(self, marker): self.updateLineouts() for marker_index in self.marker_dict: marker = self.marker_dict[marker_index]['marker'] x_line_edit = self.marker_dict[marker_index]['xlineedit'] y_line_edit = self.marker_dict[marker_index]['ylineedit'] coords = marker.getPixelCoords() x_line_edit.setText(str(coords[0])) y_line_edit.setText(str(coords[1])) @Slot(object, object) def updateLineoutRange(self, view, new_ranges): self.ui.xLineoutPlot.setRange(xRange=new_ranges[0], padding=0.0) self.ui.yLineoutPlot.setRange(yRange=new_ranges[1], padding=0.0) def updateLineouts(self): for marker_index in self.marker_dict: marker = self.marker_dict[marker_index]['marker'] xcurve = self.marker_dict[marker_index]['xcurve'] ycurve = self.marker_dict[marker_index]['ycurve'] if marker.isVisible(): result, coords = marker.getArrayRegion(self.image_data, self.ui.imageView.getImageItem()) xcurve.setData(y=result[0], x=np.arange(len(result[0]))) ycurve.setData(y=np.arange(len(result[1])), x=result[1]) @Slot() def enableSingleShotMode(self): self._average_mode_enabled = False self._average_buffer = np.ndarray(0) @Slot() def enableAverageMode(self): self._average_mode_enabled = True @Slot(str) def cameraChanged(self, new_camera): new_camera = str(new_camera) if self.imageChannel == self.cameras[new_camera]["image"]: return close_widget_connections(self) self.disable_all_markers() self.initializeCamera(new_camera) def initializeCamera(self, new_camera): new_camera = str(new_camera) self._color_map_limit_sliders_need_config = True self.times = np.zeros(10) self.old_timestamp = 0 self.image_width = 0 # current width (width of ROI) self.image_max_width = 0 # full width. Only used to reset ROI to full. self.image_max_height = 0 # full height. Only used to reset ROI to full. self.image_data = np.zeros(0) self._average_counter = 0 self._average_buffer = np.ndarray(0) self._needs_auto_range = True self.imageChannel = self.cameras[new_camera]["image"] self.widthChannel = self.cameras[new_camera]["roi_width"] or self.cameras[new_camera]["max_width"] self.maxWidthChannel = self.cameras[new_camera]["max_width"] self.maxHeightChannel = self.cameras[new_camera]["max_height"] self.roiXChannel = self.cameras[new_camera]["roi_x"] self.roiYChannel = self.cameras[new_camera]["roi_y"] self.roiWidthChannel = self.cameras[new_camera]["roi_width"] self.roiHeightChannel = self.cameras[new_camera]["roi_height"] self._channels = [PyDMChannel(address=self.imageChannel, connection_slot=self.connectionStateChanged, value_slot=self.receiveImageWaveform, severity_slot=self.alarmSeverityChanged), PyDMChannel(address=self.widthChannel, value_slot=self.receiveImageWidth), PyDMChannel(address=self.maxWidthChannel, value_slot=self.receiveMaxWidth), PyDMChannel(address=self.maxHeightChannel, value_slot=self.receiveMaxHeight)] if self.roiXChannel and self.roiYChannel and self.roiWidthChannel and self.roiHeightChannel: self._channels.extend([PyDMChannel(address=self.roiXChannel, value_slot=self.receiveRoiX, value_signal=self.roi_x_signal, write_access_slot=self.roiWriteAccessChanged), PyDMChannel(address=self.roiYChannel, value_slot=self.receiveRoiY, value_signal=self.roi_y_signal), PyDMChannel(address=self.roiWidthChannel, value_slot=self.receiveRoiWidth, value_signal=self.roi_w_signal), PyDMChannel(address=self.roiHeightChannel, value_slot=self.receiveRoiHeight, value_signal=self.roi_h_signal)]) self.ui.roiXLineEdit.setEnabled(True) self.ui.roiYLineEdit.setEnabled(True) self.ui.roiWLineEdit.setEnabled(True) self.ui.roiHLineEdit.setEnabled(True) else: self.ui.roiXLineEdit.clear() self.ui.roiXLineEdit.setEnabled(False) self.ui.roiYLineEdit.clear() self.ui.roiYLineEdit.setEnabled(False) self.ui.roiWLineEdit.clear() self.ui.roiWLineEdit.setEnabled(False) self.ui.roiHLineEdit.clear() self.ui.roiHLineEdit.setEnabled(False) establish_widget_connections(self) @Slot() def setROI(self): self.roi_x_signal.emit(self.ui.roiXLineEdit.text()) self.roi_y_signal.emit(self.ui.roiYLineEdit.text()) self.roi_w_signal.emit(self.ui.roiWLineEdit.text()) self.roi_h_signal.emit(self.ui.roiHLineEdit.text()) @Slot() def resetROI(self): self.roi_x_signal.emit(str(0)) self.roi_y_signal.emit(str(0)) self.roi_w_signal.emit(str(self.image_max_width)) self.roi_h_signal.emit(str(self.image_max_height)) @Slot(str) def colorMapChanged(self, _): self.ui.imageView.colorMap = self.ui.colorMapComboBox.currentData() def configureColorMapLimitSliders(self, max_int): self.ui.colorMapMinSlider.setMaximum(max_int) self.ui.colorMapMaxSlider.setMaximum(max_int) self.ui.colorMapMaxSlider.setValue(max_int) self.ui.colorMapMinSlider.setValue(0) self.setColorMapMin(0) self.setColorMapMax(max_int) self._color_map_limit_sliders_need_config = False @Slot() def colorMapMinLineEditChanged(self): try: new_min = int(self.ui.colorMapMinLineEdit.text()) except: self.ui.colorMapMinLineEdit.setText(str(self.ui.colorMapMinSlider.value())) return if new_min < 0: new_min = 0 if new_min > self.ui.colorMapMinSlider.maximum(): new_min = self.ui.colorMapMinSlider.maximum() self.ui.colorMapMinSlider.setValue(new_min) @Slot(int) def setColorMapMin(self, new_min): if new_min > self.ui.colorMapMaxSlider.value(): self.ui.colorMapMaxSlider.setValue(new_min) self.ui.colorMapMaxLineEdit.setText(str(new_min)) self.ui.colorMapMinLineEdit.setText(str(new_min)) self.ui.imageView.setColorMapLimits(new_min, self.ui.colorMapMaxSlider.value()) @Slot() def colorMapMaxLineEditChanged(self): try: new_max = int(self.ui.colorMapMaxLineEdit.text()) except: self.ui.colorMapMaxLineEdit.setText(str(self.ui.colorMapMaxSlider.value())) return if new_max < 0: new_max = 0 if new_max > self.ui.colorMapMaxSlider.maximum(): new_max = self.ui.colorMapMaxSlider.maximum() self.ui.colorMapMaxSlider.setValue(new_max) @Slot(int) def setColorMapMax(self, new_max): if new_max < self.ui.colorMapMinSlider.value(): self.ui.colorMapMinSlider.setValue(new_max) self.ui.colorMapMinLineEdit.setText(str(new_max)) self.ui.colorMapMaxLineEdit.setText(str(new_max)) self.ui.imageView.setColorMapLimits(self.ui.colorMapMinSlider.value(), new_max) def createAverageBuffer(self, size, type, initial_val=[]): num_shots = 1 try: num_shots = int(self.ui.numShotsLineEdit.text()) except: self.ui.numShotsLineEdit.setText(str(num_shots)) if num_shots < 1: num_shots = 1 self.ui.numShotsLineEdit.setText(str(num_shots)) if num_shots > 200: num_shots = 200 self.ui.numShotsLineEdit.setText(str(num_shots)) if len(initial_val) > 0: return np.full((num_shots, size), initial_val, dtype=type) else: return np.zeros(shape=(num_shots, size), dtype=type) @Slot() def numAverageChanged(self): self._average_buffer = np.zeros(0) @Slot(np.ndarray) def receiveImageWaveform(self, new_waveform): if not self.image_width: return # Calculate the average rate new_timestamp = time.time() if not (self.old_timestamp == 0): delta = new_timestamp - self.old_timestamp self.times = np.roll(self.times, 1) self.times[0] = delta avg_delta = np.mean(self.times) self.ui.dataRateLabel.setText("{:.1f} Hz".format((1.0 / avg_delta))) self.ui.displayRateLabel.setText("{:.1f} Hz".format((1.0 / avg_delta))) self.old_timestamp = new_timestamp # If this is the first image, set up the color map slider limits if self._color_map_limit_sliders_need_config: max_int = np.iinfo(new_waveform.dtype).max self.configureColorMapLimitSliders(max_int) # If we are in average mode, add this image to the circular averaging buffer, otherwise just display it. if self._average_mode_enabled: if len(self._average_buffer) == 0: self._average_buffer = self.createAverageBuffer(len(new_waveform), new_waveform.dtype, new_waveform) self._average_counter = 0 self._average_counter = (self._average_counter + 1) % len(self._average_buffer) # self._average_buffer = np.roll(self._average_buffer, 1, axis=0) self._average_buffer[self._average_counter] = new_waveform mean = np.mean(self._average_buffer, axis=0).astype(new_waveform.dtype) self.image_data = mean.reshape((int(self.image_width), -1), order='F') else: self.image_data = new_waveform.reshape((int(self.image_width), -1), order='F') self.setMarkerBounds() self.updateLineouts() self.ui.imageView.image_value_changed(self.image_data) self.calculateStats() if self._needs_auto_range: self.ui.imageView.getView().autoRange(padding=0.0) current_range = self.ui.imageView.getView().viewRange() self._needs_auto_range = False def calculateStats(self): # Full image stats mean = np.mean(self.image_data) std = np.std(self.image_data) width = self.image_data.shape[0] height = self.image_data.shape[1] min_val = np.min(self.image_data) max_val = np.max(self.image_data) self.ui.imageStatsLabel.setText("Mean: {0:.2f}, Std: {1:.2f}, Min: {2}, Max: {3}, Width: {4}, Height: {5}".format(mean, std, min_val, max_val, width, height)) # Current view stats current_range = self.ui.imageView.getView().viewRange() view_x_min = int(max(0, current_range[0][0])) view_x_max = int(min(self.image_data.shape[0], current_range[0][1])) view_y_min = int(max(0, current_range[1][0])) view_y_max = int(min(self.image_data.shape[1], current_range[1][1])) view_slice = self.image_data[view_x_min:view_x_max, view_y_min:view_y_max] mean = np.mean(view_slice) std = np.std(view_slice) width = view_slice.shape[0] height = view_slice.shape[1] min_val = np.min(view_slice) max_val = np.max(view_slice) self.ui.viewStatsLabel.setText("Mean: {0:.2f}, Std: {1:.2f}, Min: {2}, Max: {3}, Width: {4}, Height: {5}".format(mean, std, min_val, max_val, width, height)) def setMarkerBounds(self): for marker_index in self.marker_dict: marker = self.marker_dict[marker_index]['marker'] marker.maxBounds = QRectF(0, 0, self.image_data.shape[0] + marker.size()[0] - 1, self.image_data.shape[1] + marker.size()[1] - 1) @Slot(int) def receiveImageWidth(self, new_width): self.image_width = new_width self.ui.imageView.image_width_changed(self.image_width) @Slot(int) def receiveMaxWidth(self, new_max_width): self.image_max_width = new_max_width @Slot(int) def receiveMaxHeight(self, new_max_height): self.image_max_height = new_max_height @Slot(int) def receiveRoiX(self, new_roi_x): self.ui.roiXLineEdit.setText(str(new_roi_x)) @Slot(int) def receiveRoiY(self, new_roi_y): self.ui.roiYLineEdit.setText(str(new_roi_y)) @Slot(int) def receiveRoiWidth(self, new_roi_w): self.ui.roiWLineEdit.setText(str(new_roi_w)) @Slot(int) def receiveRoiHeight(self, new_roi_h): self.ui.roiHLineEdit.setText(str(new_roi_h)) # -2 to +2, -2 is LOLO, -1 is LOW, 0 is OK, etc. @Slot(int) def alarmStatusChanged(self, new_alarm_state): pass # 0 = NO_ALARM, 1 = MINOR, 2 = MAJOR, 3 = INVALID @Slot(int) def alarmSeverityChanged(self, new_alarm_severity): pass @Slot(bool) def roiWriteAccessChanged(self, can_write_roi): self.ui.setROIButton.setEnabled(can_write_roi) self.ui.resetROIButton.setEnabled(can_write_roi) self.ui.roiXLineEdit.setReadOnly(not can_write_roi) self.ui.roiYLineEdit.setReadOnly(not can_write_roi) self.ui.roiWLineEdit.setReadOnly(not can_write_roi) self.ui.roiHLineEdit.setReadOnly(not can_write_roi) # false = disconnected, true = connected @Slot(bool) def connectionStateChanged(self, connected): if connected: self.ui.imageView.redraw_timer.start() else: self.ui.imageView.redraw_timer.stop() self.ui.connectedLabel.setText({True: "Yes", False: "No"}[connected]) def ui_filename(self): return 'camviewer.ui' def channels(self): return self._channels
class BusMonitorWidget(QGroupBox): DEFAULT_PLOT_X_RANGE = 120 BUS_LOAD_PLOT_MAX_SAMPLES = 5000 def __init__(self, parent, node, iface_name): super(BusMonitorWidget, self).__init__(parent) self.setTitle('CAN bus activity (%s)' % iface_name.split(os.path.sep)[-1]) self._node = node self._hook_handle = self._node.can_driver.add_io_hook(self._frame_hook) self._columns = [ BasicTable.Column('Dir', lambda e: (e[0].upper()), searchable=False), BasicTable.Column('Local Time', TimestampRenderer(), searchable=False), BasicTable.Column( 'CAN ID', lambda e: (('%0*X' % (8 if e[1].extended else 3, e[1].id)).rjust(8), colorize_can_id(e[1]))), BasicTable.Column( 'Data Hex', lambda e: (' '.join(['%02X' % x for x in e[1].data]).ljust(3 * e[ 1].MAX_DATA_LENGTH), colorize_transfer_id(e))), BasicTable.Column( 'Data ASCII', lambda e: (''.join([(chr(x) if 32 <= x <= 126 else '.') for x in e[1].data]), colorize_transfer_id(e))), BasicTable.Column( 'Src', lambda e: render_node_id_with_color(e[1], 'src')), BasicTable.Column( 'Dst', lambda e: render_node_id_with_color(e[1], 'dst')), BasicTable.Column('Data Type', lambda e: render_data_type_with_color(e[1]), resize_mode=QHeaderView.Stretch), ] self._log_widget = RealtimeLogWidget( self, columns=self._columns, font=get_monospace_font(), post_redraw_hook=self._redraw_hook) self._log_widget.on_selection_changed = self._update_measurement_display def flip_row_mark(row, col): if col == 0: item = self._log_widget.table.item(row, col) if item.icon().isNull(): item.setIcon(get_icon('circle')) flash(self, 'Row %d was marked, click again to unmark', row, duration=3) else: item.setIcon(QIcon()) self._log_widget.table.cellPressed.connect(flip_row_mark) self._stat_update_timer = QTimer(self) self._stat_update_timer.setSingleShot(False) self._stat_update_timer.timeout.connect(self._update_stat) self._stat_update_timer.start(500) self._traffic_stat = TrafficStatCounter() self._stat_frames_tx = QLabel('N/A', self) self._stat_frames_rx = QLabel('N/A', self) self._stat_traffic = QLabel('N/A', self) self._load_plot = PlotWidget(background=(0, 0, 0)) self._load_plot.setRange(xRange=(0, self.DEFAULT_PLOT_X_RANGE), padding=0) self._load_plot.setMaximumHeight(150) self._load_plot.setMinimumHeight(100) self._load_plot.setMinimumWidth(100) self._load_plot.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Minimum) self._load_plot.showGrid(x=True, y=True, alpha=0.4) self._load_plot.setToolTip('Frames per second') self._load_plot.getPlotItem().getViewBox().setMouseEnabled(x=True, y=False) self._load_plot.enableAutoRange() self._bus_load_plot = self._load_plot.plot(name='Frames per second', pen=mkPen(QColor( Qt.lightGray), width=1)) self._bus_load_samples = [], [] self._started_at_mono = time.monotonic() layout = QVBoxLayout(self) layout.addWidget(self._log_widget, 1) stat_vars_layout = QGridLayout(self) stat_layout_next_row = 0 def add_stat_row(label, value): nonlocal stat_layout_next_row stat_vars_layout.addWidget(QLabel(label, self), stat_layout_next_row, 0) stat_vars_layout.addWidget(value, stat_layout_next_row, 1) value.setMinimumWidth(75) stat_layout_next_row += 1 add_stat_row('Frames transmitted:', self._stat_frames_tx) add_stat_row('Frames received:', self._stat_frames_rx) add_stat_row('Frames per second:', self._stat_traffic) stat_vars_layout.setRowStretch(stat_layout_next_row, 1) stat_layout = QHBoxLayout(self) stat_layout.addLayout(stat_vars_layout) stat_layout.addWidget(self._load_plot, 1) layout.addLayout(stat_layout, 0) self.setLayout(layout) def close(self): self._hook_handle.remove() def _update_stat(self): bus_load, ts_mono = self._traffic_stat.get_frames_per_second() self._stat_traffic.setText(str(int(bus_load + 0.5))) if len(self._bus_load_samples[0]) >= self.BUS_LOAD_PLOT_MAX_SAMPLES: self._bus_load_samples[0].pop(0) self._bus_load_samples[1].pop(0) self._bus_load_samples[1].append(bus_load) self._bus_load_samples[0].append(ts_mono - self._started_at_mono) self._bus_load_plot.setData(*self._bus_load_samples) (xmin, xmax), _ = self._load_plot.viewRange() diff = xmax - xmin xmax = self._bus_load_samples[0][-1] xmin = self._bus_load_samples[0][-1] - diff self._load_plot.setRange(xRange=(xmin, xmax), padding=0) def _redraw_hook(self): self._stat_frames_tx.setText(str(self._traffic_stat.tx)) self._stat_frames_rx.setText(str(self._traffic_stat.rx)) def _frame_hook(self, direction, frame): self._traffic_stat.add_frame(direction, frame) self._log_widget.add_item_async((direction, frame)) def _update_measurement_display(self, selected_rows_cols): if not selected_rows_cols: return min_row = min([row for row, _ in selected_rows_cols]) max_row = max([row for row, _ in selected_rows_cols]) def get_row_ts(row): return TimestampRenderer.parse_timestamp( self._log_widget.table.item(row, 1).text()) def get_load_str(num_frames, dt): if dt >= 1e-6: return 'average load %.1f FPS' % (num_frames / dt) return 'average load is unknown' if min_row == max_row: num_frames = min_row first_ts = get_row_ts(0) current_ts = get_row_ts(min_row) dt = current_ts - first_ts flash(self, '%d frames from beginning, %.3f sec since first frame, %s', num_frames, dt, get_load_str(num_frames, dt)) else: num_frames = max_row - min_row + 1 first_ts = get_row_ts(min_row) last_ts = get_row_ts(max_row) dt = last_ts - first_ts flash(self, '%d frames, timedelta %.6f sec, %s', num_frames, dt, get_load_str(num_frames, dt))
class Ui_MainWindow(object): def setupUi(self, MainWindow): pq.setConfigOption('background', 'y') pq.setConfigOption('foreground', 'k') MainWindow.setObjectName("MainWindow") MainWindow.resize(912, 659) self.centralwidget = QtWidgets.QWidget(MainWindow) self.centralwidget.setObjectName("centralwidget") self.text_hodnoty1 = QtWidgets.QTextBrowser(self.centralwidget) self.text_hodnoty1.setGeometry(QtCore.QRect(30, 60, 151, 181)) self.text_hodnoty1.setObjectName("text_hodnoty1") self.text_hodnoty2 = QtWidgets.QTextBrowser(self.centralwidget) self.text_hodnoty2.setGeometry(QtCore.QRect(445, 50, 151, 192)) self.text_hodnoty2.setObjectName("text_hodnoty2") self.label = QtWidgets.QLabel(self.centralwidget) self.label.setGeometry(QtCore.QRect(30, 10, 201, 21)) font = QtGui.QFont() font.setFamily("System") font.setPointSize(14) font.setBold(True) font.setWeight(75) self.label.setFont(font) self.label.setObjectName("label") self.label_2 = QtWidgets.QLabel(self.centralwidget) self.label_2.setGeometry(QtCore.QRect(30, 40, 47, 13)) self.label_2.setObjectName("label_2") self.label_3 = QtWidgets.QLabel(self.centralwidget) self.label_3.setGeometry(QtCore.QRect(450, 30, 47, 13)) self.label_3.setObjectName("label_3") self.label_4 = QtWidgets.QLabel(self.centralwidget) self.label_4.setGeometry(QtCore.QRect(200, 60, 121, 16)) self.label_4.setObjectName("label_4") self.label_5 = QtWidgets.QLabel(self.centralwidget) self.label_5.setGeometry(QtCore.QRect(200, 110, 121, 16)) self.label_5.setObjectName("label_5") self.label_6 = QtWidgets.QLabel(self.centralwidget) self.label_6.setGeometry(QtCore.QRect(610, 50, 121, 16)) self.label_6.setObjectName("label_6") self.label_7 = QtWidgets.QLabel(self.centralwidget) self.label_7.setGeometry(QtCore.QRect(610, 110, 121, 16)) self.label_7.setObjectName("label_7") self.prumer1 = QtWidgets.QTextBrowser(self.centralwidget) self.prumer1.setGeometry(QtCore.QRect(200, 80, 141, 31)) self.prumer1.setObjectName("prumer1") self.prumer2 = QtWidgets.QTextBrowser(self.centralwidget) self.prumer2.setGeometry(QtCore.QRect(610, 70, 141, 31)) self.prumer2.setObjectName("prumer2") self.smodch1 = QtWidgets.QTextBrowser(self.centralwidget) self.smodch1.setGeometry(QtCore.QRect(200, 130, 141, 31)) self.smodch1.setObjectName("smodch1") self.smodch2 = QtWidgets.QTextBrowser(self.centralwidget) self.smodch2.setGeometry(QtCore.QRect(610, 130, 141, 31)) self.smodch2.setObjectName("smodch2") self.groupBox = QtWidgets.QGroupBox(self.centralwidget) self.groupBox.setGeometry(QtCore.QRect(0, 0, 771, 281)) palette = QtGui.QPalette() brush = QtGui.QBrush(QtGui.QColor(0, 255, 255)) brush.setStyle(QtCore.Qt.SolidPattern) palette.setBrush(QtGui.QPalette.Active, QtGui.QPalette.Base, brush) brush = QtGui.QBrush(QtGui.QColor(85, 170, 255)) brush.setStyle(QtCore.Qt.SolidPattern) palette.setBrush(QtGui.QPalette.Active, QtGui.QPalette.Window, brush) brush = QtGui.QBrush(QtGui.QColor(0, 255, 255)) brush.setStyle(QtCore.Qt.SolidPattern) palette.setBrush(QtGui.QPalette.Inactive, QtGui.QPalette.Base, brush) brush = QtGui.QBrush(QtGui.QColor(85, 170, 255)) brush.setStyle(QtCore.Qt.SolidPattern) palette.setBrush(QtGui.QPalette.Inactive, QtGui.QPalette.Window, brush) brush = QtGui.QBrush(QtGui.QColor(85, 170, 255)) brush.setStyle(QtCore.Qt.SolidPattern) palette.setBrush(QtGui.QPalette.Disabled, QtGui.QPalette.Base, brush) brush = QtGui.QBrush(QtGui.QColor(85, 170, 255)) brush.setStyle(QtCore.Qt.SolidPattern) palette.setBrush(QtGui.QPalette.Disabled, QtGui.QPalette.Window, brush) self.groupBox.setPalette(palette) self.groupBox.setAutoFillBackground(True) self.groupBox.setTitle("") self.groupBox.setObjectName("groupBox") self.buttonMereni = QtWidgets.QPushButton(self.groupBox) self.buttonMereni.setGeometry(QtCore.QRect(610, 200, 141, 41)) self.buttonMereni.setObjectName("buttonMereni") self.buttonMereni.clicked.connect(self.one_measure) self.groupBox_2 = QtWidgets.QGroupBox(self.centralwidget) self.groupBox_2.setGeometry(QtCore.QRect(770, 0, 141, 281)) palette = QtGui.QPalette() brush = QtGui.QBrush(QtGui.QColor(0, 255, 255)) brush.setStyle(QtCore.Qt.SolidPattern) palette.setBrush(QtGui.QPalette.Active, QtGui.QPalette.Base, brush) brush = QtGui.QBrush(QtGui.QColor(255, 170, 0)) brush.setStyle(QtCore.Qt.SolidPattern) palette.setBrush(QtGui.QPalette.Active, QtGui.QPalette.Window, brush) brush = QtGui.QBrush(QtGui.QColor(0, 255, 255)) brush.setStyle(QtCore.Qt.SolidPattern) palette.setBrush(QtGui.QPalette.Inactive, QtGui.QPalette.Base, brush) brush = QtGui.QBrush(QtGui.QColor(255, 170, 0)) brush.setStyle(QtCore.Qt.SolidPattern) palette.setBrush(QtGui.QPalette.Inactive, QtGui.QPalette.Window, brush) brush = QtGui.QBrush(QtGui.QColor(255, 170, 0)) brush.setStyle(QtCore.Qt.SolidPattern) palette.setBrush(QtGui.QPalette.Disabled, QtGui.QPalette.Base, brush) brush = QtGui.QBrush(QtGui.QColor(255, 170, 0)) brush.setStyle(QtCore.Qt.SolidPattern) palette.setBrush(QtGui.QPalette.Disabled, QtGui.QPalette.Window, brush) self.groupBox_2.setPalette(palette) self.groupBox_2.setAutoFillBackground(True) self.groupBox_2.setTitle("") self.groupBox_2.setObjectName("groupBox_2") self.label_8 = QtWidgets.QLabel(self.groupBox_2) self.label_8.setGeometry(QtCore.QRect(10, 80, 121, 16)) font = QtGui.QFont() font.setPointSize(14) font.setBold(True) font.setWeight(75) self.label_8.setFont(font) self.label_8.setAlignment(QtCore.Qt.AlignCenter) self.label_8.setObjectName("label_8") self.rozdil = QtWidgets.QTextBrowser(self.groupBox_2) self.rozdil.setGeometry(QtCore.QRect(20, 100, 111, 31)) palette = QtGui.QPalette() brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) brush.setStyle(QtCore.Qt.SolidPattern) palette.setBrush(QtGui.QPalette.Active, QtGui.QPalette.Base, brush) brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) brush.setStyle(QtCore.Qt.SolidPattern) palette.setBrush(QtGui.QPalette.Inactive, QtGui.QPalette.Base, brush) brush = QtGui.QBrush(QtGui.QColor(255, 170, 0)) brush.setStyle(QtCore.Qt.SolidPattern) palette.setBrush(QtGui.QPalette.Disabled, QtGui.QPalette.Base, brush) self.rozdil.setPalette(palette) self.rozdil.setObjectName("rozdil") self.groupBox_3 = QtWidgets.QGroupBox(self.centralwidget) self.groupBox_3.setGeometry(QtCore.QRect(0, 280, 911, 381)) palette = QtGui.QPalette() brush = QtGui.QBrush(QtGui.QColor(0, 255, 255)) brush.setStyle(QtCore.Qt.SolidPattern) palette.setBrush(QtGui.QPalette.Active, QtGui.QPalette.Base, brush) brush = QtGui.QBrush(QtGui.QColor(255, 255, 0)) brush.setStyle(QtCore.Qt.SolidPattern) palette.setBrush(QtGui.QPalette.Active, QtGui.QPalette.Window, brush) brush = QtGui.QBrush(QtGui.QColor(0, 255, 255)) brush.setStyle(QtCore.Qt.SolidPattern) palette.setBrush(QtGui.QPalette.Inactive, QtGui.QPalette.Base, brush) brush = QtGui.QBrush(QtGui.QColor(255, 255, 0)) brush.setStyle(QtCore.Qt.SolidPattern) palette.setBrush(QtGui.QPalette.Inactive, QtGui.QPalette.Window, brush) brush = QtGui.QBrush(QtGui.QColor(255, 255, 0)) brush.setStyle(QtCore.Qt.SolidPattern) palette.setBrush(QtGui.QPalette.Disabled, QtGui.QPalette.Base, brush) brush = QtGui.QBrush(QtGui.QColor(255, 255, 0)) brush.setStyle(QtCore.Qt.SolidPattern) palette.setBrush(QtGui.QPalette.Disabled, QtGui.QPalette.Window, brush) self.groupBox_3.setPalette(palette) self.groupBox_3.setAutoFillBackground(True) self.groupBox_3.setTitle("") self.groupBox_3.setObjectName("groupBox_3") self.label_9 = QtWidgets.QLabel(self.groupBox_3) self.label_9.setGeometry(QtCore.QRect(20, 10, 201, 21)) font = QtGui.QFont() font.setFamily("System") font.setPointSize(14) font.setBold(True) font.setWeight(75) self.label_9.setFont(font) self.label_9.setObjectName("label_9") self.graphicsView = PlotWidget(self.groupBox_3) self.graphicsView.setGeometry(QtCore.QRect(250, 10, 651, 341)) self.graphicsView.setObjectName("graphicsView") self.label_10 = QtWidgets.QLabel(self.groupBox_3) self.label_10.setGeometry(QtCore.QRect(20, 40, 91, 16)) self.label_10.setObjectName("label_10") self.label_11 = QtWidgets.QLabel(self.groupBox_3) self.label_11.setGeometry(QtCore.QRect(20, 60, 91, 16)) self.label_11.setObjectName("label_11") self.label_12 = QtWidgets.QLabel(self.groupBox_3) self.label_12.setGeometry(QtCore.QRect(20, 80, 91, 16)) self.label_12.setObjectName("label_12") self.lineEdit = QtWidgets.QLineEdit(self.groupBox_3) self.lineEdit.setGeometry(QtCore.QRect(20, 100, 221, 20)) self.lineEdit.setObjectName("lineEdit") self.lineEdit.setText( datetime.datetime.now().strftime("Data_" + "%Y-%m-%d_%H%M%S" + ".csv")) reg_ex = QtCore.QRegExp("([a-zA-Z0-9\s_,\]\[\(\)\-:])+.csv$") self.lineEdit.setValidator( QtGui.QRegExpValidator(reg_ex, self.lineEdit)) self.lineEdit_interval = QtWidgets.QLineEdit(self.groupBox_3) self.lineEdit_interval.setGeometry(QtCore.QRect(90, 60, 151, 20)) self.lineEdit_interval.setInputMethodHints(QtCore.Qt.ImhDigitsOnly) self.lineEdit_interval.setObjectName("lineEdit_interval") self.lineEdit_interval.setValidator(QtGui.QIntValidator()) self.lineEdit_pocet_2 = QtWidgets.QLineEdit(self.groupBox_3) self.lineEdit_pocet_2.setGeometry(QtCore.QRect(90, 40, 151, 20)) self.lineEdit_pocet_2.setInputMethodHints(QtCore.Qt.ImhDigitsOnly) self.lineEdit_pocet_2.setObjectName("lineEdit_pocet_2") self.lineEdit_pocet_2.setValidator(QtGui.QIntValidator()) self.buttonMereniDynamicke = QtWidgets.QPushButton(self.groupBox_3) self.buttonMereniDynamicke.setGeometry(QtCore.QRect(20, 120, 221, 21)) self.buttonMereniDynamicke.setObjectName("buttonMereniDynamicke") self.buttonMereniDynamicke.clicked.connect(self.multiple_measure) self.text_dynhodnoty = QtWidgets.QTextBrowser(self.groupBox_3) self.text_dynhodnoty.setGeometry(QtCore.QRect(20, 170, 151, 181)) palette = QtGui.QPalette() brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) brush.setStyle(QtCore.Qt.SolidPattern) palette.setBrush(QtGui.QPalette.Active, QtGui.QPalette.Base, brush) brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) brush.setStyle(QtCore.Qt.SolidPattern) palette.setBrush(QtGui.QPalette.Inactive, QtGui.QPalette.Base, brush) brush = QtGui.QBrush(QtGui.QColor(255, 255, 0)) brush.setStyle(QtCore.Qt.SolidPattern) palette.setBrush(QtGui.QPalette.Disabled, QtGui.QPalette.Base, brush) self.text_dynhodnoty.setPalette(palette) self.text_dynhodnoty.setObjectName("text_dynhodnoty") self.label_13 = QtWidgets.QLabel(self.groupBox_3) self.label_13.setGeometry(QtCore.QRect(20, 150, 47, 13)) self.label_13.setObjectName("label_13") self.groupBox.raise_() self.text_hodnoty1.raise_() self.text_hodnoty2.raise_() self.label.raise_() self.label_2.raise_() self.label_3.raise_() self.label_4.raise_() self.label_5.raise_() self.label_6.raise_() self.label_7.raise_() self.prumer1.raise_() self.prumer2.raise_() self.smodch1.raise_() self.smodch2.raise_() self.groupBox_2.raise_() self.groupBox_3.raise_() MainWindow.setCentralWidget(self.centralwidget) self.statusbar = QtWidgets.QStatusBar(MainWindow) self.statusbar.setObjectName("statusbar") MainWindow.setStatusBar(self.statusbar) self.retranslateUi(MainWindow) QtCore.QMetaObject.connectSlotsByName(MainWindow) def multiple_measure(self): print("multiple") self.buttonMereni.setEnabled(False) self.buttonMereniDynamicke.setEnabled(False) self.graphicsView.plotItem.clear() total_measurements = int(self.lineEdit_pocet_2.text()) period_time = int(self.lineEdit_interval.text()) dyn_value = np.array([]) dyn_prumer1 = np.array([]) dyn_prumer2 = np.array([]) dyn_smodch1 = np.array([]) dyn_smodch2 = np.array([]) self.text_dynhodnoty.setText("") QtGui.QGuiApplication.processEvents() for measurement in range(total_measurements): self.text_hodnoty1.setText("") self.text_hodnoty2.setText("") self.rozdil.setText("0") self.prumer1.setText("0") self.prumer2.setText("0") self.smodch1.setText("0") self.smodch2.setText("0") json_trigger_command = """ {"id":1,"method":"call","params":{"path":"measval/cmdTriggerCapturedValue1","args":[]}} """ json_get_command = """ {"method":"fetch_all","params":{"path":"measval/values/capturedValue1"}} """ json_trigger = json.loads(json_trigger_command) json_get = json.loads(json_get_command) expected_message = """"path":"measval/values/capturedValue1""" "" sensor1_values = [None] * 10 measured_values = np.zeros((10, )) try: ws = create_connection("ws://10.0.0.46:8081") except Exception as ex: print(ex) print("Start mereni 1:" + str(datetime.datetime.now())) for mereni in range(10): ws.send(json.dumps(json_trigger)) result = ws.recv() time.sleep(.1) # TODO check result ws.send(json.dumps(json_get)) clipx_message = "" while expected_message not in clipx_message: clipx_message = ws.recv() sensor1_values[mereni] = json.loads(clipx_message) self.text_hodnoty1.append("{:.4E}".format( Decimal(sensor1_values[mereni]["params"]["value"]))) QtGui.QGuiApplication.processEvents() measured_values[mereni] = sensor1_values[mereni]["params"][ "value"] ws.close() print("Stop mereni 1:" + str(datetime.datetime.now())) dyn_prumer1 = np.append(dyn_prumer1, measured_values.mean()) dyn_smodch1 = np.append(dyn_smodch1, measured_values.std()) self.prumer1.setText("{:.4E}".format( Decimal(measured_values.mean()))) self.smodch1.setText("{:.4E}".format(Decimal( measured_values.std()))) QtGui.QGuiApplication.processEvents() sensor2_values = [None] * 10 measured2_values = np.zeros((10, 1)) ws2 = create_connection("ws://10.0.0.52:8081") self.text_hodnoty2.setText("") print("Start mereni 2:" + str(datetime.datetime.now())) for mereni in range(10): ws2.send(json.dumps(json_trigger)) result = ws2.recv() time.sleep(.1) # TODO check result ws2.send(json.dumps(json_get)) clipx_message = "" while not expected_message in clipx_message: clipx_message = ws2.recv() sensor2_values[mereni] = json.loads(clipx_message) # print(sensor1_values[mereni]["params"]["value"]) self.text_hodnoty2.append("{:.4E}".format( Decimal(sensor2_values[mereni]["params"]["value"]))) QtGui.QGuiApplication.processEvents() measured2_values[mereni] = sensor2_values[mereni]["params"][ "value"] ws2.close() print("Stop mereni 2:" + str(datetime.datetime.now())) dyn_prumer2 = np.append(dyn_prumer2, measured2_values.mean()) dyn_smodch2 = np.append(dyn_smodch2, measured2_values.std()) self.prumer2.setText("{:.4E}".format( Decimal(measured2_values.mean()))) self.smodch2.setText("{:.4E}".format( Decimal(measured2_values.std()))) dyn_value = np.append( dyn_value, measured_values.mean() - measured2_values.mean()) self.text_dynhodnoty.append("{:.4E}".format(Decimal( dyn_value[-1]))) self.rozdil.setText("{:.4E}".format(Decimal( dyn_value[measurement]))) if len(dyn_value) > 1: try: self.graphicsView.plot(dyn_value, pen=pq.mkPen( 'b', width=3, style=QtCore.Qt.SolidLine, color=(200, 200, 255))) self.graphicsView.getPlotItem().showGrid(x=True, y=True, alpha=1) QtGui.QGuiApplication.processEvents() except Exception as ex: print(ex) start_pause = (datetime.datetime.now()) time_difference = start_pause - start_pause time_difference_seconds = time_difference.total_seconds() while time_difference_seconds < period_time: time.sleep(0.05) QtGui.QGuiApplication.processEvents() time_difference = datetime.datetime.now() - start_pause time_difference_seconds = time_difference.total_seconds() self.buttonMereni.setEnabled(True) self.buttonMereniDynamicke.setEnabled(True) QtGui.QGuiApplication.processEvents() output = np.asarray( [dyn_value, dyn_value, dyn_value, dyn_value, dyn_value]) try: np.savetxt(self.lineEdit.text(), output.transpose(), delimiter=",", header="diff,smodch1,smodch2,prumer1,prumer2") except Exception as ex: print(ex) self.lineEdit.setText( datetime.datetime.now().strftime("Data_" + "%Y-%m-%d_%H%M%S" + ".csv")) QtGui.QGuiApplication.processEvents() def one_measure(self): self.buttonMereni.setEnabled(False) self.buttonMereniDynamicke.setEnabled(False) QtGui.QGuiApplication.processEvents() self.text_hodnoty1.setText("") self.text_hodnoty2.setText("") self.rozdil.setText("0") self.prumer1.setText("") self.prumer2.setText("") self.rozdil.setText("") json_trigger_command = """ {"id":1,"method":"call","params":{"path":"measval/cmdTriggerCapturedValue1","args":[]}} """ json_get_command = """ {"method":"fetch_all","params":{"path":"measval/adcBinVal32"}} """ json_trigger = json.loads(json_trigger_command) json_get = json.loads(json_get_command) expected_message = """"path":"measval/values/capturedValue1""" "" sensor1_values = [None] * 10 measured_values = np.zeros((10, )) ws = create_connection("ws://10.0.0.46:8081") for mereni in range(10): ws.send(json.dumps(json_trigger)) result = ws.recv() time.sleep(.1) # TODO check result ws.send(json.dumps(json_get)) clipx_message = "" while expected_message not in clipx_message: clipx_message = ws.recv() sensor1_values[mereni] = json.loads(clipx_message) self.text_hodnoty1.append( str(sensor1_values[mereni]["params"]["value"])) QtGui.QGuiApplication.processEvents() measured_values[mereni] = sensor1_values[mereni]["params"]["value"] ws.close() self.prumer1.setText("{:.4E}".format(Decimal(measured_values.mean()))) self.smodch1.setText("{:.4E}".format(Decimal(measured_values.std()))) QtGui.QGuiApplication.processEvents() sensor2_values = [None] * 10 measured2_values = np.zeros((10, 1)) ws2 = create_connection("ws://10.0.0.46:8081") self.text_hodnoty2.setText("") for mereni in range(10): ws2.send(json.dumps(json_trigger)) result = ws2.recv() time.sleep(.1) print(mereni) # TODO check result ws2.send(json.dumps(json_get)) clipx_message = "" while not expected_message in clipx_message: clipx_message = ws2.recv() sensor2_values[mereni] = json.loads(clipx_message) # print(sensor1_values[mereni]["params"]["value"]) self.text_hodnoty2.append("{:.4E}".format( Decimal(sensor2_values[mereni]["params"]["value"]))) QtGui.QGuiApplication.processEvents() measured2_values[mereni] = sensor2_values[mereni]["params"][ "value"] ws2.close() self.prumer2.setText("{:.4E}".format(Decimal(measured2_values.mean()))) self.smodch2.setText("{:.4E}".format(Decimal(measured2_values.std()))) rozdil = measured_values.mean() - measured2_values.mean() self.rozdil.setText("{:.4E}".format(Decimal(rozdil))) self.buttonMereni.setEnabled(True) self.buttonMereniDynamicke.setEnabled(True) QtGui.QGuiApplication.processEvents() def retranslateUi(self, MainWindow): _translate = QtCore.QCoreApplication.translate MainWindow.setWindowTitle(_translate("MainWindow", "Měření")) self.label.setText(_translate("MainWindow", "Statické měření")) self.label_2.setText(_translate("MainWindow", "Čidlo 1")) self.label_3.setText(_translate("MainWindow", "Čidlo 2")) self.label_4.setText(_translate("MainWindow", "Průměrná hodnota")) self.label_5.setText(_translate("MainWindow", "Směrodatná odchylka")) self.label_6.setText(_translate("MainWindow", "Průměrná hodnota")) self.label_7.setText(_translate("MainWindow", "Směrodatná odchylka")) self.buttonMereni.setText(_translate("MainWindow", "Měření")) self.label_8.setText(_translate("MainWindow", "Rozdíl")) self.label_9.setText(_translate("MainWindow", "Dynamické měření")) self.label_10.setText(_translate("MainWindow", "Počet měření")) self.label_11.setText(_translate("MainWindow", "Interval [s]")) self.label_12.setText(_translate("MainWindow", "Název souboru")) self.buttonMereniDynamicke.setText( _translate("MainWindow", "Zahájit měření")) self.label_13.setText(_translate("MainWindow", "Hodnoty"))
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 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 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 Ui_MainWindow(object): def setupUi(self, MainWindow): MainWindow.setObjectName("MainWindow") MainWindow.resize(1146, 673) MainWindow.setAutoFillBackground(False) self.centralwidget = QtWidgets.QWidget(MainWindow) self.centralwidget.setObjectName("centralwidget") self.pushButton = QtWidgets.QPushButton(self.centralwidget) self.pushButton.setGeometry(QtCore.QRect(20, 50, 171, 51)) self.pushButton.setObjectName("pushButton") self.pushButton_2 = QtWidgets.QPushButton(self.centralwidget) self.pushButton_2.setGeometry(QtCore.QRect(20, 110, 171, 51)) self.pushButton_2.setObjectName("pushButton_2") self.pushButton_3 = QtWidgets.QPushButton(self.centralwidget) self.pushButton_3.setGeometry(QtCore.QRect(20, 170, 171, 51)) self.pushButton_3.setObjectName("pushButton_3") self.lcdNumber = QtWidgets.QLCDNumber(self.centralwidget) self.lcdNumber.setGeometry(QtCore.QRect(20, 390, 161, 81)) self.lcdNumber.setFrameShape(QtWidgets.QFrame.StyledPanel) self.lcdNumber.setFrameShadow(QtWidgets.QFrame.Raised) self.lcdNumber.setLineWidth(4) self.lcdNumber.setSmallDecimalPoint(False) self.lcdNumber.setObjectName("lcdNumber") self.lcdNumber_2 = QtWidgets.QLCDNumber(self.centralwidget) self.lcdNumber_2.setGeometry(QtCore.QRect(20, 530, 161, 81)) self.lcdNumber_2.setFrameShape(QtWidgets.QFrame.StyledPanel) self.lcdNumber_2.setFrameShadow(QtWidgets.QFrame.Raised) self.lcdNumber_2.setLineWidth(4) self.lcdNumber_2.setSmallDecimalPoint(False) self.lcdNumber_2.setObjectName("lcdNumber_2") self.label = QtWidgets.QLabel(self.centralwidget) self.label.setGeometry(QtCore.QRect(20, 505, 91, 21)) font = QtGui.QFont() font.setPointSize(20) font.setBold(True) font.setItalic(False) font.setWeight(75) self.label.setFont(font) self.label.setObjectName("label") self.label_2 = QtWidgets.QLabel(self.centralwidget) self.label_2.setGeometry(QtCore.QRect(20, 360, 121, 21)) font = QtGui.QFont() font.setPointSize(20) font.setBold(True) font.setItalic(False) font.setWeight(75) self.label_2.setFont(font) self.label_2.setObjectName("label_2") self.label_3 = QtWidgets.QLabel(self.centralwidget) self.label_3.setGeometry(QtCore.QRect(220, 230, 71, 31)) self.label_3.setObjectName("label_3") self.label_4 = QtWidgets.QLabel(self.centralwidget) self.label_4.setGeometry(QtCore.QRect(220, 20, 60, 16)) self.label_4.setObjectName("label_4") self.wave = PlotWidget(self.centralwidget) self.wave.setGeometry(QtCore.QRect(220, 40, 901, 191)) self.wave.setObjectName("wave") self.spectrum = PlotWidget(self.centralwidget) self.spectrum.setGeometry(QtCore.QRect(220, 260, 901, 351)) self.spectrum.setObjectName("spectrum") self.progressBar = QtWidgets.QProgressBar(self.centralwidget) self.progressBar.setGeometry(QtCore.QRect(20, 330, 161, 23)) self.progressBar.setProperty("value", 0) self.progressBar.setObjectName("progressBar") self.label_5 = QtWidgets.QLabel(self.centralwidget) self.label_5.setGeometry(QtCore.QRect(20, 305, 161, 21)) font = QtGui.QFont() font.setPointSize(20) self.label_5.setFont(font) self.label_5.setText("") self.label_5.setObjectName("label_5") self.radioButton = QtWidgets.QRadioButton(self.centralwidget) self.radioButton.setGeometry(QtCore.QRect(30, 240, 100, 20)) self.radioButton.setChecked(True) self.radioButton.setObjectName("radioButton") self.radioButton_2 = QtWidgets.QRadioButton(self.centralwidget) self.radioButton_2.setGeometry(QtCore.QRect(110, 240, 100, 20)) self.radioButton_2.setObjectName("radioButton_2") MainWindow.setCentralWidget(self.centralwidget) self.menubar = QtWidgets.QMenuBar(MainWindow) self.menubar.setGeometry(QtCore.QRect(0, 0, 1146, 22)) self.menubar.setObjectName("menubar") MainWindow.setMenuBar(self.menubar) self.statusbar = QtWidgets.QStatusBar(MainWindow) self.statusbar.setObjectName("statusbar") MainWindow.setStatusBar(self.statusbar) self.retranslateUi(MainWindow) self.pushButton.clicked.connect(MainWindow.slot1) self.pushButton_2.clicked.connect(MainWindow.slot2) self.pushButton_3.clicked.connect(MainWindow.slot3) self.radioButton.clicked.connect(MainWindow.slot4) self.radioButton_2.clicked.connect(MainWindow.slot5) QtCore.QMetaObject.connectSlotsByName(MainWindow) # 波形グラフ self.plotwid1 = PlotWidget(self.centralwidget) self.plotwid1.setGeometry(QtCore.QRect(220, 40, 901, 191)) self.plotwid1.setObjectName("wave") self.plotitem1 = self.plotwid1.getPlotItem() self.plotitem1.setMouseEnabled(x=False, y=False) self.plotitem1.setYRange(-1, 1) self.plotitem1.setXRange(0, MainWindow.N, padding=0) # スペクトルグラフ self.plotwid2 = PlotWidget(self.centralwidget) self.plotwid2.setGeometry(QtCore.QRect(220, 260, 901, 351)) self.plotwid2.setObjectName("spectrum") self.plotitem2 = self.plotwid2.getPlotItem() self.plotitem2.setMouseEnabled(x=False, y=True) self.plotitem2.setYRange(35, 250) self.plotitem2.setXRange(20, MainWindow.RATE / 2, padding=0) # Plot data self.curve_wave = self.plotitem1.plot() self.curve_spectrum = self.plotitem2.plot() self.max_spectrum = self.plotitem2.plot(pen=pg.mkPen(color="r")) def retranslateUi(self, MainWindow): _translate = QtCore.QCoreApplication.translate MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow")) self.pushButton.setText(_translate("MainWindow", "校正イヤホン測定")) self.pushButton_2.setText(_translate("MainWindow", "百均イヤホン測定")) self.pushButton_3.setText(_translate("MainWindow", "終了")) self.label.setText(_translate("MainWindow", "音圧")) self.label_2.setText(_translate("MainWindow", "周波数[Hz]")) self.label_3.setText(_translate("MainWindow", "FFT")) self.label_4.setText(_translate("MainWindow", "波形")) self.radioButton.setText(_translate("MainWindow", "左耳L")) self.radioButton_2.setText(_translate("MainWindow", "右耳R"))
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 TimeSeriesWidget(QtWidgets.QWidget): """ Time-series widget with built-in display controls. """ # Internal refresh signal _refresh_signal = QtCore.pyqtSignal(np.ndarray, np.ndarray) # Signal to change the y-axis units _yaxis_units_signal = QtCore.pyqtSignal(str) def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.plot_widget = PlotWidget( parent=self, title="Diffraction time-series", labels={"left": ("Intensity", "a. u."), "bottom": ("time", "ps")}, ) self._yaxis_units_signal.connect(self.set_yaxis_units) self.plot_widget.getPlotItem().showGrid(x=True, y=True) # Internal state on whether or not to 'connect the dots' self._time_series_connect = False self._symbol_size = 5 # Internal memory on last time-series info self._last_times = None self._last_intensities_abs = None self._refresh_signal.connect(self.plot) self.connect_widget = QtWidgets.QCheckBox("Connect time-series", self) self.connect_widget.toggled.connect(self.enable_connect) self.symbol_size_widget = QtWidgets.QSpinBox(parent=self) self.symbol_size_widget.setRange(1, 25) self.symbol_size_widget.setValue(self._symbol_size) self.symbol_size_widget.setPrefix("Symbol size: ") self.symbol_size_widget.valueChanged.connect(self.set_symbol_size) self.absolute_intensity_widget = QtWidgets.QCheckBox( "Show absolute intensity", self ) self.absolute_intensity_widget.toggled.connect(self.toggle_absolute_intensity) self.exponential_fit_widget = QtWidgets.QPushButton( "Calculate exponential decay", self ) self.exponential_fit_widget.clicked.connect(self.fit_exponential_decay) self.fit_constants_label = QtWidgets.QLabel(self) self.controls = QtWidgets.QHBoxLayout() self.controls.addWidget(self.connect_widget) self.controls.addWidget(self.absolute_intensity_widget) self.controls.addWidget(self.symbol_size_widget) self.controls.addWidget(self.exponential_fit_widget) self.controls.addWidget(self.fit_constants_label) self.controls.addStretch(1) layout = QtWidgets.QVBoxLayout() layout.addWidget(self.plot_widget) layout.addLayout(self.controls) self.setLayout(layout) @QtCore.pyqtSlot(str) def set_yaxis_units(self, units): """ Set the y-axis label """ self.plot_widget.getPlotItem().setLabel("left", text="Intensity", units=units) @QtCore.pyqtSlot(bool) def toggle_absolute_intensity(self, absolute): # Normalize to intensity before time-zero if absolute: self._yaxis_units_signal.emit("counts") else: self._yaxis_units_signal.emit("a.u.") self.refresh() @QtCore.pyqtSlot(np.ndarray, np.ndarray) def plot(self, time_points, intensity): """ Plot the a time-series. Time-series are normalized to the intensity before photoexcitation. Parameters ---------- time_points : `~numpy.ndarray`, shape (N,) Time-delays [ps] intensity : `~numpy.ndarray`, shape (N,) Diffracted intensity in absolute units. """ self._last_times = np.asarray(time_points) self._last_intensities_abs = np.asarray(intensity) # Normalize to intensity before time-zero # Note that the change in units is taken care of in the toggle_absolute_intensity method absolute = self.absolute_intensity_widget.isChecked() intensity = ( self._last_intensities_abs if absolute else self._last_intensities_abs / np.mean(self._last_intensities_abs[self._last_times < 0]) ) # Only compute the colors if number of time-points changes or first time pens, brushes = pens_and_brushes(len(time_points)) connect_kwargs = {"pen": None} if not self._time_series_connect else dict() self.plot_widget.plot( x=self._last_times, y=intensity, symbol="o", symbolPen=pens, symbolBrush=brushes, symbolSize=self._symbol_size, clear=True, **connect_kwargs ) # Don't forget to clear the fit constants self.fit_constants_label.clear() @QtCore.pyqtSlot() def fit_exponential_decay(self): """ Try to fit to a time-series with an exponential decay. If successful, plot the result. """ times = self._last_times intensity = self._last_intensities_abs # time-zero, amplitude, time-constant, offset initial_guesses = (0, intensity.max(), 1, intensity.min()) try: params, pcov = curve_fit( exponential_decay, times, intensity, p0=initial_guesses ) except RuntimeError: return fit = exponential_decay(times, *params) absolute = self.absolute_intensity_widget.isChecked() if not absolute: fit /= np.mean(self._last_intensities_abs[self._last_times < 0]) self.plot_widget.plot(x=times, y=fit, symbol=None, clear=False) # Write fit parameters to text items tconst, tconsterr = params[2], np.sqrt(pcov[2, 2]) tzero, tzeroerr = params[0], np.sqrt(pcov[0, 0]) self.fit_constants_label.setText( "Time-constant: ({:.3f}±{:.3f} ps, Time-zero: ({:.3f}±{:.3f}) ps".format( tconst, tconsterr, tzero, tzeroerr ) ) @QtCore.pyqtSlot() def refresh(self): self._refresh_signal.emit(self._last_times, self._last_intensities_abs) @QtCore.pyqtSlot() def clear(self): self.plot_widget.clear() @QtCore.pyqtSlot(bool) def enable_connect(self, toggle): self._time_series_connect = toggle self.refresh() @QtCore.pyqtSlot(int) def set_symbol_size(self, size): self._symbol_size = size self.refresh()
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 Tiare(QtGui.QMainWindow): def __init__(self, *args): QtGui.QMainWindow.__init__(self, *args) self.statusBar().showMessage('Pret') self.th = 0 self.widget = QtGui.QWidget(self) exitAction = QtGui.QAction(QtGui.QIcon('exit.png'), '&Quitter', self) exitAction.setShortcut('Ctrl+Q') exitAction.setStatusTip("Ferme l'application") exitAction.triggered.connect(self.close) openAction = QtGui.QAction(QtGui.QIcon('open.png'), '&Charger', self) openAction.setShortcut('Ctrl+L') openAction.setStatusTip("Charge un fichier wav") openAction.triggered.connect(self.load) self.saveAction = QtGui.QAction(QtGui.QIcon('save.png'), '&Exporter', self) self.saveAction.setShortcut('Ctrl+S') self.saveAction.setStatusTip("Exporter en CSV") self.saveAction.triggered.connect(self.export) self.saveAction.setEnabled(False) menubar = self.menuBar() fileMenu = menubar.addMenu('&Fichier') fileMenu.addAction(openAction) fileMenu.addAction(self.saveAction) fileMenu.addAction(exitAction) self.th_slider = QtGui.QSlider(QtCore.Qt.Horizontal, self) self.th_slider.setValue(self.th) self.th_slider.valueChanged[int].connect(self.change_threshold) self.min_len = QtGui.QSlider(QtCore.Qt.Horizontal, self) self.min_len.setValue(10) self.min_len.setMinimum(1) self.min_len.setMaximum(100) self.min_len.valueChanged[int].connect(self.change_min_len) self.min_len_sil = QtGui.QSlider(QtCore.Qt.Horizontal, self) self.min_len_sil.setValue(10) self.min_len_sil.setMinimum(1) self.min_len_sil.setMaximum(100) self.min_len_sil.valueChanged[int].connect(self.change_min_len) # Make sizer and embed stuff self.sizer = QtGui.QVBoxLayout(self.widget) self.fig_signal = PlotWidget(self.widget, background="w") self.fig_signal.setLimits(xMin=0, yMin=-1, yMax=1, minXRange=1, maxXRange=30, minYRange=2, maxYRange=2) self.fig_energy = PlotWidget(self.widget, background="w") self.fig_energy.setXLink(self.fig_signal) self.fig_segments = PlotWidget(self.widget, background="w") self.fig_segments.setXLink(self.fig_signal) self.fig_segments.hideAxis('bottom') self.fig_segments.hideAxis('left') self.fig_segments.setLimits(yMin=-1, yMax=1, minYRange=2, maxYRange=2) self.sizer.addWidget(self.fig_signal, 5) self.sizer.addWidget(self.fig_energy, 5) self.sizer.addWidget(self.fig_segments, 3) self.sizer.addWidget(QtGui.QLabel('Seuil de segmentation'), 0) self.sizer.addWidget(self.th_slider, 0) self.min_seg_label = QtGui.QLabel('Longeur minimal de segment (%.3f s)' % (float(self.min_len.value())/100)) self.sizer.addWidget(self.min_seg_label, 0) self.sizer.addWidget(self.min_len, 0) self.min_sil_label = QtGui.QLabel('Longeur minimal de silence (%.3f s)' % (float(self.min_len_sil.value())/100)) self.sizer.addWidget(self.min_sil_label, 0) self.sizer.addWidget(self.min_len_sil, 0) # Apply sizers self.setCentralWidget(self.widget) # Finish self.resize(560, 420) self.setWindowTitle('Tiare') self.energy_tl, self.energy = [], [] self.thline = None self.seg_up = None self.seg_down = None self.fig_energy_plot = None self.segments = [] self.samples = [] self.sr = 0 self.filepath = None self.widget.hide() self.show() def change_threshold(self, value): value = float(value)/100 if self.thline is not None : self.thline.setData([self.energy_tl[0], self.energy_tl[-1]], [value]*2) self.segments = map(lambda (x, y): (self.energy_tl[x],self.energy_tl[y]), cut(self.energy, value, self.min_len.value(), self.min_len_sil.value())) x = [v for start, stop in self.segments for v in [start, start, stop, stop]] y = [v for _ in self.segments for v in [-0.85, 0.85, 0.85, -0.85]] self.seg_up.setData(x, y) self.seg_down.setData([self.energy_tl[0], self.energy_tl[-1]], [-0.85, -0.85]) def change_min_len(self, value=0): self.min_seg_label.setText("Longeur minimale d'un segment (%.3f s)" % (float(self.min_len.value())/100)) self.min_sil_label.setText("Longeur minimale d'un silence (%.3f s)" % (float(self.min_len_sil.value())/100)) self.change_threshold(self.th_slider.value()) def compute_energy(self, value=None): self.energy_tl, self.energy = energy(self.samples, self.sr) if self.fig_energy_plot is not None: self.fig_energy_plot.setData(self.energy_tl, self.energy) self.change_min_len() def export(self): fpath = QtGui.QFileDialog.getSaveFileName(self, "Sauvegader en CSV", self.filepath+".csv") if fpath: with open(fpath[0], "w") as f: for start, stop in self.segments: f.write("Segments\t%s\t%s\n" % (datetime(day=1, month=1, year=1901, second=int(start), microsecond=int(10e5*(start % 1))) .strftime("%H:%M:%S.%f"), datetime(day=1, month=1, year=1901, second=int(stop), microsecond=int(10e5*(stop % 1))) .strftime("%H:%M:%S.%f"))) def load(self): fpath, _ = QtGui.QFileDialog.getOpenFileName(self, 'Choisir un fichier', '~/', filter="*.wav") self.widget.show() if fpath: self.filepath = fpath self.saveAction.setEnabled(True) self.samples, self.sr = load_sound(fpath) m = max(map(abs, self.samples)) timeline = [float(t)/self.sr for t in range(len(self.samples))] self.fig_signal.setLimits(xMax=timeline[-1]) self.compute_energy() self.fig_signal.getPlotItem().plot(timeline, map(lambda x: x/m, self.samples)) self.fig_energy_plot = self.fig_energy.getPlotItem().plot(self.energy_tl, self.energy) self.thline = self.fig_energy.getPlotItem().plot([self.energy_tl[0], self.energy_tl[-1]], [float(self.th_slider.value())/100]*2, pen=({'color': "k", "width": 1.5})) self.seg_up = self.fig_segments.getPlotItem().plot([self.energy_tl[0], self.energy_tl[-1]], [-0.85, -0.85]) self.seg_down = self.fig_segments.getPlotItem().plot([self.energy_tl[0], self.energy_tl[-1]], [-0.85, -0.85]) self.segments = FillBetweenItem(self.seg_up, self.seg_down, 0.7) self.fig_segments.addItem(self.segments)
class Ui_MainWindow(object): def setupUi(self, MainWindow): self.probihaNuloveMereni = False self.nuloveHodnoty = np.array([0, 0]) self.int_validator =QtGui.QIntValidator() self.float_validator = QtGui.QDoubleValidator() self.koeficienty = {'uzavreny': [0.000615, 0.001056], 'otevreny': [0.000895, 0.000287]} pq.setConfigOption('background', 'y') pq.setConfigOption('foreground', 'k') MainWindow.setObjectName("MainWindow") MainWindow.resize(912, 732) self.centralwidget = QtWidgets.QWidget(MainWindow) self.centralwidget.setObjectName("centralwidget") self.text_hodnoty1 = QtWidgets.QTextBrowser(self.centralwidget) self.text_hodnoty1.setGeometry(QtCore.QRect(30, 60, 151, 181)) self.text_hodnoty1.setObjectName("text_hodnoty1") self.text_hodnoty2 = QtWidgets.QTextBrowser(self.centralwidget) self.text_hodnoty2.setGeometry(QtCore.QRect(445, 50, 151, 192)) self.text_hodnoty2.setObjectName("text_hodnoty2") self.label = QtWidgets.QLabel(self.centralwidget) self.label.setGeometry(QtCore.QRect(30, 10, 201, 21)) font = QtGui.QFont() font.setFamily("System") font.setPointSize(14) font.setBold(True) font.setWeight(75) self.label.setFont(font) self.label.setObjectName("label") self.label_2 = QtWidgets.QLabel(self.centralwidget) self.label_2.setGeometry(QtCore.QRect(30, 40, 47, 13)) self.label_2.setObjectName("label_2") self.label_3 = QtWidgets.QLabel(self.centralwidget) self.label_3.setGeometry(QtCore.QRect(450, 30, 47, 13)) self.label_3.setObjectName("label_3") self.label_4 = QtWidgets.QLabel(self.centralwidget) self.label_4.setGeometry(QtCore.QRect(200, 60, 121, 16)) self.label_4.setObjectName("label_4") self.label_5 = QtWidgets.QLabel(self.centralwidget) self.label_5.setGeometry(QtCore.QRect(200, 110, 121, 16)) self.label_5.setObjectName("label_5") self.label_6 = QtWidgets.QLabel(self.centralwidget) self.label_6.setGeometry(QtCore.QRect(610, 50, 121, 16)) self.label_6.setObjectName("label_6") self.label_7 = QtWidgets.QLabel(self.centralwidget) self.label_7.setGeometry(QtCore.QRect(610, 110, 121, 16)) self.label_7.setObjectName("label_7") self.prumer1 = QtWidgets.QTextBrowser(self.centralwidget) self.prumer1.setGeometry(QtCore.QRect(200, 80, 141, 31)) self.prumer1.setObjectName("prumer1") self.prumer2 = QtWidgets.QTextBrowser(self.centralwidget) self.prumer2.setGeometry(QtCore.QRect(610, 70, 141, 31)) self.prumer2.setObjectName("prumer2") self.smodch1 = QtWidgets.QTextBrowser(self.centralwidget) self.smodch1.setGeometry(QtCore.QRect(200, 130, 141, 31)) self.smodch1.setObjectName("smodch1") self.smodch2 = QtWidgets.QTextBrowser(self.centralwidget) self.smodch2.setGeometry(QtCore.QRect(610, 130, 141, 31)) self.smodch2.setObjectName("smodch2") self.groupBox = QtWidgets.QGroupBox(self.centralwidget) self.groupBox.setGeometry(QtCore.QRect(0, 0, 771, 281)) palette = QtGui.QPalette() brush = QtGui.QBrush(QtGui.QColor(0, 255, 255)) brush.setStyle(QtCore.Qt.SolidPattern) palette.setBrush(QtGui.QPalette.Active, QtGui.QPalette.Base, brush) brush = QtGui.QBrush(QtGui.QColor(85, 170, 255)) brush.setStyle(QtCore.Qt.SolidPattern) palette.setBrush(QtGui.QPalette.Active, QtGui.QPalette.Window, brush) brush = QtGui.QBrush(QtGui.QColor(0, 255, 255)) brush.setStyle(QtCore.Qt.SolidPattern) palette.setBrush(QtGui.QPalette.Inactive, QtGui.QPalette.Base, brush) brush = QtGui.QBrush(QtGui.QColor(85, 170, 255)) brush.setStyle(QtCore.Qt.SolidPattern) palette.setBrush(QtGui.QPalette.Inactive, QtGui.QPalette.Window, brush) brush = QtGui.QBrush(QtGui.QColor(85, 170, 255)) brush.setStyle(QtCore.Qt.SolidPattern) palette.setBrush(QtGui.QPalette.Disabled, QtGui.QPalette.Base, brush) brush = QtGui.QBrush(QtGui.QColor(85, 170, 255)) brush.setStyle(QtCore.Qt.SolidPattern) palette.setBrush(QtGui.QPalette.Disabled, QtGui.QPalette.Window, brush) self.groupBox.setPalette(palette) self.groupBox.setAutoFillBackground(True) self.groupBox.setTitle("") self.groupBox.setObjectName("groupBox") self.buttonMereni = QtWidgets.QPushButton(self.groupBox) self.buttonMereni.setGeometry(QtCore.QRect(610, 200, 141, 41)) self.buttonMereni.setObjectName("buttonMereni") self.buttonMereni.clicked.connect(self.one_measure) self.groupBox_2 = QtWidgets.QGroupBox(self.centralwidget) self.groupBox_2.setGeometry(QtCore.QRect(770, 0, 141, 281)) palette = QtGui.QPalette() brush = QtGui.QBrush(QtGui.QColor(0, 255, 255)) brush.setStyle(QtCore.Qt.SolidPattern) palette.setBrush(QtGui.QPalette.Active, QtGui.QPalette.Base, brush) brush = QtGui.QBrush(QtGui.QColor(255, 170, 0)) brush.setStyle(QtCore.Qt.SolidPattern) palette.setBrush(QtGui.QPalette.Active, QtGui.QPalette.Window, brush) brush = QtGui.QBrush(QtGui.QColor(0, 255, 255)) brush.setStyle(QtCore.Qt.SolidPattern) palette.setBrush(QtGui.QPalette.Inactive, QtGui.QPalette.Base, brush) brush = QtGui.QBrush(QtGui.QColor(255, 170, 0)) brush.setStyle(QtCore.Qt.SolidPattern) palette.setBrush(QtGui.QPalette.Inactive, QtGui.QPalette.Window, brush) brush = QtGui.QBrush(QtGui.QColor(255, 170, 0)) brush.setStyle(QtCore.Qt.SolidPattern) palette.setBrush(QtGui.QPalette.Disabled, QtGui.QPalette.Base, brush) brush = QtGui.QBrush(QtGui.QColor(255, 170, 0)) brush.setStyle(QtCore.Qt.SolidPattern) palette.setBrush(QtGui.QPalette.Disabled, QtGui.QPalette.Window, brush) self.groupBox_2.setPalette(palette) self.groupBox_2.setAutoFillBackground(True) self.groupBox_2.setTitle("") self.groupBox_2.setObjectName("groupBox_2") self.label_8 = QtWidgets.QLabel(self.groupBox_2) self.label_8.setGeometry(QtCore.QRect(10, 80, 121, 16)) font = QtGui.QFont() font.setPointSize(14) font.setBold(True) font.setWeight(75) self.label_8.setFont(font) self.label_8.setAlignment(QtCore.Qt.AlignCenter) self.label_8.setObjectName("label_8") self.rozdil = QtWidgets.QTextBrowser(self.groupBox_2) self.rozdil.setGeometry(QtCore.QRect(20, 100, 111, 31)) palette = QtGui.QPalette() brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) brush.setStyle(QtCore.Qt.SolidPattern) palette.setBrush(QtGui.QPalette.Active, QtGui.QPalette.Base, brush) brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) brush.setStyle(QtCore.Qt.SolidPattern) palette.setBrush(QtGui.QPalette.Inactive, QtGui.QPalette.Base, brush) brush = QtGui.QBrush(QtGui.QColor(255, 170, 0)) brush.setStyle(QtCore.Qt.SolidPattern) palette.setBrush(QtGui.QPalette.Disabled, QtGui.QPalette.Base, brush) self.rozdil.setPalette(palette) self.rozdil.setObjectName("rozdil") self.groupBox_3 = QtWidgets.QGroupBox(self.centralwidget) self.groupBox_3.setGeometry(QtCore.QRect(0, 280, 911, 381)) palette = QtGui.QPalette() brush = QtGui.QBrush(QtGui.QColor(0, 255, 255)) brush.setStyle(QtCore.Qt.SolidPattern) palette.setBrush(QtGui.QPalette.Active, QtGui.QPalette.Base, brush) brush = QtGui.QBrush(QtGui.QColor(255, 255, 0)) brush.setStyle(QtCore.Qt.SolidPattern) palette.setBrush(QtGui.QPalette.Active, QtGui.QPalette.Window, brush) brush = QtGui.QBrush(QtGui.QColor(0, 255, 255)) brush.setStyle(QtCore.Qt.SolidPattern) palette.setBrush(QtGui.QPalette.Inactive, QtGui.QPalette.Base, brush) brush = QtGui.QBrush(QtGui.QColor(255, 255, 0)) brush.setStyle(QtCore.Qt.SolidPattern) palette.setBrush(QtGui.QPalette.Inactive, QtGui.QPalette.Window, brush) brush = QtGui.QBrush(QtGui.QColor(255, 255, 0)) brush.setStyle(QtCore.Qt.SolidPattern) palette.setBrush(QtGui.QPalette.Disabled, QtGui.QPalette.Base, brush) brush = QtGui.QBrush(QtGui.QColor(255, 255, 0)) brush.setStyle(QtCore.Qt.SolidPattern) palette.setBrush(QtGui.QPalette.Disabled, QtGui.QPalette.Window, brush) self.groupBox_3.setPalette(palette) self.groupBox_3.setAutoFillBackground(True) self.groupBox_3.setTitle("") self.groupBox_3.setObjectName("groupBox_3") self.label_9 = QtWidgets.QLabel(self.groupBox_3) self.label_9.setGeometry(QtCore.QRect(20, 10, 201, 21)) font = QtGui.QFont() font.setFamily("System") font.setPointSize(14) font.setBold(True) font.setWeight(75) self.label_9.setFont(font) self.label_9.setObjectName("label_9") self.graphicsView = PlotWidget(self.groupBox_3) self.graphicsView.setGeometry(QtCore.QRect(250, 10, 651, 341)) self.graphicsView.setObjectName("graphicsView") self.label_10 = QtWidgets.QLabel(self.groupBox_3) self.label_10.setGeometry(QtCore.QRect(20, 40, 91, 16)) self.label_10.setObjectName("label_10") self.label_11 = QtWidgets.QLabel(self.groupBox_3) self.label_11.setGeometry(QtCore.QRect(20, 60, 91, 16)) self.label_11.setObjectName("label_11") self.label_12 = QtWidgets.QLabel(self.groupBox_3) self.label_12.setGeometry(QtCore.QRect(20, 80, 91, 16)) self.label_12.setObjectName("label_12") self.lineEdit = QtWidgets.QLineEdit(self.groupBox_3) self.lineEdit.setGeometry(QtCore.QRect(20, 100, 221, 20)) self.lineEdit.setObjectName("lineEdit") self.lineEdit.setText(datetime.datetime.now().strftime("Data_" + "%Y-%m-%d_%H%M%S" + ".csv")) reg_ex = QtCore.QRegExp("([0-9]\s.") validator = QtGui.QRegExpValidator(reg_ex) self.lineEdit_interval = QtWidgets.QLineEdit(self.groupBox_3) self.lineEdit_interval.setGeometry(QtCore.QRect(90, 60, 151, 20)) self.lineEdit_interval.setInputMethodHints(QtCore.Qt.ImhDigitsOnly) self.lineEdit_interval.setObjectName("lineEdit_interval") self.lineEdit_interval.setValidator(self.int_validator) self.lineEdit_pocet_2 = QtWidgets.QLineEdit(self.groupBox_3) self.lineEdit_pocet_2.setGeometry(QtCore.QRect(90, 40, 151, 20)) self.lineEdit_pocet_2.setInputMethodHints(QtCore.Qt.ImhDigitsOnly) self.lineEdit_pocet_2.setValidator(self.int_validator) self.lineEdit_pocet_2.setObjectName("lineEdit_pocet_2") self.buttonMereniDynamicke = QtWidgets.QPushButton(self.groupBox_3) self.buttonMereniDynamicke.setGeometry(QtCore.QRect(20, 120, 221, 21)) self.buttonMereniDynamicke.setObjectName("buttonMereniDynamicke") self.buttonMereniDynamicke.clicked.connect(self.multiple_measure) self.text_dynhodnoty = QtWidgets.QTextBrowser(self.groupBox_3) self.text_dynhodnoty.setGeometry(QtCore.QRect(20, 170, 151, 181)) palette = QtGui.QPalette() brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) brush.setStyle(QtCore.Qt.SolidPattern) palette.setBrush(QtGui.QPalette.Active, QtGui.QPalette.Base, brush) brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) brush.setStyle(QtCore.Qt.SolidPattern) palette.setBrush(QtGui.QPalette.Inactive, QtGui.QPalette.Base, brush) brush = QtGui.QBrush(QtGui.QColor(255, 255, 0)) brush.setStyle(QtCore.Qt.SolidPattern) palette.setBrush(QtGui.QPalette.Disabled, QtGui.QPalette.Base, brush) self.text_dynhodnoty.setPalette(palette) self.text_dynhodnoty.setObjectName("text_dynhodnoty") self.label_13 = QtWidgets.QLabel(self.groupBox_3) self.label_13.setGeometry(QtCore.QRect(10, 150, 47, 13)) self.label_13.setObjectName("label_13") self.groupBox_4 = QtWidgets.QGroupBox(self.centralwidget) self.groupBox_4.setGeometry(QtCore.QRect(295, 660, 280, 51)) self.groupBox_4.setObjectName("groupBox_4") self.pushTare2 = QtWidgets.QPushButton(self.groupBox_4) self.pushTare2.setGeometry(QtCore.QRect(10, 20, 50, 23)) self.pushTare2.setObjectName("pushTare2") self.pushTareZrusit2 = QtWidgets.QPushButton(self.groupBox_4) self.pushTareZrusit2.setGeometry(QtCore.QRect(60, 20, 90, 23)) self.pushTareZrusit2.setObjectName("pushTareZrusit2") self.pushNula2 = QtWidgets.QPushButton(self.groupBox_4) self.pushNula2.setGeometry(QtCore.QRect(150, 20, 65, 23)) self.pushNula2.setObjectName("pushNula2") self.pushNulaZrusit2 = QtWidgets.QPushButton(self.groupBox_4) self.pushNulaZrusit2.setGeometry(QtCore.QRect(215, 20, 60, 23)) self.pushNulaZrusit2.setObjectName("pushNulaZrusit2") self.groupBox_5 = QtWidgets.QGroupBox(self.centralwidget) self.groupBox_5.setGeometry(QtCore.QRect(10, 660, 280, 51)) self.groupBox_5.setObjectName("groupBox_5") self.pushTare2_2 = QtWidgets.QPushButton(self.groupBox_5) self.pushTare2_2.setGeometry(QtCore.QRect(10, 20, 50, 23)) self.pushTare2_2.setObjectName("pushTare2_2") self.pushTareZrusit2_2 = QtWidgets.QPushButton(self.groupBox_5) self.pushTareZrusit2_2.setGeometry(QtCore.QRect(60, 20, 90, 23)) self.pushTareZrusit2_2.setObjectName("pushTareZrusit2_2") self.pushNula1 = QtWidgets.QPushButton(self.groupBox_5) self.pushNula1.setGeometry(QtCore.QRect(150, 20, 65, 23)) self.pushNula1.setObjectName("pushNula1") self.pushNulaZrusit1 = QtWidgets.QPushButton(self.groupBox_5) self.pushNulaZrusit1.setGeometry(QtCore.QRect(215, 20, 60, 23)) self.pushNulaZrusit1.setObjectName("pushNulaZrusit1") # parametry self.label_20 = QtWidgets.QLabel(self.centralwidget) self.label_20.setGeometry(QtCore.QRect(590, 660, 55, 13)) self.label_20.setObjectName("label_20") self.groupBox_6 = QtWidgets.QGroupBox(self.centralwidget) self.groupBox_6.setGeometry(QtCore.QRect(580, 666, 330, 45)) self.groupBox_6.setObjectName("groupBox_6") self.label_21 = QtWidgets.QLabel(self.groupBox_6) self.label_21.setGeometry(QtCore.QRect(80, 10, 20, 13)) self.label_21.setObjectName("label_21") self.label_22 = QtWidgets.QLabel(self.groupBox_6) self.label_22.setGeometry(QtCore.QRect(80, 26, 20, 13)) self.label_22.setObjectName("label_22") self.lineEdit_koef1 = QtWidgets.QLineEdit(self.groupBox_6) self.lineEdit_koef1.setGeometry(QtCore.QRect(5, 7, 70, 18)) self.lineEdit_koef1.setInputMethodHints(QtCore.Qt.ImhDigitsOnly) self.lineEdit_koef1.setObjectName("lineEdit_koef1") self.lineEdit_koef1.setText(str(self.koeficienty["uzavreny"][0])) # self.lineEdit_koef1.setValidator(QtGui.QDoubleValidator(-0.000000,1.0000000,8,self.lineEdit_koef1)) # self.lineEdit_koef1.setValidator(self.float_validator) self.lineEdit_koef1.textChanged.connect(self.editKoef1) self.lineEdit_koef2 = QtWidgets.QLineEdit(self.groupBox_6) self.lineEdit_koef2.setGeometry(QtCore.QRect(5, 23, 70, 18)) self.lineEdit_koef2.setInputMethodHints(QtCore.Qt.ImhDigitsOnly) self.lineEdit_koef2.setObjectName("lineEdit_koef2") self.lineEdit_koef2.setText(str(self.koeficienty["uzavreny"][1])) # self.lineEdit_koef2.setValidator(self.float_validator) self.lineEdit_koef2.textChanged.connect(self.editKoef2) self.radio1 = QtWidgets.QRadioButton("Uzavřený", self.groupBox_6) self.radio1.setGeometry(QtCore.QRect(100, 3, 80, 25)) self.radio1.setChecked(True) self.radio1.toggled.connect(lambda: self.btnstate(self.radio1)) self.radio2 = QtWidgets.QRadioButton("Otevřený", self.groupBox_6) self.radio2.setGeometry(QtCore.QRect(100, 20, 80, 25)) self.radio2.toggled.connect(lambda: self.btnstate(self.radio2)) self.buttonRst = QtWidgets.QPushButton(self.groupBox_6) self.buttonRst.setGeometry(QtCore.QRect(170, 2, 55, 21)) self.buttonRst.setObjectName("buttonRst") self.buttonRst.clicked.connect(self.resetKoef) self.buttonNuloveMereni = QtWidgets.QPushButton(self.groupBox_6) self.buttonNuloveMereni.setGeometry(QtCore.QRect(170, 22, 55, 21)) self.buttonNuloveMereni.setObjectName("buttonNuloveMereni") self.buttonNuloveMereni.clicked.connect(self.nuloveMereni) self.lineEdit_nulova1 = QtWidgets.QLineEdit(self.groupBox_6) self.lineEdit_nulova1.setGeometry(QtCore.QRect(230, 3, 95, 18)) self.lineEdit_nulova1.setObjectName("lineEdit_nulova1") self.lineEdit_nulova1.setText("č.1") self.lineEdit_nulova1.setDisabled(True) self.lineEdit_nulova2 = QtWidgets.QLineEdit(self.groupBox_6) self.lineEdit_nulova2.setGeometry(QtCore.QRect(230, 23, 95, 18)) self.lineEdit_nulova2.setObjectName("lineEdit_nulova2") self.lineEdit_nulova2.setText("č.2") self.lineEdit_nulova2.setDisabled(True) self.pushNula1.clicked.connect(self.nula1) self.pushNula2.clicked.connect(self.nula2) self.pushTare2.clicked.connect(self.tare2) self.pushTare2_2.clicked.connect(self.tare1) self.pushNulaZrusit1.clicked.connect(self.nula1_zrusit) self.pushNulaZrusit2.clicked.connect(self.nula2_zrusit) self.pushTareZrusit2.clicked.connect(self.tare2_zrusit) self.pushTareZrusit2_2.clicked.connect(self.tare1_zrusit) self.groupBox.raise_() self.text_hodnoty1.raise_() self.text_hodnoty2.raise_() self.label.raise_() self.label_2.raise_() self.label_20.raise_() self.label_21.raise_() self.label_22.raise_() self.label_3.raise_() self.label_4.raise_() self.label_5.raise_() self.label_6.raise_() self.label_7.raise_() self.prumer1.raise_() self.prumer2.raise_() self.smodch1.raise_() self.smodch2.raise_() self.groupBox_2.raise_() self.groupBox_3.raise_() self.groupBox_4.raise_() self.groupBox_5.raise_() MainWindow.setCentralWidget(self.centralwidget) self.statusbar = QtWidgets.QStatusBar(MainWindow) self.statusbar.setObjectName("statusbar") MainWindow.setStatusBar(self.statusbar) self.radio2.click() self.radio1.click() self.retranslateUi(MainWindow) QtCore.QMetaObject.connectSlotsByName(MainWindow) def resetKoef(self): self.koeficienty = {'uzavreny': [0.000615, 0.001056], 'otevreny': [0.000895, 0.000287]} self.radio2.click() self.radio1.click() def retranslateUi(self, MainWindow): _translate = QtCore.QCoreApplication.translate MainWindow.setWindowTitle(_translate("MainWindow", "Měření")) self.label.setText(_translate("MainWindow", "Statické měření")) self.label_2.setText(_translate("MainWindow", "Čidlo 1")) self.label_3.setText(_translate("MainWindow", "Čidlo 2")) self.label_20.setText(_translate("MainWindow", "Parametry")) self.label_21.setText(_translate("MainWindow", "č.1")) self.label_22.setText(_translate("MainWindow", "č.2")) self.label_4.setText(_translate("MainWindow", "Průměrná hodnota")) self.label_5.setText(_translate("MainWindow", "Směrodatná odchylka")) self.label_6.setText(_translate("MainWindow", "Průměrná hodnota")) self.label_7.setText(_translate("MainWindow", "Směrodatná odchylka")) self.buttonMereni.setText(_translate("MainWindow", "Měření")) self.buttonRst.setText(_translate("MainWindow","Reset")) self.buttonNuloveMereni.setText(_translate("MainWindow","Měření 0")) self.label_8.setText(_translate("MainWindow", "Rozdíl")) self.label_9.setText(_translate("MainWindow", "Dynamické měření")) self.label_10.setText(_translate("MainWindow", "Počet měření")) self.label_11.setText(_translate("MainWindow", "Interval [s]")) self.label_12.setText(_translate("MainWindow", "Název souboru")) self.buttonMereniDynamicke.setText(_translate("MainWindow", "Zahájit měření")) self.label_13.setText(_translate("MainWindow", "Hodnoty")) self.groupBox_4.setTitle(_translate("MainWindow", "Čidlo 2")) self.pushTare2.setText(_translate("MainWindow", "Tare")) self.pushTareZrusit2.setText(_translate("MainWindow", "Vynulovat Tare")) self.pushNula2.setText(_translate("MainWindow", "Vynulovat")) self.pushNulaZrusit2.setText(_translate("MainWindow", "Zrušit 0")) self.groupBox_5.setTitle(_translate("MainWindow", "Čidlo 1")) self.pushTare2_2.setText(_translate("MainWindow", "Tare")) self.pushTareZrusit2_2.setText(_translate("MainWindow", "Vynulovat Tare")) self.pushNula1.setText(_translate("MainWindow", "Vynulovat")) self.pushNulaZrusit1.setText(_translate("MainWindow", "Zrušit 0")) def nuloveMereni(self): self.probihaNuloveMereni = True self.multiple_measure() self.probihaNuloveMereni = False self.lineEdit_nulova1.setText(str(self.nuloveHodnoty[0]) + " č.1") self.lineEdit_nulova2.setText(str(self.nuloveHodnoty[1]) + " č.2") def editKoef1(self): if self.radio1.isChecked() == True: try: self.koeficienty["uzavreny"][0] = float(self.lineEdit_koef1.text()) except ValueError: print("not a float") if self.radio2.isChecked() == True: try: self.koeficienty["otevreny"][0] = float(self.lineEdit_koef1.text()) except ValueError: print("not a float") def editKoef2(self): if self.radio1.isChecked() == True: try: self.koeficienty["uzavreny"][1] = float(self.lineEdit_koef2.text()) except ValueError: print("not a float") if self.radio2.isChecked() == True: try: self.koeficienty["otevreny"][1] = float(self.lineEdit_koef2.text()) except ValueError: print("not a float") def btnstate(self, b): if b.text() == "Otevřený": if b.isChecked() == True: self.lineEdit_koef1.setText(str(self.koeficienty['otevreny'][0])) self.lineEdit_koef2.setText(str(self.koeficienty['otevreny'][1])) if b.text() == "Uzavřený": if b.isChecked() == True: self.lineEdit_koef1.setText(str(self.koeficienty['uzavreny'][0])) self.lineEdit_koef2.setText(str(self.koeficienty['uzavreny'][1])) def nula1(self): # {"id":27,"method":"call","params":{"path":"measval/cmdSetZeroGros","args":[]}} self.send_command(1, "zero") def nula2(self): self.send_command(2, "zero") def tare2(self): self.send_command(2, "tare") def tare1(self): self.send_command(1, "tare") def nula1_zrusit(self): self.send_command(1, "clear_zero") def nula2_zrusit(self): self.send_command(2, "clear_zero") def tare1_zrusit(self): self.send_command(1, "clear_tare") def tare2_zrusit(self): self.send_command(2, "clear_tare") def multiple_measure(self): critical_fail = False koeficienty = np.array([0, 0]) if self.radio1.isChecked() == True: koeficienty[0] = self.koeficienty["uzavreny"][0] koeficienty[1] = self.koeficienty["uzavreny"][1] if self.radio2.isChecked() == True: koeficienty[0] = self.koeficienty["otevreny"][0] koeficienty[1] = self.koeficienty["otevreny"][1] print("multiple") self.buttonMereni.setEnabled(False) self.buttonMereniDynamicke.setEnabled(False) self.graphicsView.plotItem.clear() if self.probihaNuloveMereni: total_measurements = 1 period_time = 1 else: total_measurements = int(self.lineEdit_pocet_2.text()) period_time = int(self.lineEdit_interval.text()) dyn_value = np.array([]) dyn_prumer1 = np.array([]) dyn_prumer2 = np.array([]) dyn_smodch1 = np.array([]) dyn_smodch2 = np.array([]) self.text_dynhodnoty.setText("") QtGui.QGuiApplication.processEvents() for measurement in range(total_measurements): self.text_hodnoty1.setText("") self.text_hodnoty2.setText("") self.rozdil.setText("0") self.prumer1.setText("0") self.prumer2.setText("0") self.smodch1.setText("0") self.smodch2.setText("0") json_trigger_command = """ {"id":1,"method":"call","params":{"path":"measval/cmdTriggerCapturedValue1","args":[]}} """ json_get_command = """ {"method":"fetch_all","params":{"path":"measval/values/capturedValue1"}} """ json_trigger = json.loads(json_trigger_command) json_get = json.loads(json_get_command) expected_message = """"path":"measval/values/capturedValue1""""" sensor1_values = [None] * 1 measured_values = np.zeros((1,)) try: ws = create_connection("ws://169.254.178.232:8081") except Exception as ex: print(ex) critical_fail = True print("Start mereni 1:" + str(datetime.datetime.now())) if not critical_fail: for mereni in range(1): try: ws.send(json.dumps(json_trigger)) except Exception as ex: print(ex) try: result = ws.recv() except Exception as ex: print(ex) time.sleep(.1) # TODO check result try: ws.send(json.dumps(json_get)) clipx_message = "" while expected_message not in clipx_message: try: clipx_message = ws.recv() print(clipx_message) except Exception as ex: print(ex) sensor1_values[mereni] = json.loads(clipx_message) except Exception as ex: print(ex) self.text_hodnoty1.append("{:.4E}".format(Decimal(sensor1_values[mereni]["params"]["value"]/koeficienty[0]))) QtGui.QGuiApplication.processEvents() # TODO check jestli jde o nulové měření measured_values[mereni] = sensor1_values[mereni]["params"]["value"]/koeficienty[0] if self.probihaNuloveMereni: self.nuloveHodnoty[0] = measured_values[mereni] try: ws.close() except Exception as ex: print(ex) print("Stop mereni 1:" + str(datetime.datetime.now())) dyn_prumer1 = np.append(dyn_prumer1, measured_values.mean()) dyn_smodch1 = np.append(dyn_smodch1, measured_values.std()) self.prumer1.setText("{:.4E}".format(Decimal(measured_values.mean()))) self.smodch1.setText("{:.4E}".format(Decimal(measured_values.std()))) QtGui.QGuiApplication.processEvents() sensor2_values = [None] * 1 measured2_values = np.zeros((1, 1)) try: ws2 = create_connection("ws://169.254.178.218:8081") except Exception as ex: print(ex) critical_fail = True self.text_hodnoty2.setText("") print("Start mereni 2:" + str(datetime.datetime.now())) if not critical_fail: for mereni in range(1): try: ws2.send(json.dumps(json_trigger)) result = ws2.recv() time.sleep(.1) # TODO check result ws2.send(json.dumps(json_get)) clipx_message = "" while not expected_message in clipx_message: clipx_message = ws2.recv() sensor2_values[mereni] = json.loads(clipx_message) except Exception as ex: print(ex) # print(sensor1_values[mereni]["params"]["value"]) self.text_hodnoty2.append("{:.4E}".format(Decimal(sensor2_values[mereni]["params"]["value"]/koeficienty[1]))) QtGui.QGuiApplication.processEvents() measured2_values[mereni] = sensor2_values[mereni]["params"]["value"]/koeficienty[1] if self.probihaNuloveMereni: self.nuloveHodnoty[1] = measured2_values[mereni] try: ws2.close() except Exception as ex: print(ex) print("Stop mereni 2:" + str(datetime.datetime.now())) dyn_prumer2 = np.append(dyn_prumer2, measured2_values.mean()) dyn_smodch2 = np.append(dyn_smodch2, measured2_values.std()) self.prumer2.setText("{:.4E}".format(Decimal(measured2_values.mean()))) self.smodch2.setText("{:.4E}".format(Decimal(measured2_values.std()))) dyn_value = np.append(dyn_value, measured_values.mean() - measured2_values.mean()) self.text_dynhodnoty.append("{:.4E}".format(Decimal(dyn_value[-1]))) self.rozdil.setText("{:.4E}".format(Decimal(dyn_value[measurement]))) if len(dyn_value) > 1: try: self.graphicsView.plot(dyn_value, pen=pq.mkPen('b', width=3, style=QtCore.Qt.SolidLine, color=(200, 200, 255))) self.graphicsView.getPlotItem().showGrid(x=True, y=True, alpha=1) QtGui.QGuiApplication.processEvents() except Exception as ex: print(ex) start_pause = (datetime.datetime.now()) time_difference = start_pause - start_pause time_difference_seconds = time_difference.total_seconds() while time_difference_seconds < period_time: time.sleep(0.05) QtGui.QGuiApplication.processEvents() time_difference = datetime.datetime.now() - start_pause time_difference_seconds = time_difference.total_seconds() QtGui.QGuiApplication.processEvents() if self.probihaNuloveMereni: pass else: output = np.asarray([dyn_value, dyn_value, dyn_value, dyn_value, dyn_value]) try: np.savetxt(self.lineEdit.text(), output.transpose(), delimiter=",", header="diff,smodch1,smodch2,prumer1,prumer2") except Exception as ex: print(ex) self.lineEdit.setText(datetime.datetime.now().strftime("Data_" + "%Y-%m-%d_%H%M%S" + ".csv")) QtGui.QGuiApplication.processEvents() self.buttonMereni.setEnabled(True) self.buttonMereniDynamicke.setEnabled(True) def one_measure(self): critical_fail = False koeficienty = np.array([0, 0]) if self.radio1.isChecked() == True: koeficienty[0] = self.koeficienty["uzavreny"][0] koeficienty[1] = self.koeficienty["uzavreny"][1] if self.radio2.isChecked() == True: koeficienty[0] = self.koeficienty["otevreny"][0] koeficienty[1] = self.koeficienty["otevreny"][1] self.buttonMereni.setEnabled(False) self.buttonMereniDynamicke.setEnabled(False) QtGui.QGuiApplication.processEvents() self.text_hodnoty1.setText("") self.text_hodnoty2.setText("") self.rozdil.setText("0") self.prumer1.setText("") self.prumer2.setText("") self.rozdil.setText("") json_trigger_command = """ {"id":1,"method":"call","params":{"path":"measval/cmdTriggerCapturedValue1","args":[]}} """ json_get_command = """ {"method":"fetch_all","params":{"path":"measval/adcBinVal32"}} """ json_trigger = json.loads(json_trigger_command) json_get = json.loads(json_get_command) expected_message = """"path":"measval/values/capturedValue1""""" sensor1_values = [None] * 10 measured_values = np.zeros((10,)) critical_fail = False try: ws = create_connection("ws://169.254.178.232:8081") except Exception as ex: print(ex) critical_fail = True if not critical_fail: for mereni in range(10): ws.send(json.dumps(json_trigger)) result = ws.recv() time.sleep(.1) # TODO check result ws.send(json.dumps(json_get)) clipx_message = "" while expected_message not in clipx_message: clipx_message = ws.recv() sensor1_values[mereni] = json.loads(clipx_message) self.text_hodnoty1.append(str(sensor1_values[mereni]["params"]["value"]/koeficienty[0])) QtGui.QGuiApplication.processEvents() measured_values[mereni] = sensor1_values[mereni]["params"]["value"]/koeficienty[0] ws.close() self.prumer1.setText("{:.4E}".format(Decimal(measured_values.mean()))) self.smodch1.setText("{:.4E}".format(Decimal(measured_values.std()))) QtGui.QGuiApplication.processEvents() sensor2_values = [None] * 10 measured2_values = np.zeros((10, 1)) try: ws2 = create_connection("ws://169.254.178.218:8081") except Exception as ex: print(ex) critical_fail = True self.text_hodnoty2.setText("") if not critical_fail: for mereni in range(10): ws2.send(json.dumps(json_trigger)) result = ws2.recv() time.sleep(.1) print(mereni) # TODO check result ws2.send(json.dumps(json_get)) clipx_message = "" while not expected_message in clipx_message: clipx_message = ws2.recv() sensor2_values[mereni] = json.loads(clipx_message) # print(sensor1_values[mereni]["params"]["value"]) self.text_hodnoty2.append("{:.4E}".format(Decimal(sensor2_values[mereni]["params"]["value"]/koeficienty[1]))) QtGui.QGuiApplication.processEvents() measured2_values[mereni] = sensor2_values[mereni]["params"]["value"]/koeficienty[1] ws2.close() self.prumer2.setText("{:.4E}".format(Decimal(measured2_values.mean()))) self.smodch2.setText("{:.4E}".format(Decimal(measured2_values.std()))) rozdil = measured_values.mean() - measured2_values.mean() self.rozdil.setText("{:.4E}".format(Decimal(rozdil))) self.buttonMereni.setEnabled(True) self.buttonMereniDynamicke.setEnabled(True) QtGui.QGuiApplication.processEvents() def send_command(self, device, command): critical_fail = False if device == 1: connection_string = "ws://169.254.178.218:8081" else: connection_string = "ws://169.254.178.232:8081" if command == "tare": json_command = """ {"id":2,"method":"call","params":{"path":"measval/cmdSetZeroNet","args":[]}}""" elif command == "clear_tare": json_command = """ {"id":31,"method":"call","params":{"path":"measval/cmdClearOffsetNet","args":[]}}""" elif command == "zero": json_command = """ {"id":32,"method":"call","params":{"path":"measval/cmdSetZeroGros","args":[]}}""" # json_command = """ # {"id":68,"method":"set","params":{"path":"measval/scaling/zeroTargetGros","value":150}}""" elif command == "clear_zero": json_command = """ {"id":33,"method":"call","params":{"path":"measval/cmdClearOffsetGros","args":[]}}""" else: print("ERROR") json_command = """""" try: ws = create_connection(connection_string) except Exception as ex: print(ex) critical_fail = True if not critical_fail: json_tare = json.loads(json_command) ws.send(json.dumps(json_tare)) result = ws.recv() print(result) ws.close()
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_MainWindow(object): accuracy_vals = [] recording_vals = np.zeros([ 960 * 10 * 10, ]) microphone_recorder = None train_thread = None recorder_thread = None ser_inference_model = SER_Inference_Model() ser_online_model = SER_Online_Model() label_7_line_nr = 0 play_th = None def setupUi(self, MainWindow): MainWindow.setObjectName("MainWindow") self.centralwidget = QtWidgets.QWidget(MainWindow) self.centralwidget.setObjectName("centralwidget") MainWindow.resize(1300, 900) qr = MainWindow.frameGeometry() cp = QDesktopWidget().availableGeometry().center() qr.moveCenter(cp) MainWindow.move(qr.topLeft()) self.gridLayout = QtWidgets.QGridLayout(self.centralwidget) self.gridLayout.setObjectName("gridLayout") self.gridLayout_2 = QtWidgets.QGridLayout() self.gridLayout_2.setSpacing(0) self.gridLayout_2.setObjectName("gridLayout_2") self.verticalLayout = QtWidgets.QVBoxLayout() self.verticalLayout.setContentsMargins(10, 10, 10, 10) self.verticalLayout.setSpacing(2) self.verticalLayout.setObjectName("verticalLayout") self.groupBox_4 = QtWidgets.QGroupBox(self.centralwidget) self.groupBox_4.setMinimumSize(QtCore.QSize(670, 860)) self.groupBox_4.setObjectName("groupBox_4") self.label_2 = QtWidgets.QLabel(self.centralwidget) self.label_2.setGeometry(QtCore.QRect(40, 400, 400, 20)) self.label_2.setMaximumSize(QtCore.QSize(16777215, 20)) self.label_2.setObjectName("label_2") self.progressBar = QtWidgets.QProgressBar(self.centralwidget) self.progressBar.setGeometry(QtCore.QRect(40, 400, 500, 40)) self.progressBar.setMinimumSize(QtCore.QSize(500, 40)) self.progressBar.setMaximumSize(QtCore.QSize(16777215, 16777215)) self.progressBar.setStyleSheet(COMPLETED_STYLE_ANGRY) self.progressBar.setProperty("value", 0) self.progressBar.setObjectName("progressBar") self.label_3 = QtWidgets.QLabel(self.centralwidget) self.label_3.setGeometry(QtCore.QRect(40, 460, 400, 20)) self.label_3.setMaximumSize(QtCore.QSize(16777215, 20)) self.label_3.setObjectName("label_3") self.progressBar_2 = QtWidgets.QProgressBar(self.centralwidget) self.progressBar_2.setGeometry(QtCore.QRect(40, 460, 500, 40)) self.progressBar_2.setMinimumSize(QtCore.QSize(500, 40)) self.progressBar_2.setMaximumSize(QtCore.QSize(16777215, 16777215)) self.progressBar_2.setStyleSheet(COMPLETED_STYLE_HAPPY) self.progressBar_2.setProperty("value", 0) self.progressBar_2.setObjectName("progressBar_2") self.label_4 = QtWidgets.QLabel(self.centralwidget) self.label_4.setGeometry(QtCore.QRect(40, 520, 400, 20)) self.label_4.setMaximumSize(QtCore.QSize(16777215, 20)) self.label_4.setObjectName("label_4") self.progressBar_3 = QtWidgets.QProgressBar(self.centralwidget) self.progressBar_3.setGeometry(QtCore.QRect(40, 520, 500, 40)) self.progressBar_3.setMinimumSize(QtCore.QSize(500, 40)) self.progressBar_3.setMaximumSize(QtCore.QSize(16777215, 16777215)) self.progressBar_3.setStyleSheet(COMPLETED_STYLE_SAD) self.progressBar_3.setProperty("value", 0) self.progressBar_3.setObjectName("progressBar_3") self.label_5 = QtWidgets.QLabel(self.centralwidget) self.label_5.setGeometry(QtCore.QRect(40, 570, 400, 20)) self.label_5.setMaximumSize(QtCore.QSize(16777215, 20)) self.label_5.setObjectName("label_5") self.progressBar_4 = QtWidgets.QProgressBar(self.centralwidget) self.progressBar_4.setGeometry(QtCore.QRect(40, 560, 500, 40)) self.progressBar_4.setMinimumSize(QtCore.QSize(500, 40)) self.progressBar_4.setMaximumSize(QtCore.QSize(16777215, 16777215)) self.progressBar_4.setProperty("value", 0) self.progressBar_4.setObjectName("progressBar_4") self.graphicsView = PlotWidget(self.groupBox_4) self.graphicsView.setGeometry(QtCore.QRect(10, 30, 650, 400)) self.graphicsView.setObjectName("graphicsView") self.verticalLayout.addWidget(self.groupBox_4) self.gridLayout_2.addLayout(self.verticalLayout, 0, 0, 1, 1) self.gridLayout.addLayout(self.gridLayout_2, 0, 3, 1, 1) self.verticalLayout_2 = QtWidgets.QVBoxLayout() self.verticalLayout_2.setSizeConstraint( QtWidgets.QLayout.SetDefaultConstraint) self.verticalLayout_2.setContentsMargins(10, 10, 10, 10) self.verticalLayout_2.setSpacing(2) self.verticalLayout_2.setObjectName("verticalLayout_2") self.groupBox_3 = QtWidgets.QGroupBox(self.centralwidget) self.groupBox_3.setMinimumSize(QtCore.QSize(603, 110)) self.groupBox_3.setObjectName("groupBox_3") self.comboBox_2 = QtWidgets.QComboBox(self.groupBox_3) self.comboBox_2.setGeometry(QtCore.QRect(105, 72, 441, 30)) self.comboBox_2.setObjectName("comboBox_2") self.lineEdit_2 = QtWidgets.QLineEdit(self.groupBox_3) self.lineEdit_2.setGeometry(QtCore.QRect(105, 35, 441, 30)) self.lineEdit_2.setObjectName("lineEdit_2") self.label_9 = QtWidgets.QLabel(self.groupBox_3) self.label_9.setGeometry(QtCore.QRect(10, 37, 90, 30)) self.label_9.setObjectName("label_9") self.label_10 = QtWidgets.QLabel(self.groupBox_3) self.label_10.setGeometry(QtCore.QRect(60, 71, 40, 30)) self.label_10.setObjectName("label_10") self.pushButtonInfPlay = QtWidgets.QPushButton(self.groupBox_3) self.pushButtonInfPlay.setGeometry(QtCore.QRect(550, 72, 48, 30)) self.pushButtonInfPlay.setObjectName("pushButtonInfPlay") self.groupBox_2 = QtWidgets.QGroupBox(self.centralwidget) self.groupBox_2.setMinimumSize(QtCore.QSize(600, 280)) self.groupBox_2.setObjectName("groupBox_2") self.label_18 = QtWidgets.QLabel(self.groupBox_2) self.label_18.setGeometry(QtCore.QRect(10, 75, 205, 25)) self.label_18.setObjectName("label_18") self.radioButton_3 = QtWidgets.QRadioButton(self.groupBox_2) self.radioButton_3.setGeometry(QtCore.QRect(215, 77, 165, 25)) self.radioButton_3.setChecked(True) self.radioButton_3.setAutoRepeat(False) self.radioButton_3.setObjectName("radioButton_3") self.radioButton_4 = QtWidgets.QRadioButton(self.groupBox_2) self.radioButton_4.setGeometry(QtCore.QRect(325, 77, 120, 25)) self.radioButton_4.setObjectName("radioButton_4") self.label_8 = QtWidgets.QLabel(self.groupBox_2) self.label_8.setGeometry(QtCore.QRect(10, 243, 94, 25)) self.label_8.setObjectName("label_8") self.lineEdit = QtWidgets.QLineEdit(self.groupBox_2) self.lineEdit.setGeometry(QtCore.QRect(75, 240, 70, 30)) self.lineEdit.setObjectName("lineEdit") self.label_17 = QtWidgets.QLabel(self.groupBox_2) self.label_17.setGeometry(QtCore.QRect(460, 243, 110, 30)) self.label_17.setObjectName("label_17") self.label_19 = QtWidgets.QLabel(self.groupBox_2) self.label_19.setGeometry(QtCore.QRect(570, 243, 30, 30)) self.label_19.setObjectName("label_19") self.comboBox = QtWidgets.QComboBox(self.groupBox_2) self.comboBox.setGeometry(QtCore.QRect(125, 38, 460, 30)) self.comboBox.setMinimumSize(QtCore.QSize(200, 0)) self.comboBox.setFocusPolicy(QtCore.Qt.WheelFocus) self.comboBox.setMaxVisibleItems(10) self.comboBox.setIconSize(QtCore.QSize(16, 16)) self.comboBox.setObjectName("comboBox") self.comboBox.addItem("") self.comboBox.addItem("") self.comboBox.addItem("") self.comboBox.addItem("") self.comboBox.addItem("") self.comboBox.addItem("") self.comboBox.addItem("") self.comboBox.addItem("") self.comboBox.addItem("") self.label = QtWidgets.QLabel(self.groupBox_2) self.label.setGeometry(QtCore.QRect(10, 36, 105, 30)) self.label.setObjectName("label") self.label_11 = QtWidgets.QLabel(self.groupBox_2) self.label_11.setGeometry(QtCore.QRect(10, 100, 130, 30)) self.label_11.setObjectName("label_11") self.horizontalSlider = QtWidgets.QSlider(self.groupBox_2) self.horizontalSlider.setGeometry(QtCore.QRect(138, 109, 430, 17)) self.horizontalSlider.setMaximum(10) self.horizontalSlider.setOrientation(QtCore.Qt.Horizontal) self.horizontalSlider.setObjectName("horizontalSlider") self.label_12 = QtWidgets.QLabel(self.groupBox_2) self.label_12.setGeometry(QtCore.QRect(570, 102, 31, 30)) self.label_12.setObjectName("label_12") self.label_15 = QtWidgets.QLabel(self.groupBox_2) self.label_15.setGeometry(QtCore.QRect(10, 132, 121, 25)) self.label_15.setObjectName("label_15") self.horizontalSlider_2 = QtWidgets.QSlider(self.groupBox_2) self.horizontalSlider_2.setGeometry(QtCore.QRect(138, 137, 430, 17)) self.horizontalSlider_2.setMaximum(10) self.horizontalSlider_2.setOrientation(QtCore.Qt.Horizontal) self.horizontalSlider_2.setObjectName("horizontalSlider_2") self.label_16 = QtWidgets.QLabel(self.groupBox_2) self.label_16.setGeometry(QtCore.QRect(570, 134, 31, 25)) self.label_16.setObjectName("label_15") self.ooda_check_box = QtWidgets.QCheckBox(self.groupBox_2) self.ooda_check_box.setGeometry(QtCore.QRect(15, 160, 120, 31)) self.ooda_check_box.setObjectName("checkBoxOODA") self.horizontalSlider_ooda = QtWidgets.QSlider(self.groupBox_2) self.horizontalSlider_ooda.setGeometry(QtCore.QRect(138, 168, 430, 17)) self.horizontalSlider_ooda.setMaximum(9) self.horizontalSlider_ooda.setMinimum(1) self.horizontalSlider_ooda.setOrientation(QtCore.Qt.Horizontal) self.horizontalSlider_ooda.setObjectName("horizontalSlider_ooda") self.label_ooda = QtWidgets.QLabel(self.groupBox_2) self.label_ooda.setGeometry(QtCore.QRect(570, 164, 31, 25)) self.label_ooda.setObjectName("label_ooda") self.label_13 = QtWidgets.QLabel(self.groupBox_2) self.label_13.setGeometry(QtCore.QRect(10, 197, 121, 25)) self.label_13.setObjectName("label_13") self.doubleSpinBox = QtWidgets.QDoubleSpinBox(self.groupBox_2) self.doubleSpinBox.setGeometry(QtCore.QRect(121, 197, 100, 31)) self.doubleSpinBox.setDecimals(5) self.doubleSpinBox.setSingleStep(1e-05) self.doubleSpinBox.setObjectName("doubleSpinBox") self.verticalLayout_2.addWidget(self.groupBox_2) self.groupBox = QtWidgets.QGroupBox(self.centralwidget) self.groupBox.setMinimumSize(QtCore.QSize(30, 70)) self.groupBox.setObjectName("groupBox") self.radioButton = QtWidgets.QRadioButton(self.groupBox) self.radioButton.setGeometry(QtCore.QRect(10, 30, 60, 30)) self.radioButton.setChecked(True) self.radioButton.setObjectName("radioButton") self.radioButton_2 = QtWidgets.QRadioButton(self.groupBox) self.radioButton_2.setGeometry(QtCore.QRect(100, 30, 226, 30)) self.radioButton_2.setObjectName("radioButton_2") self.pushButton = QtWidgets.QPushButton(self.groupBox) self.pushButton.setGeometry(QtCore.QRect(250, 30, 100, 30)) self.pushButton.setMaximumSize(QtCore.QSize(100, 16777215)) self.pushButton.setIconSize(QtCore.QSize(16, 16)) self.pushButton.setObjectName("pushButton") self.pushButtonStop = QtWidgets.QPushButton(self.groupBox) self.pushButtonStop.setGeometry(QtCore.QRect(380, 30, 100, 30)) self.pushButtonStop.setMaximumSize(QtCore.QSize(100, 16777215)) self.pushButtonStop.setIconSize(QtCore.QSize(16, 16)) self.pushButtonStop.setObjectName("pushButtonStop") self.verticalLayout_2.addWidget(self.groupBox) self.groupBox_5 = QtWidgets.QGroupBox(self.centralwidget) self.groupBox_5.setMinimumSize(QtCore.QSize(30, 155)) self.groupBox_5.setObjectName("groupBox_5") self.verticalLayout_2.addWidget(self.groupBox_3) self.verticalLayout_2.addWidget(self.groupBox_5) self.graphicsViewRec = PlotWidget(self.groupBox_5) self.graphicsViewRec.setGeometry(QtCore.QRect(115, 37, 480, 110)) self.graphicsViewRec.setObjectName("graphicsViewRec") self.graphicsViewRec.setYRange(-20000, 20000, padding=0) self.graphicsViewRec.setXRange(0, 10 * 125 * 94, padding=0) self.pushButtonRecord = QtWidgets.QPushButton(self.groupBox_5) self.pushButtonRecord.setGeometry(QtCore.QRect(10, 37, 100, 30)) self.pushButtonRecord.setMaximumSize(QtCore.QSize(100, 16777215)) self.pushButtonRecord.setIconSize(QtCore.QSize(16, 16)) self.pushButtonRecord.setObjectName("pushButtonRecord") self.pushButtonStopRecord = QtWidgets.QPushButton(self.groupBox_5) self.pushButtonStopRecord.setGeometry(QtCore.QRect(10, 77, 100, 30)) self.pushButtonStopRecord.setMaximumSize(QtCore.QSize(100, 16777215)) self.pushButtonStopRecord.setIconSize(QtCore.QSize(16, 16)) self.pushButtonStopRecord.setObjectName("pushButtonStopRecord") self.pushButtonPlay = QtWidgets.QPushButton(self.groupBox_5) self.pushButtonPlay.setGeometry(QtCore.QRect(10, 117, 100, 30)) self.pushButtonPlay.setMaximumSize(QtCore.QSize(100, 16777215)) self.pushButtonPlay.setIconSize(QtCore.QSize(16, 16)) self.pushButtonPlay.setObjectName("pushButtonPlay") self.tabs = QtWidgets.QTabWidget(self.groupBox_4) self.tabs.setGeometry(QtCore.QRect(10, 440, 600, 400)) self.tabs.setMinimumHeight(400) self.tabs.setMinimumWidth(600) self.tabs.setIconSize(QtCore.QSize(30, 300)) self.tableWidget = QtWidgets.QTableWidget() self.tableWidget.setRowCount(5) self.tableWidget.setColumnCount(5) self.tableWidget.setHorizontalHeaderLabels( ["Angry", "Happy", "Sad", "Normal", " Total "]) # self.tableWidget.setVerticalHeaderLabels( ["Angry", "Happy", "Sad", "Normal", "Total"]) # self.tableWidget.setItem(0, 0, QtWidgets.QTableWidgetItem("0")) self.tableWidget.setItem(0, 1, QtWidgets.QTableWidgetItem("0")) self.tableWidget.setItem(0, 2, QtWidgets.QTableWidgetItem("0")) self.tableWidget.setItem(0, 3, QtWidgets.QTableWidgetItem("0")) self.tableWidget.setItem(0, 4, QtWidgets.QTableWidgetItem("0")) self.tableWidget.setItem(1, 0, QtWidgets.QTableWidgetItem("0")) self.tableWidget.setItem(1, 1, QtWidgets.QTableWidgetItem("0")) self.tableWidget.setItem(1, 2, QtWidgets.QTableWidgetItem("0")) self.tableWidget.setItem(1, 3, QtWidgets.QTableWidgetItem("0")) self.tableWidget.setItem(1, 4, QtWidgets.QTableWidgetItem("0")) self.tableWidget.setItem(2, 0, QtWidgets.QTableWidgetItem("0")) self.tableWidget.setItem(2, 1, QtWidgets.QTableWidgetItem("0")) self.tableWidget.setItem(2, 2, QtWidgets.QTableWidgetItem("0")) self.tableWidget.setItem(2, 3, QtWidgets.QTableWidgetItem("0")) self.tableWidget.setItem(2, 4, QtWidgets.QTableWidgetItem("0")) self.tableWidget.setItem(3, 0, QtWidgets.QTableWidgetItem("0")) self.tableWidget.setItem(3, 1, QtWidgets.QTableWidgetItem("0")) self.tableWidget.setItem(3, 2, QtWidgets.QTableWidgetItem("0")) self.tableWidget.setItem(3, 3, QtWidgets.QTableWidgetItem("0")) self.tableWidget.setItem(3, 4, QtWidgets.QTableWidgetItem("0")) self.tableWidget.setItem(4, 0, QtWidgets.QTableWidgetItem("0")) self.tableWidget.setItem(4, 1, QtWidgets.QTableWidgetItem("0")) self.tableWidget.setItem(4, 2, QtWidgets.QTableWidgetItem("0")) self.tableWidget.setItem(4, 3, QtWidgets.QTableWidgetItem("0")) self.tableWidget.setItem(4, 4, QtWidgets.QTableWidgetItem("0")) self.tableWidget.item(4, 4).setBackground(QtGui.QColor(102, 140, 255)) self.tableWidget.item(3, 3).setBackground(QtGui.QColor(125, 125, 125)) self.tableWidget.item(2, 2).setBackground(QtGui.QColor(125, 125, 125)) self.tableWidget.item(1, 1).setBackground(QtGui.QColor(125, 125, 125)) self.tableWidget.item(0, 0).setBackground(QtGui.QColor(125, 125, 125)) for i in range(5): for j in range(5): self.tableWidget.item(i, j).setFlags(QtCore.Qt.ItemIsEnabled) self.tabs.resize(650, 425) self.label_7 = QtWidgets.QLabel(self.groupBox_4) self.label_7.setMinimumSize(QtCore.QSize(600, 425)) self.label_7.setCursor(QtGui.QCursor(QtCore.Qt.IBeamCursor)) self.label_7.setStyleSheet("font: 9pt \"Sans Serif\";\n" "background-color: rgb(0, 0, 0);") self.label_7.setFrameShadow(QtWidgets.QFrame.Raised) self.label_7.setLineWidth(4) self.label_7.setTextFormat(QtCore.Qt.AutoText) self.label_7.setScaledContents(True) self.label_7.setAlignment(QtCore.Qt.AlignLeading | QtCore.Qt.AlignLeft | QtCore.Qt.AlignTop) self.label_7.setWordWrap(True) self.label_7.setIndent(0) self.label_7.setOpenExternalLinks(False) self.label_7.setTextInteractionFlags(QtCore.Qt.LinksAccessibleByMouse | QtCore.Qt.TextSelectableByMouse) self.label_7.setObjectName("label_7") self.verticalLayoutTable = QtWidgets.QVBoxLayout() self.verticalLayoutTable.setSizeConstraint( QtWidgets.QLayout.SetDefaultConstraint) self.verticalLayoutTable.setContentsMargins(33, 95, 33, 70) self.verticalLayoutTable.setSpacing(9) self.verticalLayoutTable.setObjectName("verticalLayoutTable") self.label_total = QtWidgets.QLabel(self.groupBox_4) self.label_total.setObjectName("label_nr") self.tab2 = QtWidgets.QWidget() self.tabs.addTab(self.label_7, "Logs") self.tabs.addTab(self.tab2, "Confusion matrix") self.tab2.layout = self.verticalLayoutTable self.tab2.layout.addWidget(self.tableWidget) self.tab2.layout.addWidget(self.label_total) self.tab2.setLayout(self.tab2.layout) self.verticalLayout_2.addWidget(self.label_2) self.verticalLayout_2.addWidget(self.progressBar) self.verticalLayout_2.addWidget(self.label_3) self.verticalLayout_2.addWidget(self.progressBar_2) self.verticalLayout_2.addWidget(self.label_4) self.verticalLayout_2.addWidget(self.progressBar_3) self.verticalLayout_2.addWidget(self.label_5) self.verticalLayout_2.addWidget(self.progressBar_4) self.gridLayout.addLayout(self.verticalLayout_2, 0, 0, 1, 1) MainWindow.setCentralWidget(self.centralwidget) self.actionReset = QtWidgets.QAction(MainWindow) self.actionReset.setObjectName("actionReset") self.retranslateUi(MainWindow) self.lineEdit_2.setText("Inference") self.lineEdit.setText("10") self.horizontalSlider_2.setValue(5) self.change_label_16() self.horizontalSlider.setValue(8) self.change_label_12() self.horizontalSlider_ooda.setValue(8) self.change_label_ooda() self.doubleSpinBox.setValue(0.0001) QtCore.QMetaObject.connectSlotsByName(MainWindow) self.fill_file() self.ooda_check_box.setChecked(False) self.horizontalSlider_ooda.setStyleSheet(SLYDER_DISABLED) self.horizontalSlider_ooda.setEnabled(False) self.pushButton.clicked.connect(lambda: self.on_start_button_clicked()) self.pushButtonStop.clicked.connect( lambda: self.on_buttonStop_clicked()) self.pushButtonRecord.clicked.connect( lambda: self.on_buttonRecord_clicked()) self.pushButtonPlay.clicked.connect(lambda: self.play_recording()) self.pushButtonInfPlay.clicked.connect( lambda: self.play_recording(self.comboBox_2.currentText())) self.pushButtonStopRecord.clicked.connect( lambda: self.on_buttonStopRecord_clicked()) self.lineEdit_2.returnPressed.connect(lambda: self.fill_file()) self.radioButton_2.toggled.connect(lambda: self.init_inference()) self.horizontalSlider.valueChanged.connect( lambda: self.change_label_12()) self.horizontalSlider_2.valueChanged.connect( lambda: self.change_label_16()) self.horizontalSlider_ooda.valueChanged.connect( lambda: self.change_label_ooda()) self.ooda_check_box.stateChanged.connect( lambda: self.change_horizontal_ooda()) self.print_accuracy_graph(0) def refresh_label_7(self): self.label_7_line_nr = 0 _translate = QtCore.QCoreApplication.translate self.label_7.setText( _translate( "MainWindow", "<html><head/><body><p><span style=\" font-weight:600; color:#55ff7f;\"> ...</span></p></body></html>" )) def refresh_graphics_view(self): self.graphicsView.clear() self.accuracy_vals = [] self.print_accuracy_graph(0) def refresh_rec_graphics_view(self): self.recording_vals = np.zeros([ 960 * 10 * 10, ]) def retranslateUi(self, MainWindow): _translate = QtCore.QCoreApplication.translate MainWindow.setWindowTitle( _translate("MainWindow", "Speech Emotion Recognizer")) self.groupBox_4.setTitle(_translate("MainWindow", "Statistics")) self.groupBox_5.setTitle(_translate("MainWindow", "Recording")) self.label_2.setText(_translate("MainWindow", "Angry")) self.label_3.setText(_translate("MainWindow", "Happy")) self.label_4.setText(_translate("MainWindow", "Sad")) self.label_5.setText(_translate("MainWindow", "Neutral")) self.groupBox_3.setTitle( _translate("MainWindow", "Pick a file to classify")) self.label_9.setText(_translate("MainWindow", "Folder path:")) self.label_10.setText(_translate("MainWindow", "File:")) self.pushButtonInfPlay.setText(_translate("MainWindow", "Play")) self.groupBox_2.setTitle(_translate("MainWindow", "Model settings")) self.radioButton_3.setText(_translate("MainWindow", "End-to-end")) self.radioButton_4.setText(_translate("MainWindow", "Hand-Crafted")) self.label_8.setText(_translate("MainWindow", "Epochs:")) self.label_18.setText( _translate("MainWindow", "Feature extraction tehnioque:")) self.label_11.setText(_translate("MainWindow", "Train / Test Ratio:")) self.label_12.setText(_translate("MainWindow", "1")) self.label_13.setText(_translate("MainWindow", "Learning Rate:")) self.label_15.setText(_translate("MainWindow", "Dropout Rate:")) self.label_16.setText(_translate("MainWindow", "1")) self.label_17.setText(_translate("MainWindow", "Current epoch:")) self.label_19.setText(_translate("MainWindow", "0")) self.label_ooda.setText(_translate("MainWindow", "0")) self.label_total.setText( _translate("MainWindow", "Numarul total de intrari = 0")) self.comboBox.setItemText(0, _translate("MainWindow", "EMO-DB")) self.comboBox.setItemText(1, _translate("MainWindow", "SAVEE")) self.comboBox.setItemText(2, _translate("MainWindow", "RAVDESS")) self.comboBox.setItemText(3, _translate("MainWindow", "ENTERFACE")) self.comboBox.setItemText(4, _translate("MainWindow", "EMOVO")) self.comboBox.setItemText(5, _translate("MainWindow", "MAV")) self.comboBox.setItemText(6, _translate("MainWindow", "MELD")) self.comboBox.setItemText(7, _translate("MainWindow", "JL")) self.comboBox.setItemText(7, _translate("MainWindow", "INRP")) self.comboBox.setItemText(8, _translate("MainWindow", "MULTIPLE")) self.ooda_check_box.setText(_translate("MainWindow", "OODA loop")) self.label.setText(_translate("MainWindow", "Select dataset:")) self.groupBox.setTitle(_translate("MainWindow", "Actions")) self.radioButton.setToolTip( _translate( "MainWindow", "<html><head/><body><p align=\"center\"><br/></p></body></html>" )) self.radioButton.setText(_translate("MainWindow", "Train")) self.radioButton_2.setText(_translate("MainWindow", "Inference")) self.pushButton.setText(_translate("MainWindow", "Start")) self.pushButtonStop.setText(_translate("MainWindow", "Stop")) self.pushButtonRecord.setText(_translate("MainWindow", "Record")) self.pushButtonPlay.setText(_translate("MainWindow", "Play")) self.pushButtonStopRecord.setText(_translate("MainWindow", "Stop")) self.label_7.setText( _translate( "MainWindow", "<html><head/><body><p><span style=\" font-weight:600; color:#55ff7f;\"> ...</span></p></body></html>" )) self.actionReset.setText(_translate("MainWindow", "Reset")) self.pushButtonRecord.setEnabled(False) self.pushButtonStopRecord.setEnabled(False) self.pushButtonStop.setEnabled(False) self.pushButtonPlay.setEnabled(False) self.pushButtonInfPlay.setEnabled(False) self.progressBar.setEnabled(False) self.progressBar_2.setEnabled(False) self.progressBar_3.setEnabled(False) self.progressBar_4.setEnabled(False) self.label_2.setEnabled(False) self.label_3.setEnabled(False) self.label_4.setEnabled(False) self.label_5.setEnabled(False) self.groupBox_3.setEnabled(False) self.groupBox_5.setEnabled(False) self.graphicsViewRec.setYRange(-20000, 20000, padding=0) self.graphicsViewRec.setXRange(0, 10 * 960 * 10, padding=0) self.graphicsViewRec.getPlotItem().hideButtons() self.graphicsViewRec.getPlotItem().hideAxis('left') self.graphicsViewRec.getPlotItem().hideAxis('bottom') def print_accuracy_graph(self, accuracy): self.accuracy_vals.append(accuracy) self.graphicsView.plot(self.accuracy_vals) def print_recording_graph(self, frames=None): self.graphicsViewRec.clear() self.recording_vals[0:9 * 960 * 10] = self.recording_vals[1 * 960 * 10:10 * 10 * 960] self.recording_vals[9 * 960 * 10:10 * 960 * 10] = frames self.graphicsViewRec.plot(self.recording_vals) def print_stats_model(self, string): self.print_in_label_7(string) def print_label_19(self, epoch): self.label_19.setText(epoch) def print_accuracy_matrix(self, matrix): for i in range(matrix.shape[0]): for j in range(matrix.shape[1]): self.tableWidget.setItem( i, j, QtWidgets.QTableWidgetItem(str(matrix[i][j]))) for i in range(4): self.tableWidget.setItem( 4, i, QtWidgets.QTableWidgetItem(str(np.sum(matrix[:, i])))) self.tableWidget.setItem( i, 4, QtWidgets.QTableWidgetItem(str(np.sum(matrix[i])))) self.tableWidget.setItem( 4, 4, QtWidgets.QTableWidgetItem(str(np.sum(np.diag(matrix))))) self.tableWidget.item(4, 4).setBackground(QtGui.QColor(102, 140, 255)) self.tableWidget.item(3, 3).setBackground(QtGui.QColor(125, 125, 125)) self.tableWidget.item(2, 2).setBackground(QtGui.QColor(125, 125, 125)) self.tableWidget.item(1, 1).setBackground(QtGui.QColor(125, 125, 125)) self.tableWidget.item(0, 0).setBackground(QtGui.QColor(125, 125, 125)) for i in range(5): for j in range(5): self.tableWidget.item(i, j).setFlags(QtCore.Qt.ItemIsEnabled) def open_alert_dialog(self, title="Alert", text="...", info="..."): msg = QtWidgets.QMessageBox() msg.setIcon(QtWidgets.QMessageBox.Critical) msg.setWindowTitle(title) msg.setText(text) msg.setInformativeText(info) msg.setStandardButtons(QtWidgets.QMessageBox.Ok) msg.exec_() def on_start_button_clicked(self): if self.radioButton.isChecked(): # training self.pushButton.setEnabled(False) self.pushButtonStop.setEnabled(True) self.radioButton_2.setEnabled(False) self.refresh_label_7() self.refresh_graphics_view() self.train_thread = Train_App(self) self.train_thread.print_accuracy_signal.connect( self.print_accuracy_graph) self.train_thread.print_stats.connect(self.print_stats_model) self.train_thread.print_matrix.connect(self.print_accuracy_matrix) self.train_thread.print_epoch.connect(self.print_label_19) self.train_thread.start() elif self.radioButton_2.isChecked(): # inference vals = self.ser_inference_model.inference( self.comboBox_2.currentText()) * 100 self.progressBar.setValue(vals[0]) self.progressBar_2.setValue(vals[1]) self.progressBar_3.setValue(vals[2]) self.progressBar_4.setValue(vals[3]) self.print_in_label_7(str(list(map('{:.8f}'.format, vals)))) pass def on_buttonStop_clicked(self): if self.train_thread != None: self.train_thread.stopFlag = True pass def change_label_16(self): self.label_16.setText(str(float(self.horizontalSlider_2.value()) / 10)) def change_label_12(self): self.label_12.setText(str(float(self.horizontalSlider.value()) / 10)) def change_label_ooda(self): self.label_ooda.setText( str(float(self.horizontalSlider_ooda.value()) / 10)) def change_horizontal_ooda(self): if self.ooda_check_box.isChecked(): self.horizontalSlider_ooda.setStyleSheet(SLYDER_ENABLED) self.horizontalSlider_ooda.setEnabled(True) else: self.horizontalSlider_ooda.setStyleSheet(SLYDER_DISABLED) self.horizontalSlider_ooda.setEnabled(False) self.label_ooda.setEnabled(self.ooda_check_box.isChecked()) def fill_file(self): self.ser_inference_model.files = get_files_from_directory( self.lineEdit_2.text()) self.comboBox_2.clear() for file in self.ser_inference_model.files: self.comboBox_2.addItem(file) if self.radioButton_2.isChecked(): # inference self.pushButton.setEnabled(True) self.pushButtonInfPlay.setEnabled(True) self.ser_inference_model.init_model(self.lineEdit_2.text()) if self.ser_inference_model.model == None: self.open_alert_dialog( title="Missing Inference inference_files Alert", text= "We could no find any inference_files to classify in the stated folder.", info= "You can continue the inference process by using the online model." ) self.pushButton.setEnabled(False) self.pushButtonInfPlay.setEnabled(False) self.ser_online_model.init_online_model() def init_inference(self): if self.radioButton_2.isChecked(): # inference if self.radioButton_4.isChecked(): self.open_alert_dialog( title= "Inference is not available for hand-crafted extraction", text= "Hand-crafted feature extraction is used only as a baseline.", info= "Please train your model using the end-to-ed extraction method in order to make inference available." ) self.radioButton.setChecked(True) self.radioButton_2.setChecked(False) return if [f for f in os.listdir("model") if not f.startswith('.')] == []: self.open_alert_dialog( title="Missing model for Inference", text="There is no machine learning model to be loaded.", info= "Please use the training mode to train a model before inference." ) self.radioButton.setChecked(True) self.radioButton_2.setChecked(False) return self.pushButtonRecord.setEnabled(True) self.pushButtonInfPlay.setEnabled(True) self.progressBar.setEnabled(True) self.progressBar_2.setEnabled(True) self.progressBar_3.setEnabled(True) self.progressBar_4.setEnabled(True) self.label_2.setEnabled(True) self.label_3.setEnabled(True) self.label_4.setEnabled(True) self.label_5.setEnabled(True) self.groupBox_3.setEnabled(True) self.groupBox_5.setEnabled(True) self.groupBox_2.setEnabled(False) self.horizontalSlider.setStyleSheet(SLYDER_DISABLED) self.horizontalSlider.setEnabled(False) self.horizontalSlider_2.setStyleSheet(SLYDER_DISABLED) self.horizontalSlider_2.setEnabled(False) self.horizontalSlider_ooda.setStyleSheet(SLYDER_DISABLED) self.horizontalSlider_ooda.setEnabled(False) self.ser_inference_model.init_model(self.lineEdit_2.text()) if self.ser_inference_model.model == None: self.open_alert_dialog( title="Missing Inference inference_files Alert", text= "We could no find any inference_files to classify in the stated folder.", info= "You can continue the inference process by using the online model." ) self.pushButton.setEnabled(False) self.pushButtonInfPlay.setEnabled(False) self.ser_online_model.init_online_model() elif self.ser_inference_model.session != None and self.radioButton.isChecked( ): self.pushButton.setEnabled(True) self.groupBox_2.setEnabled(True) self.pushButtonRecord.setEnabled(False) self.pushButtonInfPlay.setEnabled(False) self.pushButtonStopRecord.setEnabled(False) self.progressBar.setValue(0) self.progressBar.setEnabled(False) self.progressBar_2.setValue(0) self.progressBar_2.setEnabled(False) self.progressBar_3.setValue(0) self.progressBar_3.setEnabled(False) self.progressBar_4.setValue(0) self.progressBar_4.setEnabled(False) self.label_2.setEnabled(False) self.label_3.setEnabled(False) self.label_4.setEnabled(False) self.label_5.setEnabled(False) self.groupBox_3.setEnabled(False) self.groupBox_5.setEnabled(False) self.horizontalSlider.setStyleSheet(SLYDER_ENABLED) self.horizontalSlider.setEnabled(True) self.horizontalSlider_2.setStyleSheet(SLYDER_ENABLED) self.horizontalSlider_2.setEnabled(True) self.change_horizontal_ooda() self.ser_inference_model.close_model() def on_buttonRecord_clicked(self): self.refresh_rec_graphics_view() self.microphone_recorder = MicrophoneRecorder() if not self.microphone_recorder.check_device_availability(): return self.recorder_thread = Record_App(self, self.microphone_recorder) self.recorder_thread.print_recording_signal.connect( self.print_recording_graph) self.recorder_thread.start() self.pushButtonStopRecord.setEnabled(True) self.pushButton.setEnabled(False) self.pushButtonInfPlay.setEnabled(False) self.pushButtonPlay.setEnabled(False) def on_buttonStopRecord_clicked(self): import librosa import pyaudio self.microphone_recorder.close() vals = [] if np.array(self.microphone_recorder.get_frames()).shape[0] > 30: self.pushButtonPlay.setEnabled(True) self.microphone_recorder.save_to_wav() frames, _ = librosa.load("output.wav", 16000) vals = self.ser_online_model.online(frames, 44100) * 100 else: self.pushButtonPlay.setEnabled(False) vals = [0 for _ in range(4)] self.progressBar.setValue(vals[0]) self.progressBar_2.setValue(vals[1]) self.progressBar_3.setValue(vals[2]) self.progressBar_4.setValue(vals[3]) self.print_in_label_7(str(list(map('{:.8f}'.format, vals)))) self.pushButton.setEnabled(True) self.pushButtonRecord.setEnabled(True) self.pushButtonStopRecord.setEnabled(False) self.pushButtonInfPlay.setEnabled(True) self.pushButtonPlay.setEnabled(True) def print_in_label_7(self, str): _translate = QtCore.QCoreApplication.translate self.label_7_line_nr += 1 if self.label_7_line_nr >= 24: txt = self.label_7.text().split("<html>") txt = "<html>".join(txt[1:25]) self.label_7.setText( _translate( "MainWindow", txt + "<html><head/><body><span style=\" font-weight:600; color:#55ff7f;\">" + str + "</span></body></html>")) else: self.label_7.setText( _translate( "MainWindow", self.label_7.text() + "<html><head/><body><span style=\" font-weight:600; color:#55ff7f;\">" + str + "</span></body></html>")) import time def play_recording(self, file="output.wav"): self.play_th = Play_App(self, file) self.play_th.start()
class Ui_MainWindow(object): def setupUi(self, MainWindow): print('setup g') MainWindow.setObjectName("MainWindow") MainWindow.resize(1021, 839) self.centralwidget = QtWidgets.QWidget(MainWindow) self.centralwidget.setObjectName("centralwidget") self.label = QtWidgets.QLabel(self.centralwidget) self.label.setGeometry(QtCore.QRect(330, 20, 371, 51)) self.label.setObjectName("label") self.lineEditPuerto = QtWidgets.QLineEdit(self.centralwidget) self.lineEditPuerto.setGeometry(QtCore.QRect(360, 180, 271, 31)) self.lineEditPuerto.setObjectName("lineEditPuerto") self.label_2 = QtWidgets.QLabel(self.centralwidget) self.label_2.setGeometry(QtCore.QRect(380, 120, 241, 31)) self.label_2.setObjectName("label_2") self.pushButton = QtWidgets.QPushButton(self.centralwidget) self.pushButton.setGeometry(QtCore.QRect(460, 250, 75, 23)) self.pushButton.setObjectName("pushButton") self.graphicsView = PlotWidget(self.centralwidget) self.graphicsView.setGeometry(QtCore.QRect(40, 310, 961, 481)) self.graphicsView.setObjectName("graphicsView") MainWindow.setCentralWidget(self.centralwidget) self.menubar = QtWidgets.QMenuBar(MainWindow) self.menubar.setGeometry(QtCore.QRect(0, 0, 1021, 21)) self.menubar.setObjectName("menubar") MainWindow.setMenuBar(self.menubar) self.statusbar = QtWidgets.QStatusBar(MainWindow) self.statusbar.setObjectName("statusbar") MainWindow.setStatusBar(self.statusbar) self.hilo1 = Hilo1(self.lineEditPuerto.text()) self.retranslateUi(MainWindow) QtCore.QMetaObject.connectSlotsByName(MainWindow) self.pushButton.clicked.connect(self.graficar) def retranslateUi(self, MainWindow): _translate = QtCore.QCoreApplication.translate MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow")) self.label.setText(_translate("MainWindow", "<html><head/><body><p><span style=\" font-size:18pt;\">Bienvenido a ECGPythonProcessing</span></p></body></html>")) self.label_2.setText(_translate("MainWindow", "Ingrese el puerto por donde se leeran los datos:")) self.pushButton.setText(_translate("MainWindow", "Iniciar")) def graficar(self): print('holi') mensaje = QtWidgets.QMessageBox() if(len(self.lineEditPuerto.text()) == 0): mensaje.about(mensaje,'Error',"El puerto no puede quedar vacio") else: self.iniciar() def update(self,valor): global curva,data try: data.append(float(valor)) self.lecturas.append(float(valor)) if(len(self.lecturas)==512): try: print(self.lecturas) publish.single("paciente/1", str(self.lecturas), hostname="10.3.0.6") self.lecturas = [] except Exception as e: print(e) self.lecturas = [] xdata = np.array(data,dtype="float64") curva.setData(xdata) QtGui.QApplication.instance().processEvents() except Exception as e: print(e) def iniciar(self): global curva,data print('iniciar') data = [0] self.lecturas=[] curva = self.graphicsView.getPlotItem().plot() self.hilo1.start() timer = QtCore.QTimer(self.graphicsView) timer.timeout.connect(self.update) timer.start(10) print("Antes") QtGui.QApplication.instance().allWidgets() print("Despues")
class MCClassroom(QWidget): def __init__(self, settings, server): super().__init__() self.server = server self.timer = QTimer() self.timer.timeout.connect(self.time_tick) self.settings = settings self.current_class = None self.current_students = [] self.stack = QStackedLayout() self.setLayout(self.stack) # First page: connection instructions connect_widget = QWidget() connect_layout = QVBoxLayout(connect_widget) connect_layout.addStretch() connect_label = QLabel( "Open a world in Minecraft, open a terminal (press t), and type:", self) connect_layout.addWidget(connect_label) self.connect_command = f'/connect {server.get_ip()}:{PORT}' connect_command_box = QLineEdit(self.connect_command, self) connect_command_box.setReadOnly(True) connect_layout.addWidget(connect_command_box) connect_copy_button = QPushButton("Copy to Clipboard", self) connect_copy_button.clicked.connect( lambda: QApplication.clipboard().setText(self.connect_command)) connect_layout.addWidget(connect_copy_button) connection_problems_button = QPushButton("Connection Problems?", self) connection_problems_button.clicked.connect(self.show_connection_help) connect_layout.addWidget(connection_problems_button) connect_layout.addStretch() self.stack.addWidget(connect_widget) # Main page main_col_widget = QWidget() columns = QHBoxLayout(main_col_widget) col_left = QVBoxLayout() col_mid = QVBoxLayout() col_right = QVBoxLayout() columns.addLayout(col_left) columns.addSpacing(10) columns.addLayout(col_mid) columns.addSpacing(10) columns.addLayout(col_right) self.stack.addWidget(main_col_widget) self.pause_button = self.setup_toggle_button(col_left, self.server.pause_game, 'Un-pause', self.server.unpause_game, 'Pause') button_size = self.pause_button.size() self.disable_chat_button = self.setup_toggle_button( col_left, self.server.disable_chat, 'Enable Chat', self.server.enable_chat, 'Disable Chat', button_size) self.allow_mobs_button = self.setup_toggle_button( col_left, self.server.disallow_mobs, 'Allow Mobs', self.server.allow_mobs, 'Disable Mobs', button_size) self.allow_destructiveobjects_button = self.setup_toggle_button( col_left, self.server.disallow_destructiveobjects, 'Enable Destructive Items', self.server.allow_destructiveobjects, 'Disable Destructive Items', button_size) self.allow_player_damage_button = self.setup_toggle_button( col_left, self.server.disallow_player_damage, 'Enable Player Damage', self.server.allow_player_damage, 'Disable Player Damage', button_size) self.allow_pvp_button = self.setup_toggle_button( col_left, self.server.disallow_pvp, 'Allow Player Fighting', self.server.allow_pvp, 'Disable Player Fighting', button_size) self.immutable_button = self.setup_toggle_button( col_left, self.server.immutable_world, 'Enable World Modifications', self.server.mutable_world, 'Disable World Modifications', button_size) self.weather_button = self.setup_toggle_button( col_left, self.server.perfect_weather, 'Disable Perfect Weather', self.server.imperfect_weather, 'Enable Perfect Weather', button_size) self.disable_potions_button = self.setup_toggle_button( col_left, self.server.disable_potions, 'Enable Potions', self.server.enable_potions, 'Disable Potions', button_size) # self.clear_potions_button = QPushButton('Clear All Potion Effects', self) # self.clear_potions_button.resize(button_size) # self.clear_potions_button.clicked.connect(lambda: self.server.clear_effects("@a")) # col_left.addWidget(self.clear_potions_button) self.teleport_button = QPushButton('Teleport Everyone to You', self) self.teleport_button.resize(button_size) self.teleport_button.clicked.connect( lambda: self.server.teleport_all_to("@s")) col_left.addWidget(self.teleport_button) self.disconnect_button = QPushButton('Disconnect', self) self.disconnect_button.resize(button_size) self.disconnect_button.clicked.connect(self.server.socket_disconnected) col_left.addWidget(self.disconnect_button) col_left.addStretch() self.version_label = QLabel(f'Version {VERSION}', self) self.version_label.setAlignment(Qt.AlignCenter) col_left.addWidget(self.version_label) self.feedback_button = QPushButton('Feedback/Bug report', self) self.feedback_button.resize(button_size) self.feedback_button.clicked.connect( lambda: QDesktopServices.openUrl(FEEDBACK_URL)) col_left.addWidget(self.feedback_button) # Middle Column: Roll/Register self.classes_combo = QComboBox(self) class_names = self.settings.value("class_names", []) self.classes_combo.addItem("Select class") self.classes_combo.addItem("Add a class") self.classes_combo.addItem("Delete a class") self.classes_combo.addItems(class_names) self.classes_combo.currentTextChanged.connect(self.class_changed) col_mid.addWidget(self.classes_combo) self.users_table = QTableWidget(0, 2) self.users_table.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.users_table.setSizePolicy( QSizePolicy(QSizePolicy.Minimum, QSizePolicy.MinimumExpanding)) self.users_table.setFixedWidth(140) self.users_table.verticalHeader().hide() header = self.users_table.horizontalHeader() header.setSectionResizeMode(0, QHeaderView.Stretch) header.setSectionResizeMode(1, QHeaderView.ResizeToContents) header.hide() col_mid.addWidget(self.users_table) self.class_edit_button = QPushButton("Edit Class", self) col_mid.addWidget(self.class_edit_button) self.class_edit_button.clicked.connect(self.edit_class) self.chat_box = QPlainTextEdit( f'Minecraft Education Chat Logs {datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")}', self) self.chat_box.setReadOnly(True) col_right.addWidget(self.chat_box) self.chat_input = QLineEdit(self) self.chat_input.setPlaceholderText("Type chat here; enter to send") self.chat_input.returnPressed.connect(self.chat_enter) col_right.addWidget(self.chat_input) self.chat_save = QPushButton("Save Chat Logs", self) self.chat_save.clicked.connect(self.save_chat) col_right.addWidget(self.chat_save) self.user_map = PlotWidget() self.map_item = ScatterPlotItem(size=10) self.user_map.addItem(self.map_item) self.user_map.getPlotItem().hideAxis('left') self.user_map.getPlotItem().hideAxis('bottom') self.map_item.scene().sigMouseMoved.connect(self.map_hover) map_viewbox = self.map_item.getViewBox() map_viewbox.menu = None col_right.addWidget(self.user_map) self.user_map_info = QLineEdit("Hover over a user", self) self.user_map_info.setReadOnly(True) col_right.addWidget(self.user_map_info) self.setGeometry(300, 300, 800, 600) self.setWindowTitle('MineClass') self.stack.setCurrentIndex(0) self.activate_buttons(False) self.show() if is_newer_version_available(): QMessageBox.about( self, "Newer Version Available", f'A newer version of this program is available <a href="{GITHUB_DOWNLOAD_URL}">here</a>.' ) if not self.settings.value("HasRunFirstTime", False): self.show_connection_help() self.settings.setValue("HasRunFirstTime", True) def show_connection_help(self): QMessageBox.about( self, "Connection Help", '''Before using (or if Minecraft has been newly installed), go to Settings->Profile and disable "Require Encrypted Websockets"\n\n Sometimes you'll need to attempt connecting twice (use the up arrow in the Minecraft terminal to access history''' ) def save_chat(self): options = QFileDialog.Options() file_name, _ = QFileDialog.getSaveFileName( self, "Save Chat Logs", "", "Text Files (*.txt);;All Files (*)", options=options) if file_name: with open(file_name, "w") as f: f.write(self.chat_box.toPlainText()) def chat_enter(self): server.send_chat(self.chat_input.text()) self.update_chat_box("Teacher", self.chat_input.text(), "chat") self.chat_input.clear() def map_hover(self, pos): act_pos = self.map_item.mapFromScene(pos) points = self.map_item.pointsAt(act_pos) text = "" for p in points: text += f'{p.data()}: ({round(p.pos()[0])}, {round(p.pos()[1])}), ' self.user_map_info.setText(text) def time_tick(self): self.server.get_users() def start_timer(self): self.time_tick() self.timer.start(10000) def stop_timer(self): self.timer.stop() def update_chat_box(self, sender, message, message_type, receiver=None): t = datetime.datetime.now().strftime("%H:%M:%S") if message_type == "chat": out = f'{t} <{sender}> {message}' elif message_type == "tell": out = f'{t} <{sender} whispers to {receiver}> {message}' self.chat_box.appendPlainText(out) def activate_buttons(self, activate): self.pause_button.setDisabled(not activate) def setup_toggle_button(self, parent, checked_action, checked_text, unchecked_action, unchecked_text, size=None): button = QPushButton(unchecked_text, self) button.resize(button.sizeHint() if size is None else size) button.setCheckable(True) parent.addWidget(button) def toggle_button_clicked(checked_status): if checked_status: checked_action() button.setText(checked_text) else: unchecked_action() button.setText(unchecked_text) button.toggled.connect(toggle_button_clicked) return button def get_students_from_grid(self): try: return [ self.users_table.item(i, 0).text() for i in range(self.users_table.rowCount()) ] except AttributeError: return [] def edit_class(self): selection = self.classes_combo.currentText() if selection in ("Select class", "Add a class"): QMessageBox.about(self, "Error", "Please select (or create) a class first") return current_list = self.get_students_from_grid() new_list, ok_pressed = QInputDialog().getMultiLineText( self, "Edit Class List", "Add or remove students from this class", text="\n".join(current_list)) if ok_pressed: students = [i for i in new_list.split("\n") if i] # list comprehension to remove empty strings self.current_students = students self.settings.setValue(f'classes/{self.current_class}', students) self.load_users() def class_changed(self): selection = self.classes_combo.currentText() # if selection != "Select class": # self.classes_combo.removeItem(self.classes_combo.findText("Select class")) if selection == "Add a class": new_class, ok_pressed = QInputDialog.getText( self, 'Class Name', 'Enter the Class Name or Code') if ok_pressed: classes = self.settings.value('class_names', []) if new_class in classes: print('Class already exists; ignoring') else: classes.append(new_class) self.settings.setValue('class_names', classes) self.classes_combo.addItem(new_class) self.classes_combo.setCurrentIndex( self.classes_combo.findText(new_class)) elif selection == "Select class": pass elif selection == "Delete a class": current_classes = self.settings.value('class_names', []) if current_classes: class_to_delete, ok_pressed = QInputDialog.getItem( self, 'Delete Class', 'Select which class to delete', current_classes, 0, False) if ok_pressed and class_to_delete: current_classes.remove(class_to_delete) self.settings.setValue('class_names', current_classes) self.settings.remove(f'classes/{class_to_delete}') self.classes_combo.removeItem( self.classes_combo.findText(class_to_delete)) #TODO delete stdents from table self.current_class = None self.current_students = [] else: QMessageBox.information(self, "No Classes!", "No Class to delete!") self.classes_combo.setCurrentIndex(0) else: self.current_class = selection self.current_students = self.settings.value( f'classes/{selection}', []) self.load_users() def load_users(self): if len(self.current_students) != self.users_table.rowCount(): self.users_table.setRowCount(len(self.current_students)) for i, user in enumerate(self.current_students): self.users_table.setItem(i, 0, QTableWidgetItem(user)) self.users_table.sortItems(0, QtCore.Qt.AscendingOrder) self.users_table.sortItems(1, QtCore.Qt.DescendingOrder) def update_users_from_mc(self, users): table_user_count = self.users_table.rowCount() for i in range(table_user_count): current_table_user = self.users_table.item(i, 0).text() if current_table_user in users: tick = QTableWidgetItem("✓") tick.setTextAlignment(QtCore.Qt.AlignCenter) tick.setBackground(QColor(QtCore.Qt.green)) self.users_table.setItem(i, 1, tick) users.remove(current_table_user) else: cross = QTableWidgetItem("✗") cross.setTextAlignment(QtCore.Qt.AlignCenter) cross.setBackground(QColor(QtCore.Qt.red)) self.users_table.setItem(i, 1, cross) #handle users from server but not in table self.users_table.setRowCount(table_user_count + len(users)) for i, user in enumerate(users): self.users_table.setItem(i + table_user_count, 0, QTableWidgetItem(user)) self.users_table.sortItems(0, QtCore.Qt.AscendingOrder) self.users_table.sortItems(1, QtCore.Qt.DescendingOrder) self.users_table.resizeRowsToContents() def update_map(self, users): data = [ { 'pos': (int(u['position']['x']), int(u['position']['z'])), 'data': u['name'], 'brush': mkBrush( 'g' ), #mkBrush("r" if u['name'] == self.server.self_name else "g"), 'symbol': ("s" if u['name'] == self.server.self_name else "o"), } for u in users.values() ] self.map_item.setData(data)
class CallRatePlotWidget(QWidget): WWHD_FPS_ESTIMATE = 30 def __init__(self, parent: QWidget = None): super().__init__(parent) self._backlog_length = 0 self._display_as_fps = False self._main_layout = QVBoxLayout() self._plot_controls_hbox = QHBoxLayout() self._plot_controls_hbox.addWidget(QLabel('Show Latest N Seconds:')) self._backlog_time_edit = QLineEdit() self._backlog_time_edit.textChanged.connect( self._handle_backlog_time_changed) self._backlog_time_edit.setFixedWidth(40) self._plot_controls_hbox.addWidget(self._backlog_time_edit) self._plot_controls_hbox.addWidget( QLabel('Show as Calls/Frame (estimated):')) self._fps_display_checkbox = QCheckBox() self._fps_display_checkbox.stateChanged.connect( self._handle_fps_display_changed) self._plot_controls_hbox.addWidget(self._fps_display_checkbox) self._plot_controls_hbox.addStretch() self._main_layout.addLayout(self._plot_controls_hbox) self._rate_plot_widget = PlotWidget() self._rate_plot_item = self._rate_plot_widget.getPlotItem() self._rate_plot_item.setTitle('RNG Call Rate') self._rate_plot_item.setLabels(left='Call Rate [Calls/sec]', bottom='Time [s]') self._rate_plot = self._rate_plot_item.plot(antialias=False) self._main_layout.addWidget(self._rate_plot_widget) self._total_plot_widget = PlotWidget() self._total_plot_item = self._total_plot_widget.getPlotItem() self._total_plot_item.setTitle('Total RNG Calls') self._total_plot_item.setLabels(left='Total RNG Calls', bottom='Time [s]') self._total_plot = self._total_plot_item.plot() self._main_layout.addWidget(self._total_plot_widget) self._buffer = CircularFloatBuffer(3, maxlen=10000) self._start_time = time.perf_counter() self.setLayout(self._main_layout) def append_new_call_data(self, steps_taken, last_second_avg, total_steps): time_elapsed = time.perf_counter() - self._start_time self._buffer.append([time_elapsed, last_second_avg, total_steps]) time_base = self._buffer.get_all_for_channel(0) avg_data = self._buffer.get_all_for_channel(1) total_data = self._buffer.get_all_for_channel(2) if self._display_as_fps: avg_data = avg_data / self.WWHD_FPS_ESTIMATE if self._backlog_length > 0: backlog_index = (time_base > (time_elapsed - self._backlog_length)) time_base = time_base[backlog_index] avg_data = avg_data[backlog_index] total_data = total_data[backlog_index] self._rate_plot.setData(time_base, avg_data) self._total_plot.setData(time_base, total_data) def _handle_backlog_time_changed(self, new_text: str): if len(new_text) == 0: self._backlog_length = 0 try: new_backlog_length = int(new_text) except (ValueError, TypeError): return if new_backlog_length <= 0: return self._backlog_length = new_backlog_length def _handle_fps_display_changed(self, state: int): if state == Qt.Unchecked: self._display_as_fps = False self._rate_plot_item.setLabels(left='Call Rate [Calls/sec]') elif state == Qt.Checked: self._display_as_fps = True self._rate_plot_item.setLabels(left='Call Rate [Calls/frame]') def clear_plots(self): self._buffer.clear()
class BusMonitorWidget(QGroupBox): DEFAULT_PLOT_X_RANGE = 120 BUS_LOAD_PLOT_MAX_SAMPLES = 5000 def __init__(self, parent, node, iface_name): super(BusMonitorWidget, self).__init__(parent) self.setTitle('CAN bus activity (%s)' % iface_name.split(os.path.sep)[-1]) self._node = node self._hook_handle = self._node.can_driver.add_io_hook(self._frame_hook) self._columns = [ BasicTable.Column('Dir', lambda e: (e[0].upper()), searchable=False), BasicTable.Column('Local Time', TimestampRenderer(), searchable=False), BasicTable.Column('CAN ID', lambda e: (('%0*X' % (8 if e[1].extended else 3, e[1].id)).rjust(8), colorize_can_id(e[1]))), BasicTable.Column('Data Hex', lambda e: (' '.join(['%02X' % x for x in e[1].data]).ljust(3 * e[1].MAX_DATA_LENGTH), colorize_transfer_id(e))), BasicTable.Column('Data ASCII', lambda e: (''.join([(chr(x) if 32 <= x <= 126 else '.') for x in e[1].data]), colorize_transfer_id(e))), BasicTable.Column('Src', lambda e: render_node_id_with_color(e[1], 'src')), BasicTable.Column('Dst', lambda e: render_node_id_with_color(e[1], 'dst')), BasicTable.Column('Data Type', lambda e: render_data_type_with_color(e[1]), resize_mode=QHeaderView.Stretch), ] self._log_widget = RealtimeLogWidget(self, columns=self._columns, font=get_monospace_font(), post_redraw_hook=self._redraw_hook) self._log_widget.on_selection_changed = self._update_measurement_display def flip_row_mark(row, col): if col == 0: item = self._log_widget.table.item(row, col) if item.icon().isNull(): item.setIcon(get_icon('circle')) flash(self, 'Row %d was marked, click again to unmark', row, duration=3) else: item.setIcon(QIcon()) self._log_widget.table.cellPressed.connect(flip_row_mark) self._stat_update_timer = QTimer(self) self._stat_update_timer.setSingleShot(False) self._stat_update_timer.timeout.connect(self._update_stat) self._stat_update_timer.start(500) self._traffic_stat = TrafficStatCounter() self._stat_frames_tx = QLabel('N/A', self) self._stat_frames_rx = QLabel('N/A', self) self._stat_traffic = QLabel('N/A', self) self._load_plot = PlotWidget(background=(0, 0, 0)) self._load_plot.setRange(xRange=(0, self.DEFAULT_PLOT_X_RANGE), padding=0) self._load_plot.setMaximumHeight(150) self._load_plot.setMinimumHeight(100) self._load_plot.setMinimumWidth(100) self._load_plot.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Minimum) self._load_plot.showGrid(x=True, y=True, alpha=0.4) self._load_plot.setToolTip('Frames per second') self._load_plot.getPlotItem().getViewBox().setMouseEnabled(x=True, y=False) self._load_plot.enableAutoRange() self._bus_load_plot = self._load_plot.plot(name='Frames per second', pen=mkPen(QColor(Qt.lightGray), width=1)) self._bus_load_samples = [], [] self._started_at_mono = time.monotonic() layout = QVBoxLayout(self) layout.addWidget(self._log_widget, 1) stat_vars_layout = QGridLayout(self) stat_layout_next_row = 0 def add_stat_row(label, value): nonlocal stat_layout_next_row stat_vars_layout.addWidget(QLabel(label, self), stat_layout_next_row, 0) stat_vars_layout.addWidget(value, stat_layout_next_row, 1) value.setMinimumWidth(75) stat_layout_next_row += 1 add_stat_row('Frames transmitted:', self._stat_frames_tx) add_stat_row('Frames received:', self._stat_frames_rx) add_stat_row('Frames per second:', self._stat_traffic) stat_vars_layout.setRowStretch(stat_layout_next_row, 1) stat_layout = QHBoxLayout(self) stat_layout.addLayout(stat_vars_layout) stat_layout.addWidget(self._load_plot, 1) layout.addLayout(stat_layout, 0) self.setLayout(layout) def close(self): self._hook_handle.remove() def _update_stat(self): bus_load, ts_mono = self._traffic_stat.get_frames_per_second() self._stat_traffic.setText(str(int(bus_load + 0.5))) if len(self._bus_load_samples[0]) >= self.BUS_LOAD_PLOT_MAX_SAMPLES: self._bus_load_samples[0].pop(0) self._bus_load_samples[1].pop(0) self._bus_load_samples[1].append(bus_load) self._bus_load_samples[0].append(ts_mono - self._started_at_mono) self._bus_load_plot.setData(*self._bus_load_samples) (xmin, xmax), _ = self._load_plot.viewRange() diff = xmax - xmin xmax = self._bus_load_samples[0][-1] xmin = self._bus_load_samples[0][-1] - diff self._load_plot.setRange(xRange=(xmin, xmax), padding=0) def _redraw_hook(self): self._stat_frames_tx.setText(str(self._traffic_stat.tx)) self._stat_frames_rx.setText(str(self._traffic_stat.rx)) def _frame_hook(self, direction, frame): self._traffic_stat.add_frame(direction, frame) self._log_widget.add_item_async((direction, frame)) def _update_measurement_display(self, selected_rows_cols): if not selected_rows_cols: return min_row = min([row for row, _ in selected_rows_cols]) max_row = max([row for row, _ in selected_rows_cols]) def get_row_ts(row): return TimestampRenderer.parse_timestamp(self._log_widget.table.item(row, 1).text()) def get_load_str(num_frames, dt): if dt >= 1e-6: return 'average load %.1f FPS' % (num_frames / dt) return 'average load is unknown' if min_row == max_row: num_frames = min_row first_ts = get_row_ts(0) current_ts = get_row_ts(min_row) dt = current_ts - first_ts flash(self, '%d frames from beginning, %.3f sec since first frame, %s', num_frames, dt, get_load_str(num_frames, dt)) else: num_frames = max_row - min_row + 1 first_ts = get_row_ts(min_row) last_ts = get_row_ts(max_row) dt = last_ts - first_ts flash(self, '%d frames, timedelta %.6f sec, %s', num_frames, dt, get_load_str(num_frames, dt))
class CamViewer(Display): #Emitted when the user changes the value. roi_x_signal = pyqtSignal(str) roi_y_signal = pyqtSignal(str) roi_w_signal = pyqtSignal(str) roi_h_signal = pyqtSignal(str) def __init__(self, display_manager_window): super(CamViewer, self).__init__(display_manager_window) #Set up the list of cameras, and all the PVs vcc_dict = { "image": "ca://CAMR:IN20:186:IMAGE", "max_width": "ca://CAMR:IN20:186:N_OF_COL", "max_height": "ca://CAMR:IN20:186:N_OF_ROW", "roi_x": None, "roi_y": None, "roi_width": None, "roi_height": None } c_iris_dict = { "image": "ca://CAMR:LR20:119:Image:ArrayData", "max_width": "ca://CAMR:LR20:119:MaxSizeX_RBV", "max_height": "ca://CAMR:LR20:119:MaxSizeY_RBV", "roi_x": "ca://CAMR:LR20:119:MinX", "roi_y": "ca://CAMR:LR20:119:MinY", "roi_width": "ca://CAMR:LR20:119:SizeX", "roi_height": "ca://CAMR:LR20:119:SizeY" } test_dict = { "image": "ca://MTEST:Image", "max_width": "ca://MTEST:ImageWidth", "max_height": "ca://MTEST:ImageWidth", "roi_x": None, "roi_y": None, "roi_width": None, "roi_height": None } self.cameras = { "VCC": vcc_dict, "C-Iris": c_iris_dict, "Test": test_dict } self._channels = [] #Populate the camera combo box self.ui.cameraComboBox.clear() for camera in self.cameras: self.ui.cameraComboBox.addItem(camera) #Clear out any image data, reset width, get PVs ready for connection self.initializeCamera(self.ui.cameraComboBox.currentText()) #When the camera combo box changes, disconnect from PVs, re-initialize, then reconnect. self.ui.cameraComboBox.activated[str].connect(self.cameraChanged) #Set up the color map combo box. self.ui.colorMapComboBox.clear() for map_name in self.ui.imageView.color_maps: self.ui.colorMapComboBox.addItem(map_name) self.ui.imageView.setColorMapToPreset( self.ui.colorMapComboBox.currentText()) self.ui.colorMapComboBox.activated[str].connect(self.colorMapChanged) #Set up the color map limit sliders and line edits. #self._color_map_limit_sliders_need_config = True self.ui.colorMapMinSlider.valueChanged.connect(self.setColorMapMin) self.ui.colorMapMaxSlider.valueChanged.connect(self.setColorMapMax) self.ui.colorMapMinLineEdit.returnPressed.connect( self.colorMapMinLineEditChanged) self.ui.colorMapMaxLineEdit.returnPressed.connect( self.colorMapMaxLineEditChanged) #Set up the stuff for single-shot and average modes. self.ui.singleShotRadioButton.setChecked(True) self._average_mode_enabled = False self.ui.singleShotRadioButton.clicked.connect( self.enableSingleShotMode) self.ui.averageRadioButton.clicked.connect(self.enableAverageMode) self.ui.numShotsLineEdit.returnPressed.connect(self.numAverageChanged) #Add a plot for vertical lineouts self.yLineoutPlot = PlotWidget() self.yLineoutPlot.setMaximumWidth(80) self.yLineoutPlot.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Expanding) self.yLineoutPlot.getPlotItem().invertY() self.yLineoutPlot.hideAxis('bottom') #self.yLineoutPlot.setYLink(self.ui.imageView.getView()) self.ui.imageGridLayout.addWidget(self.yLineoutPlot, 0, 0) self.yLineoutPlot.hide() #We do some mangling of the .ui file here and move the imageView over a cell, kind of ugly. self.ui.imageGridLayout.removeWidget(self.ui.imageView) self.ui.imageGridLayout.addWidget(self.ui.imageView, 0, 1) #Add a plot for the horizontal lineouts self.xLineoutPlot = PlotWidget() self.xLineoutPlot.setMaximumHeight(80) self.xLineoutPlot.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Minimum) self.xLineoutPlot.hideAxis('left') #self.xLineoutPlot.setXLink(self.ui.imageView.getView()) self.ui.imageGridLayout.addWidget(self.xLineoutPlot, 1, 1) self.xLineoutPlot.hide() #Update the lineout plot ranges when the image gets panned or zoomed self.ui.imageView.getView().sigRangeChanged.connect( self.updateLineoutRange) #Instantiate markers. self.marker_dict = {1: {}, 2: {}, 3: {}, 4: {}} marker_size = QPointF(20., 20.) self.marker_dict[1]['marker'] = ImageMarker((0, 0), size=marker_size, pen=mkPen((100, 100, 255), width=3)) self.marker_dict[1]['button'] = self.ui.marker1Button self.marker_dict[1]['xlineedit'] = self.ui.marker1XPosLineEdit self.marker_dict[1]['ylineedit'] = self.ui.marker1YPosLineEdit self.marker_dict[2]['marker'] = ImageMarker((0, 0), size=marker_size, pen=mkPen((255, 100, 100), width=3)) self.marker_dict[2]['button'] = self.ui.marker2Button self.marker_dict[2]['xlineedit'] = self.ui.marker2XPosLineEdit self.marker_dict[2]['ylineedit'] = self.ui.marker2YPosLineEdit self.marker_dict[3]['marker'] = ImageMarker((0, 0), size=marker_size, pen=mkPen((60, 255, 60), width=3)) self.marker_dict[3]['button'] = self.ui.marker3Button self.marker_dict[3]['xlineedit'] = self.ui.marker3XPosLineEdit self.marker_dict[3]['ylineedit'] = self.ui.marker3YPosLineEdit self.marker_dict[4]['marker'] = ImageMarker((0, 0), size=marker_size, pen=mkPen((255, 60, 255), width=3)) self.marker_dict[4]['button'] = self.ui.marker4Button self.marker_dict[4]['xlineedit'] = self.ui.marker4XPosLineEdit self.marker_dict[4]['ylineedit'] = self.ui.marker4YPosLineEdit #Disable auto-ranging the image (it feels strange when the zoom changes as you move markers around.) self.ui.imageView.getView().disableAutoRange() for d in self.marker_dict: marker = self.marker_dict[d]['marker'] marker.setZValue(20) marker.hide() marker.sigRegionChanged.connect(self.markerMoved) self.ui.imageView.getView().addItem(marker) self.marker_dict[d]['button'].toggled.connect(self.enableMarker) curvepen = QPen(marker.pen) curvepen.setWidth(1) self.marker_dict[d]['xcurve'] = self.xLineoutPlot.plot( pen=curvepen) self.marker_dict[d]['ycurve'] = self.yLineoutPlot.plot( pen=curvepen) self.marker_dict[d]['xlineedit'].returnPressed.connect( self.markerPositionLineEditChanged) self.marker_dict[d]['ylineedit'].returnPressed.connect( self.markerPositionLineEditChanged) #Set up zoom buttons self.ui.zoomInButton.clicked.connect(self.zoomIn) self.ui.zoomOutButton.clicked.connect(self.zoomOut) self.ui.zoomToActualSizeButton.clicked.connect(self.zoomToActualSize) #Set up ROI buttons self.ui.setROIButton.clicked.connect(self.setROI) self.ui.resetROIButton.clicked.connect(self.resetROI) @pyqtSlot() def zoomIn(self): self.ui.imageView.getView().scaleBy((0.5, 0.5)) @pyqtSlot() def zoomOut(self): self.ui.imageView.getView().scaleBy((2.0, 2.0)) @pyqtSlot() def zoomToActualSize(self): if len(self.image_data) == 0: return self.ui.imageView.getView().setRange(xRange=(0, self.image_data.shape[0]), yRange=(0, self.image_data.shape[1]), padding=0.0) def disable_all_markers(self): for d in self.marker_dict: self.marker_dict[d]['button'].setChecked(False) self.marker_dict[d]['marker'].setPos((0, 0)) @pyqtSlot(bool) def enableMarker(self, checked): any_markers_visible = False for d in self.marker_dict: marker = self.marker_dict[d]['marker'] button = self.marker_dict[d]['button'] any_markers_visible = any_markers_visible or button.isChecked() marker.setVisible(button.isChecked()) self.markerMoved(d) self.marker_dict[d]['xcurve'].setVisible(button.isChecked()) self.marker_dict[d]['ycurve'].setVisible(button.isChecked()) self.marker_dict[d]['xlineedit'].setEnabled(button.isChecked()) self.marker_dict[d]['ylineedit'].setEnabled(button.isChecked()) if any_markers_visible: self.xLineoutPlot.show() self.yLineoutPlot.show() else: self.xLineoutPlot.hide() self.yLineoutPlot.hide() @pyqtSlot() def markerPositionLineEditChanged(self): for d in self.marker_dict: marker = self.marker_dict[d]['marker'] x_line_edit = self.marker_dict[d]['xlineedit'] y_line_edit = self.marker_dict[d]['ylineedit'] try: new_x = int(x_line_edit.text()) new_y = int(y_line_edit.text()) if new_x <= marker.maxBounds.width( ) and new_y <= marker.maxBounds.height(): marker.setPos((new_x, new_y)) return except: pass coords = marker.getPixelCoords() x_line_edit.setText(str(coords[0])) y_line_edit.setText(str(coords[1])) @pyqtSlot(object) def markerMoved(self, marker): self.updateLineouts() for marker_index in self.marker_dict: marker = self.marker_dict[marker_index]['marker'] x_line_edit = self.marker_dict[marker_index]['xlineedit'] y_line_edit = self.marker_dict[marker_index]['ylineedit'] coords = marker.getPixelCoords() x_line_edit.setText(str(coords[0])) y_line_edit.setText(str(coords[1])) @pyqtSlot(object, object) def updateLineoutRange(self, view, new_ranges): self.ui.xLineoutPlot.setRange(xRange=new_ranges[0], padding=0.0) self.ui.yLineoutPlot.setRange(yRange=new_ranges[1], padding=0.0) def updateLineouts(self): for marker_index in self.marker_dict: marker = self.marker_dict[marker_index]['marker'] xcurve = self.marker_dict[marker_index]['xcurve'] ycurve = self.marker_dict[marker_index]['ycurve'] if marker.isVisible(): result, coords = marker.getArrayRegion( self.image_data, self.ui.imageView.getImageItem()) xcurve.setData(y=result[0], x=np.arange(len(result[0]))) ycurve.setData(y=np.arange(len(result[1])), x=result[1]) @pyqtSlot() def enableSingleShotMode(self): self._average_mode_enabled = False self._average_buffer = np.ndarray(0) @pyqtSlot() def enableAverageMode(self): self._average_mode_enabled = True @pyqtSlot(str) def cameraChanged(self, new_camera): new_camera = str(new_camera) if self.imageChannel == self.cameras[new_camera]["image"]: return self.display_manager_window.close_widget_connections(self) self.disable_all_markers() self.initializeCamera(new_camera) self.display_manager_window.establish_widget_connections(self) def initializeCamera(self, new_camera): new_camera = str(new_camera) self._color_map_limit_sliders_need_config = True self.times = np.zeros(10) self.old_timestamp = 0 self.image_width = 0 #current width (width of ROI) self.image_max_width = 0 #full width. Only used to reset ROI to full. self.image_max_height = 0 #full height. Only used to reset ROI to full. self.image_data = np.zeros(0) self._average_counter = 0 self._average_buffer = np.ndarray(0) self._needs_auto_range = True self.imageChannel = self.cameras[new_camera]["image"] self.widthChannel = self.cameras[new_camera][ "roi_width"] or self.cameras[new_camera]["max_width"] self.maxWidthChannel = self.cameras[new_camera]["max_width"] self.maxHeightChannel = self.cameras[new_camera]["max_height"] self.roiXChannel = self.cameras[new_camera]["roi_x"] self.roiYChannel = self.cameras[new_camera]["roi_y"] self.roiWidthChannel = self.cameras[new_camera]["roi_width"] self.roiHeightChannel = self.cameras[new_camera]["roi_height"] self._channels = [ PyDMChannel(address=self.imageChannel, connection_slot=self.connectionStateChanged, waveform_slot=self.receiveImageWaveform, severity_slot=self.alarmSeverityChanged), PyDMChannel(address=self.widthChannel, value_slot=self.receiveImageWidth), PyDMChannel(address=self.maxWidthChannel, value_slot=self.receiveMaxWidth), PyDMChannel(address=self.maxHeightChannel, value_slot=self.receiveMaxHeight) ] if self.roiXChannel and self.roiYChannel and self.roiWidthChannel and self.roiHeightChannel: self._channels.extend([ PyDMChannel(address=self.roiXChannel, value_slot=self.receiveRoiX, value_signal=self.roi_x_signal, write_access_slot=self.roiWriteAccessChanged), PyDMChannel(address=self.roiYChannel, value_slot=self.receiveRoiY, value_signal=self.roi_y_signal), PyDMChannel(address=self.roiWidthChannel, value_slot=self.receiveRoiWidth, value_signal=self.roi_w_signal), PyDMChannel(address=self.roiHeightChannel, value_slot=self.receiveRoiHeight, value_signal=self.roi_h_signal) ]) self.ui.roiXLineEdit.setEnabled(True) self.ui.roiYLineEdit.setEnabled(True) self.ui.roiWLineEdit.setEnabled(True) self.ui.roiHLineEdit.setEnabled(True) else: self.ui.roiXLineEdit.clear() self.ui.roiXLineEdit.setEnabled(False) self.ui.roiYLineEdit.clear() self.ui.roiYLineEdit.setEnabled(False) self.ui.roiWLineEdit.clear() self.ui.roiWLineEdit.setEnabled(False) self.ui.roiHLineEdit.clear() self.ui.roiHLineEdit.setEnabled(False) @pyqtSlot() def setROI(self): self.roi_x_signal.emit(self.ui.roiXLineEdit.text()) self.roi_y_signal.emit(self.ui.roiYLineEdit.text()) self.roi_w_signal.emit(self.ui.roiWLineEdit.text()) self.roi_h_signal.emit(self.ui.roiHLineEdit.text()) @pyqtSlot() def resetROI(self): self.roi_x_signal.emit(str(0)) self.roi_y_signal.emit(str(0)) self.roi_w_signal.emit(str(self.image_max_width)) self.roi_h_signal.emit(str(self.image_max_height)) @pyqtSlot(str) def colorMapChanged(self, new_map_name): self.ui.imageView.setColorMapToPreset(new_map_name) def configureColorMapLimitSliders(self, max_int): self.ui.colorMapMinSlider.setMaximum(max_int) self.ui.colorMapMaxSlider.setMaximum(max_int) self.ui.colorMapMaxSlider.setValue(max_int) self.ui.colorMapMinSlider.setValue(0) self.setColorMapMin(0) self.setColorMapMax(max_int) self._color_map_limit_sliders_need_config = False @pyqtSlot() def colorMapMinLineEditChanged(self): try: new_min = int(self.ui.colorMapMinLineEdit.text()) except: self.ui.colorMapMinLineEdit.setText( str(self.ui.colorMapMinSlider.value())) return if new_min < 0: new_min = 0 if new_min > self.ui.colorMapMinSlider.maximum(): new_min = self.ui.colorMapMinSlider.maximum() self.ui.colorMapMinSlider.setValue(new_min) @pyqtSlot(int) def setColorMapMin(self, new_min): if new_min > self.ui.colorMapMaxSlider.value(): self.ui.colorMapMaxSlider.setValue(new_min) self.ui.colorMapMaxLineEdit.setText(str(new_min)) self.ui.colorMapMinLineEdit.setText(str(new_min)) self.ui.imageView.setColorMapLimits(new_min, self.ui.colorMapMaxSlider.value()) @pyqtSlot() def colorMapMaxLineEditChanged(self): try: new_max = int(self.ui.colorMapMaxLineEdit.text()) except: self.ui.colorMapMaxLineEdit.setText( str(self.ui.colorMapMaxSlider.value())) return if new_max < 0: new_max = 0 if new_max > self.ui.colorMapMaxSlider.maximum(): new_max = self.ui.colorMapMaxSlider.maximum() self.ui.colorMapMaxSlider.setValue(new_max) @pyqtSlot(int) def setColorMapMax(self, new_max): if new_max < self.ui.colorMapMinSlider.value(): self.ui.colorMapMinSlider.setValue(new_max) self.ui.colorMapMinLineEdit.setText(str(new_max)) self.ui.colorMapMaxLineEdit.setText(str(new_max)) self.ui.imageView.setColorMapLimits(self.ui.colorMapMinSlider.value(), new_max) def createAverageBuffer(self, size, type, initial_val=[]): num_shots = 1 try: num_shots = int(self.ui.numShotsLineEdit.text()) except: self.ui.numShotsLineEdit.setText(str(num_shots)) if num_shots < 1: num_shots = 1 self.ui.numShotsLineEdit.setText(str(num_shots)) if num_shots > 200: num_shots = 200 self.ui.numShotsLineEdit.setText(str(num_shots)) if len(initial_val) > 0: return np.full((num_shots, size), initial_val, dtype=type) else: return np.zeros(shape=(num_shots, size), dtype=type) @pyqtSlot() def numAverageChanged(self): self._average_buffer = np.zeros(0) @pyqtSlot(np.ndarray) def receiveImageWaveform(self, new_waveform): if not self.image_width: return #Calculate the average rate new_timestamp = time.time() if not (self.old_timestamp == 0): delta = new_timestamp - self.old_timestamp self.times = np.roll(self.times, 1) self.times[0] = delta avg_delta = np.mean(self.times) self.ui.dataRateLabel.setText("{:.1f} Hz".format( (1.0 / avg_delta))) self.ui.displayRateLabel.setText("{:.1f} Hz".format( (1.0 / avg_delta))) self.old_timestamp = new_timestamp #If this is the first image, set up the color map slider limits if self._color_map_limit_sliders_need_config: max_int = np.iinfo(new_waveform.dtype).max self.configureColorMapLimitSliders(max_int) #If we are in average mode, add this image to the circular averaging buffer, otherwise just display it. if self._average_mode_enabled: if len(self._average_buffer) == 0: self._average_buffer = self.createAverageBuffer( len(new_waveform), new_waveform.dtype, new_waveform) self._average_counter = 0 self._average_counter = (self._average_counter + 1) % len( self._average_buffer) #self._average_buffer = np.roll(self._average_buffer, 1, axis=0) self._average_buffer[self._average_counter] = new_waveform mean = np.mean(self._average_buffer, axis=0).astype(new_waveform.dtype) self.image_data = mean.reshape((int(self.image_width), -1), order='F') else: self.image_data = new_waveform.reshape((int(self.image_width), -1), order='F') self.setMarkerBounds() self.updateLineouts() self.ui.imageView.receiveImageWaveform(self.image_data) self.calculateStats() if self._needs_auto_range: self.ui.imageView.getView().autoRange(padding=0.0) current_range = self.ui.imageView.getView().viewRange() self._needs_auto_range = False def calculateStats(self): # Full image stats mean = np.mean(self.image_data) std = np.std(self.image_data) width = self.image_data.shape[0] height = self.image_data.shape[1] min_val = np.min(self.image_data) max_val = np.max(self.image_data) self.ui.imageStatsLabel.setText( "Mean: {0:.2f}, Std: {1:.2f}, Min: {2}, Max: {3}, Width: {4}, Height: {5}" .format(mean, std, min_val, max_val, width, height)) # Current view stats current_range = self.ui.imageView.getView().viewRange() view_x_min = int(max(0, current_range[0][0])) view_x_max = int(min(self.image_data.shape[0], current_range[0][1])) view_y_min = int(max(0, current_range[1][0])) view_y_max = int(min(self.image_data.shape[1], current_range[1][1])) view_slice = self.image_data[view_x_min:view_x_max, view_y_min:view_y_max] mean = np.mean(view_slice) std = np.std(view_slice) width = view_slice.shape[0] height = view_slice.shape[1] min_val = np.min(view_slice) max_val = np.max(view_slice) self.ui.viewStatsLabel.setText( "Mean: {0:.2f}, Std: {1:.2f}, Min: {2}, Max: {3}, Width: {4}, Height: {5}" .format(mean, std, min_val, max_val, width, height)) def setMarkerBounds(self): for marker_index in self.marker_dict: marker = self.marker_dict[marker_index]['marker'] marker.maxBounds = QRectF( 0, 0, self.image_data.shape[0] + marker.size()[0] - 1, self.image_data.shape[1] + marker.size()[1] - 1) @pyqtSlot(int) def receiveImageWidth(self, new_width): self.image_width = new_width self.ui.imageView.receiveImageWidth(self.image_width) @pyqtSlot(int) def receiveMaxWidth(self, new_max_width): self.image_max_width = new_max_width @pyqtSlot(int) def receiveMaxHeight(self, new_max_height): self.image_max_height = new_max_height @pyqtSlot(int) def receiveRoiX(self, new_roi_x): self.ui.roiXLineEdit.setText(str(new_roi_x)) @pyqtSlot(int) def receiveRoiY(self, new_roi_y): self.ui.roiYLineEdit.setText(str(new_roi_y)) @pyqtSlot(int) def receiveRoiWidth(self, new_roi_w): self.ui.roiWLineEdit.setText(str(new_roi_w)) @pyqtSlot(int) def receiveRoiHeight(self, new_roi_h): self.ui.roiHLineEdit.setText(str(new_roi_h)) # -2 to +2, -2 is LOLO, -1 is LOW, 0 is OK, etc. @pyqtSlot(int) def alarmStatusChanged(self, new_alarm_state): pass #0 = NO_ALARM, 1 = MINOR, 2 = MAJOR, 3 = INVALID @pyqtSlot(int) def alarmSeverityChanged(self, new_alarm_severity): pass @pyqtSlot(bool) def roiWriteAccessChanged(self, can_write_roi): self.ui.setROIButton.setEnabled(can_write_roi) self.ui.resetROIButton.setEnabled(can_write_roi) self.ui.roiXLineEdit.setReadOnly(not can_write_roi) self.ui.roiYLineEdit.setReadOnly(not can_write_roi) self.ui.roiWLineEdit.setReadOnly(not can_write_roi) self.ui.roiHLineEdit.setReadOnly(not can_write_roi) #false = disconnected, true = connected @pyqtSlot(bool) def connectionStateChanged(self, connected): self.ui.connectedLabel.setText({True: "Yes", False: "No"}[connected]) def ui_filename(self): return 'camviewer.ui' def ui_filepath(self): return path.join(path.dirname(path.realpath(__file__)), self.ui_filename()) def channels(self): return self._channels
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
def initGUI(self): self.plot = PlotWidget() self.sensorplot = PlotWidget() self.schemeplot = PlotWidget() self.scheme_plot = UTILS_QT.myplot(self.schemeplot,xlabel = ['time', 's'], ylabel =['',''],logmode=False) self.psp = UTILS_QT.pulses_scheme_plot(self.scheme_plot) date_axis = TimeAxisItem(orientation='bottom') #date_axis = pg.graphicsItems.DateAxisItem.DateAxisItem(orientation = 'bottom') self.sensorplot = PlotWidget(axisItems = {'bottom': date_axis}) win = GraphicsLayoutWidget() win2 = PlotWidget() self.view = win.addViewBox(border = 'w', invertY = True) self.view.setAspectLocked(True) self.img = ImageItem() self.plotaxes = win2.getPlotItem() #self.view.addItem(self.img) #self.view.addItem(self.plotaxes) #self.view. data = np.random.normal(size=(1, 600, 600), loc=1024, scale=64).astype(np.uint16) self.img.setImage(data[0]) self.plotaxes.getViewBox().addItem(self.img) # colormap pos = np.array([0., 1., 0.5, 0.25, 0.75]) #pos2 = np.array([1.0,0.75,0.5,0.25,0.]) pos2 = np.array([0.,0.25,0.5,0.75,1.0]) color2 = np.array([[255,242,15,255], [245,124,15,255],[170,69,16,255],[91,50,0,255],[0,0,0,255]],dtype=np.ubyte) color = np.array([[0,255,255,255], [255,255,0,255], [0,0,0,255], (0, 0, 255, 255), (255, 0, 0, 255)], dtype=np.ubyte) cmap = pg.ColorMap(pos2, color2) lut = cmap.getLookupTable(0.0, 1.0, 256) self.img.setLookupTable(lut) #self.img.setLevels([-50,1]) self.tw = QtGui.QTabWidget() self.tw.addTab(win2,'ESR data') self.tw.addTab(self.sensorplot,'B field') self.tw.addTab(self.schemeplot,'Scheme') layout = QtGui.QVBoxLayout() layout.addWidget(self.plot) #layout.addWidget(win2) layout.addWidget(self.tw) self.setLayout(layout) self.p1 = self.plot.getPlotItem() self.p2 = self.plot.getPlotItem() self.ps = self.sensorplot.getPlotItem() #self.p1.addLegend() self.p1data = self.p1.plot([0],pen = 'r') self.p2data = self.p1.plot([0],pen = 'g') self.psdata = self.ps.plot([],pen = 'w') self.ps.setLabel('left','Magnetic field', 'uT') self.vLine5 = pg.InfiniteLine(angle=90, movable=True) self.vLine6 = pg.InfiniteLine(angle=90, movable=True) self.plotaxes.addItem(self.vLine5, ignoreBounds=True) self.plotaxes.addItem(self.vLine6, ignoreBounds=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 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)