Esempio n. 1
0
class SimpleTestResultsDialog(QMainWindow):
    def __init__(self, parent=None, methods=None):
        super(SimpleTestResultsDialog, self).__init__(parent)
        self.setWindowTitle("Grismo - Wyniki dla prostego testu")
        self.setMinimumWidth(500)
        self.results_count = 0
        self.all_results = []
        self.methods = methods

        central = QWidget()
        self.setCentralWidget(central)

        result_dialog_layout = QVBoxLayout()
        central.setLayout(result_dialog_layout)

        self.results_table = QTableWidget()
        result_dialog_layout.addWidget(self.results_table)
        self.results_table.setRowCount(len(methods))
        self.results_table.setColumnCount(3)
        self.results_table.setColumnWidth(2, 200)
        self.results_table.setHorizontalHeaderLabels(["Metoda", "Wynik", "Czas [s]"])

        for i in range(len(methods)):
            self.results_table.setItem(i, 0, QTableWidgetItem(methods[i]))

        # plot box
        x_axis_dict = dict(enumerate(methods))
        x_axis = AxisItem(orientation='bottom')
        x_axis.setTicks([x_axis_dict.items()])
        self.results_plot = PlotWidget(axisItems={'bottom': x_axis})
        self.results_plot.setBackground('w')
        self.results_plot.setTitle("Porównanie metod dla wskazanych grafów")
        self.results_plot.setLabel('left', 'Czas obliczeń [s]', color='k', size=10)
        self.results_plot.setLabel('bottom', 'Metody ', color='k', size=10)
        self.results_plot.setMaximumWidth(600)
        self.results_plot.showGrid(y=True)
        result_dialog_layout.addWidget(self.results_plot)

        # prepare plot data
        pen = mkPen(color='k', width=2)
        self.plot_data = self.results_plot.plot([], [], pen=pen, symbol='+', symbolSize=10, symbolBrush='k')

    def add_result(self, result):
        for i in range(len(result)):
            self.results_table.setItem(self.results_count, i, QTableWidgetItem(str(result[i])))
        self.results_count = self.results_count + 1
        self.all_results.append(result[-1])
        self.plot_data.setData(range(len(self.all_results)), self.all_results)
Esempio n. 2
0
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
Esempio n. 3
0
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
Esempio n. 4
0
class ComplicatedTestResultsDialog(QMainWindow):
    def __init__(self, parent=None, methods=None, vertices_amounts=None, samples_amount=None, name_1=None, name_2=None):
        super(ComplicatedTestResultsDialog, self).__init__(parent)
        self.parent_window = parent
        self.setWindowTitle("Grismo - Wyniki dla testu wpływu liczby " + name_1)
        self.setMinimumWidth(630)
        self.setMinimumHeight(800)
        self.setMaximumHeight(900)
        self.methods = methods
        self.results_count = 0
        self.start_vertices = vertices_amounts[0]
        self.all_vertices_amount = len(vertices_amounts)
        self.samples_amount = samples_amount
        # store all results to calculate means
        self.all_results = []

        central = QWidget()
        self.setCentralWidget(central)
        central_layout = QVBoxLayout()
        central.setLayout(central_layout)

        # plot box
        plot_label = QLabel("Wykres dla wszystkich testów:")
        central_layout.addWidget(plot_label)
        self.plot_log_mode = False
        self.results_plot = PlotWidget()
        self.results_plot.setLogMode(False, self.plot_log_mode)
        self.results_plot.setBackground('w')
        self.results_plot.setTitle("Badanie wpływu liczby " + name_1 + " na czas testu")
        self.results_plot.setLabel('left', 'Czas obliczeń [s]', color='k', size=10)
        self.results_plot.setLabel('bottom', 'Liczba ' + name_1, color='k', size=10)
        self.results_plot.setXRange(self.start_vertices, vertices_amounts[-1])
        self.results_plot.setMaximumWidth(600)
        self.results_plot.showGrid(y=True)
        central_layout.addWidget(self.results_plot)

        switch_plot_log_button = QPushButton("Zmień skalę osi Y (logarytmiczna/liniowa)")
        switch_plot_log_button.setCheckable(False)
        switch_plot_log_button.clicked.connect(self.switch_plot_log)
        central_layout.addWidget(switch_plot_log_button)

        # prepare plot lines
        self.plot_data = []
        method_colors = ['k', 'b', 'g', 'r', 'y']
        self.results_plot.plot([], [], name="")
        self.results_plot.addLegend()
        for method_index in range(len(self.methods)):
            method_name = self.methods[method_index]
            method_color = method_colors[method_index]
            pen = mkPen(color=method_color, width=2)
            self.plot_data.append(self.results_plot.plot([], [], name=method_name, pen=pen, symbol='+', symbolSize=10,
                                                         symbolBrush=method_color))
            self.results_plot.addLegend()

        # tables box
        tables_box = QScrollArea(self)
        tables_box.setWidgetResizable(True)
        tables_box_content = QWidget(tables_box)
        tables_box_layout = QVBoxLayout(tables_box_content)
        tables_box_content.setLayout(tables_box_layout)
        tables_box.setWidget(tables_box_content)
        central_layout.addWidget(tables_box)

        # for each vertices_amount prepare table: label -> table -> label -> progress_bar
        self.results_tables = []
        self.results_progress_bars = []
        bold_font = QFont()
        bold_font.setBold(True)
        for i in vertices_amounts:
            vertices_label = QLabel("Wyniki dla grafów o  " + str(i) + " " + name_2 + ":")
            vertices_label.setFont(bold_font)
            results_table = QTableWidget()
            results_table.setRowCount(len(methods))
            results_table.setColumnCount(4)
            results_table.setColumnWidth(1, 150)
            results_table.setColumnWidth(2, 150)
            results_table.setMinimumHeight((len(methods) + 1) * 30)
            results_table.setHorizontalHeaderLabels(["Metoda", "Wyniki pozytywne", "Wyniki negatywne",
                                                     "Średni czas [s]"])
            progress_label = QLabel("Postęp:")
            results_progress_bar = QProgressBar()
            results_progress_bar.setValue(0)

            self.results_tables.append(results_table)
            self.results_progress_bars.append(results_progress_bar)
            tables_box_layout.addWidget(vertices_label)
            tables_box_layout.addWidget(results_table)
            tables_box_layout.addWidget(progress_label)
            tables_box_layout.addWidget(results_progress_bar)

            self.all_results.append([])

            for method_index in range(len(methods)):
                method_title = methods[method_index]
                results_table.setItem(method_index, 0, QTableWidgetItem(method_title))
                self.all_results[-1].append([])

    def add_result(self, result, vertices_amount, sample_number):
        # result: [method, decision, time]

        # vertices table index
        table_index = vertices_amount - self.start_vertices

        # method index
        method_index = self.methods.index(result[0])

        # add result to all stored results
        self.all_results[table_index][method_index].append(result)

        # positive and negatives
        # firstly extract 2nd column from results matrix
        new_positives = sum([row[1] for row in self.all_results[table_index][method_index]])
        new_negatives = len(self.all_results[table_index][method_index]) - new_positives

        self.results_tables[table_index].setItem(method_index, 1, QTableWidgetItem(str(new_positives)))
        self.results_tables[table_index].setItem(method_index, 2, QTableWidgetItem(str(new_negatives)))

        # mean
        new_mean = mean([row[2] for row in self.all_results[table_index][method_index]])
        self.results_tables[table_index].setItem(method_index, 3, QTableWidgetItem(str(new_mean)))

        # progress_bar
        self.results_progress_bars[table_index].setValue(sample_number / self.samples_amount * 100)
        self.results_count = self.results_count + 1

        # update plot
        self.update_plot()

    def update_plot(self):
        for method_index in range(len(self.methods)):
            # for this method find all mean values
            x = []
            y = []
            for vertices_index in range(self.all_vertices_amount):
                vertices_amount = vertices_index + self.start_vertices
                if len(self.all_results[vertices_index][method_index]):
                    x.append(vertices_amount)
                    y.append(mean([row[2] for row in self.all_results[vertices_index][method_index]]))
            self.plot_data[method_index].setData(x, y)

    def switch_plot_log(self):
        self.plot_log_mode = not self.plot_log_mode
        self.results_plot.setLogMode(False, self.plot_log_mode)

    def closeEvent(self, event):
        self.parent_window.stop_test = True
Esempio n. 5
0
class SSR_plot(QtGui.QWidget):
    def __init__(self, parent=None):
        QtGui.QWidget.__init__(self, parent)
        self.initGUI()

    def initGUI(self):

        # scheme plot

        self.p_upper_l = PlotWidget()
        self.p_upper_r = PlotWidget()
        self.p_lower_l = PlotWidget()
        self.p_lower_r = PlotWidget()
        self.p_upper_r.setMaximumWidth(300)
        layout = QtGui.QVBoxLayout()

        upperlay = QtGui.QHBoxLayout()
        downlay = QtGui.QHBoxLayout()

        downlay.addWidget(self.p_lower_l)
        downlay.addWidget(self.p_lower_r)

        upperlay.addWidget(self.p_upper_l)
        upperlay.addWidget(self.p_upper_r)
        layout.addLayout(upperlay)
        layout.addLayout(downlay)
        self.setLayout(layout)

        # object oriented style using UTILS_QT.myplot()
        self.scheme_plot = UTILS_QT.myplot(self.p_lower_l,
                                           xlabel=['time', 's'],
                                           ylabel=['', ''],
                                           logmode=False)
        self.data_plot = UTILS_QT.myplot(self.p_upper_l,
                                         xlabel=['time', 's'],
                                         ylabel=['Signal', 'a.u.'],
                                         logmode=False)
        self.standErrorMeans = UTILS_QT.myplot(self.p_lower_r,
                                               xlabel=['freq', 's'],
                                               ylabel=['Relative signal', ''],
                                               logmode=False)
        self.hist = UTILS_QT.myplot(self.p_upper_r,
                                    xlabel=['probability', 'a.u.'],
                                    ylabel=['Counts', 'kcps'],
                                    logmode=False)
        self.hist.plots.append(
            self.p_upper_r.plot([0], [0],
                                stepMode=True,
                                fillLevel=0,
                                brush=(0, 0, 255, 80)))
        self.hist.plots[0].rotate(-90)
        self.psp = UTILS_QT.pulses_scheme_plot(self.scheme_plot)

        self.p_upper_l.setTitle('Data')
        self.p_lower_l.setTitle('Pulses Scheme')
        self.p_lower_r.setTitle('Statistics')
        self.p_upper_r.setTitle('Histogram')

    def plot_histogramm(self, data):

        datay, datax = np.histogram(data, bins=20)
        self.hist.updateSubplot(0, dataX=-datax[0:-1], dataY=datay)