Exemplo n.º 1
0
 def init_colorbar(self):
     """ Create the colorbar """
     self.my_colors = ColorScaleInferno()
     self._color_map = ColorScaleMagma()
     self._cb = ColorBar(self.my_colors.cmap_normed,
                         width=100,
                         cb_min=self._cb_min,
                         cb_max=self._cb_max)
     self.colorbar.addItem(self._cb)
     self.colorbar.hideAxis('bottom')
     self.colorbar.setLabel('left', 'Intensity', units=self.unit)
     self.colorbar.setMouseEnabled(x=False, y=False)
Exemplo n.º 2
0
    def __init_roi_scan_image(self):
        # Get the color scheme
        my_colors = ColorScaleInferno()
        # Setting up display of ROI xy scan image
        self.roi_image = ScanImageItem(axisOrder='row-major', lut=my_colors.lut)
        self._mw.roi_map_ViewWidget.addItem(self.roi_image)
        self._mw.roi_map_ViewWidget.setLabel('bottom', 'X position', units='m')
        self._mw.roi_map_ViewWidget.setLabel('left', 'Y position', units='m')
        self._mw.roi_map_ViewWidget.setAspectLocked(lock=True, ratio=1.0)
        # Set up color bar
        self.roi_cb = ColorBar(my_colors.cmap_normed, 100, 0, 100000)
        self._mw.roi_cb_ViewWidget.addItem(self.roi_cb)
        self._mw.roi_cb_ViewWidget.hideAxis('bottom')
        self._mw.roi_cb_ViewWidget.setLabel('left', 'Fluorescence', units='c/s')
        self._mw.roi_cb_ViewWidget.setMouseEnabled(x=False, y=False)

        # Get scan image from logic and update initialize plot
        self._update_scan_image(self.poimanagerlogic().roi_scan_image,
                                self.poimanagerlogic().roi_scan_image_extent)
        return
Exemplo n.º 3
0
class ODMRGui(GUIBase):
    """
    This is the GUI Class for ODMR measurements
    """

    # declare connectors
    odmrlogic1 = Connector(interface='ODMRAWGLogic')
    savelogic = Connector(interface='SaveLogic')

    sigStartOdmrScan = QtCore.Signal()
    sigStopOdmrScan = QtCore.Signal()
    sigContinueOdmrScan = QtCore.Signal()
    sigClearData = QtCore.Signal()
    sigCwMwOn = QtCore.Signal()
    sigMwOff = QtCore.Signal()
    sigMwPowerChanged = QtCore.Signal(float)
    sigMwCwParamsChanged = QtCore.Signal(float, float)
    sigMwSweepParamsChanged = QtCore.Signal(float, float, float, float)
    sigClockFreqChanged = QtCore.Signal(float)
    sigOversamplingChanged = QtCore.Signal(int)
    sigLockInChanged = QtCore.Signal(bool)
    sigFitChanged = QtCore.Signal(str)
    sigNumberOfLinesChanged = QtCore.Signal(int)
    sigRuntimeChanged = QtCore.Signal(float)
    sigDoFit = QtCore.Signal(str, object, object, int)
    sigSaveMeasurement = QtCore.Signal(str, list, list)
    sigAverageLinesChanged = QtCore.Signal(int)

    def __init__(self, config, **kwargs):
        super().__init__(config=config, **kwargs)

    def on_activate(self):
        """ Definition, configuration and initialisation of the ODMR GUI.

        This init connects all the graphic modules, which were created in the
        *.ui file and configures the event handling between the modules.
        """

        self._odmr_logic = self.odmrlogic1()

        # Use the inherited class 'Ui_ODMRGuiUI' to create now the GUI element:
        self._mw = ODMRMainWindow()
        self._sd = ODMRSettingDialog()

        # Create a QSettings object for the mainwindow and store the actual GUI layout
        self.mwsettings = QtCore.QSettings("QUDI", "ODMR")
        self.mwsettings.setValue("geometry", self._mw.saveGeometry())
        self.mwsettings.setValue("windowState", self._mw.saveState())

        # Get hardware constraints to set limits for input widgets
        constraints = self._odmr_logic.get_hw_constraints()

        # Adjust range of scientific spinboxes above what is possible in Qt Designer
        self._mw.cw_frequency_DoubleSpinBox.setMaximum(
            constraints.max_frequency)
        self._mw.cw_frequency_DoubleSpinBox.setMinimum(
            constraints.min_frequency)
        self._mw.start_freq_DoubleSpinBox.setMaximum(constraints.max_frequency)
        self._mw.start_freq_DoubleSpinBox.setMinimum(constraints.min_frequency)
        self._mw.step_freq_DoubleSpinBox.setMaximum(100e9)
        self._mw.stop_freq_DoubleSpinBox.setMaximum(constraints.max_frequency)
        self._mw.stop_freq_DoubleSpinBox.setMinimum(constraints.min_frequency)
        self._mw.cw_power_DoubleSpinBox.setMaximum(constraints.max_power)
        self._mw.cw_power_DoubleSpinBox.setMinimum(constraints.min_power)
        self._mw.sweep_power_DoubleSpinBox.setMaximum(constraints.max_power)
        self._mw.sweep_power_DoubleSpinBox.setMinimum(constraints.min_power)

        # Add save file tag input box
        self._mw.save_tag_LineEdit = QtWidgets.QLineEdit(self._mw)
        self._mw.save_tag_LineEdit.setMaximumWidth(500)
        self._mw.save_tag_LineEdit.setMinimumWidth(200)
        self._mw.save_tag_LineEdit.setToolTip('Enter a nametag which will be\n'
                                              'added to the filename.')
        self._mw.save_ToolBar.addWidget(self._mw.save_tag_LineEdit)

        # add a clear button to clear the ODMR plots:
        self._mw.clear_odmr_PushButton = QtWidgets.QPushButton(self._mw)
        self._mw.clear_odmr_PushButton.setText('Clear ODMR')
        self._mw.clear_odmr_PushButton.setToolTip('Clear the data of the\n'
                                                  'current ODMR measurements.')
        self._mw.clear_odmr_PushButton.setEnabled(False)
        self._mw.toolBar.addWidget(self._mw.clear_odmr_PushButton)

        # Set up and connect channel combobox
        self.display_channel = 0
        odmr_channels = self._odmr_logic.get_odmr_channels()
        for n, ch in enumerate(odmr_channels):
            self._mw.odmr_channel_ComboBox.addItem(str(ch), n)

        self._mw.odmr_channel_ComboBox.activated.connect(self.update_channel)

        # Get the image from the logic
        self.odmr_matrix_image = pg.ImageItem(
            self._odmr_logic.odmr_plot_xy[:, self.display_channel],
            axisOrder='row-major')
        self.odmr_matrix_image.setRect(
            QtCore.QRectF(self._odmr_logic.mw_start, 0,
                          self._odmr_logic.mw_stop - self._odmr_logic.mw_start,
                          self._odmr_logic.number_of_lines))

        self.odmr_image = pg.PlotDataItem(
            self._odmr_logic.odmr_plot_x,
            self._odmr_logic.odmr_plot_y[self.display_channel],
            pen=pg.mkPen(palette.c1, style=QtCore.Qt.DotLine),
            symbol='o',
            symbolPen=palette.c1,
            symbolBrush=palette.c1,
            symbolSize=7)

        self.odmr_fit_image = pg.PlotDataItem(self._odmr_logic.odmr_fit_x,
                                              self._odmr_logic.odmr_fit_y,
                                              pen=pg.mkPen(palette.c2))

        # Add the display item to the xy and xz ViewWidget, which was defined in the UI file.
        self._mw.odmr_PlotWidget.addItem(self.odmr_image)
        self._mw.odmr_PlotWidget.setLabel(axis='left',
                                          text='Counts',
                                          units='Counts/s')
        self._mw.odmr_PlotWidget.setLabel(axis='bottom',
                                          text='Frequency',
                                          units='Hz')
        self._mw.odmr_PlotWidget.showGrid(x=True, y=True, alpha=0.8)

        self._mw.odmr_matrix_PlotWidget.addItem(self.odmr_matrix_image)
        self._mw.odmr_matrix_PlotWidget.setLabel(axis='left',
                                                 text='Matrix Lines',
                                                 units='#')
        self._mw.odmr_matrix_PlotWidget.setLabel(axis='bottom',
                                                 text='Frequency',
                                                 units='Hz')

        # Get the colorscales at set LUT
        my_colors = ColorScaleInferno()
        self.odmr_matrix_image.setLookupTable(my_colors.lut)

        ########################################################################
        #                  Configuration of the Colorbar                       #
        ########################################################################
        self.odmr_cb = ColorBar(my_colors.cmap_normed, 100, 0, 100000)

        # adding colorbar to ViewWidget
        self._mw.odmr_cb_PlotWidget.addItem(self.odmr_cb)
        self._mw.odmr_cb_PlotWidget.hideAxis('bottom')
        self._mw.odmr_cb_PlotWidget.hideAxis('left')
        self._mw.odmr_cb_PlotWidget.setLabel('right',
                                             'Fluorescence',
                                             units='counts/s')

        ########################################################################
        #          Configuration of the various display Widgets                #
        ########################################################################
        # Take the default values from logic:
        self._mw.cw_frequency_DoubleSpinBox.setValue(
            self._odmr_logic.cw_mw_frequency)
        self._mw.start_freq_DoubleSpinBox.setValue(self._odmr_logic.mw_start)
        self._mw.stop_freq_DoubleSpinBox.setValue(self._odmr_logic.mw_stop)
        self._mw.step_freq_DoubleSpinBox.setValue(self._odmr_logic.mw_step)
        self._mw.cw_power_DoubleSpinBox.setValue(self._odmr_logic.cw_mw_power)
        self._mw.sweep_power_DoubleSpinBox.setValue(
            self._odmr_logic.sweep_mw_power)

        self._mw.runtime_DoubleSpinBox.setValue(self._odmr_logic.run_time)
        self._mw.elapsed_time_DisplayWidget.display(
            int(np.rint(self._odmr_logic.elapsed_time)))
        self._mw.elapsed_sweeps_DisplayWidget.display(
            self._odmr_logic.elapsed_sweeps)
        self._mw.average_level_SpinBox.setValue(
            self._odmr_logic.lines_to_average)

        self._sd.matrix_lines_SpinBox.setValue(
            self._odmr_logic.number_of_lines)
        self._sd.clock_frequency_DoubleSpinBox.setValue(
            self._odmr_logic.clock_frequency)
        self._sd.oversampling_SpinBox.setValue(self._odmr_logic.oversampling)
        self._sd.lock_in_CheckBox.setChecked(self._odmr_logic.lock_in)

        # fit settings
        self._fsd = FitSettingsDialog(self._odmr_logic.fc)
        self._fsd.sigFitsUpdated.connect(
            self._mw.fit_methods_ComboBox.setFitFunctions)
        self._fsd.applySettings()
        self._mw.action_FitSettings.triggered.connect(self._fsd.show)

        ########################################################################
        #                       Connect signals                                #
        ########################################################################
        # Internal user input changed signals
        self._mw.cw_frequency_DoubleSpinBox.editingFinished.connect(
            self.change_cw_params)
        self._mw.start_freq_DoubleSpinBox.editingFinished.connect(
            self.change_sweep_params)
        self._mw.step_freq_DoubleSpinBox.editingFinished.connect(
            self.change_sweep_params)
        self._mw.stop_freq_DoubleSpinBox.editingFinished.connect(
            self.change_sweep_params)
        self._mw.sweep_power_DoubleSpinBox.editingFinished.connect(
            self.change_sweep_params)
        self._mw.cw_power_DoubleSpinBox.editingFinished.connect(
            self.change_cw_params)
        self._mw.runtime_DoubleSpinBox.editingFinished.connect(
            self.change_runtime)
        self._mw.odmr_cb_max_DoubleSpinBox.valueChanged.connect(
            self.colorscale_changed)
        self._mw.odmr_cb_min_DoubleSpinBox.valueChanged.connect(
            self.colorscale_changed)
        self._mw.odmr_cb_high_percentile_DoubleSpinBox.valueChanged.connect(
            self.colorscale_changed)
        self._mw.odmr_cb_low_percentile_DoubleSpinBox.valueChanged.connect(
            self.colorscale_changed)
        self._mw.average_level_SpinBox.valueChanged.connect(
            self.average_level_changed)
        # Internal trigger signals
        self._mw.odmr_cb_manual_RadioButton.clicked.connect(
            self.colorscale_changed)
        self._mw.odmr_cb_centiles_RadioButton.clicked.connect(
            self.colorscale_changed)
        self._mw.clear_odmr_PushButton.clicked.connect(self.clear_odmr_data)
        self._mw.action_run_stop.triggered.connect(self.run_stop_odmr)
        self._mw.action_resume_odmr.triggered.connect(self.resume_odmr)
        self._mw.action_toggle_cw.triggered.connect(self.toggle_cw_mode)
        self._mw.action_Save.triggered.connect(self.save_data)
        self._mw.action_RestoreDefault.triggered.connect(
            self.restore_defaultview)
        self._mw.do_fit_PushButton.clicked.connect(self.do_fit)

        # Control/values-changed signals to logic
        self.sigCwMwOn.connect(self._odmr_logic.mw_cw_on,
                               QtCore.Qt.QueuedConnection)
        self.sigMwOff.connect(self._odmr_logic.mw_off,
                              QtCore.Qt.QueuedConnection)
        self.sigClearData.connect(self._odmr_logic.clear_odmr_data,
                                  QtCore.Qt.QueuedConnection)
        self.sigStartOdmrScan.connect(self._odmr_logic.start_odmr_scan,
                                      QtCore.Qt.QueuedConnection)
        self.sigStopOdmrScan.connect(self._odmr_logic.stop_odmr_scan,
                                     QtCore.Qt.QueuedConnection)
        self.sigContinueOdmrScan.connect(self._odmr_logic.continue_odmr_scan,
                                         QtCore.Qt.QueuedConnection)
        self.sigDoFit.connect(self._odmr_logic.do_fit,
                              QtCore.Qt.QueuedConnection)
        self.sigMwCwParamsChanged.connect(self._odmr_logic.set_cw_parameters,
                                          QtCore.Qt.QueuedConnection)
        self.sigMwSweepParamsChanged.connect(
            self._odmr_logic.set_sweep_parameters, QtCore.Qt.QueuedConnection)
        self.sigRuntimeChanged.connect(self._odmr_logic.set_runtime,
                                       QtCore.Qt.QueuedConnection)
        self.sigNumberOfLinesChanged.connect(
            self._odmr_logic.set_matrix_line_number,
            QtCore.Qt.QueuedConnection)
        self.sigClockFreqChanged.connect(self._odmr_logic.set_clock_frequency,
                                         QtCore.Qt.QueuedConnection)
        self.sigOversamplingChanged.connect(self._odmr_logic.set_oversampling,
                                            QtCore.Qt.QueuedConnection)
        self.sigLockInChanged.connect(self._odmr_logic.set_lock_in,
                                      QtCore.Qt.QueuedConnection)
        self.sigSaveMeasurement.connect(self._odmr_logic.save_odmr_data,
                                        QtCore.Qt.QueuedConnection)
        self.sigAverageLinesChanged.connect(
            self._odmr_logic.set_average_length, QtCore.Qt.QueuedConnection)

        # Update signals coming from logic:
        self._odmr_logic.sigParameterUpdated.connect(
            self.update_parameter, QtCore.Qt.QueuedConnection)
        self._odmr_logic.sigOutputStateUpdated.connect(
            self.update_status, QtCore.Qt.QueuedConnection)
        self._odmr_logic.sigOdmrPlotsUpdated.connect(
            self.update_plots, QtCore.Qt.QueuedConnection)
        self._odmr_logic.sigOdmrFitUpdated.connect(self.update_fit,
                                                   QtCore.Qt.QueuedConnection)
        self._odmr_logic.sigOdmrElapsedTimeUpdated.connect(
            self.update_elapsedtime, QtCore.Qt.QueuedConnection)

        # connect settings signals
        self._mw.action_Settings.triggered.connect(self._menu_settings)
        self._sd.accepted.connect(self.update_settings)
        self._sd.rejected.connect(self.reject_settings)
        self._sd.buttonBox.button(
            QtWidgets.QDialogButtonBox.Apply).clicked.connect(
                self.update_settings)
        self.reject_settings()

        # Show the Main ODMR GUI:
        self.show()

    def on_deactivate(self):
        """ Reverse steps of activation

        @return int: error code (0:OK, -1:error)
        """
        # Disconnect signals
        self._sd.buttonBox.button(
            QtWidgets.QDialogButtonBox.Apply).clicked.disconnect()
        self._sd.accepted.disconnect()
        self._sd.rejected.disconnect()
        self._mw.action_Settings.triggered.disconnect()
        self._odmr_logic.sigParameterUpdated.disconnect()
        self._odmr_logic.sigOutputStateUpdated.disconnect()
        self._odmr_logic.sigOdmrPlotsUpdated.disconnect()
        self._odmr_logic.sigOdmrFitUpdated.disconnect()
        self._odmr_logic.sigOdmrElapsedTimeUpdated.disconnect()
        self.sigCwMwOn.disconnect()
        self.sigMwOff.disconnect()
        self.sigClearData.disconnect()
        self.sigStartOdmrScan.disconnect()
        self.sigStopOdmrScan.disconnect()
        self.sigContinueOdmrScan.disconnect()
        self.sigDoFit.disconnect()
        self.sigMwCwParamsChanged.disconnect()
        self.sigMwSweepParamsChanged.disconnect()
        self.sigRuntimeChanged.disconnect()
        self.sigNumberOfLinesChanged.disconnect()
        self.sigClockFreqChanged.disconnect()
        self.sigOversamplingChanged.disconnect()
        self.sigLockInChanged.disconnect()
        self.sigSaveMeasurement.disconnect()
        self.sigAverageLinesChanged.disconnect()
        self._mw.odmr_cb_manual_RadioButton.clicked.disconnect()
        self._mw.odmr_cb_centiles_RadioButton.clicked.disconnect()
        self._mw.clear_odmr_PushButton.clicked.disconnect()
        self._mw.action_run_stop.triggered.disconnect()
        self._mw.action_resume_odmr.triggered.disconnect()
        self._mw.action_Save.triggered.disconnect()
        self._mw.action_toggle_cw.triggered.disconnect()
        self._mw.action_RestoreDefault.triggered.disconnect()
        self._mw.do_fit_PushButton.clicked.disconnect()
        self._mw.cw_frequency_DoubleSpinBox.editingFinished.disconnect()
        self._mw.start_freq_DoubleSpinBox.editingFinished.disconnect()
        self._mw.step_freq_DoubleSpinBox.editingFinished.disconnect()
        self._mw.stop_freq_DoubleSpinBox.editingFinished.disconnect()
        self._mw.cw_power_DoubleSpinBox.editingFinished.disconnect()
        self._mw.sweep_power_DoubleSpinBox.editingFinished.disconnect()
        self._mw.runtime_DoubleSpinBox.editingFinished.disconnect()
        self._mw.odmr_cb_max_DoubleSpinBox.valueChanged.disconnect()
        self._mw.odmr_cb_min_DoubleSpinBox.valueChanged.disconnect()
        self._mw.odmr_cb_high_percentile_DoubleSpinBox.valueChanged.disconnect(
        )
        self._mw.odmr_cb_low_percentile_DoubleSpinBox.valueChanged.disconnect()
        self._mw.average_level_SpinBox.valueChanged.disconnect()
        self._fsd.sigFitsUpdated.disconnect()
        self._mw.action_FitSettings.triggered.disconnect()
        self._mw.close()
        return 0

    def show(self):
        """Make window visible and put it above all other windows. """
        self._mw.show()
        self._mw.activateWindow()
        self._mw.raise_()

    def _menu_settings(self):
        """ Open the settings menu """
        self._sd.exec_()

    def run_stop_odmr(self, is_checked):
        """ Manages what happens if odmr scan is started/stopped. """
        if is_checked:
            # change the axes appearance according to input values:
            self._mw.action_run_stop.setEnabled(False)
            self._mw.action_resume_odmr.setEnabled(False)
            self._mw.action_toggle_cw.setEnabled(False)
            self._mw.odmr_PlotWidget.removeItem(self.odmr_fit_image)
            self._mw.cw_power_DoubleSpinBox.setEnabled(False)
            self._mw.sweep_power_DoubleSpinBox.setEnabled(False)
            self._mw.cw_frequency_DoubleSpinBox.setEnabled(False)
            self._mw.start_freq_DoubleSpinBox.setEnabled(False)
            self._mw.step_freq_DoubleSpinBox.setEnabled(False)
            self._mw.stop_freq_DoubleSpinBox.setEnabled(False)
            self._mw.runtime_DoubleSpinBox.setEnabled(False)
            self._sd.clock_frequency_DoubleSpinBox.setEnabled(False)
            self._sd.oversampling_SpinBox.setEnabled(False)
            self._sd.lock_in_CheckBox.setEnabled(False)
            self.sigStartOdmrScan.emit()
        else:
            self._mw.action_run_stop.setEnabled(False)
            self._mw.action_resume_odmr.setEnabled(False)
            self._mw.action_toggle_cw.setEnabled(False)
            self.sigStopOdmrScan.emit()
        return

    def resume_odmr(self, is_checked):
        if is_checked:
            self._mw.action_run_stop.setEnabled(False)
            self._mw.action_resume_odmr.setEnabled(False)
            self._mw.action_toggle_cw.setEnabled(False)
            self._mw.cw_power_DoubleSpinBox.setEnabled(False)
            self._mw.sweep_power_DoubleSpinBox.setEnabled(False)
            self._mw.cw_frequency_DoubleSpinBox.setEnabled(False)
            self._mw.start_freq_DoubleSpinBox.setEnabled(False)
            self._mw.step_freq_DoubleSpinBox.setEnabled(False)
            self._mw.stop_freq_DoubleSpinBox.setEnabled(False)
            self._mw.runtime_DoubleSpinBox.setEnabled(False)
            self._sd.clock_frequency_DoubleSpinBox.setEnabled(False)
            self._sd.oversampling_SpinBox.setEnabled(False)
            self._sd.lock_in_CheckBox.setEnabled(False)
            self.sigContinueOdmrScan.emit()
        else:
            self._mw.action_run_stop.setEnabled(False)
            self._mw.action_resume_odmr.setEnabled(False)
            self._mw.action_toggle_cw.setEnabled(False)
            self.sigStopOdmrScan.emit()
        return

    def toggle_cw_mode(self, is_checked):
        """ Starts or stops CW microwave output if no measurement is running. """
        if is_checked:
            self._mw.action_run_stop.setEnabled(False)
            self._mw.action_resume_odmr.setEnabled(False)
            self._mw.action_toggle_cw.setEnabled(False)
            self._mw.cw_power_DoubleSpinBox.setEnabled(False)
            self._mw.cw_frequency_DoubleSpinBox.setEnabled(False)
            self.sigCwMwOn.emit()
        else:
            self._mw.action_toggle_cw.setEnabled(False)
            self.sigMwOff.emit()
        return

    def update_status(self, mw_mode, is_running):
        """
        Update the display for a change in the microwave status (mode and output).

        @param str mw_mode: is the microwave output active?
        @param bool is_running: is the microwave output active?
        """
        # Block signals from firing
        self._mw.action_run_stop.blockSignals(True)
        self._mw.action_resume_odmr.blockSignals(True)
        self._mw.action_toggle_cw.blockSignals(True)

        # Update measurement status (activate/deactivate widgets/actions)
        if is_running:
            self._mw.action_resume_odmr.setEnabled(False)
            self._mw.cw_power_DoubleSpinBox.setEnabled(False)
            self._mw.cw_frequency_DoubleSpinBox.setEnabled(False)
            if mw_mode != 'cw':
                self._mw.clear_odmr_PushButton.setEnabled(True)
                self._mw.action_run_stop.setEnabled(True)
                self._mw.action_toggle_cw.setEnabled(False)
                self._mw.start_freq_DoubleSpinBox.setEnabled(False)
                self._mw.step_freq_DoubleSpinBox.setEnabled(False)
                self._mw.stop_freq_DoubleSpinBox.setEnabled(False)
                self._mw.sweep_power_DoubleSpinBox.setEnabled(False)
                self._mw.runtime_DoubleSpinBox.setEnabled(False)
                self._sd.clock_frequency_DoubleSpinBox.setEnabled(False)
                self._sd.oversampling_SpinBox.setEnabled(False)
                self._sd.lock_in_CheckBox.setEnabled(False)
                self._mw.action_run_stop.setChecked(True)
                self._mw.action_resume_odmr.setChecked(True)
                self._mw.action_toggle_cw.setChecked(False)
            else:
                self._mw.clear_odmr_PushButton.setEnabled(False)
                self._mw.action_run_stop.setEnabled(False)
                self._mw.action_toggle_cw.setEnabled(True)
                self._mw.start_freq_DoubleSpinBox.setEnabled(True)
                self._mw.step_freq_DoubleSpinBox.setEnabled(True)
                self._mw.stop_freq_DoubleSpinBox.setEnabled(True)
                self._mw.sweep_power_DoubleSpinBox.setEnabled(True)
                self._mw.runtime_DoubleSpinBox.setEnabled(True)
                self._sd.clock_frequency_DoubleSpinBox.setEnabled(True)
                self._sd.oversampling_SpinBox.setEnabled(True)
                self._sd.lock_in_CheckBox.setEnabled(True)
                self._mw.action_run_stop.setChecked(False)
                self._mw.action_resume_odmr.setChecked(False)
                self._mw.action_toggle_cw.setChecked(True)
        else:
            self._mw.action_resume_odmr.setEnabled(True)
            self._mw.cw_power_DoubleSpinBox.setEnabled(True)
            self._mw.sweep_power_DoubleSpinBox.setEnabled(True)
            self._mw.cw_frequency_DoubleSpinBox.setEnabled(True)
            self._mw.clear_odmr_PushButton.setEnabled(False)
            self._mw.action_run_stop.setEnabled(True)
            self._mw.action_toggle_cw.setEnabled(True)
            self._mw.start_freq_DoubleSpinBox.setEnabled(True)
            self._mw.step_freq_DoubleSpinBox.setEnabled(True)
            self._mw.stop_freq_DoubleSpinBox.setEnabled(True)
            self._mw.runtime_DoubleSpinBox.setEnabled(True)
            self._sd.clock_frequency_DoubleSpinBox.setEnabled(True)
            self._sd.oversampling_SpinBox.setEnabled(True)
            self._sd.lock_in_CheckBox.setEnabled(True)
            self._mw.action_run_stop.setChecked(False)
            self._mw.action_resume_odmr.setChecked(False)
            self._mw.action_toggle_cw.setChecked(False)

        # Unblock signal firing
        self._mw.action_run_stop.blockSignals(False)
        self._mw.action_resume_odmr.blockSignals(False)
        self._mw.action_toggle_cw.blockSignals(False)
        return

    def clear_odmr_data(self):
        """ Clear the ODMR data. """
        self.sigClearData.emit()
        return

    def update_plots(self, odmr_data_x, odmr_data_y, odmr_matrix):
        """ Refresh the plot widgets with new data. """
        # Update mean signal plot
        self.odmr_image.setData(odmr_data_x, odmr_data_y[self.display_channel])
        # Update raw data matrix plot
        cb_range = self.get_matrix_cb_range()
        self.update_colorbar(cb_range)
        self.odmr_matrix_image.setRect(
            QtCore.QRectF(odmr_data_x[0], 0,
                          np.abs(odmr_data_x[-1] - odmr_data_x[0]),
                          odmr_matrix.shape[0]))
        self.odmr_matrix_image.setImage(
            image=odmr_matrix[:, self.display_channel],
            axisOrder='row-major',
            levels=(cb_range[0], cb_range[1]))

    def update_channel(self, index):
        self.display_channel = int(
            self._mw.odmr_channel_ComboBox.itemData(index, QtCore.Qt.UserRole))
        self.update_plots(self._odmr_logic.odmr_plot_x,
                          self._odmr_logic.odmr_plot_y,
                          self._odmr_logic.odmr_plot_xy)

    def average_level_changed(self):
        """
        Sends to lines to average to the logic
        """
        self.sigAverageLinesChanged.emit(
            self._mw.average_level_SpinBox.value())
        return

    def colorscale_changed(self):
        """
        Updates the range of the displayed colorscale in both the colorbar and the matrix plot.
        """
        cb_range = self.get_matrix_cb_range()
        self.update_colorbar(cb_range)
        matrix_image = self.odmr_matrix_image.image
        self.odmr_matrix_image.setImage(image=matrix_image,
                                        levels=(cb_range[0], cb_range[1]))
        return

    def update_colorbar(self, cb_range):
        """
        Update the colorbar to a new range.

        @param list cb_range: List or tuple containing the min and max values for the cb range
        """
        self.odmr_cb.refresh_colorbar(cb_range[0], cb_range[1])
        return

    def get_matrix_cb_range(self):
        """
        Determines the cb_min and cb_max values for the matrix plot
        """
        matrix_image = self.odmr_matrix_image.image

        # If "Manual" is checked or the image is empty (all zeros), then take manual cb range.
        # Otherwise, calculate cb range from percentiles.
        if self._mw.odmr_cb_manual_RadioButton.isChecked(
        ) or np.count_nonzero(matrix_image) < 1:
            cb_min = self._mw.odmr_cb_min_DoubleSpinBox.value()
            cb_max = self._mw.odmr_cb_max_DoubleSpinBox.value()
        else:
            # Exclude any zeros (which are typically due to unfinished scan)
            matrix_image_nonzero = matrix_image[np.nonzero(matrix_image)]

            # Read centile range
            low_centile = self._mw.odmr_cb_low_percentile_DoubleSpinBox.value()
            high_centile = self._mw.odmr_cb_high_percentile_DoubleSpinBox.value(
            )

            cb_min = np.percentile(matrix_image_nonzero, low_centile)
            cb_max = np.percentile(matrix_image_nonzero, high_centile)

        cb_range = [cb_min, cb_max]
        return cb_range

    def restore_defaultview(self):
        self._mw.restoreGeometry(self.mwsettings.value("geometry", ""))
        self._mw.restoreState(self.mwsettings.value("windowState", ""))

    def update_elapsedtime(self, elapsed_time, scanned_lines):
        """ Updates current elapsed measurement time and completed frequency sweeps """
        self._mw.elapsed_time_DisplayWidget.display(int(np.rint(elapsed_time)))
        self._mw.elapsed_sweeps_DisplayWidget.display(scanned_lines)
        return

    def update_settings(self):
        """ Write the new settings from the gui to the file. """
        number_of_lines = self._sd.matrix_lines_SpinBox.value()
        clock_frequency = self._sd.clock_frequency_DoubleSpinBox.value()
        oversampling = self._sd.oversampling_SpinBox.value()
        lock_in = self._sd.lock_in_CheckBox.isChecked()
        self.sigOversamplingChanged.emit(oversampling)
        self.sigLockInChanged.emit(lock_in)
        self.sigClockFreqChanged.emit(clock_frequency)
        self.sigNumberOfLinesChanged.emit(number_of_lines)
        return

    def reject_settings(self):
        """ Keep the old settings and restores the old settings in the gui. """
        self._sd.matrix_lines_SpinBox.setValue(
            self._odmr_logic.number_of_lines)
        self._sd.clock_frequency_DoubleSpinBox.setValue(
            self._odmr_logic.clock_frequency)
        self._sd.oversampling_SpinBox.setValue(self._odmr_logic.oversampling)
        self._sd.lock_in_CheckBox.setChecked(self._odmr_logic.lock_in)
        return

    def do_fit(self):
        fit_function = self._mw.fit_methods_ComboBox.getCurrentFit()[0]
        self.sigDoFit.emit(fit_function, None, None,
                           self._mw.odmr_channel_ComboBox.currentIndex())
        return

    def update_fit(self, x_data, y_data, result_str_dict, current_fit):
        """ Update the shown fit. """
        if current_fit != 'No Fit':
            # display results as formatted text
            self._mw.odmr_fit_results_DisplayWidget.clear()
            try:
                formated_results = units.create_formatted_output(
                    result_str_dict)
            except:
                formated_results = 'this fit does not return formatted results'
            self._mw.odmr_fit_results_DisplayWidget.setPlainText(
                formated_results)

        self._mw.fit_methods_ComboBox.blockSignals(True)
        self._mw.fit_methods_ComboBox.setCurrentFit(current_fit)
        self._mw.fit_methods_ComboBox.blockSignals(False)

        # check which Fit method is used and remove or add again the
        # odmr_fit_image, check also whether a odmr_fit_image already exists.
        if current_fit != 'No Fit':
            self.odmr_fit_image.setData(x=x_data, y=y_data)
            if self.odmr_fit_image not in self._mw.odmr_PlotWidget.listDataItems(
            ):
                self._mw.odmr_PlotWidget.addItem(self.odmr_fit_image)
        else:
            if self.odmr_fit_image in self._mw.odmr_PlotWidget.listDataItems():
                self._mw.odmr_PlotWidget.removeItem(self.odmr_fit_image)

        self._mw.odmr_PlotWidget.getViewBox().updateAutoRange()
        return

    def update_parameter(self, param_dict):
        """ Update the parameter display in the GUI.

        @param param_dict:
        @return:

        Any change event from the logic should call this update function.
        The update will block the GUI signals from emitting a change back to the
        logic.
        """
        param = param_dict.get('sweep_mw_power')
        if param is not None:
            self._mw.sweep_power_DoubleSpinBox.blockSignals(True)
            self._mw.sweep_power_DoubleSpinBox.setValue(param)
            self._mw.sweep_power_DoubleSpinBox.blockSignals(False)

        param = param_dict.get('mw_start')
        if param is not None:
            self._mw.start_freq_DoubleSpinBox.blockSignals(True)
            self._mw.start_freq_DoubleSpinBox.setValue(param)
            self._mw.start_freq_DoubleSpinBox.blockSignals(False)

        param = param_dict.get('mw_step')
        if param is not None:
            self._mw.step_freq_DoubleSpinBox.blockSignals(True)
            self._mw.step_freq_DoubleSpinBox.setValue(param)
            self._mw.step_freq_DoubleSpinBox.blockSignals(False)

        param = param_dict.get('mw_stop')
        if param is not None:
            self._mw.stop_freq_DoubleSpinBox.blockSignals(True)
            self._mw.stop_freq_DoubleSpinBox.setValue(param)
            self._mw.stop_freq_DoubleSpinBox.blockSignals(False)

        param = param_dict.get('run_time')
        if param is not None:
            self._mw.runtime_DoubleSpinBox.blockSignals(True)
            self._mw.runtime_DoubleSpinBox.setValue(param)
            self._mw.runtime_DoubleSpinBox.blockSignals(False)

        param = param_dict.get('number_of_lines')
        if param is not None:
            self._sd.matrix_lines_SpinBox.blockSignals(True)
            self._sd.matrix_lines_SpinBox.setValue(param)
            self._sd.matrix_lines_SpinBox.blockSignals(False)

        param = param_dict.get('clock_frequency')
        if param is not None:
            self._sd.clock_frequency_DoubleSpinBox.blockSignals(True)
            self._sd.clock_frequency_DoubleSpinBox.setValue(param)
            self._sd.clock_frequency_DoubleSpinBox.blockSignals(False)

        param = param_dict.get('oversampling')
        if param is not None:
            self._sd.oversampling_SpinBox.blockSignals(True)
            self._sd.oversampling_SpinBox.setValue(param)
            self._sd.oversampling_SpinBox.blockSignals(False)

        param = param_dict.get('lock_in')
        if param is not None:
            self._sd.lock_in_CheckBox.blockSignals(True)
            self._sd.lock_in_CheckBox.setChecked(param)
            self._sd.lock_in_CheckBox.blockSignals(False)

        param = param_dict.get('cw_mw_frequency')
        if param is not None:
            self._mw.cw_frequency_DoubleSpinBox.blockSignals(True)
            self._mw.cw_frequency_DoubleSpinBox.setValue(param)
            self._mw.cw_frequency_DoubleSpinBox.blockSignals(False)

        param = param_dict.get('cw_mw_power')
        if param is not None:
            self._mw.cw_power_DoubleSpinBox.blockSignals(True)
            self._mw.cw_power_DoubleSpinBox.setValue(param)
            self._mw.cw_power_DoubleSpinBox.blockSignals(False)

        param = param_dict.get('average_length')
        if param is not None:
            self._mw.average_level_SpinBox.blockSignals(True)
            self._mw.average_level_SpinBox.setValue(param)
            self._mw.average_level_SpinBox.blockSignals(False)
        return

    ############################################################################
    #                           Change Methods                                 #
    ############################################################################

    def change_cw_params(self):
        """ Change CW frequency and power of microwave source """
        frequency = self._mw.cw_frequency_DoubleSpinBox.value()
        power = self._mw.cw_power_DoubleSpinBox.value()
        self.sigMwCwParamsChanged.emit(frequency, power)
        return

    def change_sweep_params(self):
        """ Change start, stop and step frequency of frequency sweep """
        start = self._mw.start_freq_DoubleSpinBox.value()
        stop = self._mw.stop_freq_DoubleSpinBox.value()
        step = self._mw.step_freq_DoubleSpinBox.value()
        power = self._mw.sweep_power_DoubleSpinBox.value()
        self.sigMwSweepParamsChanged.emit(start, stop, step, power)
        return

    def change_runtime(self):
        """ Change time after which microwave sweep is stopped """
        runtime = self._mw.runtime_DoubleSpinBox.value()
        self.sigRuntimeChanged.emit(runtime)
        return

    def save_data(self):
        """ Save the sum plot, the scan marix plot and the scan data """
        filetag = self._mw.save_tag_LineEdit.text()
        cb_range = self.get_matrix_cb_range()

        # Percentile range is None, unless the percentile scaling is selected in GUI.
        pcile_range = None
        if self._mw.odmr_cb_centiles_RadioButton.isChecked():
            low_centile = self._mw.odmr_cb_low_percentile_DoubleSpinBox.value()
            high_centile = self._mw.odmr_cb_high_percentile_DoubleSpinBox.value(
            )
            pcile_range = [low_centile, high_centile]

        self.sigSaveMeasurement.emit(filetag, cb_range, pcile_range)
        return
Exemplo n.º 4
0
    def on_activate(self):
        """ 

        """
        self._voltscan_logic = self.get_connector('voltagescannerlogic1')
        self._savelogic = self.get_connector('savelogic')

        # Use the inherited class 'Ui_VoltagescannerGuiUI' to create now the
        # GUI element:
        self._mw = VoltScanMainWindow()

        # Add save file tag input box
        self._mw.save_tag_LineEdit = QtWidgets.QLineEdit(self._mw)
        self._mw.save_tag_LineEdit.setMaximumWidth(500)
        self._mw.save_tag_LineEdit.setMinimumWidth(200)
        self._mw.save_tag_LineEdit.setToolTip('Enter a nametag which will be\n'
                                              'added to the filename.')
        self._mw.toolBar.addWidget(self._mw.save_tag_LineEdit)

        # Get the image from the logic
        self.scan_matrix_image = pg.ImageItem(
            self._voltscan_logic.scan_matrix,
            axisOrder='row-major')

        self.scan_matrix_image.setRect(
            QtCore.QRectF(
                self._voltscan_logic.scan_range[0],
                0,
                self._voltscan_logic.scan_range[1] - self._voltscan_logic.scan_range[0],
                self._voltscan_logic.number_of_repeats)
        )

        self.scan_matrix_image2 = pg.ImageItem(
            self._voltscan_logic.scan_matrix2,
            axisOrder='row-major')

        self.scan_matrix_image2.setRect(
            QtCore.QRectF(
                self._voltscan_logic.scan_range[0],
                0,
                self._voltscan_logic.scan_range[1] - self._voltscan_logic.scan_range[0],
                self._voltscan_logic.number_of_repeats)
        )

        self.scan_image = pg.PlotDataItem(
            self._voltscan_logic.plot_x,
            self._voltscan_logic.plot_y)

        self.scan_image2 = pg.PlotDataItem(
            self._voltscan_logic.plot_x,
            self._voltscan_logic.plot_y2)

        self.scan_fit_image = pg.PlotDataItem(
            self._voltscan_logic.fit_x,
            self._voltscan_logic.fit_y,
            pen=QtGui.QPen(QtGui.QColor(255, 255, 255, 255)))

        # Add the display item to the xy and xz VieWidget, which was defined in
        # the UI file.
        self._mw.voltscan_ViewWidget.addItem(self.scan_image)
        #self._mw.voltscan_ViewWidget.addItem(self.scan_fit_image)
        self._mw.voltscan_ViewWidget.showGrid(x=True, y=True, alpha=0.8)
        self._mw.voltscan_matrix_ViewWidget.addItem(self.scan_matrix_image)

        self._mw.voltscan2_ViewWidget.addItem(self.scan_image2)
        #self._mw.voltscan2_ViewWidget.addItem(self.scan_fit_image)
        self._mw.voltscan2_ViewWidget.showGrid(x=True, y=True, alpha=0.8)
        self._mw.voltscan_matrix2_ViewWidget.addItem(self.scan_matrix_image2)

        # Get the colorscales at set LUT
        my_colors = ColorScaleInferno()

        self.scan_matrix_image.setLookupTable(my_colors.lut)
        self.scan_matrix_image2.setLookupTable(my_colors.lut)

        # Configuration of the Colorbar
        self.scan_cb = ColorBar(my_colors.cmap_normed, 100, 0, 100000)

        #adding colorbar to ViewWidget
        self._mw.voltscan_cb_ViewWidget.addItem(self.scan_cb)
        self._mw.voltscan_cb_ViewWidget.hideAxis('bottom')
        self._mw.voltscan_cb_ViewWidget.hideAxis('left')
        self._mw.voltscan_cb_ViewWidget.setLabel('right', 'Fluorescence', units='c/s')

        # Connect the buttons and inputs for colorbar
        self._mw.voltscan_cb_manual_RadioButton.clicked.connect(self.refresh_matrix)
        self._mw.voltscan_cb_centiles_RadioButton.clicked.connect(self.refresh_matrix)

        # set initial values
        self._mw.startDoubleSpinBox.setValue(self._voltscan_logic.scan_range[0])
        self._mw.speedDoubleSpinBox.setValue(self._voltscan_logic._scan_speed)
        self._mw.stopDoubleSpinBox.setValue(self._voltscan_logic.scan_range[1])
        self._mw.constDoubleSpinBox.setValue(self._voltscan_logic._static_v)
        self._mw.resolutionSpinBox.setValue(self._voltscan_logic.resolution)
        self._mw.linesSpinBox.setValue(self._voltscan_logic.number_of_repeats)

        # Update the inputed/displayed numbers if the cursor has left the field:
        self._mw.startDoubleSpinBox.editingFinished.connect(self.change_start_volt)
        self._mw.speedDoubleSpinBox.editingFinished.connect(self.change_speed)
        self._mw.stopDoubleSpinBox.editingFinished.connect(self.change_stop_volt)
        self._mw.resolutionSpinBox.editingFinished.connect(self.change_resolution)
        self._mw.linesSpinBox.editingFinished.connect(self.change_lines)
        self._mw.constDoubleSpinBox.editingFinished.connect(self.change_voltage)

        #
        self._mw.voltscan_cb_max_InputWidget.valueChanged.connect(self.refresh_matrix)
        self._mw.voltscan_cb_min_InputWidget.valueChanged.connect(self.refresh_matrix)
        self._mw.voltscan_cb_high_centile_InputWidget.valueChanged.connect(self.refresh_matrix)
        self._mw.voltscan_cb_low_centile_InputWidget.valueChanged.connect(self.refresh_matrix)

        # Connect signals
        self._voltscan_logic.sigUpdatePlots.connect(self.refresh_matrix)
        self._voltscan_logic.sigUpdatePlots.connect(self.refresh_plot)
        self._voltscan_logic.sigUpdatePlots.connect(self.refresh_lines)
        self._voltscan_logic.sigScanFinished.connect(self.scan_stopped)
        self._voltscan_logic.sigScanStarted.connect(self.scan_started)

        self.sigStartScan.connect(self._voltscan_logic.start_scanning)
        self.sigStopScan.connect(self._voltscan_logic.stop_scanning)
        self.sigChangeVoltage.connect(self._voltscan_logic.set_voltage)
        self.sigChangeRange.connect(self._voltscan_logic.set_scan_range)
        self.sigChangeSpeed.connect(self._voltscan_logic.set_scan_speed)
        self.sigChangeLines.connect(self._voltscan_logic.set_scan_lines)
        self.sigChangeResolution.connect(self._voltscan_logic.set_resolution)
        self.sigSaveMeasurement.connect(self._voltscan_logic.save_data)

        self._mw.action_run_stop.triggered.connect(self.run_stop)
        self._mw.action_Save.triggered.connect(self.save_data)
        self._mw.show()
Exemplo n.º 5
0
class PoiManagerGui(GUIBase):
    """ This is the GUI Class for PoiManager """

    _modclass = 'PoiManagerGui'
    _modtype = 'gui'

    # declare connectors
    poimanagerlogic1 = Connector(interface='PoiManagerLogic')
    confocallogic1 = Connector(interface='ConfocalLogic')

    def __init__(self, config, **kwargs):
        super().__init__(config=config, **kwargs)

    def on_activate(self):
        """ Initializes the overall GUI, and establishes the connectors.

        This method executes the init methods for each of the GUIs.
        """

        # Connectors
        self._poi_manager_logic = self.poimanagerlogic1()
        self._confocal_logic = self.confocallogic1()
        self.log.debug("POI Manager logic is {0}".format(
            self._poi_manager_logic))
        self.log.debug("Confocal logic is {0}".format(self._confocal_logic))

        # Initializing the GUIs
        self.initMainUI()
        self.initReorientRoiDialogUI()

        # There could be POIs created in the logic already, so update lists and map
        self.populate_poi_list()
        self._redraw_sample_shift()
        self._redraw_poi_markers()

    def mouseMoved(self, event):
        """ Handles any mouse movements inside the image.

        @param event:   Event that signals the new mouse movement.
                        This should be of type QPointF.

        Gets the mouse position, converts it to a position scaled to the image axis
        and than calculates and updated the position to the current POI.
        """

        # converts the absolute mouse position to a position relative to the axis
        mouse_point = self._mw.roi_map_ViewWidget.getPlotItem().getViewBox(
        ).mapSceneToView(event.toPoint())
        #self.log.debug("Mouse at x = {0:0.2e}, y = {1:0.2e}".format(mouse_point.x(), mouse_point.y()))

        # only calculate distance, if a POI is selected
        if self._poi_manager_logic.active_poi is not None:
            cur_poi_pos = self._poi_manager_logic.get_poi_position(
                poikey=self._poi_manager_logic.active_poi.get_key())
            dx = ScaledFloat(mouse_point.x() - cur_poi_pos[0])
            dy = ScaledFloat(mouse_point.y() - cur_poi_pos[1])
            d_total = ScaledFloat(
                np.sqrt((mouse_point.x() - cur_poi_pos[0])**2 +
                        (mouse_point.y() - cur_poi_pos[1])**2))

            self._mw.poi_distance_label.setText(
                '{0:.2r}m ({1:.2r}m, {2:.2r}m)'.format(d_total, dx, dy))

    def initMainUI(self):
        """ Definition, configuration and initialisation of the POI Manager GUI.
        This init connects all the graphic modules, which were created in the
        *.ui file and configures the event handling between the modules.
        """

        # Use the inherited class 'Ui_PoiManagerGuiTemplate' to create now the
        # GUI element:
        self._mw = PoiManagerMainWindow()

        #####################
        # Configuring the dock widgets
        #####################

        # All our gui elements are dockable, and so there should be no "central" widget.
        self._mw.centralwidget.hide()
        self._mw.setDockNestingEnabled(True)
        #####################
        # Setting up display of ROI map xy image
        #####################

        # Get the image for the display from the logic:
        self.roi_xy_image_data = self._poi_manager_logic.roi_map_data[:, :, 3]

        # Load the image in the display:
        self.roi_map_image = pg.ImageItem(image=self.roi_xy_image_data,
                                          axisOrder='row-major')
        self.roi_map_image.setRect(
            QtCore.QRectF(
                self._confocal_logic.image_x_range[0],
                self._confocal_logic.image_y_range[0],
                self._confocal_logic.image_x_range[1] -
                self._confocal_logic.image_x_range[0],
                self._confocal_logic.image_y_range[1] -
                self._confocal_logic.image_y_range[0]))

        # Add the display item to the roi map ViewWidget defined in the UI file
        self._mw.roi_map_ViewWidget.addItem(self.roi_map_image)
        self._mw.roi_map_ViewWidget.setLabel('bottom', 'X position', units='m')
        self._mw.roi_map_ViewWidget.setLabel('left', 'Y position', units='m')

        # Set to fixed 1.0 aspect ratio, since the metaphor is a "map" of the sample
        self._mw.roi_map_ViewWidget.setAspectLocked(lock=True, ratio=1.0)

        # Get the colorscales and set LUT
        my_colors = ColorScaleInferno()

        self.roi_map_image.setLookupTable(my_colors.lut)

        # Add color bar:
        self.roi_cb = ColorBar(my_colors.cmap_normed, 100, 0, 100000)

        self._mw.roi_cb_ViewWidget.addItem(self.roi_cb)
        self._mw.roi_cb_ViewWidget.hideAxis('bottom')
        self._mw.roi_cb_ViewWidget.setLabel('left',
                                            'Fluorescence',
                                            units='c/s')
        self._mw.roi_cb_ViewWidget.setMouseEnabled(x=False, y=False)

        #####################
        # Setting up display of sample shift plot
        #####################

        # Load image in the display
        self.x_shift_plot = pg.PlotDataItem([0], [0],
                                            pen=pg.mkPen(
                                                palette.c1,
                                                style=QtCore.Qt.DotLine),
                                            symbol='o',
                                            symbolPen=palette.c1,
                                            symbolBrush=palette.c1,
                                            symbolSize=5,
                                            name='x')
        self.y_shift_plot = pg.PlotDataItem([0], [0],
                                            pen=pg.mkPen(
                                                palette.c2,
                                                style=QtCore.Qt.DotLine),
                                            symbol='s',
                                            symbolPen=palette.c2,
                                            symbolBrush=palette.c2,
                                            symbolSize=5,
                                            name='y')
        self.z_shift_plot = pg.PlotDataItem([0], [0],
                                            pen=pg.mkPen(
                                                palette.c3,
                                                style=QtCore.Qt.DotLine),
                                            symbol='t',
                                            symbolPen=palette.c3,
                                            symbolBrush=palette.c3,
                                            symbolSize=5,
                                            name='z')

        self._mw.sample_shift_ViewWidget.addLegend()

        # Add the plot to the ViewWidget defined in the UI file
        self._mw.sample_shift_ViewWidget.addItem(self.x_shift_plot)
        self._mw.sample_shift_ViewWidget.addItem(self.y_shift_plot)
        self._mw.sample_shift_ViewWidget.addItem(self.z_shift_plot)

        # Label axes
        self._mw.sample_shift_ViewWidget.setLabel('bottom', 'Time', units='s')
        self._mw.sample_shift_ViewWidget.setLabel('left',
                                                  'Sample shift',
                                                  units='m')

        #####################
        # Connect signals
        #####################

        # Distance Measurement:
        # Introducing a SignalProxy will limit the rate of signals that get fired.
        # Otherwise we will run into a heap of unhandled function calls.
        proxy = pg.SignalProxy(self.roi_map_image.scene().sigMouseMoved,
                               rateLimit=60,
                               slot=self.mouseMoved)
        # Connecting a Mouse Signal to trace to mouse movement function.
        self.roi_map_image.scene().sigMouseMoved.connect(self.mouseMoved)

        # Toolbar actions
        self._mw.new_roi_Action.triggered.connect(self.make_new_roi)
        self._mw.save_roi_Action.triggered.connect(self.save_roi)
        self._mw.load_roi_Action.triggered.connect(self.load_roi)
        self._mw.reorient_roi_Action.triggered.connect(
            self.open_reorient_roi_dialog)
        self._mw.autofind_pois_Action.triggered.connect(
            self.do_autofind_poi_procedure)
        self._mw.optimize_roi_Action.triggered.connect(self.optimize_roi)

        self._mw.new_poi_Action.triggered.connect(self.set_new_poi)
        self._mw.goto_poi_Action.triggered.connect(self.goto_poi)
        self._mw.refind_poi_Action.triggered.connect(self.update_poi_pos)
        self._mw.track_poi_Action.triggered.connect(self.toggle_tracking)

        # Interface controls
        self._mw.get_confocal_image_PushButton.clicked.connect(
            self.get_confocal_image)
        self._mw.set_poi_PushButton.clicked.connect(self.set_new_poi)
        self._mw.delete_last_pos_Button.clicked.connect(self.delete_last_point)
        self._mw.manual_update_poi_PushButton.clicked.connect(
            self.manual_update_poi)
        self._mw.move_poi_PushButton.clicked.connect(self.move_poi)
        self._mw.poi_name_LineEdit.returnPressed.connect(self.change_poi_name)
        self._mw.roi_name_LineEdit.editingFinished.connect(self.set_roi_name)
        self._mw.delete_poi_PushButton.clicked.connect(self.delete_poi)

        self._mw.goto_poi_after_update_checkBox.toggled.connect(
            self.toggle_follow)

        # This needs to be activated so that it only listens to user input, and ignores
        # algorithmic index changes
        self._mw.active_poi_ComboBox.activated.connect(
            self.handle_active_poi_ComboBox_index_change)
        self._mw.refind_method_ComboBox.currentIndexChanged.connect(
            self.change_refind_method)

        # Connect the buttons and inputs for the colorbar
        self._mw.roi_cb_centiles_RadioButton.toggled.connect(
            self.refresh_roi_colorscale)
        self._mw.roi_cb_manual_RadioButton.toggled.connect(
            self.refresh_roi_colorscale)
        self._mw.roi_cb_min_SpinBox.valueChanged.connect(
            self.shortcut_to_roi_cb_manual)
        self._mw.roi_cb_max_SpinBox.valueChanged.connect(
            self.shortcut_to_roi_cb_manual)
        self._mw.roi_cb_low_percentile_DoubleSpinBox.valueChanged.connect(
            self.shortcut_to_roi_cb_centiles)
        self._mw.roi_cb_high_percentile_DoubleSpinBox.valueChanged.connect(
            self.shortcut_to_roi_cb_centiles)

        self._mw.display_shift_vs_duration_RadioButton.toggled.connect(
            self._redraw_sample_shift)
        self._mw.display_shift_vs_clocktime_RadioButton.toggled.connect(
            self._redraw_sample_shift)

        self._markers = dict()

        # Signal at end of refocus
        self._poi_manager_logic.signal_timer_updated.connect(
            self._update_timer, QtCore.Qt.QueuedConnection)
        self._poi_manager_logic.signal_poi_updated.connect(
            self._redraw_sample_shift, QtCore.Qt.QueuedConnection)
        self._poi_manager_logic.signal_poi_updated.connect(
            self.populate_poi_list, QtCore.Qt.QueuedConnection)
        self._poi_manager_logic.signal_poi_updated.connect(
            self._redraw_poi_markers, QtCore.Qt.QueuedConnection)
        self._poi_manager_logic.signal_poi_deleted.connect(
            self._remove_poi_marker)
        self._poi_manager_logic.signal_confocal_image_updated.connect(
            self._redraw_roi_image)

        self._poi_manager_logic.signal_periodic_opt_duration_changed.connect(
            self._track_period_changed)
        self._poi_manager_logic.signal_periodic_opt_started.connect(
            self._tracking_started)
        self._poi_manager_logic.signal_periodic_opt_stopped.connect(
            self._tracking_stopped)

        # Connect track period after setting the GUI value from the logic
        initial_period = self._poi_manager_logic.timer_duration
        self._mw.track_period_SpinBox.setValue(initial_period)
        self._mw.time_till_next_update_ProgressBar.setMaximum(initial_period)
        self._mw.time_till_next_update_ProgressBar.setValue(initial_period)
        self._mw.track_period_SpinBox.valueChanged.connect(
            self.set_track_period)

        # Redraw the sample_shift axes if the range changes
        self._mw.sample_shift_ViewWidget.plotItem.sigRangeChanged.connect(
            self._redraw_sample_shift)

        self._mw.show()

    def initReorientRoiDialogUI(self):
        """ Definition, configuration and initialization fo the Reorient ROI Dialog GUI.

        This init connects all the graphic modules which were created in the
        *.ui file and configures event handling.
        """

        # Create the Reorient ROI Dialog window
        self._rrd = ReorientRoiDialog()

        # Connect the QDialog buttons to methods in the GUI
        self._rrd.accepted.connect(self.do_roi_reorientation)
        self._rrd.rejected.connect(self.reset_reorientation_dialog)

        # Connect the at_crosshair buttons
        self._rrd.ref_a_at_crosshair_PushButton.clicked.connect(
            self.ref_a_at_crosshair)
        self._rrd.ref_b_at_crosshair_PushButton.clicked.connect(
            self.ref_b_at_crosshair)
        self._rrd.ref_c_at_crosshair_PushButton.clicked.connect(
            self.ref_c_at_crosshair)

        # Connect input value changes to update the sanity-check values
        self._rrd.ref_a_poi_ComboBox.activated.connect(
            self.reorientation_sanity_check)
        self._rrd.ref_b_poi_ComboBox.activated.connect(
            self.reorientation_sanity_check)
        self._rrd.ref_c_poi_ComboBox.activated.connect(
            self.reorientation_sanity_check)
        self._rrd.ref_a_x_pos_DoubleSpinBox.valueChanged.connect(
            self.reorientation_sanity_check)
        self._rrd.ref_a_y_pos_DoubleSpinBox.valueChanged.connect(
            self.reorientation_sanity_check)
        self._rrd.ref_a_z_pos_DoubleSpinBox.valueChanged.connect(
            self.reorientation_sanity_check)
        self._rrd.ref_b_x_pos_DoubleSpinBox.valueChanged.connect(
            self.reorientation_sanity_check)
        self._rrd.ref_b_y_pos_DoubleSpinBox.valueChanged.connect(
            self.reorientation_sanity_check)
        self._rrd.ref_b_z_pos_DoubleSpinBox.valueChanged.connect(
            self.reorientation_sanity_check)
        self._rrd.ref_c_x_pos_DoubleSpinBox.valueChanged.connect(
            self.reorientation_sanity_check)
        self._rrd.ref_c_y_pos_DoubleSpinBox.valueChanged.connect(
            self.reorientation_sanity_check)
        self._rrd.ref_c_z_pos_DoubleSpinBox.valueChanged.connect(
            self.reorientation_sanity_check)

    def on_deactivate(self):
        """ Deinitialisation performed during deactivation of the module.
        """
        self._mw.close()

    def show(self):
        """Make main window visible and put it above all other windows. """
        QtWidgets.QMainWindow.show(self._mw)
        self._mw.activateWindow()
        self._mw.raise_()

    def get_confocal_image(self):
        """ Update the roi_map_data in poi manager logic, and use this updated
            data to redraw an image of the ROI.
        """

        # Make poi manager logic get the confocal data
        self._poi_manager_logic.get_confocal_image_data()

    def _redraw_roi_image(self):

        # the image data is the fluorescence part
        self.roi_xy_image_data = self._poi_manager_logic.roi_map_data[:, :, 3]

        # Also get the x and y range limits and hold them locally
        self.roi_map_xmin = np.min(self._poi_manager_logic.roi_map_data[:, :,
                                                                        0])
        self.roi_map_xmax = np.max(self._poi_manager_logic.roi_map_data[:, :,
                                                                        0])
        self.roi_map_ymin = np.min(self._poi_manager_logic.roi_map_data[:, :,
                                                                        1])
        self.roi_map_ymax = np.max(self._poi_manager_logic.roi_map_data[:, :,
                                                                        1])

        self.roi_map_image.getViewBox().enableAutoRange()
        self.roi_map_image.setRect(
            QtCore.QRectF(self.roi_map_xmin, self.roi_map_ymin,
                          self.roi_map_xmax - self.roi_map_xmin,
                          self.roi_map_ymax - self.roi_map_ymin))
        self.roi_map_image.setImage(image=self.roi_xy_image_data,
                                    autoLevels=True)

    def shortcut_to_roi_cb_manual(self):
        self._mw.roi_cb_manual_RadioButton.setChecked(True)
        self.refresh_roi_colorscale()

    def shortcut_to_roi_cb_centiles(self):
        self._mw.roi_cb_centiles_RadioButton.setChecked(True)
        self.refresh_roi_colorscale()

    def refresh_roi_colorscale(self):
        """ Adjust the colorbar in the ROI xy image, and update the image with the
        new color scale.

        Calls the refresh method from colorbar, which takes either the lowest
        and higherst value in the image or predefined ranges. Note that you can
        invert the colorbar if the lower border is bigger then the higher one.
        """

        cb_min, cb_max = self.determine_cb_range()

        self.roi_map_image.setImage(image=self.roi_xy_image_data,
                                    levels=(cb_min, cb_max))

        self.roi_cb.refresh_colorbar(cb_min, cb_max)
        self._mw.roi_cb_ViewWidget.update()

    def determine_cb_range(self):
        """ Process UI input to determine color bar range"""

        # If "Centiles" is checked, adjust colour scaling automatically to centiles.
        # Otherwise, take user-defined values.
        if self._mw.roi_cb_centiles_RadioButton.isChecked():
            low_centile = self._mw.roi_cb_low_percentile_DoubleSpinBox.value()
            high_centile = self._mw.roi_cb_high_percentile_DoubleSpinBox.value(
            )

            cb_min = np.percentile(self.roi_xy_image_data, low_centile)
            cb_max = np.percentile(self.roi_xy_image_data, high_centile)

        else:
            cb_min = self._mw.roi_cb_min_SpinBox.value()
            cb_max = self._mw.roi_cb_max_SpinBox.value()

        return cb_min, cb_max

    def set_new_poi(self):
        """ This method sets a new poi from the current crosshair position."""
        key = self._poi_manager_logic.add_poi()

    def delete_last_point(self):
        """ Delete the last track position of a chosen poi. """
        if self._poi_manager_logic.active_poi is None:
            self.log.warning("No POI selected. No datapoint can be deleted")
        else:
            self._poi_manager_logic.delete_last_position(
                poikey=self._poi_manager_logic.active_poi.get_key())

    def delete_poi(self):
        """ Delete the active poi from the list of managed points. """
        if self._poi_manager_logic.active_poi is None:
            self.log.warning("No POI selected.")
        else:
            key = self._poi_manager_logic.active_poi.get_key()

            # todo: this needs to handle the case where the logic deletes a POI.

            self._poi_manager_logic.delete_poi(poikey=key)

    def _remove_poi_marker(self, poikey):
        """ Remove the POI marker for a POI that was deleted.
        """
        self._markers[poikey].delete_from_viewwidget()
        del self._markers[poikey]

    def manual_update_poi(self):
        """ Manually adds a point to the trace of a given poi without refocussing, and uses that information to update sample position.
        """
        if self._poi_manager_logic.active_poi is None:
            self.log.warning("No POI selected.")
        else:
            self._poi_manager_logic.set_new_position(
                poikey=self._poi_manager_logic.active_poi.get_key())

    def move_poi(self):
        """Manually move a POI to a new location in the sample map, but WITHOUT changing the sample position.  This moves a POI relative to all the others.
        """
        if self._poi_manager_logic.active_poi is None:
            self.log.warning("No POI selected.")
        else:
            self._poi_manager_logic.move_coords(
                poikey=self._poi_manager_logic.active_poi.get_key())

    def toggle_tracking(self):
        if self._poi_manager_logic.active_poi is None:
            self.log.warning("No POI selected.")
        else:
            if self._poi_manager_logic.timer is None:
                self._poi_manager_logic.start_periodic_refocus(
                    poikey=self._poi_manager_logic.active_poi.get_key())

            else:
                self._poi_manager_logic.stop_periodic_refocus()

    def _tracking_started(self):
        self._mw.track_poi_Action.setChecked(True)

    def _tracking_stopped(self):
        self._mw.track_poi_Action.setChecked(False)

    def goto_poi(self, key):
        """ Go to the last known position of poi <key>."""
        if self._poi_manager_logic.active_poi is None:
            self.log.warning("No POI selected.")
        else:
            self._poi_manager_logic.go_to_poi(
                poikey=self._poi_manager_logic.active_poi.get_key())

    def populate_poi_list(self):
        """ Populate the dropdown box for selecting a poi. """
        self.log.debug('started populate_poi_list at {0}'.format(time.time()))
        self._mw.active_poi_ComboBox.clear()
        self._mw.offset_anchor_ComboBox.clear()
        self._rrd.ref_a_poi_ComboBox.clear()
        self._rrd.ref_b_poi_ComboBox.clear()
        self._rrd.ref_c_poi_ComboBox.clear()

        for key in self._poi_manager_logic.get_all_pois(abc_sort=True):
            if key is not 'crosshair' and key is not 'sample':
                poi_list_empty = False
                self._mw.active_poi_ComboBox.addItem(
                    self._poi_manager_logic.poi_list[key].get_name(), key)
                self._mw.offset_anchor_ComboBox.addItem(
                    self._poi_manager_logic.poi_list[key].get_name(), key)
                self._rrd.ref_a_poi_ComboBox.addItem(
                    self._poi_manager_logic.poi_list[key].get_name(), key)
                self._rrd.ref_b_poi_ComboBox.addItem(
                    self._poi_manager_logic.poi_list[key].get_name(), key)
                self._rrd.ref_c_poi_ComboBox.addItem(
                    self._poi_manager_logic.poi_list[key].get_name(), key)

        # If there is no active POI, set the combobox to nothing (-1)
        if self._poi_manager_logic.active_poi is None:
            self._mw.active_poi_ComboBox.setCurrentIndex(-1)

        # Otherwise, set it to the active POI
        else:
            self._mw.active_poi_ComboBox.setCurrentIndex(
                self._mw.active_poi_ComboBox.findData(
                    self._poi_manager_logic.active_poi.get_key()))

        self.log.debug('finished populating at '.format(time.time()))

    def change_refind_method(self):
        """ Make appropriate changes in the GUI to reflect the newly chosen refind method."""

        if self._mw.refind_method_ComboBox.currentText(
        ) == 'position optimisation':
            self._mw.offset_anchor_ComboBox.setEnabled(False)
        elif self._mw.refind_method_ComboBox.currentText() == 'offset anchor':
            self.log.error(
                "Anchor method not fully implemented yet. "
                "Feel free to fix this method. Using position optimisation instead."
            )
            self._mw.offset_anchor_ComboBox.setEnabled(True)
        else:
            # TODO: throw an error
            self.log.debug('error 123')

    def set_roi_name(self):
        """ Set the name of a ROI (useful when saving)."""

        self._poi_manager_logic.roi_name = self._mw.roi_name_LineEdit.text(
        ).replace(" ", "_")

    def change_poi_name(self):
        """ Change the name of a poi."""

        newname = self._mw.poi_name_LineEdit.text()

        self._poi_manager_logic.rename_poi(
            poikey=self._poi_manager_logic.active_poi.get_key(), name=newname)

        # After POI name is changed, empty name field
        self._mw.poi_name_LineEdit.setText('')

    def handle_active_poi_ComboBox_index_change(self):
        """ Handle the change of index in the active POI combobox."""

        key = self._mw.active_poi_ComboBox.itemData(
            self._mw.active_poi_ComboBox.currentIndex())

        self._poi_manager_logic.set_active_poi(poikey=key)

        self._redraw_poi_markers(
        )  # todo when line 660 signal in logic is done, this is not necessary

    def select_poi_from_marker(self, poikey=None):
        """ Process the selection of a POI from click on POImark."""

        # Keep track of selected POI
        self._poi_manager_logic.set_active_poi(poikey=poikey)

#        # Set the selected POI in the combobox
#        self._mw.active_poi_ComboBox.setCurrentIndex(self._mw.active_poi_ComboBox.findData(poikey))
#        self._redraw_poi_markers()

    def update_poi_pos(self):
        if self._poi_manager_logic.active_poi is None:
            self.log.warning("No POI selected.")
        else:
            if self._mw.refind_method_ComboBox.currentText(
            ) == 'position optimisation':
                self._poi_manager_logic.optimise_poi(
                    poikey=self._poi_manager_logic.active_poi.get_key())

            elif self._mw.refind_method_ComboBox.currentText(
            ) == 'offset anchor':
                anchor_key = self._mw.offset_anchor_ComboBox.itemData(
                    self._mw.offset_anchor_ComboBox.currentIndex())
                self._poi_manager_logic.optimise_poi(
                    poikey=self._poi_manager_logic.active_poi.get_key(),
                    anchorkey=anchor_key)

    def toggle_follow(self):
        if self._mw.goto_poi_after_update_checkBox.isChecked():
            self._poi_manager_logic.go_to_crosshair_after_refocus = False
        else:
            self._poi_manager_logic.go_to_crosshair_after_refocus = True

    def _update_timer(self):
        self._mw.time_till_next_update_ProgressBar.setValue(
            self._poi_manager_logic.time_left)

    def set_track_period(self):
        """ Change the progress bar and update the timer duration."""

        new_track_period = self._mw.track_period_SpinBox.value()
        self._poi_manager_logic.set_periodic_optimize_duration(
            duration=new_track_period)

    def _track_period_changed(self):
        """ Reflect the changed track period in the GUI elements.
        """
        new_track_period = self._poi_manager_logic.timer_duration
        # Set the new maximum for the progress bar
        self._mw.time_till_next_update_ProgressBar.setMaximum(new_track_period)

        # If the tracker is not active, then set the value of the progress bar to the
        # new maximum
        if not self._mw.track_poi_Action.isChecked():
            self._mw.time_till_next_update_ProgressBar.setValue(
                new_track_period)

    def _redraw_clocktime_ticks(self):
        """If duration is displayed, reset ticks to default.
        Otherwise, create and update custom date/time ticks to the new axis range.
        """
        myAxisItem = self._mw.sample_shift_ViewWidget.plotItem.axes['bottom'][
            'item']

        # if duration display, reset to default ticks
        if self._mw.display_shift_vs_duration_RadioButton.isChecked():
            myAxisItem.setTicks(None)

        # otherwise, convert tick strings to clock format
        else:

            # determine size of the sample shift bottom axis item in pixels
            bounds = myAxisItem.mapRectFromParent(myAxisItem.geometry())
            span = (bounds.topLeft(), bounds.topRight())
            lengthInPixels = (span[1] - span[0]).manhattanLength()

            if lengthInPixels == 0:
                return -1
            if myAxisItem.range[0] < 0:
                return -1

            default_ticks = myAxisItem.tickValues(myAxisItem.range[0],
                                                  myAxisItem.range[1],
                                                  lengthInPixels)

            newticks = []
            for i, tick_level in enumerate(default_ticks):
                newticks_this_level = []
                ticks = tick_level[1]
                for ii, tick in enumerate(ticks):
                    # For major ticks, include date
                    if i == 0:
                        string = time.strftime("%H:%M (%d.%m.)",
                                               time.localtime(tick * 3600))
                        # (the axis is plotted in hours to get naturally better placed ticks.)

                    # for middle and minor ticks, just display clock time
                    else:
                        string = time.strftime("%H:%M",
                                               time.localtime(tick * 3600))

                    newticks_this_level.append((tick, string))
                newticks.append(newticks_this_level)

            myAxisItem.setTicks(newticks)
            return 0

    def _redraw_sample_shift(self):

        # Get trace data and calculate shifts in x,y,z
        poi_trace = self._poi_manager_logic.poi_list[
            'sample'].get_position_history()

        # If duration display is checked, subtract initial time and convert to
        # mins or hours as appropriate
        if self._mw.display_shift_vs_duration_RadioButton.isChecked():
            time_shift_data = (poi_trace[:, 0] - poi_trace[0, 0])

            if np.max(time_shift_data) < 300:
                self._mw.sample_shift_ViewWidget.setLabel('bottom',
                                                          'Time elapsed',
                                                          units='s')
            elif np.max(time_shift_data) < 7200:
                time_shift_data = time_shift_data / 60.0
                self._mw.sample_shift_ViewWidget.setLabel('bottom',
                                                          'Time elapsed',
                                                          units='min')
            else:
                time_shift_data = time_shift_data / 3600.0
                self._mw.sample_shift_ViewWidget.setLabel('bottom',
                                                          'Time elapsed',
                                                          units='hr')

        # Otherwise, take the actual time but divide by 3600 so that tickmarks
        # automatically fall on whole hours
        else:
            time_shift_data = poi_trace[:, 0] / 3600.0
            self._mw.sample_shift_ViewWidget.setLabel('bottom',
                                                      'Time',
                                                      units='')

        # Subtract initial position to get shifts
        x_shift_data = (poi_trace[:, 1] - poi_trace[0, 1])
        y_shift_data = (poi_trace[:, 2] - poi_trace[0, 2])
        z_shift_data = (poi_trace[:, 3] - poi_trace[0, 3])

        # Plot data
        self.x_shift_plot.setData(time_shift_data, x_shift_data)
        self.y_shift_plot.setData(time_shift_data, y_shift_data)
        self.z_shift_plot.setData(time_shift_data, z_shift_data)

        self._redraw_clocktime_ticks()

    def _redraw_poi_markers(self):

        self.log.debug('starting redraw_poi_markers {0}'.format(time.time()))

        for key in self._poi_manager_logic.get_all_pois():
            if key is not 'crosshair' and key is not 'sample':
                position = self._poi_manager_logic.get_poi_position(poikey=key)
                position = position[:2]

                if key in self._markers.keys():
                    self._markers[key].set_position(position)
                    self._markers[key].deselect()
                else:
                    # Create Region of Interest as marker:
                    marker = PoiMark(position,
                                     poi=self._poi_manager_logic.poi_list[key],
                                     click_action=self.select_poi_from_marker,
                                     movable=False,
                                     scaleSnap=False,
                                     snapSize=1.0e-6)

                    # Add to the Map Widget
                    marker.add_to_viewwidget(self._mw.roi_map_ViewWidget)
                    self._markers[key] = marker

        if self._poi_manager_logic.active_poi is not None:
            active_poi_key = self._poi_manager_logic.active_poi.get_key()

            self._markers[active_poi_key].select()
            cur_poi_pos = self._poi_manager_logic.get_poi_position(
                poikey=active_poi_key)
            self._mw.poi_coords_label.setText(
                '({0:.2r}m, {1:.2r}m, {2:.2r}m)'.format(
                    ScaledFloat(cur_poi_pos[0]), ScaledFloat(cur_poi_pos[1]),
                    ScaledFloat(cur_poi_pos[2])))
        self.log.debug('finished redraw at {0}'.format(time.time()))

    def make_new_roi(self):
        """ Start new ROI by removing all POIs and resetting the sample history."""

        for key in self._poi_manager_logic.get_all_pois():
            if key is not 'crosshair' and key is not 'sample':
                self._markers[key].delete_from_viewwidget()

        del self._markers
        self._markers = dict()

        self._poi_manager_logic.reset_roi()

        self.populate_poi_list()

    def save_roi(self):
        """ Save ROI to file."""

        self._poi_manager_logic.save_poi_map_as_roi()

    def load_roi(self):
        """ Load a saved ROI from file."""

        this_file = QtWidgets.QFileDialog.getOpenFileName(
            self._mw, str("Open ROI"), None, str("Data files (*.dat)"))[0]

        self._poi_manager_logic.load_roi_from_file(filename=this_file)

        self.populate_poi_list()

    def open_reorient_roi_dialog(self):
        """ Open the dialog for reorienting the ROI. """
        self._rrd.show()

    def ref_a_at_crosshair(self):
        """ Set the newpos for ref A from the current crosshair position. """
        # TODO: get the range for these spinboxes from the hardware scanner range!
        self._rrd.ref_a_x_pos_DoubleSpinBox.setValue(
            self._confocal_logic.get_position()[0])
        self._rrd.ref_a_y_pos_DoubleSpinBox.setValue(
            self._confocal_logic.get_position()[1])
        self._rrd.ref_a_z_pos_DoubleSpinBox.setValue(
            self._confocal_logic.get_position()[2])

    def ref_b_at_crosshair(self):
        """ Set the newpos for ref B from the current crosshair position. """
        self._rrd.ref_b_x_pos_DoubleSpinBox.setValue(
            self._confocal_logic.get_position()[0])
        self._rrd.ref_b_y_pos_DoubleSpinBox.setValue(
            self._confocal_logic.get_position()[1])
        self._rrd.ref_b_z_pos_DoubleSpinBox.setValue(
            self._confocal_logic.get_position()[2])

    def ref_c_at_crosshair(self):
        """ Set the newpos for ref C from the current crosshair position. """
        self._rrd.ref_c_x_pos_DoubleSpinBox.setValue(
            self._confocal_logic.get_position()[0])
        self._rrd.ref_c_y_pos_DoubleSpinBox.setValue(
            self._confocal_logic.get_position()[1])
        self._rrd.ref_c_z_pos_DoubleSpinBox.setValue(
            self._confocal_logic.get_position()[2])

    def do_roi_reorientation(self):
        """Pass the old and new positions of refs A, B, C to PoiManager Logic to reorient every POI in the ROI.
        """

        ref_a_coords, ref_b_coords, ref_c_coords, ref_a_newpos, ref_b_newpos, ref_c_newpos = self._read_reorient_roi_dialog_values(
        )

        self._poi_manager_logic.reorient_roi(ref_a_coords, ref_b_coords,
                                             ref_c_coords, ref_a_newpos,
                                             ref_b_newpos, ref_c_newpos)

        # Clear the values in the Reorient Roi Dialog in case it is needed again
        self.reset_reorientation_dialog()

    def _read_reorient_roi_dialog_values(self):
        """ This reads the values from reorient ROI Dialog, and returns them. """

        # Get POI keys for the chosen ref points
        ref_a_key = self._rrd.ref_a_poi_ComboBox.itemData(
            self._rrd.ref_a_poi_ComboBox.currentIndex())
        ref_b_key = self._rrd.ref_b_poi_ComboBox.itemData(
            self._rrd.ref_b_poi_ComboBox.currentIndex())
        ref_c_key = self._rrd.ref_c_poi_ComboBox.itemData(
            self._rrd.ref_c_poi_ComboBox.currentIndex())

        # Get the old coords for these refs
        ref_a_coords = np.array(
            self._poi_manager_logic.poi_list[ref_a_key].get_coords_in_sample())
        ref_b_coords = np.array(
            self._poi_manager_logic.poi_list[ref_b_key].get_coords_in_sample())
        ref_c_coords = np.array(
            self._poi_manager_logic.poi_list[ref_c_key].get_coords_in_sample())

        ref_a_newpos = np.array([
            self._rrd.ref_a_x_pos_DoubleSpinBox.value(),
            self._rrd.ref_a_y_pos_DoubleSpinBox.value(),
            self._rrd.ref_a_z_pos_DoubleSpinBox.value()
        ])
        ref_b_newpos = np.array([
            self._rrd.ref_b_x_pos_DoubleSpinBox.value(),
            self._rrd.ref_b_y_pos_DoubleSpinBox.value(),
            self._rrd.ref_b_z_pos_DoubleSpinBox.value()
        ])
        ref_c_newpos = np.array([
            self._rrd.ref_c_x_pos_DoubleSpinBox.value(),
            self._rrd.ref_c_y_pos_DoubleSpinBox.value(),
            self._rrd.ref_c_z_pos_DoubleSpinBox.value()
        ])

        return ref_a_coords, ref_b_coords, ref_c_coords, ref_a_newpos * 1e-6, ref_b_newpos * 1e-6, ref_c_newpos * 1e-6

    def reset_reorientation_dialog(self):
        """ Reset all the values in the reorient roi dialog. """

        self._rrd.ref_a_x_pos_DoubleSpinBox.setValue(0)
        self._rrd.ref_a_y_pos_DoubleSpinBox.setValue(0)
        self._rrd.ref_a_z_pos_DoubleSpinBox.setValue(0)

        self._rrd.ref_b_x_pos_DoubleSpinBox.setValue(0)
        self._rrd.ref_b_y_pos_DoubleSpinBox.setValue(0)
        self._rrd.ref_b_z_pos_DoubleSpinBox.setValue(0)

        self._rrd.ref_c_x_pos_DoubleSpinBox.setValue(0)
        self._rrd.ref_c_y_pos_DoubleSpinBox.setValue(0)
        self._rrd.ref_c_z_pos_DoubleSpinBox.setValue(0)

    def reorientation_sanity_check(self):
        """ Calculate the difference in length between edges of old triangle defined by refs A, B, C and the new triangle.
        """

        # Get set of positions from GUI
        ref_a_coords, ref_b_coords, ref_c_coords, ref_a_newpos, ref_b_newpos, ref_c_newpos = self._read_reorient_roi_dialog_values(
        )

        # Calculate the difference in side lengths AB, BC, CA between the old triangle and the new triangle
        delta_ab = np.linalg.norm(ref_b_coords -
                                  ref_a_coords) - np.linalg.norm(ref_b_newpos -
                                                                 ref_a_newpos)
        delta_bc = np.linalg.norm(ref_c_coords -
                                  ref_b_coords) - np.linalg.norm(ref_c_newpos -
                                                                 ref_b_newpos)
        delta_ca = np.linalg.norm(ref_a_coords -
                                  ref_c_coords) - np.linalg.norm(ref_a_newpos -
                                                                 ref_c_newpos)

        # Write to the GUI
        self._rrd.length_difference_ab_Label.setText(str(delta_ab))
        self._rrd.length_difference_bc_Label.setText(str(delta_bc))
        self._rrd.length_difference_ca_Label.setText(str(delta_ca))

    def do_autofind_poi_procedure(self):
        """Run the autofind_pois procedure in the POI Manager Logic to get all the POIs in the current ROI image."""
        #Fixme: Add here the appropriate functionality

        self.log.error("Has to be implemented properly. Feel free to do it.")

        # # Get the thresholds from the user-chosen color bar range
        # cb_min, cb_max = self.determine_cb_range()
        #
        # this_min_threshold = cb_min + 0.3 * (cb_max - cb_min)
        # this_max_threshold = cb_max
        #
        # self._poi_manager_logic.autofind_pois(neighborhood_size=1, min_threshold=this_min_threshold, max_threshold=this_max_threshold)

    def optimize_roi(self):
        """Run the autofind_pois procedure in the POI Manager Logic to get all the POIs in the current ROI image."""
        #Fixme: Add here the appropriate functionality
        self.log.error("Not implemented yet. Feel free to help!")
Exemplo n.º 6
0
class CameraGUI(GUIBase):
    """ Main spectrometer camera class.
    """

    camera_logic = Connector(interface='CameraLogic')
    savelogic = Connector(interface='SaveLogic')

    sigVideoStart = QtCore.Signal()
    sigVideoStop = QtCore.Signal()
    sigImageStart = QtCore.Signal()
    sigImageStop = QtCore.Signal()

    _image = []

    _logic = None
    _mw = None

    def __init__(self, config, **kwargs):

        # load connection
        super().__init__(config=config, **kwargs)

    def on_activate(self):
        """ Initializes all needed UI files and establishes the connectors.
        """

        self._logic = self.camera_logic()
        self._save_logic = self.savelogic()

        # Windows
        self._mw = CameraWindow()
        self._mw.centralwidget.hide()
        self._mw.setDockNestingEnabled(True)
        self.initSettingsUI()

        self._mw.start_video_Action.setEnabled(True)
        self._mw.start_video_Action.setChecked(self._logic.enabled)
        self._mw.start_video_Action.triggered.connect(self.start_video_clicked)

        self._mw.start_image_Action.setEnabled(True)
        self._mw.start_image_Action.setChecked(self._logic.enabled)
        self._mw.start_image_Action.triggered.connect(self.start_image_clicked)

        self._logic.sigUpdateDisplay.connect(self.update_data)
        self._logic.sigAcquisitionFinished.connect(self.acquisition_finished)
        self._logic.sigVideoFinished.connect(self.enable_start_image_action)

        # starting the physical measurement
        self.sigVideoStart.connect(self._logic.start_loop)
        self.sigVideoStop.connect(self._logic.stop_loop)
        self.sigImageStart.connect(self._logic.start_single_acquistion)

        # connect Settings action under Options menu
        self._mw.actionSettings.triggered.connect(self.menu_settings)
        # connect save action to save function
        self._mw.actionSave_XY_Scan.triggered.connect(self.save_xy_scan_data)

        raw_data_image = self._logic.get_last_image()
        self._image = pg.ImageItem(image=raw_data_image, axisOrder='row-major')
        self._mw.image_PlotWidget.addItem(self._image)
        self._mw.image_PlotWidget.setAspectLocked(True)

        # Get the colorscale and set the LUTs
        self.my_colors = ColorScaleInferno()

        self._image.setLookupTable(self.my_colors.lut)

        # Connect the buttons and inputs for the colorbar
        self._mw.xy_cb_manual_RadioButton.clicked.connect(self.update_xy_cb_range)
        self._mw.xy_cb_centiles_RadioButton.clicked.connect(self.update_xy_cb_range)

        self._mw.xy_cb_min_DoubleSpinBox.valueChanged.connect(self.shortcut_to_xy_cb_manual)
        self._mw.xy_cb_max_DoubleSpinBox.valueChanged.connect(self.shortcut_to_xy_cb_manual)
        self._mw.xy_cb_low_percentile_DoubleSpinBox.valueChanged.connect(self.shortcut_to_xy_cb_centiles)
        self._mw.xy_cb_high_percentile_DoubleSpinBox.valueChanged.connect(self.shortcut_to_xy_cb_centiles)

        # create color bar
        self.xy_cb = ColorBar(self.my_colors.cmap_normed, width=100, cb_min=0, cb_max=100)
        self.depth_cb = ColorBar(self.my_colors.cmap_normed, width=100, cb_min=0, cb_max=100)
        self._mw.xy_cb_ViewWidget.addItem(self.xy_cb)
        self._mw.xy_cb_ViewWidget.hideAxis('bottom')
        self._mw.xy_cb_ViewWidget.setLabel('left', 'Fluorescence', units='c')
        self._mw.xy_cb_ViewWidget.setMouseEnabled(x=False, y=False)

    def on_deactivate(self):
        """ Deinitialisation performed during deactivation of the module.
        """
        self._mw.close()

    def show(self):
        """Make window visible and put it above all other windows.
        """
        QtWidgets.QMainWindow.show(self._mw)
        self._mw.activateWindow()
        self._mw.raise_()

    def initSettingsUI(self):
        """ Definition, configuration and initialisation of the settings GUI.

        This init connects all the graphic modules, which were created in the
        *.ui file and configures the event handling between the modules.
        Moreover it sets default values if not existed in the logic modules.
        """
        # Create the Settings window
        self._sd = CameraSettingDialog()
        # Connect the action of the settings window with the code:
        self._sd.accepted.connect(self.update_settings)
        self._sd.rejected.connect(self.keep_former_settings)
        self._sd.buttonBox.button(QtWidgets.QDialogButtonBox.Apply).clicked.connect(self.update_settings)

        # write the configuration to the settings window of the GUI.
        self.keep_former_settings()

    def update_settings(self):
        """ Write new settings from the gui to the file. """
        self._logic.set_exposure(self._sd.exposureDSpinBox.value())
        self._logic.set_gain(self._sd.gainSpinBox.value())

    def keep_former_settings(self):
        """ Keep the old settings and restores them in the gui. """
        self._sd.exposureDSpinBox.setValue(self._logic._exposure)
        self._sd.gainSpinBox.setValue(self._logic._gain)

    def menu_settings(self):
        """ This method opens the settings menu. """
        self._sd.exec_()

    def start_image_clicked(self):
        self.sigImageStart.emit()
        self._mw.start_image_Action.setDisabled(True)
        self._mw.start_video_Action.setDisabled(True)

    def acquisition_finished(self):
        self._mw.start_image_Action.setChecked(False)
        self._mw.start_image_Action.setDisabled(False)
        self._mw.start_video_Action.setDisabled(False)

    def start_video_clicked(self):
        """ Handling the Start button to stop and restart the counter.
        """
        self._mw.start_image_Action.setDisabled(True)
        if self._logic.enabled:
            self._mw.start_video_Action.setText('Start Video')
            self.sigVideoStop.emit()
        else:
            self._mw.start_video_Action.setText('Stop Video')
            self.sigVideoStart.emit()

    def enable_start_image_action(self):
        self._mw.start_image_Action.setEnabled(True)

    def update_data(self):
        """
        Get the image data from the logic and print it on the window
        """
        raw_data_image = self._logic.get_last_image()
        levels = (0., 1.)
        self._image.setImage(image=raw_data_image)
        self.update_xy_cb_range()
        # self._image.setImage(image=raw_data_image, levels=levels)

    def updateView(self):
        """
        Update the view when the model change
        """
        pass

# color bar functions
    def get_xy_cb_range(self):
        """ Determines the cb_min and cb_max values for the xy scan image
        """
        # If "Manual" is checked, or the image data is empty (all zeros), then take manual cb range.
        if self._mw.xy_cb_manual_RadioButton.isChecked() or np.max(self._image.image) == 0.0:
            cb_min = self._mw.xy_cb_min_DoubleSpinBox.value()
            cb_max = self._mw.xy_cb_max_DoubleSpinBox.value()

        # Otherwise, calculate cb range from percentiles.
        else:
            # xy_image_nonzero = self._image.image[np.nonzero(self._image.image)]

            # Read centile range
            low_centile = self._mw.xy_cb_low_percentile_DoubleSpinBox.value()
            high_centile = self._mw.xy_cb_high_percentile_DoubleSpinBox.value()

            cb_min = np.percentile(self._image.image, low_centile)
            cb_max = np.percentile(self._image.image, high_centile)

        cb_range = [cb_min, cb_max]

        return cb_range

    def refresh_xy_colorbar(self):
        """ Adjust the xy colorbar.

        Calls the refresh method from colorbar, which takes either the lowest
        and higherst value in the image or predefined ranges. Note that you can
        invert the colorbar if the lower border is bigger then the higher one.
        """
        cb_range = self.get_xy_cb_range()
        self.xy_cb.refresh_colorbar(cb_range[0], cb_range[1])

    def refresh_xy_image(self):
        """ Update the current XY image from the logic.

        Everytime the scanner is scanning a line in xy the
        image is rebuild and updated in the GUI.
        """
        self._image.getViewBox().updateAutoRange()

        xy_image_data = self._logic._last_image

        cb_range = self.get_xy_cb_range()

        # Now update image with new color scale, and update colorbar
        self._image.setImage(image=xy_image_data, levels=(cb_range[0], cb_range[1]))
        self.refresh_xy_colorbar()

    def shortcut_to_xy_cb_manual(self):
        """Someone edited the absolute counts range for the xy colour bar, better update."""
        self._mw.xy_cb_manual_RadioButton.setChecked(True)
        self.update_xy_cb_range()

    def shortcut_to_xy_cb_centiles(self):
        """Someone edited the centiles range for the xy colour bar, better update."""
        self._mw.xy_cb_centiles_RadioButton.setChecked(True)
        self.update_xy_cb_range()

    def update_xy_cb_range(self):
        """Redraw xy colour bar and scan image."""
        self.refresh_xy_colorbar()
        self.refresh_xy_image()

# save functions

    def save_xy_scan_data(self):
        """ Run the save routine from the logic to save the xy confocal data."""
        cb_range = self.get_xy_cb_range()

        # Percentile range is None, unless the percentile scaling is selected in GUI.
        pcile_range = None
        if not self._mw.xy_cb_manual_RadioButton.isChecked():
            low_centile = self._mw.xy_cb_low_percentile_DoubleSpinBox.value()
            high_centile = self._mw.xy_cb_high_percentile_DoubleSpinBox.value()
            pcile_range = [low_centile, high_centile]

        self._logic.save_xy_data(colorscale_range=cb_range, percentile_range=pcile_range)

        # TODO: find a way to produce raw image in savelogic.  For now it is saved here.
        filepath = self._save_logic.get_path_for_module(module_name='Confocal')
        filename = filepath + os.sep + time.strftime('%Y%m%d-%H%M-%S_confocal_xy_scan_raw_pixel_image')

        self._image.save(filename + '_raw.png')
Exemplo n.º 7
0
    def on_activate(self):
        """ Definition, configuration and initialisation of the ODMR GUI.

        This init connects all the graphic modules, which were created in the
        *.ui file and configures the event handling between the modules.
        """

        self._odmr_logic = self.get_connector('odmrlogic1')

        # Use the inherited class 'Ui_ODMRGuiUI' to create now the GUI element:
        self._mw = ODMRMainWindow()
        self._sd = ODMRSettingDialog()

        # Create a QSettings object for the mainwindow and store the actual GUI layout
        self.mwsettings = QtCore.QSettings("QUDI", "ODMR")
        self.mwsettings.setValue("geometry", self._mw.saveGeometry())
        self.mwsettings.setValue("windowState", self._mw.saveState())

        # Get hardware constraints to set limits for input widgets
        constraints = self._odmr_logic.get_hw_constraints()

        # Adjust range of scientific spinboxes above what is possible in Qt Designer
        self._mw.cw_frequency_DoubleSpinBox.setMaximum(constraints.max_frequency)
        self._mw.cw_frequency_DoubleSpinBox.setMinimum(constraints.min_frequency)
        self._mw.start_freq_DoubleSpinBox.setMaximum(constraints.max_frequency)
        self._mw.start_freq_DoubleSpinBox.setMinimum(constraints.min_frequency)
        self._mw.step_freq_DoubleSpinBox.setMaximum(100e9)
        self._mw.step_freq_DoubleSpinBox.setOpts(minStep=1.0)  # set the minimal step to 1Hz
        self._mw.stop_freq_DoubleSpinBox.setMaximum(constraints.max_frequency)
        self._mw.stop_freq_DoubleSpinBox.setMinimum(constraints.min_frequency)
        self._mw.cw_power_DoubleSpinBox.setMaximum(constraints.max_power)
        self._mw.cw_power_DoubleSpinBox.setMinimum(constraints.min_power)
        self._mw.cw_power_DoubleSpinBox.setOpts(minStep=0.1)
        self._mw.sweep_power_DoubleSpinBox.setMaximum(constraints.max_power)
        self._mw.sweep_power_DoubleSpinBox.setMinimum(constraints.min_power)
        self._mw.sweep_power_DoubleSpinBox.setOpts(minStep=0.1)

        # Add save file tag input box
        self._mw.save_tag_LineEdit = QtWidgets.QLineEdit(self._mw)
        self._mw.save_tag_LineEdit.setMaximumWidth(500)
        self._mw.save_tag_LineEdit.setMinimumWidth(200)
        self._mw.save_tag_LineEdit.setToolTip('Enter a nametag which will be\n'
                                              'added to the filename.')
        self._mw.save_ToolBar.addWidget(self._mw.save_tag_LineEdit)

        # add a clear button to clear the ODMR plots:
        self._mw.clear_odmr_PushButton = QtWidgets.QPushButton(self._mw)
        self._mw.clear_odmr_PushButton.setText('Clear ODMR')
        self._mw.clear_odmr_PushButton.setToolTip('Clear the data of the\n'
                                                  'current ODMR measurements.')
        self._mw.clear_odmr_PushButton.setEnabled(False)
        self._mw.toolBar.addWidget(self._mw.clear_odmr_PushButton)

        # Get the image from the logic
        self.odmr_matrix_image = pg.ImageItem(self._odmr_logic.odmr_plot_xy.transpose())
        self.odmr_matrix_image.setRect(QtCore.QRectF(
                self._odmr_logic.mw_start,
                0,
                self._odmr_logic.mw_stop - self._odmr_logic.mw_start,
                self._odmr_logic.number_of_lines
            ))

        self.odmr_image = pg.PlotDataItem(self._odmr_logic.odmr_plot_x,
                                          self._odmr_logic.odmr_plot_y,
                                          pen=pg.mkPen(palette.c1, style=QtCore.Qt.DotLine),
                                          symbol='o',
                                          symbolPen=palette.c1,
                                          symbolBrush=palette.c1,
                                          symbolSize=7)

        self.odmr_fit_image = pg.PlotDataItem(self._odmr_logic.odmr_fit_x,
                                              self._odmr_logic.odmr_fit_y,
                                              pen=pg.mkPen(palette.c2))

        # Add the display item to the xy and xz ViewWidget, which was defined in the UI file.
        self._mw.odmr_PlotWidget.addItem(self.odmr_image)
        self._mw.odmr_PlotWidget.setLabel(axis='left', text='Counts', units='Counts/s')
        self._mw.odmr_PlotWidget.setLabel(axis='bottom', text='Frequency', units='Hz')
        self._mw.odmr_PlotWidget.showGrid(x=True, y=True, alpha=0.8)

        self._mw.odmr_matrix_PlotWidget.addItem(self.odmr_matrix_image)
        self._mw.odmr_matrix_PlotWidget.setLabel(axis='left', text='Matrix Lines', units='#')
        self._mw.odmr_matrix_PlotWidget.setLabel(axis='bottom', text='Frequency', units='Hz')

        # Get the colorscales at set LUT
        my_colors = ColorScaleInferno()
        self.odmr_matrix_image.setLookupTable(my_colors.lut)

        ########################################################################
        #                  Configuration of the Colorbar                       #
        ########################################################################
        self.odmr_cb = ColorBar(my_colors.cmap_normed, 100, 0, 100000)

        # adding colorbar to ViewWidget
        self._mw.odmr_cb_PlotWidget.addItem(self.odmr_cb)
        self._mw.odmr_cb_PlotWidget.hideAxis('bottom')
        self._mw.odmr_cb_PlotWidget.hideAxis('left')
        self._mw.odmr_cb_PlotWidget.setLabel('right', 'Fluorescence', units='counts/s')

        ########################################################################
        #          Configuration of the various display Widgets                #
        ########################################################################
        # Take the default values from logic:
        self._mw.cw_frequency_DoubleSpinBox.setValue(self._odmr_logic.cw_mw_frequency)
        self._mw.start_freq_DoubleSpinBox.setValue(self._odmr_logic.mw_start)
        self._mw.stop_freq_DoubleSpinBox.setValue(self._odmr_logic.mw_stop)
        self._mw.step_freq_DoubleSpinBox.setValue(self._odmr_logic.mw_step)
        self._mw.cw_power_DoubleSpinBox.setValue(self._odmr_logic.cw_mw_power)
        self._mw.sweep_power_DoubleSpinBox.setValue(self._odmr_logic.sweep_mw_power)

        self._mw.runtime_DoubleSpinBox.setValue(self._odmr_logic.run_time)
        self._mw.elapsed_time_DisplayWidget.display(int(np.rint(self._odmr_logic.elapsed_time)))
        self._mw.elapsed_sweeps_DisplayWidget.display(self._odmr_logic.elapsed_sweeps)

        self._sd.matrix_lines_SpinBox.setValue(self._odmr_logic.number_of_lines)
        self._sd.clock_frequency_DoubleSpinBox.setValue(self._odmr_logic.clock_frequency)

        # fit settings
        self._fsd = FitSettingsDialog(self._odmr_logic.fc)
        self._fsd.sigFitsUpdated.connect(self._mw.fit_methods_ComboBox.setFitFunctions)
        self._fsd.applySettings()
        self._mw.action_FitSettings.triggered.connect(self._fsd.show)

        ########################################################################
        #                       Connect signals                                #
        ########################################################################
        # Internal user input changed signals
        self._mw.cw_frequency_DoubleSpinBox.editingFinished.connect(self.change_cw_params)
        self._mw.start_freq_DoubleSpinBox.editingFinished.connect(self.change_sweep_params)
        self._mw.step_freq_DoubleSpinBox.editingFinished.connect(self.change_sweep_params)
        self._mw.stop_freq_DoubleSpinBox.editingFinished.connect(self.change_sweep_params)
        self._mw.sweep_power_DoubleSpinBox.editingFinished.connect(self.change_sweep_params)
        self._mw.cw_power_DoubleSpinBox.editingFinished.connect(self.change_cw_params)
        self._mw.runtime_DoubleSpinBox.editingFinished.connect(self.change_runtime)
        self._mw.odmr_cb_max_DoubleSpinBox.valueChanged.connect(self.colorscale_changed)
        self._mw.odmr_cb_min_DoubleSpinBox.valueChanged.connect(self.colorscale_changed)
        self._mw.odmr_cb_high_percentile_DoubleSpinBox.valueChanged.connect(self.colorscale_changed)
        self._mw.odmr_cb_low_percentile_DoubleSpinBox.valueChanged.connect(self.colorscale_changed)
        # Internal trigger signals
        self._mw.odmr_cb_manual_RadioButton.clicked.connect(self.colorscale_changed)
        self._mw.odmr_cb_centiles_RadioButton.clicked.connect(self.colorscale_changed)
        self._mw.clear_odmr_PushButton.clicked.connect(self.clear_odmr_data)
        self._mw.action_run_stop.triggered.connect(self.run_stop_odmr)
        self._mw.action_resume_odmr.triggered.connect(self.resume_odmr)
        self._mw.action_toggle_cw.triggered.connect(self.toggle_cw_mode)
        self._mw.action_Save.triggered.connect(self.save_data)
        self._mw.action_RestoreDefault.triggered.connect(self.restore_defaultview)
        self._mw.do_fit_PushButton.clicked.connect(self.do_fit)

        # Control/values-changed signals to logic
        self.sigCwMwOn.connect(self._odmr_logic.mw_cw_on, QtCore.Qt.QueuedConnection)
        self.sigMwOff.connect(self._odmr_logic.mw_off, QtCore.Qt.QueuedConnection)
        self.sigClearData.connect(self._odmr_logic.clear_odmr_data, QtCore.Qt.QueuedConnection)
        self.sigStartOdmrScan.connect(self._odmr_logic.start_odmr_scan, QtCore.Qt.QueuedConnection)
        self.sigStopOdmrScan.connect(self._odmr_logic.stop_odmr_scan, QtCore.Qt.QueuedConnection)
        self.sigContinueOdmrScan.connect(self._odmr_logic.continue_odmr_scan,
                                         QtCore.Qt.QueuedConnection)
        self.sigDoFit.connect(self._odmr_logic.do_fit, QtCore.Qt.QueuedConnection)
        self.sigMwCwParamsChanged.connect(self._odmr_logic.set_cw_parameters,
                                          QtCore.Qt.QueuedConnection)
        self.sigMwSweepParamsChanged.connect(self._odmr_logic.set_sweep_parameters,
                                             QtCore.Qt.QueuedConnection)
        self.sigRuntimeChanged.connect(self._odmr_logic.set_runtime, QtCore.Qt.QueuedConnection)
        self.sigNumberOfLinesChanged.connect(self._odmr_logic.set_matrix_line_number,
                                             QtCore.Qt.QueuedConnection)
        self.sigSaveMeasurement.connect(self._odmr_logic.save_odmr_data, QtCore.Qt.QueuedConnection)

        # Update signals coming from logic:
        self._odmr_logic.sigParameterUpdated.connect(self.update_parameter,
                                                     QtCore.Qt.QueuedConnection)
        self._odmr_logic.sigOutputStateUpdated.connect(self.update_status,
                                                       QtCore.Qt.QueuedConnection)
        self._odmr_logic.sigOdmrPlotsUpdated.connect(self.update_plots, QtCore.Qt.QueuedConnection)
        self._odmr_logic.sigOdmrFitUpdated.connect(self.update_fit, QtCore.Qt.QueuedConnection)
        self._odmr_logic.sigOdmrElapsedTimeUpdated.connect(self.update_elapsedtime,
                                                           QtCore.Qt.QueuedConnection)

        # connect settings signals
        self._mw.action_Settings.triggered.connect(self._menu_settings)
        self._sd.accepted.connect(self.update_settings)
        self._sd.rejected.connect(self.reject_settings)
        self._sd.buttonBox.button(QtWidgets.QDialogButtonBox.Apply).clicked.connect(
            self.update_settings)
        self.reject_settings()

        # Show the Main ODMR GUI:
        self._show()
Exemplo n.º 8
0
    def on_activate(self):
        """ Initializes all needed UI files and establishes the connectors.
        """

        self._logic = self.camera_logic()
        self._save_logic = self.savelogic()

        # Windows
        self._mw = CameraWindow()
        self._mw.centralwidget.hide()
        self._mw.setDockNestingEnabled(True)
        self.initSettingsUI()
        self._sd.exposureDSpinBox.setDecimals(5)

        self._mw.start_video_Action.setEnabled(True)
        self._mw.start_video_Action.setChecked(self._logic.enabled)
        self._mw.start_video_Action.triggered.connect(self.start_video_clicked)

        self._mw.start_image_Action.setEnabled(True)
        self._mw.start_image_Action.setChecked(self._logic.enabled)
        self._mw.start_image_Action.triggered.connect(self.start_image_clicked)

        self._mw.action_toggle_cooling.toggled.connect(self.toggle_fan)

        self._logic.sigUpdateDisplay.connect(self.update_data)
        self._logic.sigAcquisitionFinished.connect(self.acquisition_finished)
        self._logic.sigVideoFinished.connect(self.enable_start_image_action)

        # starting the physical measurement
        self.sigVideoStart.connect(self._logic.start_loop)
        self.sigVideoStop.connect(self._logic.stop_loop)
        self.sigImageStart.connect(self._logic.start_single_acquistion)

        # connect Settings action under Options menu
        self._mw.actionSettings.triggered.connect(self.menu_settings)
        # connect save action to save function
        self._mw.actionSave_XY_Scan.triggered.connect(self.save_xy_scan_data)

        raw_data_image = self._logic.get_last_image()
        # This allows the camera GUI to take care of a 3darray of images if the cam GUI is initialized after
        # and ODMR measuremnt.
        try:
            if raw_data_image.ndim > 2:
                raw_data_image = np.zeros(self._logic.get_sensor())
        except BaseException:
            pass
        self._image = pg.ImageItem(image=raw_data_image, axisOrder='row-major')
        self._mw.image_PlotWidget.addItem(self._image)
        # Set ROI widget with default sensor size, snapping true and invisible color until and image is clicked.
        # Extra scale handles are added as well.
        # It has not been added to main window yet, so as to give a clean look when an image has not yet been
        # clicked.
        self.roi_p1 = self.roi_p2 = 0
        self.roi_s1, self.roi_s2 = self._logic.get_sensor()
        self.roi = pg.RectROI([self.roi_p1, self.roi_p2],
                              [self.roi_s1, self.roi_s2],
                              pen=(0, 0, 0, 0),
                              scaleSnap=True,
                              translateSnap=True,
                              maxBounds=QtCore.QRectF(self.roi_p1, self.roi_p2,
                                                      self.roi_s1,
                                                      self.roi_s2),
                              movable=False)
        self.roi.handleSize = 12
        self.roi.addScaleHandle((0, 1), (1, 0))
        self.roi.addScaleHandle((0, 0), (1, 1))
        self.roi.addScaleHandle((1, 0), (0, 1))
        self.roi.addTranslateHandle((1, 1), (0, 0))
        # self._mw.image_PlotWidget.addItem(self.roi)
        self._mw.image_PlotWidget.setAspectLocked(True)
        self.sigROISet.connect(self._logic.set_image_roi)
        # ROI button actions
        self._mw.DefaultRoi.clicked.connect(self.default_roi)
        self._mw.SetRoi.clicked.connect(self.set_roi)
        self._mw.DefaultRoi.setEnabled(False)
        self._mw.SetRoi.setEnabled(False)
        self._mw.image_PlotWidget.addItem(self.roi)

        self.cross = pg.CrosshairROI(pos=(self.roi_s1 / 2, self.roi_s2 / 2),
                                     size=(40, 40),
                                     translateSnap=True,
                                     rotateSnap=True,
                                     maxBounds=QtCore.QRectF(0, 0, 1200, 1200))
        self.cross.sigRegionChanged.connect(self.print_counts)
        self._mw.image_PlotWidget.addItem(self.cross)

        self.scaleBar = pg.LineSegmentROI(([0, 0], [100, 0]),
                                          pen={
                                              'color': "#E0D8D8",
                                              'width': 3
                                          })
        self._mw.image_PlotWidget.addItem(self.scaleBar)
        self.scaleBar.sigRegionChanged.connect(self.print_scale)

        # Get the colorscale and set the LUTs
        self.my_colors = ColorScaleInferno()

        self._image.setLookupTable(self.my_colors.lut)

        # Connect the buttons and inputs for the colorbar
        self._mw.xy_cb_manual_RadioButton.clicked.connect(
            self.update_xy_cb_range)
        self._mw.xy_cb_centiles_RadioButton.clicked.connect(
            self.update_xy_cb_range)

        self._mw.xy_cb_min_DoubleSpinBox.valueChanged.connect(
            self.shortcut_to_xy_cb_manual)
        self._mw.xy_cb_max_DoubleSpinBox.valueChanged.connect(
            self.shortcut_to_xy_cb_manual)
        self._mw.xy_cb_low_percentile_DoubleSpinBox.valueChanged.connect(
            self.shortcut_to_xy_cb_centiles)
        self._mw.xy_cb_high_percentile_DoubleSpinBox.valueChanged.connect(
            self.shortcut_to_xy_cb_centiles)

        # create color bar
        self.xy_cb = ColorBar(self.my_colors.cmap_normed,
                              width=100,
                              cb_min=0,
                              cb_max=100)
        self.depth_cb = ColorBar(self.my_colors.cmap_normed,
                                 width=100,
                                 cb_min=0,
                                 cb_max=100)
        self._mw.xy_cb_ViewWidget.addItem(self.xy_cb)
        self._mw.xy_cb_ViewWidget.hideAxis('bottom')
        self._mw.xy_cb_ViewWidget.setLabel('left', 'Fluorescence', units='c')
        self._mw.xy_cb_ViewWidget.setMouseEnabled(x=False, y=False)
Exemplo n.º 9
0
    def initMainUI(self):
        """ Definition, configuration and initialisation of the confocal GUI.

        This init connects all the graphic modules, which were created in the
        *.ui file and configures the event handling between the modules.
        Moreover it sets default values.
        """
        self._mainwindow = SnvmWindow()

        # All our gui elements are dockable, and so there should be no "central" widget.
        self._mainwindow.centralwidget.hide()
        self._mainwindow.setDockNestingEnabled(True)

        self.photon_colormap = ColorScaleInferno()
        self.afm_cmap = BlackAndWhite()
        self._crosshair_maxrange = None

        #Set up the SNVM image and colorbar
        self.snvm_image = ScanImageItem(axisOrder='row-major')
        self.snvm_image.setLookupTable(self.photon_colormap.lut)
        self._mainwindow.multiFreqPlotView.addItem(self.snvm_image)
        self._mainwindow.multiFreqPlotView.setLabel('bottom', 'X (nm)')
        self._mainwindow.multiFreqPlotView.setLabel('left', 'Y (nm)')
        self._mainwindow.multiFreqPlotView.toggle_crosshair(True, movable=True)
        self._mainwindow.multiFreqPlotView.set_crosshair_size((1, 1))
        self._mainwindow.multiFreqPlotView.sigCrosshairDraggedPosChanged.connect(
            self.move_afm_crosshair)

        snvm_im_vb = self.get_image_viewbox(self.snvm_image)
        snvm_im_vb.setAspectLocked(True)
        snvm_im_vb.toggle_selection(True)
        snvm_im_vb.toggle_zoom_by_selection(True)

        self.multifreq_cb = ColorBar(self.photon_colormap.cmap_normed,
                                     width=100,
                                     cb_min=0,
                                     cb_max=1)
        self._mainwindow.multiFreqCbarView.addItem(self.multifreq_cb)
        self._mainwindow.multiFreqCbarView.hideAxis('bottom')
        self._mainwindow.multiFreqCbarView.setMouseEnabled(x=False, y=False)

        #Set up the AFM image and colorbar
        self.afm_image = ScanImageItem(axisOrder='row-major')
        self._mainwindow.afmPlotView.addItem(self.afm_image)
        self._mainwindow.afmPlotView.setLabel('bottom', 'X (nm)')
        self._mainwindow.afmPlotView.setLabel('left', 'Y (nm)')
        self._mainwindow.afmPlotView.toggle_crosshair(True, movable=True)
        self._mainwindow.afmPlotView.set_crosshair_size((1, 1))
        self._mainwindow.afmPlotView.sigCrosshairDraggedPosChanged.connect(
            self.move_multifreq_crosshair)

        afm_im_vb = self.get_image_viewbox(self.afm_image)
        afm_im_vb.setAspectLocked(True)
        afm_im_vb.toggle_selection(True)
        afm_im_vb.toggle_zoom_by_selection(True)

        self.afm_cb = ColorBar(self.afm_cmap.cmap_normed,
                               width=100,
                               cb_min=0,
                               cb_max=1)
        self._mainwindow.afmCbarView.addItem(self.afm_cb)

        # Set up the confocal image and colorbar
        self.cfc_image = ScanImageItem(axisOrder='row-major')
        self.cfc_image.setLookupTable(self.photon_colormap.lut)
        self._mainwindow.confocalScannerView.addItem(self.cfc_image)
        self._mainwindow.confocalScannerView.setLabel('bottom', 'X (nm)')
        self._mainwindow.confocalScannerView.setLabel('left', 'Y (nm)')
        self._mainwindow.confocalScannerView.toggle_crosshair(True,
                                                              movable=True)
        self._mainwindow.confocalScannerView.set_crosshair_size((1, 1))

        cfc_im_vb = self.get_image_viewbox(self.cfc_image)
        cfc_im_vb.setAspectLocked(True)
        cfc_im_vb.toggle_selection(True)
        cfc_im_vb.toggle_zoom_by_selection(True)

        self.cfc_cb = ColorBar(self.photon_colormap.cmap_normed,
                               width=100,
                               cb_min=0,
                               cb_max=1)
        self._mainwindow.confocalCbarView.addItem(self.cfc_cb)

        # Set up the optimizer image and colorbar
        self.optimizer_image = ScanImageItem(axisOrder='row-major')
        self.optimizer_image.setLookupTable(self.photon_colormap.lut)
        self._mainwindow.optimizerView.addItem(self.optimizer_image)
        self._mainwindow.optimizerView.setLabel('bottom', 'X (nm)')
        self._mainwindow.optimizerView.setLabel('left', 'Y (nm)')

        opt_im_vb = self.get_image_viewbox(self.optimizer_image)
        opt_im_vb.setAspectLocked(True)

        self.opt_cb = ColorBar(self.photon_colormap.cmap_normed,
                               width=100,
                               cb_min=0,
                               cb_max=1)
        self._mainwindow.optimizerCbarView.addItem(self.opt_cb)

        #Set up the ODMR plot
        self.curr_odmr_trace = pg.PlotDataItem(skipFiniteCheck=False,
                                               connect='finite',
                                               pen=pg.mkPen(color='w'))
        self.average_odmr_trace = pg.PlotDataItem(skipFiniteCheck=True,
                                                  pen=pg.mkPen(color='r'))
        self._mainwindow.odmrPlotWidget.addItem(self.curr_odmr_trace)
        self._mainwindow.odmrPlotWidget.addItem(self.average_odmr_trace)
        self._mainwindow.odmrPlotWidget.setLabel('bottom', 'Frequency (GHz)')
        self._mainwindow.odmrPlotWidget.setLabel('left', 'Counts (GHz)')

        #Quick settings for the spinbox to view the frequency slices
        self._mainwindow.frequencySliceSelector.lineEdit().setReadOnly(True)

        self._viewIndex = 0  #Variable used to scroll through the SNVM images.Gets updated when clicking the frequency selector

        ########
        # AFM scanning settings
        ########
        #Put all the settings in a dictionary, for ease of access
        self._afm_widgets = dict()
        self._afm_widgets[self._mainwindow.xResolution.objectName(
        )] = self._mainwindow.xResolution
        self._afm_widgets[self._mainwindow.yResolution.objectName(
        )] = self._mainwindow.yResolution
        self._afm_widgets[self._mainwindow.xMinRange.objectName(
        )] = self._mainwindow.xMinRange
        self._afm_widgets[self._mainwindow.xMaxRange.objectName(
        )] = self._mainwindow.xMaxRange
        self._afm_widgets[self._mainwindow.yMinRange.objectName(
        )] = self._mainwindow.yMinRange
        self._afm_widgets[self._mainwindow.yMaxRange.objectName(
        )] = self._mainwindow.yMaxRange
        self._afm_widgets[
            self._mainwindow.fwpxTime.objectName()] = self._mainwindow.fwpxTime
        self._afm_widgets[self._mainwindow.storeRetrace.objectName(
        )] = self._mainwindow.storeRetrace

        #########
        self._afm_widgets['xResolution'].setValue(
            self._scanning_logic.scanning_x_resolution)
        self._afm_widgets['yResolution'].setValue(
            self._scanning_logic.scanning_y_resolution)
        self._afm_widgets['xMinRange'].setValue(
            self._scanning_logic.scanning_x_range[0] /
            self.xy_range_multiplier)
        self._afm_widgets['yMinRange'].setValue(
            self._scanning_logic.scanning_y_range[0] /
            self.xy_range_multiplier)
        self._afm_widgets['xMaxRange'].setValue(
            self._scanning_logic.scanning_x_range[1] /
            self.xy_range_multiplier)
        self._afm_widgets['yMaxRange'].setValue(
            self._scanning_logic.scanning_y_range[1] /
            self.xy_range_multiplier)
        self._afm_widgets['fwpxTime'].setValue(self._scanning_logic.px_time /
                                               self.px_time_multiplier)
        self._afm_widgets['storeRetrace'].setChecked(
            self._scanning_logic.store_retrace)
        #########

        #######
        # ODMR scanning settings
        ######
        #Also here, store in a dictionary if the widgets need to be accessed in for loops
        self._odmr_widgets = dict()
        self._odmr_widgets[
            self._mainwindow.mwStart.objectName()] = self._mainwindow.mwStart
        self._odmr_widgets[
            self._mainwindow.mwEnd.objectName()] = self._mainwindow.mwEnd
        self._odmr_widgets[
            self._mainwindow.mwStep.objectName()] = self._mainwindow.mwStep
        self._odmr_widgets[
            self._mainwindow.mwPower.objectName()] = self._mainwindow.mwPower
        self._odmr_widgets[self._mainwindow.mwAverages.objectName(
        )] = self._mainwindow.mwAverages

        #TODO: maybe turn the freq resolution of the GUI into a settable value
        self._mainwindow.mwStart.setDecimals(6)
        self._mainwindow.mwEnd.setDecimals(6)
        self._mainwindow.mwStep.setDecimals(6)

        #########
        self._odmr_widgets['mwStart'].setValue(
            self._scanning_logic.start_freq / self.startstopFreq_multiplier)
        self._odmr_widgets['mwEnd'].setValue(self._scanning_logic.stop_freq /
                                             self.startstopFreq_multiplier)
        self._odmr_widgets['mwStep'].setValue(
            self._scanning_logic.freq_resolution / self.stepFreq_multiplier)
        self._odmr_widgets['mwPower'].setValue(self._scanning_logic.mw_power)
        self._odmr_widgets['mwAverages'].setValue(
            self._scanning_logic.odmr_averages)
        #########

        #Connect the signals
        self.sigStartOptimizer.connect(self.optimize_counts,
                                       QtCore.Qt.QueuedConnection)
        self.sigStartScanning.connect(self.start_scanning,
                                      QtCore.Qt.QueuedConnection)
        self.sigGoTo.connect(self.go_to_point, QtCore.Qt.QueuedConnection)

        self._odmr_widgets['mwStart'].valueChanged.connect(
            self.accept_frequency_ranges)
        self._odmr_widgets['mwEnd'].valueChanged.connect(
            self.accept_frequency_ranges)
        self._odmr_widgets['mwStep'].valueChanged.connect(
            self.accept_frequency_ranges)

        self._scanning_logic.signal_scan_finished.connect(
            self.snvm_confocal_finished)
        self._scanning_logic.signal_freq_px_acquired.connect(
            self.refresh_odmr_plot)
        self._scanning_logic.signal_snvm_image_updated.connect(
            self.refresh_snvm_image)
        self._scanning_logic.signal_snvm_image_updated.connect(
            self.refresh_afm_image)
        self._scanning_logic.signal_xy_image_updated.connect(
            self.refresh_confocal_image)
        self._scanning_logic.signal_snvm_initialized.connect(
            self.set_snvm_im_range)
        self._scanning_logic.signal_confocal_initialized.connect(
            self.set_confocal_im_range)
        self._scanning_logic.signal_moved_to_point.connect(self.go_to_finished)

        self._optimizer_logic.sigImageUpdated.connect(
            self.refresh_optimizer_image)
        self._optimizer_logic.sigRefocusStarted.connect(
            self.set_optimizer_im_range)
        self._optimizer_logic.sigRefocusFinished.connect(
            self._optimization_complete)

        self._mainwindow.frequencySliceSelector.stepClicked.connect(
            self.frequency_selector_clicked)
        self._mainwindow.sampleTraceViewSpinBox.valueChanged.connect(
            self.refresh_snvm_image)
        self._mainwindow.sampleTraceViewSpinBox.valueChanged.connect(
            self.refresh_afm_image)
        self._mainwindow.tipTraceViewSpinBox.valueChanged.connect(
            self.refresh_confocal_image)

        ##############
        # Connect the actions to their slots
        ##############
        self._mainwindow.actionStart_snvmscan.triggered.connect(
            self.scanning_action_clicked)
        self._mainwindow.actionStart_conf_scan.triggered.connect(
            self.scanning_action_clicked)
        self._mainwindow.actionStop_scan.triggered.connect(
            self.stop_scanning_request)
        self._mainwindow.actionOptimize.triggered.connect(
            self.scanning_action_clicked)
        self._mainwindow.actionOptimizer_settings.triggered.connect(
            self.menu_optimizer_settings)
        self._mainwindow.actionSnvm_settings.triggered.connect(
            self.menu_snvm_settings)
        self._mainwindow.action_snvm_goToPoint.triggered.connect(
            self.scanning_action_clicked)
        self._mainwindow.action_cfc_goToPoint.triggered.connect(
            self.scanning_action_clicked)
        self._mainwindow.actionSave_snvm.triggered.connect(self.save_snvm_data)
        self._mainwindow.actionSave_confocal.triggered.connect(
            self.save_confocal_data)

        self._mainwindow.actionStop_scan.setEnabled(False)
        self.show()
Exemplo n.º 10
0
    def on_activate(self):
        """ Definition, configuration and initialisation of the ODMR GUI.

        This init connects all the graphic modules, which were created in the
        *.ui file and configures the event handling between the modules.

        """

        self._voltscan_logic = self.get_connector('odmrlogic1')
        print("ODMR logic is", self._odmr_logic)

        # Use the inherited class 'Ui_VoltagescannerGuiUI' to create now the
        # GUI element:
        self._mw = VoltScanMainWindow()

        # Get the image from the logic
        self.odmr_matrix_image = pg.ImageItem(self._odmr_logic.ODMR_plot_xy.transpose())
        self.odmr_matrix_image.setRect(QtCore.QRectF(self._odmr_logic.mw_start,0,self._odmr_logic.mw_stop-self._odmr_logic.mw_start,self._odmr_logic.number_of_lines))
        self.odmr_image = pg.PlotDataItem(self._odmr_logic.ODMR_plot_x,self._odmr_logic.ODMR_plot_y)
        self.odmr_fit_image = pg.PlotDataItem(self._odmr_logic.ODMR_fit_x,self._odmr_logic.ODMR_fit_y,
                                                    pen=QtGui.QPen(QtGui.QColor(255,255,255,255)))


        # Add the display item to the xy and xz VieWidget, which was defined in
        # the UI file.
        self._mw.voltscan_ViewWidget.addItem(self.odmr_image)
        self._mw.voltscan_ViewWidget.addItem(self.odmr_fit_image)
        self._mw.voltscan_matrix_ViewWidget.addItem(self.odmr_matrix_image)
        self._mw.vonsoltscan_ViewWidget.showGrid(x=True, y=True, alpha=0.8)



        # Get the colorscales at set LUT
        my_colors = ColorScaleInferno()

        self.odmr_matrix_image.setLookupTable(my_colors.lut)

        # Set the state button as ready button as default setting.
        # self._mw.idle_StateWidget.click()

        # Configuration of the comboWidget
        self._mw.mode_ComboWidget.addItem('Off')
        self._mw.mode_ComboWidget.addItem('CW')

        self._mw.fit_methods_ComboWidget.addItem('No Fit')
        self._mw.fit_methods_ComboWidget.addItem('Lorentzian')
        self._mw.fit_methods_ComboWidget.addItem('Double Lorentzian')
        self._mw.fit_methods_ComboWidget.addItem('Double Lorentzian with fixed splitting')
        self._mw.fit_methods_ComboWidget.addItem('N14')
        self._mw.fit_methods_ComboWidget.addItem('N15')


        #######################################################################
        ##                Configuration of the Colorbar                      ##
        #######################################################################

        self.odmr_cb = ColorBar(my_colors.cmap_normed, 100, 0, 100000)

        #adding colorbar to ViewWidget
        self._mw.odmr_cb_ViewWidget.addItem(self.odmr_cb)
        self._mw.odmr_cb_ViewWidget.hideAxis('bottom')
        self._mw.odmr_cb_ViewWidget.hideAxis('left')
        self._mw.odmr_cb_ViewWidget.setLabel('right', 'Fluorescence', units='c/s')

        # Connect the buttons and inputs for the odmr colorbar
        self._mw.odmr_cb_manual_RadioButton.clicked.connect(self.refresh_matrix)
        self._mw.odmr_cb_centiles_RadioButton.clicked.connect(self.refresh_matrix)


        #######################################################################
        ##                Configuration of the InputWidgets                  ##
        #######################################################################

        # Add Validators to InputWidgets
        validator = QtGui.QDoubleValidator()
        validator2 = QtGui.QIntValidator()

        self._mw.frequency_InputWidget.setValidator(validator)
        self._mw.start_freq_InputWidget.setValidator(validator)
        self._mw.step_freq_InputWidget.setValidator(validator)
        self._mw.stop_freq_InputWidget.setValidator(validator)
        self._mw.power_InputWidget.setValidator(validator)
        self._mw.runtime_InputWidget.setValidator(validator2)
        self._sd.matrix_lines_InputWidget.setValidator(validator)
        self._sd.clock_frequency_InputWidget.setValidator(validator2)

        # Take the default values from logic:
        self._mw.frequency_InputWidget.setText(str(self._odmr_logic.mw_frequency))
        self._mw.start_freq_InputWidget.setText(str(self._odmr_logic.mw_start))
        self._mw.step_freq_InputWidget.setText(str(self._odmr_logic.mw_step))
        self._mw.stop_freq_InputWidget.setText(str(self._odmr_logic.mw_stop))
        self._mw.power_InputWidget.setText(str(self._odmr_logic.mw_power))
        self._mw.runtime_InputWidget.setText(str(self._odmr_logic.run_time))
        self._mw.elapsed_time_DisplayWidget.display(int(self._odmr_logic.ElapsedTime))
        self._sd.matrix_lines_InputWidget.setText(str(self._odmr_logic.number_of_lines))
        self._sd.clock_frequency_InputWidget.setText(str(self._odmr_logic._clock_frequency))

        # Update the inputed/displayed numbers if return key is hit:

        self._mw.frequency_InputWidget.returnPressed.connect(self.change_frequency)
        self._mw.start_freq_InputWidget.returnPressed.connect(self.change_start_freq)
        self._mw.step_freq_InputWidget.returnPressed.connect(self.change_step_freq)
        self._mw.stop_freq_InputWidget.returnPressed.connect(self.change_stop_freq)
        self._mw.power_InputWidget.returnPressed.connect(self.change_power)
        self._mw.runtime_InputWidget.returnPressed.connect(self.change_runtime)

        # Update the inputed/displayed numbers if the cursor has left the field:

        self._mw.frequency_InputWidget.editingFinished.connect(self.change_frequency)
        self._mw.start_freq_InputWidget.editingFinished.connect(self.change_start_freq)
        self._mw.step_freq_InputWidget.editingFinished.connect(self.change_step_freq)
        self._mw.stop_freq_InputWidget.editingFinished.connect(self.change_stop_freq)
        self._mw.power_InputWidget.editingFinished.connect(self.change_power)
        self._mw.runtime_InputWidget.editingFinished.connect(self.change_runtime)

        #

        self._mw.odmr_cb_max_InputWidget.valueChanged.connect(self.refresh_matrix)
        self._mw.odmr_cb_min_InputWidget.valueChanged.connect(self.refresh_matrix)
        self._mw.odmr_cb_high_centile_InputWidget.valueChanged.connect(self.refresh_matrix)
        self._mw.odmr_cb_low_centile_InputWidget.valueChanged.connect(self.refresh_matrix)

        #######################################################################
        ##                      Connect signals                              ##
        #######################################################################

        # Connect the RadioButtons and connect to the events if they are clicked:
        # self._mw.idle_StateWidget.toggled.connect(self.idle_clicked)
        # self._mw.run_StateWidget.toggled.connect(self.run_clicked)
        self._mw.action_run_stop.toggled.connect(self.run_stop)
        self._mw.action_Save.triggered.connect(self._odmr_logic.save_ODMR_Data)

        self._odmr_logic.sigOdmrPlotUpdated.connect(self.refresh_plot)
        self._odmr_logic.sigOdmrPlotUpdated.connect(self.refresh_matrix)
        self._odmr_logic.sigOdmrElapsedTimeChanged.connect(self.refresh_elapsedtime)
        # connect settings signals
        self._mw.action_Settings.triggered.connect(self.menue_settings)
        self._sd.accepted.connect(self.update_settings)
        self._sd.rejected.connect(self.reject_settings)
        self._sd.buttonBox.button(QtWidgets.QDialogButtonBox.Apply).clicked.connect(self.update_settings)
        self.reject_settings()
        # Connect stop odmr
        # self._odmr_logic.sigOdmrFinished.connect(self._mw.idle_StateWidget.click)
        self._odmr_logic.sigOdmrFinished.connect(self.odmr_stopped)
        # Combo Widget
        self._mw.mode_ComboWidget.activated[str].connect(self.mw_stop)
        self._mw.fit_methods_ComboWidget.activated[str].connect(self.update_fit_variable)
        # Push Buttons
        self._mw.do_fit_PushButton.clicked.connect(self.update_fit)

        # Show the Main ODMR GUI:
        self._mw.show()
Exemplo n.º 11
0
class VoltScanGui(GUIBase):
    """
    This is the GUI Class for ODMR
    """
    _modclass = 'VoltScanGui'
    _modtype = 'gui'
    ## declare connectors
    _connectors = {'voltagescannerlogic1': 'VoltageScannerLogic',
          }

    def __init__(self, config, **kwargs):
        super().__init__(config=config, **kwargs)

        self.log.info('The following configuration was found.')

        # checking for the right configuration
        for key in config.keys():
            self.log.info('{0}: {1}'.format(key,config[key]))

    def on_deactivate(self):
        """ Reverse steps of activation

        @return int: error code (0:OK, -1:error)
        """
        self._mw.close()
        return 0

    def on_activate(self):
        """ Definition, configuration and initialisation of the ODMR GUI.

        This init connects all the graphic modules, which were created in the
        *.ui file and configures the event handling between the modules.

        """

        self._voltscan_logic = self.get_connector('odmrlogic1')
        print("ODMR logic is", self._odmr_logic)

        # Use the inherited class 'Ui_VoltagescannerGuiUI' to create now the
        # GUI element:
        self._mw = VoltScanMainWindow()

        # Get the image from the logic
        self.odmr_matrix_image = pg.ImageItem(self._odmr_logic.ODMR_plot_xy.transpose())
        self.odmr_matrix_image.setRect(QtCore.QRectF(self._odmr_logic.mw_start,0,self._odmr_logic.mw_stop-self._odmr_logic.mw_start,self._odmr_logic.number_of_lines))
        self.odmr_image = pg.PlotDataItem(self._odmr_logic.ODMR_plot_x,self._odmr_logic.ODMR_plot_y)
        self.odmr_fit_image = pg.PlotDataItem(self._odmr_logic.ODMR_fit_x,self._odmr_logic.ODMR_fit_y,
                                                    pen=QtGui.QPen(QtGui.QColor(255,255,255,255)))


        # Add the display item to the xy and xz VieWidget, which was defined in
        # the UI file.
        self._mw.voltscan_ViewWidget.addItem(self.odmr_image)
        self._mw.voltscan_ViewWidget.addItem(self.odmr_fit_image)
        self._mw.voltscan_matrix_ViewWidget.addItem(self.odmr_matrix_image)
        self._mw.vonsoltscan_ViewWidget.showGrid(x=True, y=True, alpha=0.8)



        # Get the colorscales at set LUT
        my_colors = ColorScaleInferno()

        self.odmr_matrix_image.setLookupTable(my_colors.lut)

        # Set the state button as ready button as default setting.
        # self._mw.idle_StateWidget.click()

        # Configuration of the comboWidget
        self._mw.mode_ComboWidget.addItem('Off')
        self._mw.mode_ComboWidget.addItem('CW')

        self._mw.fit_methods_ComboWidget.addItem('No Fit')
        self._mw.fit_methods_ComboWidget.addItem('Lorentzian')
        self._mw.fit_methods_ComboWidget.addItem('Double Lorentzian')
        self._mw.fit_methods_ComboWidget.addItem('Double Lorentzian with fixed splitting')
        self._mw.fit_methods_ComboWidget.addItem('N14')
        self._mw.fit_methods_ComboWidget.addItem('N15')


        #######################################################################
        ##                Configuration of the Colorbar                      ##
        #######################################################################

        self.odmr_cb = ColorBar(my_colors.cmap_normed, 100, 0, 100000)

        #adding colorbar to ViewWidget
        self._mw.odmr_cb_ViewWidget.addItem(self.odmr_cb)
        self._mw.odmr_cb_ViewWidget.hideAxis('bottom')
        self._mw.odmr_cb_ViewWidget.hideAxis('left')
        self._mw.odmr_cb_ViewWidget.setLabel('right', 'Fluorescence', units='c/s')

        # Connect the buttons and inputs for the odmr colorbar
        self._mw.odmr_cb_manual_RadioButton.clicked.connect(self.refresh_matrix)
        self._mw.odmr_cb_centiles_RadioButton.clicked.connect(self.refresh_matrix)


        #######################################################################
        ##                Configuration of the InputWidgets                  ##
        #######################################################################

        # Add Validators to InputWidgets
        validator = QtGui.QDoubleValidator()
        validator2 = QtGui.QIntValidator()

        self._mw.frequency_InputWidget.setValidator(validator)
        self._mw.start_freq_InputWidget.setValidator(validator)
        self._mw.step_freq_InputWidget.setValidator(validator)
        self._mw.stop_freq_InputWidget.setValidator(validator)
        self._mw.power_InputWidget.setValidator(validator)
        self._mw.runtime_InputWidget.setValidator(validator2)
        self._sd.matrix_lines_InputWidget.setValidator(validator)
        self._sd.clock_frequency_InputWidget.setValidator(validator2)

        # Take the default values from logic:
        self._mw.frequency_InputWidget.setText(str(self._odmr_logic.mw_frequency))
        self._mw.start_freq_InputWidget.setText(str(self._odmr_logic.mw_start))
        self._mw.step_freq_InputWidget.setText(str(self._odmr_logic.mw_step))
        self._mw.stop_freq_InputWidget.setText(str(self._odmr_logic.mw_stop))
        self._mw.power_InputWidget.setText(str(self._odmr_logic.mw_power))
        self._mw.runtime_InputWidget.setText(str(self._odmr_logic.run_time))
        self._mw.elapsed_time_DisplayWidget.display(int(self._odmr_logic.ElapsedTime))
        self._sd.matrix_lines_InputWidget.setText(str(self._odmr_logic.number_of_lines))
        self._sd.clock_frequency_InputWidget.setText(str(self._odmr_logic._clock_frequency))

        # Update the inputed/displayed numbers if return key is hit:

        self._mw.frequency_InputWidget.returnPressed.connect(self.change_frequency)
        self._mw.start_freq_InputWidget.returnPressed.connect(self.change_start_freq)
        self._mw.step_freq_InputWidget.returnPressed.connect(self.change_step_freq)
        self._mw.stop_freq_InputWidget.returnPressed.connect(self.change_stop_freq)
        self._mw.power_InputWidget.returnPressed.connect(self.change_power)
        self._mw.runtime_InputWidget.returnPressed.connect(self.change_runtime)

        # Update the inputed/displayed numbers if the cursor has left the field:

        self._mw.frequency_InputWidget.editingFinished.connect(self.change_frequency)
        self._mw.start_freq_InputWidget.editingFinished.connect(self.change_start_freq)
        self._mw.step_freq_InputWidget.editingFinished.connect(self.change_step_freq)
        self._mw.stop_freq_InputWidget.editingFinished.connect(self.change_stop_freq)
        self._mw.power_InputWidget.editingFinished.connect(self.change_power)
        self._mw.runtime_InputWidget.editingFinished.connect(self.change_runtime)

        #

        self._mw.odmr_cb_max_InputWidget.valueChanged.connect(self.refresh_matrix)
        self._mw.odmr_cb_min_InputWidget.valueChanged.connect(self.refresh_matrix)
        self._mw.odmr_cb_high_centile_InputWidget.valueChanged.connect(self.refresh_matrix)
        self._mw.odmr_cb_low_centile_InputWidget.valueChanged.connect(self.refresh_matrix)

        #######################################################################
        ##                      Connect signals                              ##
        #######################################################################

        # Connect the RadioButtons and connect to the events if they are clicked:
        # self._mw.idle_StateWidget.toggled.connect(self.idle_clicked)
        # self._mw.run_StateWidget.toggled.connect(self.run_clicked)
        self._mw.action_run_stop.toggled.connect(self.run_stop)
        self._mw.action_Save.triggered.connect(self._odmr_logic.save_ODMR_Data)

        self._odmr_logic.sigOdmrPlotUpdated.connect(self.refresh_plot)
        self._odmr_logic.sigOdmrPlotUpdated.connect(self.refresh_matrix)
        self._odmr_logic.sigOdmrElapsedTimeChanged.connect(self.refresh_elapsedtime)
        # connect settings signals
        self._mw.action_Settings.triggered.connect(self.menue_settings)
        self._sd.accepted.connect(self.update_settings)
        self._sd.rejected.connect(self.reject_settings)
        self._sd.buttonBox.button(QtWidgets.QDialogButtonBox.Apply).clicked.connect(self.update_settings)
        self.reject_settings()
        # Connect stop odmr
        # self._odmr_logic.sigOdmrFinished.connect(self._mw.idle_StateWidget.click)
        self._odmr_logic.sigOdmrFinished.connect(self.odmr_stopped)
        # Combo Widget
        self._mw.mode_ComboWidget.activated[str].connect(self.mw_stop)
        self._mw.fit_methods_ComboWidget.activated[str].connect(self.update_fit_variable)
        # Push Buttons
        self._mw.do_fit_PushButton.clicked.connect(self.update_fit)

        # Show the Main ODMR GUI:
        self._mw.show()




    def show(self):
        """Make window visible and put it above all other windows. """
        QtWidgets.QMainWindow.show(self._mw)
        self._mw.activateWindow()
        self._mw.raise_()

#     def idle_clicked(self):
#         """ Stopp the scan if the state has switched to idle. """
#         self._odmr_logic.stop_odmr_scan()
#         self._sd.matrix_lines_InputWidget.setReadOnly(False)
# #        self._odmr_logic.kill_odmr()
#
#
#     def run_clicked(self, enabled):
#         """ Manages what happens if odmr scan is started.
#
#         @param bool enabled: start scan if that is possible
#         """
#
#         #Firstly stop any scan that might be in progress
#         self._odmr_logic.stop_odmr_scan()
# #        self._odmr_logic.kill_odmr()
#         #Then if enabled. start a new odmr scan.
#         if enabled:
#             self._odmr_logic.start_odmr_scan()
#             self._sd.matrix_lines_InputWidget.setReadOnly(True)

    def run_stop(self, is_checked):
        """ Manages what happens if odmr scan is started/stopped """
        if is_checked:
            self._odmr_logic.stop_odmr_scan()
            self._odmr_logic.start_odmr_scan()
            self._mw.odmr_ViewWidget.removeItem(self.odmr_fit_image)
            self._sd.matrix_lines_InputWidget.setReadOnly(True)
        else:
            self._odmr_logic.stop_odmr_scan()
            self._sd.matrix_lines_InputWidget.setReadOnly(False)

    def odmr_stopped(self):
        """ Switch the run/stop button to stop after receiving an odmr_stoped signal """
        self._mw.action_run_stop.setChecked(False)

    def menue_settings(self):
        """ Open the settings menue """
        self._sd.exec_()

    def refresh_plot(self):
        """ Refresh the xy-plot image """
        self.odmr_image.setData(self._odmr_logic.ODMR_plot_x,self._odmr_logic.ODMR_plot_y)
        if not self._mw.fit_methods_ComboWidget.currentText() == 'No Fit':
            self.odmr_fit_image.setData(self._odmr_logic.ODMR_fit_x,self._odmr_logic.ODMR_fit_y,pen=QtGui.QPen(QtGui.QColor(255,0,255,255)))
        else:
            if self.odmr_fit_image in self._mw.odmr_ViewWidget.listDataItems():
                self._mw.odmr_ViewWidget.removeItem(self.odmr_fit_image)

    def refresh_matrix(self):
        """ Refresh the xy-matrix image """
#        self.odmr_matrix_image.setImage(self._odmr_logic.ODMR_plot_xy.transpose())
#        self.odmr_matrix_image.setRect(QtCore.QRectF(self._odmr_logic.mw_start,0,self._odmr_logic.mw_stop-self._odmr_logic.mw_start,self._odmr_logic.number_of_lines))
#        self.refresh_odmr_colorbar()


        odmr_image_data = self._odmr_logic.ODMR_plot_xy.transpose()

        # If "Centiles" is checked, adjust colour scaling automatically to centiles.
        # Otherwise, take user-defined values.
        if self._mw.odmr_cb_centiles_RadioButton.isChecked():
            low_centile = self._mw.odmr_cb_low_centile_InputWidget.value()
            high_centile = self._mw.odmr_cb_high_centile_InputWidget.value()

            cb_min = np.percentile( odmr_image_data, low_centile )
            cb_max = np.percentile( odmr_image_data, high_centile )

        else:
            cb_min = self._mw.odmr_cb_min_InputWidget.value()
            cb_max = self._mw.odmr_cb_max_InputWidget.value()

        # Now update image with new color scale, and update colorbar
        self.odmr_matrix_image.setImage(image=odmr_image_data, levels=(cb_min, cb_max) )
        self.odmr_matrix_image.setRect(QtCore.QRectF(self._odmr_logic.mw_start,0,self._odmr_logic.mw_stop-self._odmr_logic.mw_start,self._odmr_logic.number_of_lines))
        self.refresh_odmr_colorbar()


    def refresh_odmr_colorbar(self):
        """ Update the colorbar to a new scaling."""

        # If "Centiles" is checked, adjust colour scaling automatically to centiles.
        # Otherwise, take user-defined values.
        if self._mw.odmr_cb_centiles_RadioButton.isChecked():
            low_centile = self._mw.odmr_cb_low_centile_InputWidget.value()
            high_centile = self._mw.odmr_cb_high_centile_InputWidget.value()

            cb_min = np.percentile( self.odmr_matrix_image.image, low_centile )
            cb_max = np.percentile( self.odmr_matrix_image.image, high_centile )

        else:
            cb_min = self._mw.odmr_cb_min_InputWidget.value()
            cb_max = self._mw.odmr_cb_max_InputWidget.value()

        self.odmr_cb.refresh_colorbar(cb_min,cb_max)
        self._mw.odmr_cb_ViewWidget.update()

    def refresh_elapsedtime(self):
        self._mw.elapsed_time_DisplayWidget.display(int(self._odmr_logic.ElapsedTime))

    def update_settings(self):
        """ Write the new settings from the gui to the file. """
        self._odmr_logic.number_of_lines = int(self._sd.matrix_lines_InputWidget.text())
        self._odmr_logic.set_clock_frequency(int(self._sd.clock_frequency_InputWidget.text()))
        self._odmr_logic.safeRawData = self._sd.save_raw_data_box.isChecked()

    def update_fit_variable(self, txt):
        self._odmr_logic.current_fit_function = txt

    def update_fit(self):
        self._odmr_logic.do_fit(fit_function = self._odmr_logic.current_fit_function)
        self.refresh_plot()

        # check which Fit method is used and remove or add again the
        # odmr_fit_image, check also whether a odmr_fit_image already exists.
        if self._mw.fit_methods_ComboWidget.currentText() == 'No Fit':
            if self.odmr_fit_image in self._mw.odmr_ViewWidget.listDataItems():
                self._mw.odmr_ViewWidget.removeItem(self.odmr_fit_image)
        else:
            if self.odmr_fit_image not in self._mw.odmr_ViewWidget.listDataItems():
                self._mw.odmr_ViewWidget.addItem(self.odmr_fit_image)

        self._mw.odmr_ViewWidget.getViewBox().updateAutoRange()
        self._mw.odmr_fit_results_DisplayWidget.clear()
        self._mw.odmr_fit_results_DisplayWidget.setPlainText(str(self._odmr_logic.fit_result))

    def reject_settings(self):
        """ Keep the old settings and restores the old settings in the gui. """
        self._sd.matrix_lines_InputWidget.setText(str(self._odmr_logic.number_of_lines))
        self._sd.clock_frequency_InputWidget.setText(str(self._odmr_logic._clock_frequency))
        self._sd.save_raw_data_box.setChecked(self._odmr_logic.safeRawData)

    def mw_stop(self, txt):
        if txt == 'Off':
            self._odmr_logic.MW_off()
        if txt == 'CW':
            self.change_frequency()
            self.change_power()
            self._odmr_logic.MW_on()



    ###########################################################################
    ##                         Change Methods                                ##
    ###########################################################################

    def change_frequency(self):
        self._odmr_logic.set_frequency(frequency = float(self._mw.frequency_InputWidget.text()))

    def change_start_freq(self):
        self._odmr_logic.mw_start = float(self._mw.start_freq_InputWidget.text())

    def change_step_freq(self):
        self._odmr_logic.mw_step = float(self._mw.step_freq_InputWidget.text())

    def change_stop_freq(self):
        self._odmr_logic.mw_stop = float(self._mw.stop_freq_InputWidget.text())

    def change_power(self):
        self._odmr_logic.mw_power = float(self._mw.power_InputWidget.text())
        self._odmr_logic.set_power(power = self._odmr_logic.mw_power)

    def change_runtime(self):
        self._odmr_logic.run_time = float(self._mw.runtime_InputWidget.text())
Exemplo n.º 12
0
class PoiManagerGui(GUIBase):

    """ This is the GUI Class for PoiManager """

    _modclass = 'PoiManagerGui'
    _modtype = 'gui'

    # declare connectors
    poimanagerlogic = Connector(interface='PoiManagerLogic')
    scannerlogic = Connector(interface='ConfocalLogic')

    # declare signals
    sigTrackPeriodChanged = QtCore.Signal(float)
    sigPoiNameChanged = QtCore.Signal(str)
    sigPoiNameTagChanged = QtCore.Signal(str)
    sigRoiNameChanged = QtCore.Signal(str)
    sigAddPoiByClick = QtCore.Signal(np.ndarray)

    def __init__(self, config, **kwargs):
        super().__init__(config=config, **kwargs)

        self._mw = None             # QMainWindow handle
        self.roi_image = None       # pyqtgraph PlotImage for ROI scan image
        self.roi_cb = None          # The qudi colorbar to use with roi_image
        self.x_shift_plot = None    # pyqtgraph PlotDataItem for ROI history plot
        self.y_shift_plot = None    # pyqtgraph PlotDataItem for ROI history plot
        self.z_shift_plot = None    # pyqtgraph PlotDataItem for ROI history plot

        self._markers = dict()      # dict to hold handles for the POI markers

        self._mouse_moved_proxy = None  # Signal proxy to limit mousMoved event rate

        self.__poi_selector_active = False  # Flag indicating if the poi selector is active
        return

    def on_activate(self):
        """
        Initializes the overall GUI, and establishes the connectors.

        This method executes the init methods for each of the GUIs.
        """
        self._markers = dict()

        self._mw = PoiManagerMainWindow()
        # Configuring the dock widgets.
        # All our gui elements are dockable, so there should be no "central" widget.
        self._mw.centralwidget.hide()
        self._mw.setDockNestingEnabled(True)

        # Add validator to LineEdits
        self._mw.roi_name_LineEdit.setValidator(NameValidator())
        self._mw.poi_name_LineEdit.setValidator(NameValidator())
        self._mw.poi_nametag_LineEdit.setValidator(NameValidator(empty_allowed=True))

        # Initialize plots
        self.__init_roi_scan_image()
        self.__init_roi_history_plot()

        # Initialize refocus timer
        self.update_refocus_timer(self.poimanagerlogic().module_state() == 'locked',
                                  self.poimanagerlogic().refocus_period,
                                  self.poimanagerlogic().refocus_period)
        # Initialize POIs
        self._update_pois(self.poimanagerlogic().poi_positions)
        # Initialize ROI name
        self._update_roi_name(self.poimanagerlogic().roi_name)
        # Initialize POI nametag
        self._update_poi_nametag(self.poimanagerlogic().poi_nametag)

        # Distance Measurement:
        # Introducing a SignalProxy will limit the rate of signals that get fired.
        self._mouse_moved_proxy = pg.SignalProxy(signal=self.roi_image.scene().sigMouseMoved,
                                                 rateLimit=30,
                                                 slot=self.mouse_moved_callback)

        # Connect signals
        self.__connect_internal_signals()
        self.__connect_update_signals_from_logic()
        self.__connect_control_signals_to_logic()

        self._mw.show()
        return

    def on_deactivate(self):
        """
        De-initialisation performed during deactivation of the module.
        """
        self.toggle_poi_selector(False)
        self.__disconnect_control_signals_to_logic()
        self.__disconnect_update_signals_from_logic()
        self.__disconnect_internal_signals()
        self._mw.close()

    def __init_roi_scan_image(self):
        # Get the color scheme
        my_colors = ColorScaleInferno()
        # Setting up display of ROI xy scan image
        self.roi_image = ScanImageItem(axisOrder='row-major', lut=my_colors.lut)
        self._mw.roi_map_ViewWidget.addItem(self.roi_image)
        self._mw.roi_map_ViewWidget.setLabel('bottom', 'X position', units='m')
        self._mw.roi_map_ViewWidget.setLabel('left', 'Y position', units='m')
        self._mw.roi_map_ViewWidget.setAspectLocked(lock=True, ratio=1.0)
        # Set up color bar
        self.roi_cb = ColorBar(my_colors.cmap_normed, 100, 0, 100000)
        self._mw.roi_cb_ViewWidget.addItem(self.roi_cb)
        self._mw.roi_cb_ViewWidget.hideAxis('bottom')
        self._mw.roi_cb_ViewWidget.setLabel('left', 'Fluorescence', units='c/s')
        self._mw.roi_cb_ViewWidget.setMouseEnabled(x=False, y=False)

        # Get scan image from logic and update initialize plot
        self._update_scan_image(self.poimanagerlogic().roi_scan_image,
                                self.poimanagerlogic().roi_scan_image_extent)
        return

    def __init_roi_history_plot(self):
        # Setting up display of sample shift plot
        self.x_shift_plot = pg.PlotDataItem(x=[0],
                                            y=[0],
                                            pen=pg.mkPen(palette.c1, style=QtCore.Qt.DotLine),
                                            symbol='o',
                                            symbolPen=palette.c1,
                                            symbolBrush=palette.c1,
                                            symbolSize=5,
                                            name='x')
        self.y_shift_plot = pg.PlotDataItem(x=[0],
                                            y=[0],
                                            pen=pg.mkPen(palette.c2, style=QtCore.Qt.DotLine),
                                            symbol='s',
                                            symbolPen=palette.c2,
                                            symbolBrush=palette.c2,
                                            symbolSize=5,
                                            name='y')
        self.z_shift_plot = pg.PlotDataItem(x=[0],
                                            y=[0],
                                            pen=pg.mkPen(palette.c3, style=QtCore.Qt.DotLine),
                                            symbol='t',
                                            symbolPen=palette.c3,
                                            symbolBrush=palette.c3,
                                            symbolSize=5,
                                            name='z')

        self._mw.sample_shift_ViewWidget.addLegend()

        # Add the plot to the ViewWidget defined in the UI file
        self._mw.sample_shift_ViewWidget.addItem(self.x_shift_plot)
        self._mw.sample_shift_ViewWidget.addItem(self.y_shift_plot)
        self._mw.sample_shift_ViewWidget.addItem(self.z_shift_plot)

        # Label axes
        self._mw.sample_shift_ViewWidget.setLabel('bottom', 'Time', units='s')
        self._mw.sample_shift_ViewWidget.setLabel('left', 'Sample shift', units='m')

        self._update_roi_history(self.poimanagerlogic().roi_pos_history)
        return

    def __connect_update_signals_from_logic(self):
        self.poimanagerlogic().sigRefocusTimerUpdated.connect(
            self.update_refocus_timer, QtCore.Qt.QueuedConnection)
        self.poimanagerlogic().sigPoiUpdated.connect(
            self.update_poi, QtCore.Qt.QueuedConnection)
        self.poimanagerlogic().sigActivePoiUpdated.connect(
            self.update_active_poi, QtCore.Qt.QueuedConnection)
        self.poimanagerlogic().sigRoiUpdated.connect(self.update_roi, QtCore.Qt.QueuedConnection)
        self.poimanagerlogic().sigRefocusStateUpdated.connect(
            self.update_refocus_state, QtCore.Qt.QueuedConnection)
        return

    def __disconnect_update_signals_from_logic(self):
        self.poimanagerlogic().sigRefocusTimerUpdated.disconnect()
        self.poimanagerlogic().sigPoiUpdated.disconnect()
        self.poimanagerlogic().sigActivePoiUpdated.disconnect()
        self.poimanagerlogic().sigRoiUpdated.disconnect()
        self.poimanagerlogic().sigRefocusStateUpdated.disconnect()
        return

    def __connect_control_signals_to_logic(self):
        self._mw.new_poi_Action.triggered.connect(
            self.poimanagerlogic().add_poi, QtCore.Qt.QueuedConnection)
        self._mw.goto_poi_Action.triggered.connect(
            self.poimanagerlogic().go_to_poi, QtCore.Qt.QueuedConnection)
        self._mw.new_roi_Action.triggered.connect(
            self.poimanagerlogic().reset_roi, QtCore.Qt.QueuedConnection)
        self._mw.refind_poi_Action.triggered.connect(
            self.poimanagerlogic().optimise_poi_position, QtCore.Qt.QueuedConnection)
        self._mw.get_confocal_image_PushButton.clicked.connect(
            self.poimanagerlogic().set_scan_image, QtCore.Qt.QueuedConnection)
        self._mw.set_poi_PushButton.clicked.connect(
            self.poimanagerlogic().add_poi, QtCore.Qt.QueuedConnection)
        self._mw.delete_last_pos_Button.clicked.connect(
            self.poimanagerlogic().delete_history_entry, QtCore.Qt.QueuedConnection)
        self._mw.manual_update_poi_PushButton.clicked.connect(
            self.poimanagerlogic().move_roi_from_poi_position, QtCore.Qt.QueuedConnection)
        self._mw.move_poi_PushButton.clicked.connect(
            self.poimanagerlogic().set_poi_anchor_from_position, QtCore.Qt.QueuedConnection)
        self._mw.delete_poi_PushButton.clicked.connect(
            self.poimanagerlogic().delete_poi, QtCore.Qt.QueuedConnection)
        self._mw.active_poi_ComboBox.activated[str].connect(
            self.poimanagerlogic().set_active_poi, QtCore.Qt.QueuedConnection)
        self._mw.goto_poi_after_update_checkBox.stateChanged.connect(
            self.poimanagerlogic().set_move_scanner_after_optimise, QtCore.Qt.QueuedConnection)
        self._mw.track_poi_Action.triggered.connect(
            self.poimanagerlogic().toggle_periodic_refocus, QtCore.Qt.QueuedConnection)
        self.sigTrackPeriodChanged.connect(
            self.poimanagerlogic().set_refocus_period, QtCore.Qt.QueuedConnection)
        self.sigRoiNameChanged.connect(
            self.poimanagerlogic().rename_roi, QtCore.Qt.QueuedConnection)
        self.sigPoiNameChanged.connect(
            self.poimanagerlogic().rename_poi, QtCore.Qt.QueuedConnection)
        self.sigPoiNameTagChanged.connect(
            self.poimanagerlogic().set_poi_nametag, QtCore.Qt.QueuedConnection)
        self.sigAddPoiByClick.connect(self.poimanagerlogic().add_poi, QtCore.Qt.QueuedConnection)
        return

    def __disconnect_control_signals_to_logic(self):
        self._mw.new_poi_Action.triggered.disconnect()
        self._mw.goto_poi_Action.triggered.disconnect()
        self._mw.new_roi_Action.triggered.disconnect()
        self._mw.refind_poi_Action.triggered.disconnect()
        self._mw.get_confocal_image_PushButton.clicked.disconnect()
        self._mw.set_poi_PushButton.clicked.disconnect()
        self._mw.delete_last_pos_Button.clicked.disconnect()
        self._mw.manual_update_poi_PushButton.clicked.disconnect()
        self._mw.move_poi_PushButton.clicked.disconnect()
        self._mw.delete_poi_PushButton.clicked.disconnect()
        self._mw.active_poi_ComboBox.activated[str].disconnect()
        self._mw.goto_poi_after_update_checkBox.stateChanged.disconnect()
        self._mw.track_poi_Action.triggered.disconnect()
        self.sigTrackPeriodChanged.disconnect()
        self.sigRoiNameChanged.disconnect()
        self.sigPoiNameChanged.disconnect()
        self.sigPoiNameTagChanged.disconnect()
        self.sigAddPoiByClick.disconnect()
        for marker in self._markers.values():
            marker.sigPoiSelected.disconnect()
        return

    def __connect_internal_signals(self):
        self._mw.track_period_SpinBox.editingFinished.connect(self.track_period_changed)
        self._mw.roi_name_LineEdit.editingFinished.connect(self.roi_name_changed)
        self._mw.poi_name_LineEdit.returnPressed.connect(self.poi_name_changed)
        self._mw.poi_nametag_LineEdit.editingFinished.connect(self.poi_nametag_changed)
        self._mw.save_roi_Action.triggered.connect(self.save_roi)
        self._mw.load_roi_Action.triggered.connect(self.load_roi)
        self._mw.blink_correction_view_Action.triggered.connect(self.toggle_blink_correction)
        self._mw.poi_selector_Action.toggled.connect(self.toggle_poi_selector)
        self._mw.roi_cb_centiles_RadioButton.toggled.connect(self.update_cb)
        self._mw.roi_cb_manual_RadioButton.toggled.connect(self.update_cb)
        self._mw.roi_cb_min_SpinBox.valueChanged.connect(self.update_cb_absolute)
        self._mw.roi_cb_max_SpinBox.valueChanged.connect(self.update_cb_absolute)
        self._mw.roi_cb_low_percentile_DoubleSpinBox.valueChanged.connect(self.update_cb_centiles)
        self._mw.roi_cb_high_percentile_DoubleSpinBox.valueChanged.connect(self.update_cb_centiles)
        return

    def __disconnect_internal_signals(self):
        self._mw.track_period_SpinBox.editingFinished.disconnect()
        self._mw.roi_name_LineEdit.editingFinished.disconnect()
        self._mw.poi_name_LineEdit.returnPressed.disconnect()
        self._mw.poi_nametag_LineEdit.editingFinished.disconnect()
        self._mw.save_roi_Action.triggered.disconnect()
        self._mw.load_roi_Action.triggered.disconnect()
        self._mw.blink_correction_view_Action.triggered.disconnect()
        self._mw.poi_selector_Action.toggled.disconnect()
        self._mw.roi_cb_centiles_RadioButton.toggled.disconnect()
        self._mw.roi_cb_manual_RadioButton.toggled.disconnect()
        self._mw.roi_cb_min_SpinBox.valueChanged.disconnect()
        self._mw.roi_cb_max_SpinBox.valueChanged.disconnect()
        self._mw.roi_cb_low_percentile_DoubleSpinBox.valueChanged.disconnect()
        self._mw.roi_cb_high_percentile_DoubleSpinBox.valueChanged.disconnect()
        return

    def show(self):
        """Make main window visible and put it above all other windows. """
        QtWidgets.QMainWindow.show(self._mw)
        self._mw.activateWindow()
        self._mw.raise_()

    @QtCore.Slot(bool)
    def toggle_blink_correction(self, is_active):
        self.roi_image.activate_blink_correction(is_active)
        return

    @QtCore.Slot(object)
    def mouse_moved_callback(self, event):
        """ Handles any mouse movements inside the image.

        @param event:   Event that signals the new mouse movement.
                        This should be of type QPointF.

        Gets the mouse position, converts it to a position scaled to the image axis
        and than calculates and updated the position to the current POI.
        """

        # converts the absolute mouse position to a position relative to the axis
        mouse_pos = self.roi_image.getViewBox().mapSceneToView(event[0])

        # only calculate distance, if a POI is selected
        active_poi = self.poimanagerlogic().active_poi
        if active_poi:
            poi_pos = self.poimanagerlogic().get_poi_position(active_poi)
            dx = ScaledFloat(mouse_pos.x() - poi_pos[0])
            dy = ScaledFloat(mouse_pos.y() - poi_pos[1])
            d_total = ScaledFloat(
                np.sqrt((mouse_pos.x() - poi_pos[0])**2 + (mouse_pos.y() - poi_pos[1])**2))

            self._mw.poi_distance_label.setText(
                '{0:.2r}m ({1:.2r}m, {2:.2r}m)'.format(d_total, dx, dy))
        else:
            self._mw.poi_distance_label.setText('? (?, ?)')
        pass

    @QtCore.Slot(bool)
    def toggle_poi_selector(self, is_active):
        if is_active != self._mw.poi_selector_Action.isChecked():
            self._mw.poi_selector_Action.blockSignals(True)
            self._mw.poi_selector_Action.setChecked(is_active)
            self._mw.poi_selector_Action.blockSignals(False)
        if is_active != self.__poi_selector_active:
            if is_active:
                self.roi_image.sigMouseClicked.connect(self.create_poi_from_click)
                self.roi_image.setCursor(QtCore.Qt.CrossCursor)
            else:
                self.roi_image.sigMouseClicked.disconnect()
                self.roi_image.setCursor(QtCore.Qt.ArrowCursor)
        self.__poi_selector_active = is_active
        return

    @QtCore.Slot(QtCore.Qt.MouseButton, QtCore.QPointF)
    def create_poi_from_click(self, button, pos):
        # Only create new POI if the mouse click event has not been accepted by some other means
        # In our case this is most likely the POI marker to select the active POI from.
        if button != QtCore.Qt.LeftButton:
            return
        # Z position from ROI origin, X and Y positions from click event
        new_pos = self.poimanagerlogic().roi_origin
        new_pos[0] = pos.x()
        new_pos[1] = pos.y()
        self.sigAddPoiByClick.emit(new_pos)
        return

    @QtCore.Slot(dict)
    def update_roi(self, roi_dict):
        if not isinstance(roi_dict, dict):
            self.log.error('ROI parameters to update must be given in a single dictionary.')
            return

        if 'name' in roi_dict:
            self._update_roi_name(name=roi_dict['name'])
        if 'poi_nametag' in roi_dict:
            self._update_poi_nametag(tag=roi_dict['poi_nametag'])
        if 'history' in roi_dict:
            self._update_roi_history(history=roi_dict['history'])
        if 'scan_image' in roi_dict and 'scan_image_extent' in roi_dict:
            self._update_scan_image(scan_image=roi_dict['scan_image'],
                                    image_extent=roi_dict['scan_image_extent'])
        if 'pois' in roi_dict:
            self._update_pois(poi_dict=roi_dict['pois'])
        return

    @QtCore.Slot(bool, float, float)
    def update_refocus_timer(self, is_active, period, time_until_refocus):
        if not self._mw.track_period_SpinBox.hasFocus():
            self._mw.track_period_SpinBox.blockSignals(True)
            self._mw.track_period_SpinBox.setValue(period)
            self._mw.track_period_SpinBox.blockSignals(False)

        self._mw.track_poi_Action.blockSignals(True)
        self._mw.time_till_next_update_ProgressBar.blockSignals(True)

        self._mw.track_poi_Action.setChecked(is_active)
        self._mw.time_till_next_update_ProgressBar.setMaximum(period)
        self._mw.time_till_next_update_ProgressBar.setValue(time_until_refocus)

        self._mw.time_till_next_update_ProgressBar.blockSignals(False)
        self._mw.track_poi_Action.blockSignals(False)
        return

    @QtCore.Slot(bool)
    def update_refocus_state(self, is_active):
        self._mw.refind_poi_Action.setEnabled(not is_active)
        return

    @QtCore.Slot(str, str, np.ndarray)
    def update_poi(self, old_name, new_name, position):
        # Handle changed names and deleted/added POIs
        if old_name != new_name:
            self._mw.active_poi_ComboBox.blockSignals(True)
            # Remember current text
            text_active_poi = self._mw.active_poi_ComboBox.currentText()
            # sort POI names and repopulate ComboBoxes
            self._mw.active_poi_ComboBox.clear()
            poi_names = natural_sort(self.poimanagerlogic().poi_names)
            self._mw.active_poi_ComboBox.addItems(poi_names)
            if text_active_poi == old_name:
                self._mw.active_poi_ComboBox.setCurrentText(new_name)
            else:
                self._mw.active_poi_ComboBox.setCurrentText(text_active_poi)
            self._mw.active_poi_ComboBox.blockSignals(False)

        # Delete/add/update POI marker to image
        if not old_name:
            # POI has been added
            self._add_poi_marker(name=new_name, position=position)
        elif not new_name:
            # POI has been deleted
            self._remove_poi_marker(name=old_name)
        else:
            # POI has been renamed and/or changed position
            size = self.poimanagerlogic().optimise_xy_size * np.sqrt(2)
            self._markers[old_name].set_name(new_name)
            self._markers[new_name] = self._markers.pop(old_name)
            self._markers[new_name].setSize((size, size))
            self._markers[new_name].set_position(position[:2])

        active_poi = self._mw.active_poi_ComboBox.currentText()
        if active_poi:
            self._markers[active_poi].select()
        return

    @QtCore.Slot(str)
    def update_active_poi(self, name):

        # Deselect current marker
        for marker in self._markers.values():
            if marker.selected:
                marker.deselect()
                break

        # Unselect POI if name is None or empty str
        self._mw.active_poi_ComboBox.blockSignals(True)
        if not name:
            self._mw.active_poi_ComboBox.setCurrentIndex(-1)
        else:
            self._mw.active_poi_ComboBox.setCurrentText(name)
        self._mw.active_poi_ComboBox.blockSignals(False)

        if name:
            active_poi_pos = self.poimanagerlogic().get_poi_position(name)
        else:
            active_poi_pos = np.zeros(3)
        self._mw.poi_coords_label.setText(
            '({0:.2r}m, {1:.2r}m, {2:.2r}m)'.format(ScaledFloat(active_poi_pos[0]),
                                                    ScaledFloat(active_poi_pos[1]),
                                                    ScaledFloat(active_poi_pos[2])))

        if name in self._markers:
            self._markers[name].set_radius(self.poimanagerlogic().optimise_xy_size / np.sqrt(2))
            self._markers[name].select()
        return

    @QtCore.Slot()
    def track_period_changed(self):
        self.sigTrackPeriodChanged.emit(self._mw.track_period_SpinBox.value())
        return

    @QtCore.Slot()
    def roi_name_changed(self):
        """ Set the name of the current ROI."""
        self.sigRoiNameChanged.emit(self._mw.roi_name_LineEdit.text())
        return

    @QtCore.Slot()
    def poi_name_changed(self):
        """ Change the name of the active poi."""
        new_name = self._mw.poi_name_LineEdit.text()
        if self._mw.active_poi_ComboBox.currentText() == new_name or not new_name:
            return

        self.sigPoiNameChanged.emit(new_name)

        # After POI name is changed, empty name field
        self._mw.poi_name_LineEdit.blockSignals(True)
        self._mw.poi_name_LineEdit.setText('')
        self._mw.poi_name_LineEdit.blockSignals(False)
        return

    @QtCore.Slot()
    def poi_nametag_changed(self):
        self.sigPoiNameTagChanged.emit(self._mw.poi_nametag_LineEdit.text())
        return

    @QtCore.Slot()
    def save_roi(self):
        """ Save ROI to file."""
        roi_name = self._mw.roi_name_LineEdit.text()
        self.poimanagerlogic().rename_roi(roi_name)
        self.poimanagerlogic().save_roi()
        return

    @QtCore.Slot()
    def load_roi(self):
        """ Load a saved ROI from file."""
        this_file = QtWidgets.QFileDialog.getOpenFileName(self._mw,
                                                          'Open ROI',
                                                          self.poimanagerlogic().data_directory,
                                                          'Data files (*.dat)')[0]
        if this_file:
            self.poimanagerlogic().load_roi(complete_path=this_file)
        return

    @QtCore.Slot()
    def update_cb_centiles(self):
        if not self._mw.roi_cb_centiles_RadioButton.isChecked():
            self._mw.roi_cb_centiles_RadioButton.toggle()
        else:
            self.update_cb()
        return

    @QtCore.Slot()
    def update_cb_absolute(self):
        if not self._mw.roi_cb_manual_RadioButton.isChecked():
            self._mw.roi_cb_manual_RadioButton.toggle()
        else:
            self.update_cb()
        return

    @QtCore.Slot()
    def update_cb(self):
        image = self.poimanagerlogic().roi_scan_image
        if image is None:
            return
        cb_range = self.get_cb_range(image)
        self.roi_image.setLevels(cb_range)
        self.roi_cb.refresh_colorbar(*cb_range)
        return

    def _update_scan_image(self, scan_image, image_extent):
        """

        @param scan_image:
        @param image_extent:
        """
        if scan_image is None or image_extent is None:
            self._mw.roi_map_ViewWidget.removeItem(self.roi_image)
            return
        elif self.roi_image not in self._mw.roi_map_ViewWidget.items():
            self._mw.roi_map_ViewWidget.addItem(self.roi_image)
        self.roi_image.setImage(image=scan_image)
        (x_min, x_max), (y_min, y_max) = image_extent
        self.roi_image.getViewBox().enableAutoRange()
        self.roi_image.setRect(QtCore.QRectF(x_min, y_min, x_max - x_min, y_max - y_min))

        self.update_cb()
        return

    def _update_roi_name(self, name):
        self._mw.roi_name_LineEdit.blockSignals(True)
        self._mw.roi_name_LineEdit.setText(name)
        self._mw.roi_name_LineEdit.blockSignals(False)
        return

    def _update_poi_nametag(self, tag):
        if tag is None:
            tag = ''
        self._mw.poi_nametag_LineEdit.blockSignals(True)
        self._mw.poi_nametag_LineEdit.setText(tag)
        self._mw.poi_nametag_LineEdit.blockSignals(False)
        return

    def _update_roi_history(self, history=None):
        if history is None:
            history = self.poimanagerlogic().roi_pos_history

        if history.shape[1] != 4:
            self.log.error('ROI history must be an array of type float[][4].')
            return

        max_time = np.max(history[:, 0])
        if max_time < 300:
            self._mw.sample_shift_ViewWidget.setLabel('bottom', 'Time', units='s')
            time_arr = history[:, 0]
        elif max_time < 7200:
            self._mw.sample_shift_ViewWidget.setLabel('bottom', 'Time', units='min')
            time_arr = history[:, 0] / 60
        elif max_time < 172800:
            self._mw.sample_shift_ViewWidget.setLabel('bottom', 'Time', units='h')
            time_arr = history[:, 0] / 3600
        else:
            self._mw.sample_shift_ViewWidget.setLabel('bottom', 'Time', units='d')
            time_arr = history[:, 0] / 86400

        self.x_shift_plot.setData(time_arr, history[:, 1])
        self.y_shift_plot.setData(time_arr, history[:, 2])
        self.z_shift_plot.setData(time_arr, history[:, 3])
        return

    def _update_pois(self, poi_dict):
        """ Populate the dropdown box for selecting a poi. """
        self._mw.active_poi_ComboBox.blockSignals(True)

        self._mw.active_poi_ComboBox.clear()

        poi_names = natural_sort(poi_dict)
        self._mw.active_poi_ComboBox.addItems(poi_names)

        # Get two list of POI names. One of those to delete and one of those to add
        old_poi_names = set(self._markers)
        new_poi_names = set(poi_names)
        names_to_delete = list(old_poi_names.difference(new_poi_names))
        names_to_add = list(new_poi_names.difference(old_poi_names))

        # Delete markers accordingly
        for name in names_to_delete:
            self._remove_poi_marker(name)
        # Update positions of all remaining markers
        size = self.poimanagerlogic().optimise_xy_size * np.sqrt(2)
        for name, marker in self._markers.items():
            marker.setSize((size, size))
            marker.set_position(poi_dict[name])
        # Add new markers
        for name in names_to_add:
            self._add_poi_marker(name=name, position=poi_dict[name])

        # If there is no active POI, set the combobox to nothing (-1)
        active_poi = self.poimanagerlogic().active_poi
        if active_poi in poi_names:
            self._mw.active_poi_ComboBox.setCurrentText(active_poi)
            self._markers[active_poi].select()
            active_poi_pos = poi_dict[active_poi]
            self._mw.poi_coords_label.setText(
                '({0:.2r}m, {1:.2r}m, {2:.2r}m)'.format(ScaledFloat(active_poi_pos[0]),
                                                        ScaledFloat(active_poi_pos[1]),
                                                        ScaledFloat(active_poi_pos[2])))
        else:
            self._mw.active_poi_ComboBox.setCurrentIndex(-1)

        self._mw.active_poi_ComboBox.blockSignals(False)
        return

    def get_cb_range(self, image):
        """ Process UI input to determine color bar range"""
        # If "Centiles" is checked, adjust colour scaling automatically to centiles.
        # Otherwise, take user-defined values.
        if self._mw.roi_cb_centiles_RadioButton.isChecked():
            low_centile = self._mw.roi_cb_low_percentile_DoubleSpinBox.value()
            high_centile = self._mw.roi_cb_high_percentile_DoubleSpinBox.value()

            cb_min = np.percentile(image, low_centile)
            cb_max = np.percentile(image, high_centile)
        else:
            cb_min = self._mw.roi_cb_min_SpinBox.value()
            cb_max = self._mw.roi_cb_max_SpinBox.value()
        return cb_min, cb_max

    def _add_poi_marker(self, name, position):
        """ Add a circular POI marker to the ROI scan image. """
        if name:
            if name in self._markers:
                self.log.error('Unable to add POI marker to ROI image. POI marker already present.')
                return
            marker = PoiMarker(position=position[:2],
                               view_widget=self._mw.roi_map_ViewWidget,
                               poi_name=name,
                               radius=self.poimanagerlogic().optimise_xy_size / np.sqrt(2),
                               movable=False)
            # Add to the scan image widget
            marker.add_to_view_widget()
            marker.sigPoiSelected.connect(
                self.poimanagerlogic().set_active_poi, QtCore.Qt.QueuedConnection)
            self._markers[name] = marker
        return

    def _remove_poi_marker(self, name):
        """ Remove the POI marker for a POI that was deleted. """
        if name in self._markers:
            self._markers[name].delete_from_view_widget()
            self._markers[name].sigPoiSelected.disconnect()
            del self._markers[name]
        return
Exemplo n.º 13
0
    def on_activate(self, e=None):
        """ Definition, configuration and initialisation of the ODMR GUI.

          @param class e: event class from Fysom


        This init connects all the graphic modules, which were created in the
        *.ui file and configures the event handling between the modules.

        """

        self._voltscan_logic = self.get_in_connector('odmrlogic1')
        print("ODMR logic is", self._odmr_logic)

        # Use the inherited class 'Ui_VoltagescannerGuiUI' to create now the
        # GUI element:
        self._mw = VoltScanMainWindow()

        # Get the image from the logic
        self.odmr_matrix_image = pg.ImageItem(self._odmr_logic.ODMR_plot_xy.transpose())
        self.odmr_matrix_image.setRect(QtCore.QRectF(self._odmr_logic.mw_start,0,self._odmr_logic.mw_stop-self._odmr_logic.mw_start,self._odmr_logic.number_of_lines))
        self.odmr_image = pg.PlotDataItem(self._odmr_logic.ODMR_plot_x,self._odmr_logic.ODMR_plot_y)
        self.odmr_fit_image = pg.PlotDataItem(self._odmr_logic.ODMR_fit_x,self._odmr_logic.ODMR_fit_y,
                                                    pen=QtGui.QPen(QtGui.QColor(255,255,255,255)))


        # Add the display item to the xy and xz VieWidget, which was defined in
        # the UI file.
        self._mw.voltscan_ViewWidget.addItem(self.odmr_image)
        self._mw.voltscan_ViewWidget.addItem(self.odmr_fit_image)
        self._mw.voltscan_matrix_ViewWidget.addItem(self.odmr_matrix_image)
        self._mw.vonsoltscan_ViewWidget.showGrid(x=True, y=True, alpha=0.8)



        # Get the colorscales at set LUT
        my_colors = ColorScaleInferno()

        self.odmr_matrix_image.setLookupTable(my_colors.lut)

        # Set the state button as ready button as default setting.
        # self._mw.idle_StateWidget.click()

        # Configuration of the comboWidget
        self._mw.mode_ComboWidget.addItem('Off')
        self._mw.mode_ComboWidget.addItem('CW')

        self._mw.fit_methods_ComboWidget.addItem('No Fit')
        self._mw.fit_methods_ComboWidget.addItem('Lorentzian')
        self._mw.fit_methods_ComboWidget.addItem('Double Lorentzian')
        self._mw.fit_methods_ComboWidget.addItem('Double Lorentzian with fixed splitting')
        self._mw.fit_methods_ComboWidget.addItem('N14')
        self._mw.fit_methods_ComboWidget.addItem('N15')


        #######################################################################
        ##                Configuration of the Colorbar                      ##
        #######################################################################

        self.odmr_cb = ColorBar(my_colors.cmap_normed, 100, 0, 100000)

        #adding colorbar to ViewWidget
        self._mw.odmr_cb_ViewWidget.addItem(self.odmr_cb)
        self._mw.odmr_cb_ViewWidget.hideAxis('bottom')
        self._mw.odmr_cb_ViewWidget.hideAxis('left')
        self._mw.odmr_cb_ViewWidget.setLabel('right', 'Fluorescence', units='c/s')

        # Connect the buttons and inputs for the odmr colorbar
        self._mw.odmr_cb_manual_RadioButton.clicked.connect(self.refresh_matrix)
        self._mw.odmr_cb_centiles_RadioButton.clicked.connect(self.refresh_matrix)


        #######################################################################
        ##                Configuration of the InputWidgets                  ##
        #######################################################################

        # Add Validators to InputWidgets
        validator = QtGui.QDoubleValidator()
        validator2 = QtGui.QIntValidator()

        self._mw.frequency_InputWidget.setValidator(validator)
        self._mw.start_freq_InputWidget.setValidator(validator)
        self._mw.step_freq_InputWidget.setValidator(validator)
        self._mw.stop_freq_InputWidget.setValidator(validator)
        self._mw.power_InputWidget.setValidator(validator)
        self._mw.runtime_InputWidget.setValidator(validator2)
        self._sd.matrix_lines_InputWidget.setValidator(validator)
        self._sd.clock_frequency_InputWidget.setValidator(validator2)

        # Take the default values from logic:
        self._mw.frequency_InputWidget.setText(str(self._odmr_logic.mw_frequency))
        self._mw.start_freq_InputWidget.setText(str(self._odmr_logic.mw_start))
        self._mw.step_freq_InputWidget.setText(str(self._odmr_logic.mw_step))
        self._mw.stop_freq_InputWidget.setText(str(self._odmr_logic.mw_stop))
        self._mw.power_InputWidget.setText(str(self._odmr_logic.mw_power))
        self._mw.runtime_InputWidget.setText(str(self._odmr_logic.run_time))
        self._mw.elapsed_time_DisplayWidget.display(int(self._odmr_logic.ElapsedTime))
        self._sd.matrix_lines_InputWidget.setText(str(self._odmr_logic.number_of_lines))
        self._sd.clock_frequency_InputWidget.setText(str(self._odmr_logic._clock_frequency))

        # Update the inputed/displayed numbers if return key is hit:

        self._mw.frequency_InputWidget.returnPressed.connect(self.change_frequency)
        self._mw.start_freq_InputWidget.returnPressed.connect(self.change_start_freq)
        self._mw.step_freq_InputWidget.returnPressed.connect(self.change_step_freq)
        self._mw.stop_freq_InputWidget.returnPressed.connect(self.change_stop_freq)
        self._mw.power_InputWidget.returnPressed.connect(self.change_power)
        self._mw.runtime_InputWidget.returnPressed.connect(self.change_runtime)

        # Update the inputed/displayed numbers if the cursor has left the field:

        self._mw.frequency_InputWidget.editingFinished.connect(self.change_frequency)
        self._mw.start_freq_InputWidget.editingFinished.connect(self.change_start_freq)
        self._mw.step_freq_InputWidget.editingFinished.connect(self.change_step_freq)
        self._mw.stop_freq_InputWidget.editingFinished.connect(self.change_stop_freq)
        self._mw.power_InputWidget.editingFinished.connect(self.change_power)
        self._mw.runtime_InputWidget.editingFinished.connect(self.change_runtime)

        #

        self._mw.odmr_cb_max_InputWidget.valueChanged.connect(self.refresh_matrix)
        self._mw.odmr_cb_min_InputWidget.valueChanged.connect(self.refresh_matrix)
        self._mw.odmr_cb_high_centile_InputWidget.valueChanged.connect(self.refresh_matrix)
        self._mw.odmr_cb_low_centile_InputWidget.valueChanged.connect(self.refresh_matrix)

        #######################################################################
        ##                      Connect signals                              ##
        #######################################################################

        # Connect the RadioButtons and connect to the events if they are clicked:
        # self._mw.idle_StateWidget.toggled.connect(self.idle_clicked)
        # self._mw.run_StateWidget.toggled.connect(self.run_clicked)
        self._mw.action_run_stop.toggled.connect(self.run_stop)
        self._mw.action_Save.triggered.connect(self._odmr_logic.save_ODMR_Data)

        self._odmr_logic.sigOdmrPlotUpdated.connect(self.refresh_plot)
        self._odmr_logic.sigOdmrPlotUpdated.connect(self.refresh_matrix)
        self._odmr_logic.sigOdmrElapsedTimeChanged.connect(self.refresh_elapsedtime)
        # connect settings signals
        self._mw.action_Settings.triggered.connect(self.menue_settings)
        self._sd.accepted.connect(self.update_settings)
        self._sd.rejected.connect(self.reject_settings)
        self._sd.buttonBox.button(QtWidgets.QDialogButtonBox.Apply).clicked.connect(self.update_settings)
        self.reject_settings()
        # Connect stop odmr
        # self._odmr_logic.sigOdmrFinished.connect(self._mw.idle_StateWidget.click)
        self._odmr_logic.sigOdmrFinished.connect(self.odmr_stopped)
        # Combo Widget
        self._mw.mode_ComboWidget.activated[str].connect(self.mw_stop)
        self._mw.fit_methods_ComboWidget.activated[str].connect(self.update_fit_variable)
        # Push Buttons
        self._mw.do_fit_PushButton.clicked.connect(self.update_fit)

        # Show the Main ODMR GUI:
        self._mw.show()
Exemplo n.º 14
0
class VoltScanGui(GUIBase):
    """
    This is the GUI Class for ODMR
    """
    _modclass = 'VoltScanGui'
    _modtype = 'gui'
    ## declare connectors
    _in = {'voltagescannerlogic1': 'VoltageScannerLogic',
          }

    def __init__(self, config, **kwargs):
        super().__init__(config=config, **kwargs)

        self.log.info('The following configuration was found.')

        # checking for the right configuration
        for key in config.keys():
            self.log.info('{0}: {1}'.format(key,config[key]))

    def on_deactivate(self, e):
        """ Reverse steps of activation

        @param e: error code

        @return int: error code (0:OK, -1:error)
        """
        self._mw.close()
        return 0

    def on_activate(self, e=None):
        """ Definition, configuration and initialisation of the ODMR GUI.

          @param class e: event class from Fysom


        This init connects all the graphic modules, which were created in the
        *.ui file and configures the event handling between the modules.

        """

        self._voltscan_logic = self.get_in_connector('odmrlogic1')
        print("ODMR logic is", self._odmr_logic)

        # Use the inherited class 'Ui_VoltagescannerGuiUI' to create now the
        # GUI element:
        self._mw = VoltScanMainWindow()

        # Get the image from the logic
        self.odmr_matrix_image = pg.ImageItem(self._odmr_logic.ODMR_plot_xy.transpose())
        self.odmr_matrix_image.setRect(QtCore.QRectF(self._odmr_logic.mw_start,0,self._odmr_logic.mw_stop-self._odmr_logic.mw_start,self._odmr_logic.number_of_lines))
        self.odmr_image = pg.PlotDataItem(self._odmr_logic.ODMR_plot_x,self._odmr_logic.ODMR_plot_y)
        self.odmr_fit_image = pg.PlotDataItem(self._odmr_logic.ODMR_fit_x,self._odmr_logic.ODMR_fit_y,
                                                    pen=QtGui.QPen(QtGui.QColor(255,255,255,255)))


        # Add the display item to the xy and xz VieWidget, which was defined in
        # the UI file.
        self._mw.voltscan_ViewWidget.addItem(self.odmr_image)
        self._mw.voltscan_ViewWidget.addItem(self.odmr_fit_image)
        self._mw.voltscan_matrix_ViewWidget.addItem(self.odmr_matrix_image)
        self._mw.vonsoltscan_ViewWidget.showGrid(x=True, y=True, alpha=0.8)



        # Get the colorscales at set LUT
        my_colors = ColorScaleInferno()

        self.odmr_matrix_image.setLookupTable(my_colors.lut)

        # Set the state button as ready button as default setting.
        # self._mw.idle_StateWidget.click()

        # Configuration of the comboWidget
        self._mw.mode_ComboWidget.addItem('Off')
        self._mw.mode_ComboWidget.addItem('CW')

        self._mw.fit_methods_ComboWidget.addItem('No Fit')
        self._mw.fit_methods_ComboWidget.addItem('Lorentzian')
        self._mw.fit_methods_ComboWidget.addItem('Double Lorentzian')
        self._mw.fit_methods_ComboWidget.addItem('Double Lorentzian with fixed splitting')
        self._mw.fit_methods_ComboWidget.addItem('N14')
        self._mw.fit_methods_ComboWidget.addItem('N15')


        #######################################################################
        ##                Configuration of the Colorbar                      ##
        #######################################################################

        self.odmr_cb = ColorBar(my_colors.cmap_normed, 100, 0, 100000)

        #adding colorbar to ViewWidget
        self._mw.odmr_cb_ViewWidget.addItem(self.odmr_cb)
        self._mw.odmr_cb_ViewWidget.hideAxis('bottom')
        self._mw.odmr_cb_ViewWidget.hideAxis('left')
        self._mw.odmr_cb_ViewWidget.setLabel('right', 'Fluorescence', units='c/s')

        # Connect the buttons and inputs for the odmr colorbar
        self._mw.odmr_cb_manual_RadioButton.clicked.connect(self.refresh_matrix)
        self._mw.odmr_cb_centiles_RadioButton.clicked.connect(self.refresh_matrix)


        #######################################################################
        ##                Configuration of the InputWidgets                  ##
        #######################################################################

        # Add Validators to InputWidgets
        validator = QtGui.QDoubleValidator()
        validator2 = QtGui.QIntValidator()

        self._mw.frequency_InputWidget.setValidator(validator)
        self._mw.start_freq_InputWidget.setValidator(validator)
        self._mw.step_freq_InputWidget.setValidator(validator)
        self._mw.stop_freq_InputWidget.setValidator(validator)
        self._mw.power_InputWidget.setValidator(validator)
        self._mw.runtime_InputWidget.setValidator(validator2)
        self._sd.matrix_lines_InputWidget.setValidator(validator)
        self._sd.clock_frequency_InputWidget.setValidator(validator2)

        # Take the default values from logic:
        self._mw.frequency_InputWidget.setText(str(self._odmr_logic.mw_frequency))
        self._mw.start_freq_InputWidget.setText(str(self._odmr_logic.mw_start))
        self._mw.step_freq_InputWidget.setText(str(self._odmr_logic.mw_step))
        self._mw.stop_freq_InputWidget.setText(str(self._odmr_logic.mw_stop))
        self._mw.power_InputWidget.setText(str(self._odmr_logic.mw_power))
        self._mw.runtime_InputWidget.setText(str(self._odmr_logic.run_time))
        self._mw.elapsed_time_DisplayWidget.display(int(self._odmr_logic.ElapsedTime))
        self._sd.matrix_lines_InputWidget.setText(str(self._odmr_logic.number_of_lines))
        self._sd.clock_frequency_InputWidget.setText(str(self._odmr_logic._clock_frequency))

        # Update the inputed/displayed numbers if return key is hit:

        self._mw.frequency_InputWidget.returnPressed.connect(self.change_frequency)
        self._mw.start_freq_InputWidget.returnPressed.connect(self.change_start_freq)
        self._mw.step_freq_InputWidget.returnPressed.connect(self.change_step_freq)
        self._mw.stop_freq_InputWidget.returnPressed.connect(self.change_stop_freq)
        self._mw.power_InputWidget.returnPressed.connect(self.change_power)
        self._mw.runtime_InputWidget.returnPressed.connect(self.change_runtime)

        # Update the inputed/displayed numbers if the cursor has left the field:

        self._mw.frequency_InputWidget.editingFinished.connect(self.change_frequency)
        self._mw.start_freq_InputWidget.editingFinished.connect(self.change_start_freq)
        self._mw.step_freq_InputWidget.editingFinished.connect(self.change_step_freq)
        self._mw.stop_freq_InputWidget.editingFinished.connect(self.change_stop_freq)
        self._mw.power_InputWidget.editingFinished.connect(self.change_power)
        self._mw.runtime_InputWidget.editingFinished.connect(self.change_runtime)

        #

        self._mw.odmr_cb_max_InputWidget.valueChanged.connect(self.refresh_matrix)
        self._mw.odmr_cb_min_InputWidget.valueChanged.connect(self.refresh_matrix)
        self._mw.odmr_cb_high_centile_InputWidget.valueChanged.connect(self.refresh_matrix)
        self._mw.odmr_cb_low_centile_InputWidget.valueChanged.connect(self.refresh_matrix)

        #######################################################################
        ##                      Connect signals                              ##
        #######################################################################

        # Connect the RadioButtons and connect to the events if they are clicked:
        # self._mw.idle_StateWidget.toggled.connect(self.idle_clicked)
        # self._mw.run_StateWidget.toggled.connect(self.run_clicked)
        self._mw.action_run_stop.toggled.connect(self.run_stop)
        self._mw.action_Save.triggered.connect(self._odmr_logic.save_ODMR_Data)

        self._odmr_logic.sigOdmrPlotUpdated.connect(self.refresh_plot)
        self._odmr_logic.sigOdmrPlotUpdated.connect(self.refresh_matrix)
        self._odmr_logic.sigOdmrElapsedTimeChanged.connect(self.refresh_elapsedtime)
        # connect settings signals
        self._mw.action_Settings.triggered.connect(self.menue_settings)
        self._sd.accepted.connect(self.update_settings)
        self._sd.rejected.connect(self.reject_settings)
        self._sd.buttonBox.button(QtWidgets.QDialogButtonBox.Apply).clicked.connect(self.update_settings)
        self.reject_settings()
        # Connect stop odmr
        # self._odmr_logic.sigOdmrFinished.connect(self._mw.idle_StateWidget.click)
        self._odmr_logic.sigOdmrFinished.connect(self.odmr_stopped)
        # Combo Widget
        self._mw.mode_ComboWidget.activated[str].connect(self.mw_stop)
        self._mw.fit_methods_ComboWidget.activated[str].connect(self.update_fit_variable)
        # Push Buttons
        self._mw.do_fit_PushButton.clicked.connect(self.update_fit)

        # Show the Main ODMR GUI:
        self._mw.show()




    def show(self):
        """Make window visible and put it above all other windows. """
        QtWidgets.QMainWindow.show(self._mw)
        self._mw.activateWindow()
        self._mw.raise_()

#     def idle_clicked(self):
#         """ Stopp the scan if the state has switched to idle. """
#         self._odmr_logic.stop_odmr_scan()
#         self._sd.matrix_lines_InputWidget.setReadOnly(False)
# #        self._odmr_logic.kill_odmr()
#
#
#     def run_clicked(self, enabled):
#         """ Manages what happens if odmr scan is started.
#
#         @param bool enabled: start scan if that is possible
#         """
#
#         #Firstly stop any scan that might be in progress
#         self._odmr_logic.stop_odmr_scan()
# #        self._odmr_logic.kill_odmr()
#         #Then if enabled. start a new odmr scan.
#         if enabled:
#             self._odmr_logic.start_odmr_scan()
#             self._sd.matrix_lines_InputWidget.setReadOnly(True)

    def run_stop(self, is_checked):
        """ Manages what happens if odmr scan is started/stopped """
        if is_checked:
            self._odmr_logic.stop_odmr_scan()
            self._odmr_logic.start_odmr_scan()
            self._mw.odmr_ViewWidget.removeItem(self.odmr_fit_image)
            self._sd.matrix_lines_InputWidget.setReadOnly(True)
        else:
            self._odmr_logic.stop_odmr_scan()
            self._sd.matrix_lines_InputWidget.setReadOnly(False)

    def odmr_stopped(self):
        """ Switch the run/stop button to stop after receiving an odmr_stoped signal """
        self._mw.action_run_stop.setChecked(False)

    def menue_settings(self):
        """ Open the settings menue """
        self._sd.exec_()

    def refresh_plot(self):
        """ Refresh the xy-plot image """
        self.odmr_image.setData(self._odmr_logic.ODMR_plot_x,self._odmr_logic.ODMR_plot_y)
        if not self._mw.fit_methods_ComboWidget.currentText() == 'No Fit':
            self.odmr_fit_image.setData(self._odmr_logic.ODMR_fit_x,self._odmr_logic.ODMR_fit_y,pen=QtGui.QPen(QtGui.QColor(255,0,255,255)))
        else:
            if self.odmr_fit_image in self._mw.odmr_ViewWidget.listDataItems():
                self._mw.odmr_ViewWidget.removeItem(self.odmr_fit_image)

    def refresh_matrix(self):
        """ Refresh the xy-matrix image """
#        self.odmr_matrix_image.setImage(self._odmr_logic.ODMR_plot_xy.transpose())
#        self.odmr_matrix_image.setRect(QtCore.QRectF(self._odmr_logic.mw_start,0,self._odmr_logic.mw_stop-self._odmr_logic.mw_start,self._odmr_logic.number_of_lines))
#        self.refresh_odmr_colorbar()


        odmr_image_data = self._odmr_logic.ODMR_plot_xy.transpose()

        # If "Centiles" is checked, adjust colour scaling automatically to centiles.
        # Otherwise, take user-defined values.
        if self._mw.odmr_cb_centiles_RadioButton.isChecked():
            low_centile = self._mw.odmr_cb_low_centile_InputWidget.value()
            high_centile = self._mw.odmr_cb_high_centile_InputWidget.value()

            cb_min = np.percentile( odmr_image_data, low_centile )
            cb_max = np.percentile( odmr_image_data, high_centile )

        else:
            cb_min = self._mw.odmr_cb_min_InputWidget.value()
            cb_max = self._mw.odmr_cb_max_InputWidget.value()

        # Now update image with new color scale, and update colorbar
        self.odmr_matrix_image.setImage(image=odmr_image_data, levels=(cb_min, cb_max) )
        self.odmr_matrix_image.setRect(QtCore.QRectF(self._odmr_logic.mw_start,0,self._odmr_logic.mw_stop-self._odmr_logic.mw_start,self._odmr_logic.number_of_lines))
        self.refresh_odmr_colorbar()


    def refresh_odmr_colorbar(self):
        """ Update the colorbar to a new scaling."""

        # If "Centiles" is checked, adjust colour scaling automatically to centiles.
        # Otherwise, take user-defined values.
        if self._mw.odmr_cb_centiles_RadioButton.isChecked():
            low_centile = self._mw.odmr_cb_low_centile_InputWidget.value()
            high_centile = self._mw.odmr_cb_high_centile_InputWidget.value()

            cb_min = np.percentile( self.odmr_matrix_image.image, low_centile )
            cb_max = np.percentile( self.odmr_matrix_image.image, high_centile )

        else:
            cb_min = self._mw.odmr_cb_min_InputWidget.value()
            cb_max = self._mw.odmr_cb_max_InputWidget.value()

        self.odmr_cb.refresh_colorbar(cb_min,cb_max)
        self._mw.odmr_cb_ViewWidget.update()

    def refresh_elapsedtime(self):
        self._mw.elapsed_time_DisplayWidget.display(int(self._odmr_logic.ElapsedTime))

    def update_settings(self):
        """ Write the new settings from the gui to the file. """
        self._odmr_logic.number_of_lines = int(self._sd.matrix_lines_InputWidget.text())
        self._odmr_logic.set_clock_frequency(int(self._sd.clock_frequency_InputWidget.text()))
        self._odmr_logic.safeRawData = self._sd.save_raw_data_box.isChecked()

    def update_fit_variable(self, txt):
        self._odmr_logic.current_fit_function = txt

    def update_fit(self):
        self._odmr_logic.do_fit(fit_function = self._odmr_logic.current_fit_function)
        self.refresh_plot()

        # check which Fit method is used and remove or add again the
        # odmr_fit_image, check also whether a odmr_fit_image already exists.
        if self._mw.fit_methods_ComboWidget.currentText() == 'No Fit':
            if self.odmr_fit_image in self._mw.odmr_ViewWidget.listDataItems():
                self._mw.odmr_ViewWidget.removeItem(self.odmr_fit_image)
        else:
            if self.odmr_fit_image not in self._mw.odmr_ViewWidget.listDataItems():
                self._mw.odmr_ViewWidget.addItem(self.odmr_fit_image)

        self._mw.odmr_ViewWidget.getViewBox().updateAutoRange()
        self._mw.odmr_fit_results_DisplayWidget.clear()
        self._mw.odmr_fit_results_DisplayWidget.setPlainText(str(self._odmr_logic.fit_result))

    def reject_settings(self):
        """ Keep the old settings and restores the old settings in the gui. """
        self._sd.matrix_lines_InputWidget.setText(str(self._odmr_logic.number_of_lines))
        self._sd.clock_frequency_InputWidget.setText(str(self._odmr_logic._clock_frequency))
        self._sd.save_raw_data_box.setChecked(self._odmr_logic.safeRawData)

    def mw_stop(self, txt):
        if txt == 'Off':
            self._odmr_logic.MW_off()
        if txt == 'CW':
            self.change_frequency()
            self.change_power()
            self._odmr_logic.MW_on()



    ###########################################################################
    ##                         Change Methods                                ##
    ###########################################################################

    def change_frequency(self):
        self._odmr_logic.set_frequency(frequency = float(self._mw.frequency_InputWidget.text()))

    def change_start_freq(self):
        self._odmr_logic.mw_start = float(self._mw.start_freq_InputWidget.text())

    def change_step_freq(self):
        self._odmr_logic.mw_step = float(self._mw.step_freq_InputWidget.text())

    def change_stop_freq(self):
        self._odmr_logic.mw_stop = float(self._mw.stop_freq_InputWidget.text())

    def change_power(self):
        self._odmr_logic.mw_power = float(self._mw.power_InputWidget.text())
        self._odmr_logic.set_power(power = self._odmr_logic.mw_power)

    def change_runtime(self):
        self._odmr_logic.run_time = float(self._mw.runtime_InputWidget.text())
Exemplo n.º 15
0
    def on_activate(self):
        """ Definition, configuration and initialisation of the ODMR GUI.

        This init connects all the graphic modules, which were created in the
        *.ui file and configures the event handling between the modules.
        """

        self._odmr_logic = self.odmrlogic1()

        # Use the inherited class 'Ui_ODMRGuiUI' to create now the GUI element:
        self._mw = ODMRMainWindow()
        self._sd = ODMRSettingDialog()

        # Create a QSettings object for the mainwindow and store the actual GUI layout
        self.mwsettings = QtCore.QSettings("QUDI", "ODMR")
        self.mwsettings.setValue("geometry", self._mw.saveGeometry())
        self.mwsettings.setValue("windowState", self._mw.saveState())

        # Get hardware constraints to set limits for input widgets
        constraints = self._odmr_logic.get_hw_constraints()

        # Adjust range of scientific spinboxes above what is possible in Qt Designer
        self._mw.cw_frequency_DoubleSpinBox.setMaximum(
            constraints.max_frequency)
        self._mw.cw_frequency_DoubleSpinBox.setMinimum(
            constraints.min_frequency)
        self._mw.start_freq_DoubleSpinBox.setMaximum(constraints.max_frequency)
        self._mw.start_freq_DoubleSpinBox.setMinimum(constraints.min_frequency)
        self._mw.step_freq_DoubleSpinBox.setMaximum(100e9)
        self._mw.stop_freq_DoubleSpinBox.setMaximum(constraints.max_frequency)
        self._mw.stop_freq_DoubleSpinBox.setMinimum(constraints.min_frequency)
        self._mw.cw_power_DoubleSpinBox.setMaximum(constraints.max_power)
        self._mw.cw_power_DoubleSpinBox.setMinimum(constraints.min_power)
        self._mw.sweep_power_DoubleSpinBox.setMaximum(constraints.max_power)
        self._mw.sweep_power_DoubleSpinBox.setMinimum(constraints.min_power)

        # Add save file tag input box
        self._mw.save_tag_LineEdit = QtWidgets.QLineEdit(self._mw)
        self._mw.save_tag_LineEdit.setMaximumWidth(500)
        self._mw.save_tag_LineEdit.setMinimumWidth(200)
        self._mw.save_tag_LineEdit.setToolTip('Enter a nametag which will be\n'
                                              'added to the filename.')
        self._mw.save_ToolBar.addWidget(self._mw.save_tag_LineEdit)

        # add a clear button to clear the ODMR plots:
        self._mw.clear_odmr_PushButton = QtWidgets.QPushButton(self._mw)
        self._mw.clear_odmr_PushButton.setText('Clear ODMR')
        self._mw.clear_odmr_PushButton.setToolTip('Clear the data of the\n'
                                                  'current ODMR measurements.')
        self._mw.clear_odmr_PushButton.setEnabled(False)
        self._mw.toolBar.addWidget(self._mw.clear_odmr_PushButton)

        # Set up and connect channel combobox
        self.display_channel = 0
        odmr_channels = self._odmr_logic.get_odmr_channels()
        for n, ch in enumerate(odmr_channels):
            self._mw.odmr_channel_ComboBox.addItem(str(ch), n)

        self._mw.odmr_channel_ComboBox.activated.connect(self.update_channel)

        # Get the image from the logic
        self.odmr_matrix_image = pg.ImageItem(
            self._odmr_logic.odmr_plot_xy[:, self.display_channel],
            axisOrder='row-major')
        self.odmr_matrix_image.setRect(
            QtCore.QRectF(self._odmr_logic.mw_start, 0,
                          self._odmr_logic.mw_stop - self._odmr_logic.mw_start,
                          self._odmr_logic.number_of_lines))

        self.odmr_image = pg.PlotDataItem(
            self._odmr_logic.odmr_plot_x,
            self._odmr_logic.odmr_plot_y[self.display_channel],
            pen=pg.mkPen(palette.c1, style=QtCore.Qt.DotLine),
            symbol='o',
            symbolPen=palette.c1,
            symbolBrush=palette.c1,
            symbolSize=7)

        self.odmr_fit_image = pg.PlotDataItem(self._odmr_logic.odmr_fit_x,
                                              self._odmr_logic.odmr_fit_y,
                                              pen=pg.mkPen(palette.c2))

        # Add the display item to the xy and xz ViewWidget, which was defined in the UI file.
        self._mw.odmr_PlotWidget.addItem(self.odmr_image)
        self._mw.odmr_PlotWidget.setLabel(axis='left',
                                          text='Counts',
                                          units='Counts/s')
        self._mw.odmr_PlotWidget.setLabel(axis='bottom',
                                          text='Frequency',
                                          units='Hz')
        self._mw.odmr_PlotWidget.showGrid(x=True, y=True, alpha=0.8)

        self._mw.odmr_matrix_PlotWidget.addItem(self.odmr_matrix_image)
        self._mw.odmr_matrix_PlotWidget.setLabel(axis='left',
                                                 text='Matrix Lines',
                                                 units='#')
        self._mw.odmr_matrix_PlotWidget.setLabel(axis='bottom',
                                                 text='Frequency',
                                                 units='Hz')

        # Get the colorscales at set LUT
        my_colors = ColorScaleInferno()
        self.odmr_matrix_image.setLookupTable(my_colors.lut)

        ########################################################################
        #                  Configuration of the Colorbar                       #
        ########################################################################
        self.odmr_cb = ColorBar(my_colors.cmap_normed, 100, 0, 100000)

        # adding colorbar to ViewWidget
        self._mw.odmr_cb_PlotWidget.addItem(self.odmr_cb)
        self._mw.odmr_cb_PlotWidget.hideAxis('bottom')
        self._mw.odmr_cb_PlotWidget.hideAxis('left')
        self._mw.odmr_cb_PlotWidget.setLabel('right',
                                             'Fluorescence',
                                             units='counts/s')

        ########################################################################
        #          Configuration of the various display Widgets                #
        ########################################################################
        # Take the default values from logic:
        self._mw.cw_frequency_DoubleSpinBox.setValue(
            self._odmr_logic.cw_mw_frequency)
        self._mw.start_freq_DoubleSpinBox.setValue(self._odmr_logic.mw_start)
        self._mw.stop_freq_DoubleSpinBox.setValue(self._odmr_logic.mw_stop)
        self._mw.step_freq_DoubleSpinBox.setValue(self._odmr_logic.mw_step)
        self._mw.cw_power_DoubleSpinBox.setValue(self._odmr_logic.cw_mw_power)
        self._mw.sweep_power_DoubleSpinBox.setValue(
            self._odmr_logic.sweep_mw_power)

        self._mw.runtime_DoubleSpinBox.setValue(self._odmr_logic.run_time)
        self._mw.elapsed_time_DisplayWidget.display(
            int(np.rint(self._odmr_logic.elapsed_time)))
        self._mw.elapsed_sweeps_DisplayWidget.display(
            self._odmr_logic.elapsed_sweeps)
        self._mw.average_level_SpinBox.setValue(
            self._odmr_logic.lines_to_average)

        self._sd.matrix_lines_SpinBox.setValue(
            self._odmr_logic.number_of_lines)
        self._sd.clock_frequency_DoubleSpinBox.setValue(
            self._odmr_logic.clock_frequency)
        self._sd.oversampling_SpinBox.setValue(self._odmr_logic.oversampling)
        self._sd.lock_in_CheckBox.setChecked(self._odmr_logic.lock_in)

        # fit settings
        self._fsd = FitSettingsDialog(self._odmr_logic.fc)
        self._fsd.sigFitsUpdated.connect(
            self._mw.fit_methods_ComboBox.setFitFunctions)
        self._fsd.applySettings()
        self._mw.action_FitSettings.triggered.connect(self._fsd.show)

        ########################################################################
        #                       Connect signals                                #
        ########################################################################
        # Internal user input changed signals
        self._mw.cw_frequency_DoubleSpinBox.editingFinished.connect(
            self.change_cw_params)
        self._mw.start_freq_DoubleSpinBox.editingFinished.connect(
            self.change_sweep_params)
        self._mw.step_freq_DoubleSpinBox.editingFinished.connect(
            self.change_sweep_params)
        self._mw.stop_freq_DoubleSpinBox.editingFinished.connect(
            self.change_sweep_params)
        self._mw.sweep_power_DoubleSpinBox.editingFinished.connect(
            self.change_sweep_params)
        self._mw.cw_power_DoubleSpinBox.editingFinished.connect(
            self.change_cw_params)
        self._mw.runtime_DoubleSpinBox.editingFinished.connect(
            self.change_runtime)
        self._mw.odmr_cb_max_DoubleSpinBox.valueChanged.connect(
            self.colorscale_changed)
        self._mw.odmr_cb_min_DoubleSpinBox.valueChanged.connect(
            self.colorscale_changed)
        self._mw.odmr_cb_high_percentile_DoubleSpinBox.valueChanged.connect(
            self.colorscale_changed)
        self._mw.odmr_cb_low_percentile_DoubleSpinBox.valueChanged.connect(
            self.colorscale_changed)
        self._mw.average_level_SpinBox.valueChanged.connect(
            self.average_level_changed)
        # Internal trigger signals
        self._mw.odmr_cb_manual_RadioButton.clicked.connect(
            self.colorscale_changed)
        self._mw.odmr_cb_centiles_RadioButton.clicked.connect(
            self.colorscale_changed)
        self._mw.clear_odmr_PushButton.clicked.connect(self.clear_odmr_data)
        self._mw.action_run_stop.triggered.connect(self.run_stop_odmr)
        self._mw.action_resume_odmr.triggered.connect(self.resume_odmr)
        self._mw.action_toggle_cw.triggered.connect(self.toggle_cw_mode)
        self._mw.action_Save.triggered.connect(self.save_data)
        self._mw.action_RestoreDefault.triggered.connect(
            self.restore_defaultview)
        self._mw.do_fit_PushButton.clicked.connect(self.do_fit)

        # Control/values-changed signals to logic
        self.sigCwMwOn.connect(self._odmr_logic.mw_cw_on,
                               QtCore.Qt.QueuedConnection)
        self.sigMwOff.connect(self._odmr_logic.mw_off,
                              QtCore.Qt.QueuedConnection)
        self.sigClearData.connect(self._odmr_logic.clear_odmr_data,
                                  QtCore.Qt.QueuedConnection)
        self.sigStartOdmrScan.connect(self._odmr_logic.start_odmr_scan,
                                      QtCore.Qt.QueuedConnection)
        self.sigStopOdmrScan.connect(self._odmr_logic.stop_odmr_scan,
                                     QtCore.Qt.QueuedConnection)
        self.sigContinueOdmrScan.connect(self._odmr_logic.continue_odmr_scan,
                                         QtCore.Qt.QueuedConnection)
        self.sigDoFit.connect(self._odmr_logic.do_fit,
                              QtCore.Qt.QueuedConnection)
        self.sigMwCwParamsChanged.connect(self._odmr_logic.set_cw_parameters,
                                          QtCore.Qt.QueuedConnection)
        self.sigMwSweepParamsChanged.connect(
            self._odmr_logic.set_sweep_parameters, QtCore.Qt.QueuedConnection)
        self.sigRuntimeChanged.connect(self._odmr_logic.set_runtime,
                                       QtCore.Qt.QueuedConnection)
        self.sigNumberOfLinesChanged.connect(
            self._odmr_logic.set_matrix_line_number,
            QtCore.Qt.QueuedConnection)
        self.sigClockFreqChanged.connect(self._odmr_logic.set_clock_frequency,
                                         QtCore.Qt.QueuedConnection)
        self.sigOversamplingChanged.connect(self._odmr_logic.set_oversampling,
                                            QtCore.Qt.QueuedConnection)
        self.sigLockInChanged.connect(self._odmr_logic.set_lock_in,
                                      QtCore.Qt.QueuedConnection)
        self.sigSaveMeasurement.connect(self._odmr_logic.save_odmr_data,
                                        QtCore.Qt.QueuedConnection)
        self.sigAverageLinesChanged.connect(
            self._odmr_logic.set_average_length, QtCore.Qt.QueuedConnection)

        # Update signals coming from logic:
        self._odmr_logic.sigParameterUpdated.connect(
            self.update_parameter, QtCore.Qt.QueuedConnection)
        self._odmr_logic.sigOutputStateUpdated.connect(
            self.update_status, QtCore.Qt.QueuedConnection)
        self._odmr_logic.sigOdmrPlotsUpdated.connect(
            self.update_plots, QtCore.Qt.QueuedConnection)
        self._odmr_logic.sigOdmrFitUpdated.connect(self.update_fit,
                                                   QtCore.Qt.QueuedConnection)
        self._odmr_logic.sigOdmrElapsedTimeUpdated.connect(
            self.update_elapsedtime, QtCore.Qt.QueuedConnection)

        # connect settings signals
        self._mw.action_Settings.triggered.connect(self._menu_settings)
        self._sd.accepted.connect(self.update_settings)
        self._sd.rejected.connect(self.reject_settings)
        self._sd.buttonBox.button(
            QtWidgets.QDialogButtonBox.Apply).clicked.connect(
                self.update_settings)
        self.reject_settings()

        # Show the Main ODMR GUI:
        self.show()
Exemplo n.º 16
0
class ODMRGui(GUIBase):
    """
    This is the GUI Class for ODMR
    """

    _modclass = 'ODMRGui'
    _modtype = 'gui'

    # declare connectors
    _in = {'odmrlogic1': 'ODMRLogic', 'savelogic': 'SaveLogic'}

    sigStartODMRScan = QtCore.Signal()
    sigStopODMRScan = QtCore.Signal()
    sigContinueODMRScan = QtCore.Signal()
    sigClearPlots = QtCore.Signal()
    sigMWOn = QtCore.Signal()
    sigMWOff = QtCore.Signal()
    sigMWPowerChanged = QtCore.Signal(float)
    sigMWFreqChanged = QtCore.Signal(float)

    def __init__(self, config, **kwargs):
        super().__init__(config=config, **kwargs)

        self.log.info('The following configuration was found.')

        # checking for the right configuration
        for key in config.keys():
            self.log.info('{0}: {1}'.format(key, config[key]))

    def on_activate(self, e=None):
        """ Definition, configuration and initialisation of the ODMR GUI.

        @param object e: Fysom.event object from Fysom class.
                         An object created by the state machine module Fysom,
                         which is connected to a specific event (have a look in
                         the Base Class). This object contains the passed event,
                         the state before the event happened and the destination
                         of the state which should be reached after the event
                         had happened.

        This init connects all the graphic modules, which were created in the
        *.ui file and configures the event handling between the modules.
        """

        self._odmr_logic = self.get_in_connector('odmrlogic1')
        self._save_logic = self.get_in_connector('savelogic')

        # Use the inherited class 'Ui_ODMRGuiUI' to create now the
        # GUI element:
        self._mw = ODMRMainWindow()
        self._sd = ODMRSettingDialog()

        # Create a QSettings object for the mainwindow and store the actual GUI layout
        self.mwsettings = QtCore.QSettings("QUDI", "ODMR")
        self.mwsettings.setValue("geometry", self._mw.saveGeometry())
        self.mwsettings.setValue("windowState", self._mw.saveState())

        # Adjust range of scientific spinboxes above what is possible in Qt Designer
        self._mw.frequency_DoubleSpinBox.setMaximum(
            self._odmr_logic.limits.max_frequency)
        self._mw.frequency_DoubleSpinBox.setMinimum(
            self._odmr_logic.limits.min_frequency)
        self._mw.start_freq_DoubleSpinBox.setMaximum(
            self._odmr_logic.limits.max_frequency)
        self._mw.start_freq_DoubleSpinBox.setMinimum(
            self._odmr_logic.limits.min_frequency)
        self._mw.step_freq_DoubleSpinBox.setMaximum(100e9)
        self._mw.stop_freq_DoubleSpinBox.setMaximum(
            self._odmr_logic.limits.max_frequency)
        self._mw.stop_freq_DoubleSpinBox.setMinimum(
            self._odmr_logic.limits.min_frequency)
        self._mw.power_DoubleSpinBox.setMaximum(
            self._odmr_logic.limits.max_power)
        self._mw.power_DoubleSpinBox.setMinimum(
            self._odmr_logic.limits.min_power)

        # Add save file tag input box
        self._mw.save_tag_LineEdit = QtWidgets.QLineEdit(self._mw)
        self._mw.save_tag_LineEdit.setMaximumWidth(200)
        self._mw.save_tag_LineEdit.setToolTip(
            'Enter a nametag which will be\nadded to the filename.')
        self._mw.save_ToolBar.addWidget(self._mw.save_tag_LineEdit)

        # add a clear button to clear the ODMR plots:
        self._mw.clear_odmr_PushButton = QtWidgets.QPushButton(self._mw)
        self._mw.clear_odmr_PushButton.setText('Clear ODMR')
        self._mw.clear_odmr_PushButton.setToolTip(
            'Clear the plots of the\ncurrent ODMR measurements.')
        self._mw.clear_odmr_PushButton.setEnabled(False)
        self._mw.save_ToolBar.addWidget(self._mw.clear_odmr_PushButton)
        self.sigClearPlots.connect(self._odmr_logic.clear_odmr_plots)

        # Get the image from the logic
        self.odmr_matrix_image = pg.ImageItem(
            self._odmr_logic.ODMR_plot_xy.transpose())
        self.odmr_matrix_image.setRect(
            QtCore.QRectF(self._odmr_logic.mw_start, 0,
                          self._odmr_logic.mw_stop - self._odmr_logic.mw_start,
                          self._odmr_logic.number_of_lines))

        self.odmr_image = pg.PlotDataItem(self._odmr_logic.ODMR_plot_x,
                                          self._odmr_logic.ODMR_plot_y,
                                          pen=pg.mkPen(
                                              palette.c1,
                                              style=QtCore.Qt.DotLine),
                                          symbol='o',
                                          symbolPen=palette.c1,
                                          symbolBrush=palette.c1,
                                          symbolSize=7)

        self.odmr_fit_image = pg.PlotDataItem(self._odmr_logic.ODMR_fit_x,
                                              self._odmr_logic.ODMR_fit_y,
                                              pen=pg.mkPen(palette.c2))

        # Add the display item to the xy and xz VieWidget, which was defined in
        # the UI file.
        self._mw.odmr_PlotWidget.addItem(self.odmr_image)
        self._mw.odmr_PlotWidget.setLabel(axis='left',
                                          text='Counts',
                                          units='Counts/s')
        self._mw.odmr_PlotWidget.setLabel(axis='bottom',
                                          text='Frequency',
                                          units='Hz')

        self._mw.odmr_matrix_PlotWidget.addItem(self.odmr_matrix_image)
        self._mw.odmr_matrix_PlotWidget.setLabel(axis='left',
                                                 text='Matrix Lines',
                                                 units='#')
        self._mw.odmr_matrix_PlotWidget.setLabel(axis='bottom',
                                                 text='Frequency',
                                                 units='Hz')

        self._mw.odmr_PlotWidget.showGrid(x=True, y=True, alpha=0.8)

        # Get the colorscales at set LUT
        my_colors = ColorScaleInferno()
        self.odmr_matrix_image.setLookupTable(my_colors.lut)

        # Configuration of the comboWidget
        self._mw.mode_ComboBox.addItem('Off')
        self._mw.mode_ComboBox.addItem('CW')

        fit_functions = self._odmr_logic.get_fit_functions()
        self._mw.fit_methods_ComboBox.clear()
        self._mw.fit_methods_ComboBox.addItems(fit_functions)

        ########################################################################
        #                  Configuration of the Colorbar                       #
        ########################################################################

        self.odmr_cb = ColorBar(my_colors.cmap_normed, 100, 0, 100000)

        # adding colorbar to ViewWidget
        self._mw.odmr_cb_PlotWidget.addItem(self.odmr_cb)
        self._mw.odmr_cb_PlotWidget.hideAxis('bottom')
        self._mw.odmr_cb_PlotWidget.hideAxis('left')
        self._mw.odmr_cb_PlotWidget.setLabel('right',
                                             'Fluorescence',
                                             units='counts/s')

        # Connect the buttons and inputs for the odmr colorbar
        self._mw.odmr_cb_manual_RadioButton.clicked.connect(
            self.refresh_matrix)
        self._mw.odmr_cb_centiles_RadioButton.clicked.connect(
            self.refresh_matrix)

        ########################################################################
        #          Configuration of the various display Widgets                #
        ########################################################################

        # Take the default values from logic:
        self._mw.frequency_DoubleSpinBox.setValue(
            self._odmr_logic.mw_frequency)
        self._mw.start_freq_DoubleSpinBox.setValue(self._odmr_logic.mw_start)

        self._mw.step_freq_DoubleSpinBox.setValue(self._odmr_logic.mw_step)
        self._mw.step_freq_DoubleSpinBox.setOpts(
            minStep=1.0)  # set the minimal step to 1Hz.

        self._mw.stop_freq_DoubleSpinBox.setValue(self._odmr_logic.mw_stop)

        self._mw.power_DoubleSpinBox.setValue(self._odmr_logic.mw_power)
        self._mw.power_DoubleSpinBox.setOpts(minStep=0.1)

        self._mw.runtime_DoubleSpinBox.setValue(self._odmr_logic.run_time)
        self._mw.elapsed_time_DisplayWidget.display(
            int(self._odmr_logic.elapsed_time))

        self._sd.matrix_lines_SpinBox.setValue(
            self._odmr_logic.number_of_lines)
        self._sd.clock_frequency_DoubleSpinBox.setValue(
            self._odmr_logic._clock_frequency)
        self._sd.fit_tabs = {}
        for name, model in self._odmr_logic.fit_models.items():
            try:
                self._sd.fit_tabs[name] = FitSettingsWidget(model[1])
            except:
                self.log.warning('Could not load fitmodel {0}'.format(name))
            else:
                self._sd.tabWidget.addTab(self._sd.fit_tabs[name], name)

        # Update the inputed/displayed numbers if return key is hit:

        # If the attribute setKeyboardTracking is set in a SpinBox or
        # DoubleSpinBox the valueChanged method will actually hold on the signal
        #  until the return key is pressed which is pretty useful ;)

        # self._mw.frequency_DoubleSpinBox.setKeyboardTracking(False)

        # Update the inputed/displayed numbers if the cursor has left the field:

        self._mw.frequency_DoubleSpinBox.editingFinished.connect(
            self.change_frequency)
        self._mw.start_freq_DoubleSpinBox.editingFinished.connect(
            self.change_start_freq)
        self._mw.step_freq_DoubleSpinBox.editingFinished.connect(
            self.change_step_freq)
        self._mw.stop_freq_DoubleSpinBox.editingFinished.connect(
            self.change_stop_freq)
        self._mw.power_DoubleSpinBox.editingFinished.connect(self.change_power)
        self._mw.runtime_DoubleSpinBox.editingFinished.connect(
            self.change_runtime)

        self._mw.odmr_cb_max_DoubleSpinBox.valueChanged.connect(
            self.refresh_matrix)
        self._mw.odmr_cb_min_DoubleSpinBox.valueChanged.connect(
            self.refresh_matrix)
        self._mw.odmr_cb_high_percentile_DoubleSpinBox.valueChanged.connect(
            self.refresh_matrix)
        self._mw.odmr_cb_low_percentile_DoubleSpinBox.valueChanged.connect(
            self.refresh_matrix)

        ########################################################################
        #                       Connect signals                                #
        ########################################################################

        # Connect the RadioButtons and connect to the events if they are clicked:
        self._mw.action_run_stop.triggered.connect(self.run_stop)
        self._mw.action_resume_odmr.triggered.connect(self.resume_odmr)
        self._mw.action_Save.triggered.connect(self.save_data)
        self._mw.action_RestoreDefault.triggered.connect(
            self.restore_defaultview)
        self.sigStartODMRScan.connect(self._odmr_logic.start_odmr_scan)
        self.sigStopODMRScan.connect(self._odmr_logic.stop_odmr_scan)
        self.sigContinueODMRScan.connect(self._odmr_logic.continue_odmr_scan)

        self.sigMWOn.connect(self._odmr_logic.MW_on)
        self.sigMWOff.connect(self._odmr_logic.MW_off)
        self.sigMWFreqChanged.connect(self._odmr_logic.set_frequency)
        self.sigMWPowerChanged.connect(self._odmr_logic.set_power)

        # react on an axis change in the logic by adapting the display:
        self._odmr_logic.sigODMRMatrixAxesChanged.connect(
            self.update_matrix_axes)

        # connect the clear button:
        self._mw.clear_odmr_PushButton.clicked.connect(
            self.clear_odmr_plots_clicked)

        self._odmr_logic.sigOdmrPlotUpdated.connect(self.refresh_plot)
        self._odmr_logic.sigOdmrFitUpdated.connect(self.refresh_plot_fit)
        self._odmr_logic.sigOdmrMatrixUpdated.connect(self.refresh_matrix)
        self._odmr_logic.sigOdmrElapsedTimeChanged.connect(
            self.refresh_elapsedtime)
        # connect settings signals
        self._mw.action_Settings.triggered.connect(self.menu_settings)
        self._sd.accepted.connect(self.update_settings)
        self._sd.rejected.connect(self.reject_settings)
        self._sd.buttonBox.button(
            QtWidgets.QDialogButtonBox.Apply).clicked.connect(
                self.update_settings)
        self.reject_settings()
        # Connect stop odmr
        self._odmr_logic.sigOdmrStarted.connect(self.odmr_started)
        self._odmr_logic.sigOdmrStopped.connect(self.odmr_stopped)
        # Combo Widget
        self._mw.mode_ComboBox.activated[str].connect(self.mw_stop)
        self._mw.fit_methods_ComboBox.activated[str].connect(
            self.update_fit_variable)
        # Push Buttons
        self._mw.do_fit_PushButton.clicked.connect(self.update_fit)

        # let the gui react on the signals from the GUI
        self._odmr_logic.sigMicrowaveCWModeChanged.connect(
            self.update_cw_display)
        self._odmr_logic.sigMicrowaveListModeChanged.connect(
            self.update_run_stop_display)

        # Show the Main ODMR GUI:
        self._mw.show()

    def on_deactivate(self, e):
        """ Reverse steps of activation

        @param object e: Fysom.event object from Fysom class. A more detailed
                         explanation can be found in the method initUI.

        @return int: error code (0:OK, -1:error)
        """
        self._mw.close()
        return 0

    def show(self):
        """Make window visible and put it above all other windows. """
        QtWidgets.QMainWindow.show(self._mw)
        self._mw.activateWindow()
        self._mw.raise_()

    def run_stop(self, is_checked):
        """ Manages what happens if odmr scan is started/stopped. """
        if is_checked:
            # change the axes appearance according to input values:
            self.sigStopODMRScan.emit()
            self.sigStartODMRScan.emit()
            self._mw.action_run_stop.setEnabled(False)
            self._mw.action_resume_odmr.setEnabled(False)
            self._mw.odmr_PlotWidget.removeItem(self.odmr_fit_image)

            # during scan, enable the clear plot possibility.
            self._mw.clear_odmr_PushButton.setEnabled(True)
        else:
            self.sigStopODMRScan.emit()
            self._mw.action_run_stop.setEnabled(False)
            self._mw.action_resume_odmr.setEnabled(False)
            # Disable the clear functionality since that is not needed if no
            # scan is running:
            self._mw.clear_odmr_PushButton.setEnabled(False)

    def update_cw_display(self, cw_on):
        """ Update the display for the cw state of the microwave.

        @param bool cw_on: for True the mw on display will be shown, otherwise
                           mw off will be displayed.
        """
        if cw_on:
            # # prevent any triggering, which results from changing the state of
            # # the combobox:
            # self._mw.mode_ComboBox.blockSignals(True)
            text = 'CW'
        else:
            text = 'Off'

        index = self._mw.mode_ComboBox.findText(text,
                                                QtCore.Qt.MatchFixedString)
        if index >= 0:
            self._mw.mode_ComboBox.setCurrentIndex(index)
        else:
            self.log.warning(
                'No proper state to display was found in the combobox!')

    def update_run_stop_display(self, run_odmr):
        """ Update the display for the odmr measurement.

        @param bool run_odmr: True indicates that the measurement is running and
                              False that it is stopped.
        """
        if run_odmr:
            self._mw.action_resume_odmr.setEnabled(False)
            self._mw.clear_odmr_PushButton.setEnabled(True)
        else:
            self._mw.action_resume_odmr.setEnabled(True)
            self._mw.clear_odmr_PushButton.setEnabled(False)

    def resume_odmr(self, is_checked):
        if is_checked:
            self.sigStopODMRScan.emit()
            self.sigContinueODMRScan.emit()
            self._mw.action_run_stop.setChecked(True)
            self._mw.action_run_stop.setEnabled(False)
            self._mw.action_resume_odmr.setEnabled(False)

            # during scan, enable the clear plot possibility.
            self._mw.clear_odmr_PushButton.setEnabled(True)
        else:
            self.sigStopODMRScan.emit()
            self._mw.action_run_stop.setChecked(False)
            self._mw.action_run_stop.setEnabled(True)
            self._mw.action_resume_odmr.setEnabled(True)
            # Disable the clear functionality since that is not needed if no scan is running:
            self._mw.clear_odmr_PushButton.setEnabled(False)

    def odmr_started(self):
        """ Switch the run/stop button to stop after receiving an odmsStarted
                    signal """
        self._mw.action_run_stop.setEnabled(True)
        self._mw.action_resume_odmr.setEnabled(False)

    def odmr_stopped(self):
        """ Switch the run/stop button to stop after receiving an odmr_stoped
            signal """
        self._mw.action_run_stop.setChecked(False)
        self._mw.action_resume_odmr.setChecked(False)
        self._mw.action_run_stop.setEnabled(True)
        self._mw.action_resume_odmr.setEnabled(True)

    def clear_odmr_plots_clicked(self):
        """ Clear the ODMR plots. """
        self.sigClearPlots.emit()

    def menu_settings(self):
        """ Open the settings menu """
        self._sd.exec_()

    def refresh_plot(self):
        """ Refresh the xy-plot image """
        self.odmr_image.setData(self._odmr_logic.ODMR_plot_x,
                                self._odmr_logic.ODMR_plot_y)

    def refresh_plot_fit(self):
        """ Refresh the xy fit plot image. """

        if not self._mw.fit_methods_ComboBox.currentText() == 'No Fit':
            self.odmr_fit_image.setData(x=self._odmr_logic.ODMR_fit_x,
                                        y=self._odmr_logic.ODMR_fit_y)
        else:
            if self.odmr_fit_image in self._mw.odmr_PlotWidget.listDataItems():
                self._mw.odmr_PlotWidget.removeItem(self.odmr_fit_image)

    def refresh_matrix(self):
        """ Refresh the xy-matrix image """
        odmr_image_data = self._odmr_logic.ODMR_plot_xy.transpose()

        cb_range = self.get_matrix_cb_range()

        # Now update image with new color scale, and update colorbar
        self.odmr_matrix_image.setImage(image=odmr_image_data,
                                        levels=(cb_range[0], cb_range[1]))
        self.refresh_odmr_colorbar()

    def update_matrix_axes(self):
        """ Adjust the x and y axes in the image according to the input. """

        self.odmr_matrix_image.setRect(
            QtCore.QRectF(self._odmr_logic.mw_start, 0,
                          self._odmr_logic.mw_stop - self._odmr_logic.mw_start,
                          self._odmr_logic.number_of_lines))

    def refresh_odmr_colorbar(self):
        """ Update the colorbar to a new scaling.

        Calls the refresh method from colorbar.
        """
        cb_range = self.get_matrix_cb_range()
        self.odmr_cb.refresh_colorbar(cb_range[0], cb_range[1])

        self._mw.odmr_cb_PlotWidget.update(
        )  # TODO: Is this necessary?  It is not in refresh_xy_colorbar in confocal gui

    def get_matrix_cb_range(self):
        """ Determines the cb_min and cb_max values for the matrix plot
        """
        matrix_image = self.odmr_matrix_image.image

        # If "Manual" is checked or the image is empty (all zeros), then take manual cb range.
        if self._mw.odmr_cb_manual_RadioButton.isChecked() or np.max(
                matrix_image) == 0.0:
            cb_min = self._mw.odmr_cb_min_DoubleSpinBox.value()
            cb_max = self._mw.odmr_cb_max_DoubleSpinBox.value()

        # Otherwise, calculate cb range from percentiles.
        else:
            # Exclude any zeros (which are typically due to unfinished scan)
            matrix_image_nonzero = matrix_image[np.nonzero(matrix_image)]

            # Read centile range
            low_centile = self._mw.odmr_cb_low_percentile_DoubleSpinBox.value()
            high_centile = self._mw.odmr_cb_high_percentile_DoubleSpinBox.value(
            )

            cb_min = np.percentile(matrix_image_nonzero, low_centile)
            cb_max = np.percentile(matrix_image_nonzero, high_centile)

        cb_range = [cb_min, cb_max]
        return cb_range

    def refresh_elapsedtime(self):
        """ Show current elapsed measurement time """
        self._mw.elapsed_time_DisplayWidget.display(
            int(self._odmr_logic.elapsed_time))

    def update_settings(self):
        """ Write the new settings from the gui to the file. """
        self._odmr_logic.number_of_lines = self._sd.matrix_lines_SpinBox.value(
        )
        self._odmr_logic.set_clock_frequency(
            self._sd.clock_frequency_DoubleSpinBox.value())
        self._odmr_logic.saveRawData = self._sd.save_raw_data_CheckBox.isChecked(
        )
        for name, tab in self._sd.fit_tabs.items():
            self._odmr_logic.use_custom_params[name] = tab.updateFitSettings(
                self._odmr_logic.fit_models[name][1])

    def reject_settings(self):
        """ Keep the old settings and restores the old settings in the gui. """
        self._sd.matrix_lines_SpinBox.setValue(
            self._odmr_logic.number_of_lines)
        self._sd.clock_frequency_DoubleSpinBox.setValue(
            self._odmr_logic._clock_frequency)
        self._sd.save_raw_data_CheckBox.setChecked(
            self._odmr_logic.saveRawData)
        for name, tab in self._sd.fit_tabs.items():
            tab.keepFitSettings(self._odmr_logic.fit_models[name][1],
                                self._odmr_logic.use_custom_params[name])

    def update_fit_variable(self, txt):
        """ Set current fit function """
        self._odmr_logic.current_fit_function = txt

    def update_fit(self):
        """ Do the configured fit and show it in the sum plot """
        x_data_fit, y_data_fit, fit_param, fit_result = self._odmr_logic.do_fit(
            fit_function=self._odmr_logic.current_fit_function)
        self._sd.fit_tabs[
            self._odmr_logic.current_fit_function].keepFitSettings(
                fit_result.params, 0)
        # The fit signal was already emitted in the logic, so there is no need
        # to set the fit data

        # check which Fit method is used and remove or add again the
        # odmr_fit_image, check also whether a odmr_fit_image already exists.
        if self._mw.fit_methods_ComboBox.currentText() == 'No Fit':
            if self.odmr_fit_image in self._mw.odmr_PlotWidget.listDataItems():
                self._mw.odmr_PlotWidget.removeItem(self.odmr_fit_image)
        else:
            if self.odmr_fit_image not in self._mw.odmr_PlotWidget.listDataItems(
            ):
                self._mw.odmr_PlotWidget.addItem(self.odmr_fit_image)

        self._mw.odmr_PlotWidget.getViewBox().updateAutoRange()
        self._mw.odmr_fit_results_DisplayWidget.clear()

        formated_results = units.create_formatted_output(fit_param)

        self._mw.odmr_fit_results_DisplayWidget.setPlainText(formated_results)

    def _format_param_dict(self, param_dict):
        """ Create from the passed param_dict a proper display of the parameters.

        @param dict param_dict: the dictionary with keys being the names of the
                                parameter and items being values/parameters.

        @return:
        """
        pass

    def mw_stop(self, txt):
        """ Stop frequency sweep and change to CW of off"""
        if txt == 'Off':
            self.sigMWOff.emit()
        if txt == 'CW':
            self.change_frequency()
            self.change_power()
            self.sigMWOn.emit()

    ############################################################################
    #                           Change Methods                                 #
    ############################################################################

    def change_frequency(self):
        """ Change CW frequency of microwave source """
        frequency = self._mw.frequency_DoubleSpinBox.value()
        self.sigMWFreqChanged.emit(frequency)

    def change_start_freq(self):
        """ Change start frequency of frequency sweep """
        self._odmr_logic.mw_start = self._mw.start_freq_DoubleSpinBox.value()

    def change_step_freq(self):
        """ Change step size in which frequency is changed """
        self._odmr_logic.mw_step = self._mw.step_freq_DoubleSpinBox.value()

    def change_stop_freq(self):
        """ Change end of frequency sweep """
        self._odmr_logic.mw_stop = self._mw.stop_freq_DoubleSpinBox.value()

    def change_power(self):
        """ Change microwave power """
        power = self._mw.power_DoubleSpinBox.value()
        self.sigMWPowerChanged.emit(power)

    def change_runtime(self):
        """ Change time after which microwave sweep is stopped """
        self._odmr_logic.run_time = self._mw.runtime_DoubleSpinBox.value()

    def save_data(self):
        """ Save the sum plot, the scan marix plot and the scan data """
        filetag = self._mw.save_tag_LineEdit.text()
        cb_range = self.get_matrix_cb_range()

        # Percentile range is None, unless the percentile scaling is selected in GUI.
        pcile_range = None
        if self._mw.odmr_cb_centiles_RadioButton.isChecked():
            low_centile = self._mw.odmr_cb_low_percentile_DoubleSpinBox.value()
            high_centile = self._mw.odmr_cb_high_percentile_DoubleSpinBox.value(
            )
            pcile_range = [low_centile, high_centile]

        self._odmr_logic.save_ODMR_Data(filetag,
                                        colorscale_range=cb_range,
                                        percentile_range=pcile_range)

    def restore_defaultview(self):
        self._mw.restoreGeometry(self.mwsettings.value("geometry", ""))
        self._mw.restoreState(self.mwsettings.value("windowState", ""))
Exemplo n.º 17
0
class CameraGUI(GUIBase):
    """ Main spectrometer camera class.
    """

    camera_logic = Connector(interface='CameraLogic')
    savelogic = Connector(interface='SaveLogic')

    sigVideoStart = QtCore.Signal()
    sigVideoStop = QtCore.Signal()
    sigImageStart = QtCore.Signal()
    sigImageStop = QtCore.Signal()
    sigROISet = QtCore.Signal(dict)

    _image = []

    _logic = None
    _mw = None

    def __init__(self, config, **kwargs):

        # load connection
        super().__init__(config=config, **kwargs)

    def on_activate(self):
        """ Initializes all needed UI files and establishes the connectors.
        """

        self._logic = self.camera_logic()
        self._save_logic = self.savelogic()

        # Windows
        self._mw = CameraWindow()
        self._mw.centralwidget.hide()
        self._mw.setDockNestingEnabled(True)
        self.initSettingsUI()
        self._sd.exposureDSpinBox.setDecimals(5)

        self._mw.start_video_Action.setEnabled(True)
        self._mw.start_video_Action.setChecked(self._logic.enabled)
        self._mw.start_video_Action.triggered.connect(self.start_video_clicked)

        self._mw.start_image_Action.setEnabled(True)
        self._mw.start_image_Action.setChecked(self._logic.enabled)
        self._mw.start_image_Action.triggered.connect(self.start_image_clicked)

        self._mw.action_toggle_cooling.toggled.connect(self.toggle_fan)

        self._logic.sigUpdateDisplay.connect(self.update_data)
        self._logic.sigAcquisitionFinished.connect(self.acquisition_finished)
        self._logic.sigVideoFinished.connect(self.enable_start_image_action)

        # starting the physical measurement
        self.sigVideoStart.connect(self._logic.start_loop)
        self.sigVideoStop.connect(self._logic.stop_loop)
        self.sigImageStart.connect(self._logic.start_single_acquistion)

        # connect Settings action under Options menu
        self._mw.actionSettings.triggered.connect(self.menu_settings)
        # connect save action to save function
        self._mw.actionSave_XY_Scan.triggered.connect(self.save_xy_scan_data)

        raw_data_image = self._logic.get_last_image()
        # This allows the camera GUI to take care of a 3darray of images if the cam GUI is initialized after
        # and ODMR measuremnt.
        try:
            if raw_data_image.ndim > 2:
                raw_data_image = np.zeros(self._logic.get_sensor())
        except BaseException:
            pass
        self._image = pg.ImageItem(image=raw_data_image, axisOrder='row-major')
        self._mw.image_PlotWidget.addItem(self._image)
        # Set ROI widget with default sensor size, snapping true and invisible color until and image is clicked.
        # Extra scale handles are added as well.
        # It has not been added to main window yet, so as to give a clean look when an image has not yet been
        # clicked.
        self.roi_p1 = self.roi_p2 = 0
        self.roi_s1, self.roi_s2 = self._logic.get_sensor()
        self.roi = pg.RectROI([self.roi_p1, self.roi_p2],
                              [self.roi_s1, self.roi_s2],
                              pen=(0, 0, 0, 0),
                              scaleSnap=True,
                              translateSnap=True,
                              maxBounds=QtCore.QRectF(self.roi_p1, self.roi_p2,
                                                      self.roi_s1,
                                                      self.roi_s2),
                              movable=False)
        self.roi.handleSize = 12
        self.roi.addScaleHandle((0, 1), (1, 0))
        self.roi.addScaleHandle((0, 0), (1, 1))
        self.roi.addScaleHandle((1, 0), (0, 1))
        self.roi.addTranslateHandle((1, 1), (0, 0))
        # self._mw.image_PlotWidget.addItem(self.roi)
        self._mw.image_PlotWidget.setAspectLocked(True)
        self.sigROISet.connect(self._logic.set_image_roi)
        # ROI button actions
        self._mw.DefaultRoi.clicked.connect(self.default_roi)
        self._mw.SetRoi.clicked.connect(self.set_roi)
        self._mw.DefaultRoi.setEnabled(False)
        self._mw.SetRoi.setEnabled(False)
        self._mw.image_PlotWidget.addItem(self.roi)

        self.cross = pg.CrosshairROI(pos=(self.roi_s1 / 2, self.roi_s2 / 2),
                                     size=(40, 40),
                                     translateSnap=True,
                                     rotateSnap=True,
                                     maxBounds=QtCore.QRectF(0, 0, 1200, 1200))
        self.cross.sigRegionChanged.connect(self.print_counts)
        self._mw.image_PlotWidget.addItem(self.cross)

        self.scaleBar = pg.LineSegmentROI(([0, 0], [100, 0]),
                                          pen={
                                              'color': "#E0D8D8",
                                              'width': 3
                                          })
        self._mw.image_PlotWidget.addItem(self.scaleBar)
        self.scaleBar.sigRegionChanged.connect(self.print_scale)

        # Get the colorscale and set the LUTs
        self.my_colors = ColorScaleInferno()

        self._image.setLookupTable(self.my_colors.lut)

        # Connect the buttons and inputs for the colorbar
        self._mw.xy_cb_manual_RadioButton.clicked.connect(
            self.update_xy_cb_range)
        self._mw.xy_cb_centiles_RadioButton.clicked.connect(
            self.update_xy_cb_range)

        self._mw.xy_cb_min_DoubleSpinBox.valueChanged.connect(
            self.shortcut_to_xy_cb_manual)
        self._mw.xy_cb_max_DoubleSpinBox.valueChanged.connect(
            self.shortcut_to_xy_cb_manual)
        self._mw.xy_cb_low_percentile_DoubleSpinBox.valueChanged.connect(
            self.shortcut_to_xy_cb_centiles)
        self._mw.xy_cb_high_percentile_DoubleSpinBox.valueChanged.connect(
            self.shortcut_to_xy_cb_centiles)

        # create color bar
        self.xy_cb = ColorBar(self.my_colors.cmap_normed,
                              width=100,
                              cb_min=0,
                              cb_max=100)
        self.depth_cb = ColorBar(self.my_colors.cmap_normed,
                                 width=100,
                                 cb_min=0,
                                 cb_max=100)
        self._mw.xy_cb_ViewWidget.addItem(self.xy_cb)
        self._mw.xy_cb_ViewWidget.hideAxis('bottom')
        self._mw.xy_cb_ViewWidget.setLabel('left', 'Fluorescence', units='c')
        self._mw.xy_cb_ViewWidget.setMouseEnabled(x=False, y=False)

    def on_deactivate(self):
        """ Deinitialisation performed during deactivation of the module.
        """
        self._mw.close()

    def show(self):
        """Make window visible and put it above all other windows.
        """
        QtWidgets.QMainWindow.show(self._mw)
        self._mw.activateWindow()
        self._mw.raise_()

    def initSettingsUI(self):
        """ Definition, configuration and initialisation of the settings GUI.

        This init connects all the graphic modules, which were created in the
        *.ui file and configures the event handling between the modules.
        Moreover it sets default values if not existed in the logic modules.
        """
        # Create the Settings window
        self._sd = CameraSettingDialog()
        # Connect the action of the settings window with the code:
        self._sd.accepted.connect(self.update_settings)
        self._sd.rejected.connect(self.keep_former_settings)
        self._sd.buttonBox.button(
            QtWidgets.QDialogButtonBox.Apply).clicked.connect(
                self.update_settings)

        # write the configuration to the settings window of the GUI.
        self.keep_former_settings()

    def update_settings(self):
        """ Write new settings from the gui to the file. """
        self._logic.set_exposure(self._sd.exposureDSpinBox.value())
        self._logic.set_gain(self._sd.gainSpinBox.value())
        exp_res = self._sd.rescomboBox.currentIndex()
        self._logic.set_exposure_resolution(exp_res)

    def keep_former_settings(self):
        """ Keep the old settings and restores them in the gui. """
        self._sd.exposureDSpinBox.setValue(self._logic._exposure)
        self._sd.gainSpinBox.setValue(self._logic._gain)
        if self._sd.rescomboBox.currentIndex() == 0:
            self._sd.exposureDSpinBox.setMaximum(10000000)
        else:
            self._sd.exposureDSpinBox.setMaximum(1000000000)

    def menu_settings(self):
        """ This method opens the settings menu. """
        self._sd.exec_()

    def start_image_clicked(self):
        # Adds the ROI widget when an image is clicked. Only serves aesthetic purpose when added here and not
        # in initialization.
        # self._mw.image_PlotWidget.addItem(self.roi)
        self.sigImageStart.emit()
        self._mw.start_image_Action.setDisabled(True)
        self._mw.start_video_Action.setDisabled(True)

    def acquisition_finished(self):
        self._mw.start_image_Action.setChecked(False)
        self._mw.start_image_Action.setDisabled(False)
        self._mw.start_video_Action.setDisabled(False)

    def start_video_clicked(self):
        """ Handling the Start button to stop and restart the counter.
        """
        self._mw.start_image_Action.setDisabled(True)
        # self._mw.image_PlotWidget.addItem(self.roi)
        if self._logic.enabled:
            self._mw.start_video_Action.setText('Start Video')
            self.sigVideoStop.emit()
        else:
            self._mw.start_video_Action.setText('Stop Video')
            self.sigVideoStart.emit()

    def enable_start_image_action(self):
        self._mw.start_image_Action.setEnabled(True)

    def update_data(self):
        """
        Get the image data from the logic and print it on the window
        """
        raw_data_image = self._logic.get_last_image()
        # levels = (0., 1.)
        # The button for ROI are enabled here, as well as the pen drawing the
        # ROI is given color.
        self._mw.DefaultRoi.setEnabled(True)
        self._mw.SetRoi.setEnabled(True)
        self.roi.setPen((6, 9))
        self._image.setImage(image=raw_data_image)
        self.update_xy_cb_range()
        self._sd.exposureDSpinBox.setValue(self._logic._exposure)
        self.print_counts()
        # self._image.setImage(image=raw_data_image, levels=levels)

    def print_counts(self):
        x, y = self.cross.pos()
        self.counts = self._logic.get_last_image()[int(y), int(x)]
        self._mw.counts_label.setText(str(self.counts))

    def print_scale(self):
        x1, y1, x2, y2 = self.scaleBar.boundingRect().getCoords()
        px_um = self._mw.dist_px.value()
        self.dist = np.sqrt((x1 - x2)**2 + (y1 - y2)**2) * px_um
        self._mw.dist_label.setText(f'{self.dist:.3f}')

    def updateView(self):
        """
        Update the view when the model change
        """
        pass

    def update_shape(self):
        '''Not used but for updating the default ROI shape to sensor size.
        '''
        self.roi_s1, self.roi_s2 = self._logic.get_sensor()

    def default_roi(self):
        '''Sets the ROI to initialized defualt coords.  set_roi is called as well to update the image
        and update camera as well of the new ROI coords.
        '''
        self.roi.setPos((self.roi_p1, self.roi_p2))
        self.roi.setSize((self.roi_s1, self.roi_s2))
        self.set_roi()

    def set_roi(self):
        '''The ROI coord. dict. is emitted to update the camera of the coorect ROI, starts image updation by
        calling the image_clicked function and repositons the ROI to fit the new ROIed imaged.
        '''
        was_enabled = False
        if self.roi.saveState()['size'] < (3, 3):
            return
        if self._logic.enabled:
            self._mw.start_video_Action.setText('Start Video')
            self.sigVideoStop.emit()
            was_enabled = True
        self.sigROISet.emit(self.roi.saveState())
        self.start_image_clicked()
        self.roi.setSize(self.roi.saveState()['size'])
        self.cross.maxBounds = QtCore.QRectF(
            0, 0,
            self.roi.saveState()['size'][0] - 1,
            self.roi.saveState()['size'][1] - 1)
        self.cross.setPos((self.roi.saveState()['size'][0] / 2,
                           self.roi.saveState()['size'][1] / 2))
        self.roi.setPos((self.roi_p1, self.roi_p2))
        if was_enabled:
            self._mw.start_video_Action.setText('Stop Video')
            self.sigVideoStart.emit()
            was_enabled = False

    def toggle_fan(self):
        fan_speed = 3 if self._mw.action_toggle_cooling.isChecked() else 0
        self._logic.set_fan_speed(fan_speed)

# color bar functions

    def get_xy_cb_range(self):
        """ Determines the cb_min and cb_max values for the xy scan image
        """
        # If "Manual" is checked, or the image data is empty (all zeros), then
        # take manual cb range.
        if self._mw.xy_cb_manual_RadioButton.isChecked() or np.max(
                self._image.image) == 0.0:
            cb_min = self._mw.xy_cb_min_DoubleSpinBox.value()
            cb_max = self._mw.xy_cb_max_DoubleSpinBox.value()

        # Otherwise, calculate cb range from percentiles.
        else:
            # xy_image_nonzero = self._image.image[np.nonzero(self._image.image)]

            # Read centile range
            low_centile = self._mw.xy_cb_low_percentile_DoubleSpinBox.value()
            high_centile = self._mw.xy_cb_high_percentile_DoubleSpinBox.value()

            cb_min = np.percentile(self._image.image, low_centile)
            cb_max = np.percentile(self._image.image, high_centile)

        cb_range = [cb_min, cb_max]

        return cb_range

    def refresh_xy_colorbar(self):
        """ Adjust the xy colorbar.

        Calls the refresh method from colorbar, which takes either the lowest
        and higherst value in the image or predefined ranges. Note that you can
        invert the colorbar if the lower border is bigger then the higher one.
        """
        cb_range = self.get_xy_cb_range()
        self.xy_cb.refresh_colorbar(cb_range[0], cb_range[1])

    def refresh_xy_image(self):
        """ Update the current XY image from the logic.

        Everytime the scanner is scanning a line in xy the
        image is rebuild and updated in the GUI.
        """
        self._image.getViewBox().updateAutoRange()

        xy_image_data = self._logic._last_image

        cb_range = self.get_xy_cb_range()

        # Now update image with new color scale, and update colorbar
        self._image.setImage(image=xy_image_data,
                             levels=(cb_range[0], cb_range[1]))
        self.refresh_xy_colorbar()

    def shortcut_to_xy_cb_manual(self):
        """Someone edited the absolute counts range for the xy colour bar, better update."""
        self._mw.xy_cb_manual_RadioButton.setChecked(True)
        self.update_xy_cb_range()

    def shortcut_to_xy_cb_centiles(self):
        """Someone edited the centiles range for the xy colour bar, better update."""
        self._mw.xy_cb_centiles_RadioButton.setChecked(True)
        self.update_xy_cb_range()

    def update_xy_cb_range(self):
        """Redraw xy colour bar and scan image."""
        self.refresh_xy_colorbar()
        self.refresh_xy_image()

# save functions

    def save_xy_scan_data(self):
        """ Run the save routine from the logic to save the xy confocal data."""
        cb_range = self.get_xy_cb_range()

        # Percentile range is None, unless the percentile scaling is selected
        # in GUI.
        pcile_range = None
        if not self._mw.xy_cb_manual_RadioButton.isChecked():
            low_centile = self._mw.xy_cb_low_percentile_DoubleSpinBox.value()
            high_centile = self._mw.xy_cb_high_percentile_DoubleSpinBox.value()
            pcile_range = [low_centile, high_centile]

        self._logic.save_xy_data(colorscale_range=cb_range,
                                 percentile_range=pcile_range)

        # TODO: find a way to produce raw image in savelogic.  For now it is
        # saved here.
        filepath = self._save_logic.get_path_for_module(module_name='Confocal')
        filename = filepath + os.sep + \
            time.strftime('%Y%m%d-%H%M-%S_confocal_xy_scan_raw_pixel_image')

        self._image.save(filename + '_raw.png')
Exemplo n.º 18
0
    def on_activate(self, e=None):
        """ Definition, configuration and initialisation of the ODMR GUI.

        @param object e: Fysom.event object from Fysom class.
                         An object created by the state machine module Fysom,
                         which is connected to a specific event (have a look in
                         the Base Class). This object contains the passed event,
                         the state before the event happened and the destination
                         of the state which should be reached after the event
                         had happened.

        This init connects all the graphic modules, which were created in the
        *.ui file and configures the event handling between the modules.
        """

        self._odmr_logic = self.get_in_connector('odmrlogic1')
        self._save_logic = self.get_in_connector('savelogic')

        # Use the inherited class 'Ui_ODMRGuiUI' to create now the
        # GUI element:
        self._mw = ODMRMainWindow()
        self._sd = ODMRSettingDialog()

        # Create a QSettings object for the mainwindow and store the actual GUI layout
        self.mwsettings = QtCore.QSettings("QUDI", "ODMR")
        self.mwsettings.setValue("geometry", self._mw.saveGeometry())
        self.mwsettings.setValue("windowState", self._mw.saveState())

        # Adjust range of scientific spinboxes above what is possible in Qt Designer
        self._mw.frequency_DoubleSpinBox.setMaximum(
            self._odmr_logic.limits.max_frequency)
        self._mw.frequency_DoubleSpinBox.setMinimum(
            self._odmr_logic.limits.min_frequency)
        self._mw.start_freq_DoubleSpinBox.setMaximum(
            self._odmr_logic.limits.max_frequency)
        self._mw.start_freq_DoubleSpinBox.setMinimum(
            self._odmr_logic.limits.min_frequency)
        self._mw.step_freq_DoubleSpinBox.setMaximum(100e9)
        self._mw.stop_freq_DoubleSpinBox.setMaximum(
            self._odmr_logic.limits.max_frequency)
        self._mw.stop_freq_DoubleSpinBox.setMinimum(
            self._odmr_logic.limits.min_frequency)
        self._mw.power_DoubleSpinBox.setMaximum(
            self._odmr_logic.limits.max_power)
        self._mw.power_DoubleSpinBox.setMinimum(
            self._odmr_logic.limits.min_power)

        # Add save file tag input box
        self._mw.save_tag_LineEdit = QtWidgets.QLineEdit(self._mw)
        self._mw.save_tag_LineEdit.setMaximumWidth(200)
        self._mw.save_tag_LineEdit.setToolTip(
            'Enter a nametag which will be\nadded to the filename.')
        self._mw.save_ToolBar.addWidget(self._mw.save_tag_LineEdit)

        # add a clear button to clear the ODMR plots:
        self._mw.clear_odmr_PushButton = QtWidgets.QPushButton(self._mw)
        self._mw.clear_odmr_PushButton.setText('Clear ODMR')
        self._mw.clear_odmr_PushButton.setToolTip(
            'Clear the plots of the\ncurrent ODMR measurements.')
        self._mw.clear_odmr_PushButton.setEnabled(False)
        self._mw.save_ToolBar.addWidget(self._mw.clear_odmr_PushButton)
        self.sigClearPlots.connect(self._odmr_logic.clear_odmr_plots)

        # Get the image from the logic
        self.odmr_matrix_image = pg.ImageItem(
            self._odmr_logic.ODMR_plot_xy.transpose())
        self.odmr_matrix_image.setRect(
            QtCore.QRectF(self._odmr_logic.mw_start, 0,
                          self._odmr_logic.mw_stop - self._odmr_logic.mw_start,
                          self._odmr_logic.number_of_lines))

        self.odmr_image = pg.PlotDataItem(self._odmr_logic.ODMR_plot_x,
                                          self._odmr_logic.ODMR_plot_y,
                                          pen=pg.mkPen(
                                              palette.c1,
                                              style=QtCore.Qt.DotLine),
                                          symbol='o',
                                          symbolPen=palette.c1,
                                          symbolBrush=palette.c1,
                                          symbolSize=7)

        self.odmr_fit_image = pg.PlotDataItem(self._odmr_logic.ODMR_fit_x,
                                              self._odmr_logic.ODMR_fit_y,
                                              pen=pg.mkPen(palette.c2))

        # Add the display item to the xy and xz VieWidget, which was defined in
        # the UI file.
        self._mw.odmr_PlotWidget.addItem(self.odmr_image)
        self._mw.odmr_PlotWidget.setLabel(axis='left',
                                          text='Counts',
                                          units='Counts/s')
        self._mw.odmr_PlotWidget.setLabel(axis='bottom',
                                          text='Frequency',
                                          units='Hz')

        self._mw.odmr_matrix_PlotWidget.addItem(self.odmr_matrix_image)
        self._mw.odmr_matrix_PlotWidget.setLabel(axis='left',
                                                 text='Matrix Lines',
                                                 units='#')
        self._mw.odmr_matrix_PlotWidget.setLabel(axis='bottom',
                                                 text='Frequency',
                                                 units='Hz')

        self._mw.odmr_PlotWidget.showGrid(x=True, y=True, alpha=0.8)

        # Get the colorscales at set LUT
        my_colors = ColorScaleInferno()
        self.odmr_matrix_image.setLookupTable(my_colors.lut)

        # Configuration of the comboWidget
        self._mw.mode_ComboBox.addItem('Off')
        self._mw.mode_ComboBox.addItem('CW')

        fit_functions = self._odmr_logic.get_fit_functions()
        self._mw.fit_methods_ComboBox.clear()
        self._mw.fit_methods_ComboBox.addItems(fit_functions)

        ########################################################################
        #                  Configuration of the Colorbar                       #
        ########################################################################

        self.odmr_cb = ColorBar(my_colors.cmap_normed, 100, 0, 100000)

        # adding colorbar to ViewWidget
        self._mw.odmr_cb_PlotWidget.addItem(self.odmr_cb)
        self._mw.odmr_cb_PlotWidget.hideAxis('bottom')
        self._mw.odmr_cb_PlotWidget.hideAxis('left')
        self._mw.odmr_cb_PlotWidget.setLabel('right',
                                             'Fluorescence',
                                             units='counts/s')

        # Connect the buttons and inputs for the odmr colorbar
        self._mw.odmr_cb_manual_RadioButton.clicked.connect(
            self.refresh_matrix)
        self._mw.odmr_cb_centiles_RadioButton.clicked.connect(
            self.refresh_matrix)

        ########################################################################
        #          Configuration of the various display Widgets                #
        ########################################################################

        # Take the default values from logic:
        self._mw.frequency_DoubleSpinBox.setValue(
            self._odmr_logic.mw_frequency)
        self._mw.start_freq_DoubleSpinBox.setValue(self._odmr_logic.mw_start)

        self._mw.step_freq_DoubleSpinBox.setValue(self._odmr_logic.mw_step)
        self._mw.step_freq_DoubleSpinBox.setOpts(
            minStep=1.0)  # set the minimal step to 1Hz.

        self._mw.stop_freq_DoubleSpinBox.setValue(self._odmr_logic.mw_stop)

        self._mw.power_DoubleSpinBox.setValue(self._odmr_logic.mw_power)
        self._mw.power_DoubleSpinBox.setOpts(minStep=0.1)

        self._mw.runtime_DoubleSpinBox.setValue(self._odmr_logic.run_time)
        self._mw.elapsed_time_DisplayWidget.display(
            int(self._odmr_logic.elapsed_time))

        self._sd.matrix_lines_SpinBox.setValue(
            self._odmr_logic.number_of_lines)
        self._sd.clock_frequency_DoubleSpinBox.setValue(
            self._odmr_logic._clock_frequency)
        self._sd.fit_tabs = {}
        for name, model in self._odmr_logic.fit_models.items():
            try:
                self._sd.fit_tabs[name] = FitSettingsWidget(model[1])
            except:
                self.log.warning('Could not load fitmodel {0}'.format(name))
            else:
                self._sd.tabWidget.addTab(self._sd.fit_tabs[name], name)

        # Update the inputed/displayed numbers if return key is hit:

        # If the attribute setKeyboardTracking is set in a SpinBox or
        # DoubleSpinBox the valueChanged method will actually hold on the signal
        #  until the return key is pressed which is pretty useful ;)

        # self._mw.frequency_DoubleSpinBox.setKeyboardTracking(False)

        # Update the inputed/displayed numbers if the cursor has left the field:

        self._mw.frequency_DoubleSpinBox.editingFinished.connect(
            self.change_frequency)
        self._mw.start_freq_DoubleSpinBox.editingFinished.connect(
            self.change_start_freq)
        self._mw.step_freq_DoubleSpinBox.editingFinished.connect(
            self.change_step_freq)
        self._mw.stop_freq_DoubleSpinBox.editingFinished.connect(
            self.change_stop_freq)
        self._mw.power_DoubleSpinBox.editingFinished.connect(self.change_power)
        self._mw.runtime_DoubleSpinBox.editingFinished.connect(
            self.change_runtime)

        self._mw.odmr_cb_max_DoubleSpinBox.valueChanged.connect(
            self.refresh_matrix)
        self._mw.odmr_cb_min_DoubleSpinBox.valueChanged.connect(
            self.refresh_matrix)
        self._mw.odmr_cb_high_percentile_DoubleSpinBox.valueChanged.connect(
            self.refresh_matrix)
        self._mw.odmr_cb_low_percentile_DoubleSpinBox.valueChanged.connect(
            self.refresh_matrix)

        ########################################################################
        #                       Connect signals                                #
        ########################################################################

        # Connect the RadioButtons and connect to the events if they are clicked:
        self._mw.action_run_stop.triggered.connect(self.run_stop)
        self._mw.action_resume_odmr.triggered.connect(self.resume_odmr)
        self._mw.action_Save.triggered.connect(self.save_data)
        self._mw.action_RestoreDefault.triggered.connect(
            self.restore_defaultview)
        self.sigStartODMRScan.connect(self._odmr_logic.start_odmr_scan)
        self.sigStopODMRScan.connect(self._odmr_logic.stop_odmr_scan)
        self.sigContinueODMRScan.connect(self._odmr_logic.continue_odmr_scan)

        self.sigMWOn.connect(self._odmr_logic.MW_on)
        self.sigMWOff.connect(self._odmr_logic.MW_off)
        self.sigMWFreqChanged.connect(self._odmr_logic.set_frequency)
        self.sigMWPowerChanged.connect(self._odmr_logic.set_power)

        # react on an axis change in the logic by adapting the display:
        self._odmr_logic.sigODMRMatrixAxesChanged.connect(
            self.update_matrix_axes)

        # connect the clear button:
        self._mw.clear_odmr_PushButton.clicked.connect(
            self.clear_odmr_plots_clicked)

        self._odmr_logic.sigOdmrPlotUpdated.connect(self.refresh_plot)
        self._odmr_logic.sigOdmrFitUpdated.connect(self.refresh_plot_fit)
        self._odmr_logic.sigOdmrMatrixUpdated.connect(self.refresh_matrix)
        self._odmr_logic.sigOdmrElapsedTimeChanged.connect(
            self.refresh_elapsedtime)
        # connect settings signals
        self._mw.action_Settings.triggered.connect(self.menu_settings)
        self._sd.accepted.connect(self.update_settings)
        self._sd.rejected.connect(self.reject_settings)
        self._sd.buttonBox.button(
            QtWidgets.QDialogButtonBox.Apply).clicked.connect(
                self.update_settings)
        self.reject_settings()
        # Connect stop odmr
        self._odmr_logic.sigOdmrStarted.connect(self.odmr_started)
        self._odmr_logic.sigOdmrStopped.connect(self.odmr_stopped)
        # Combo Widget
        self._mw.mode_ComboBox.activated[str].connect(self.mw_stop)
        self._mw.fit_methods_ComboBox.activated[str].connect(
            self.update_fit_variable)
        # Push Buttons
        self._mw.do_fit_PushButton.clicked.connect(self.update_fit)

        # let the gui react on the signals from the GUI
        self._odmr_logic.sigMicrowaveCWModeChanged.connect(
            self.update_cw_display)
        self._odmr_logic.sigMicrowaveListModeChanged.connect(
            self.update_run_stop_display)

        # Show the Main ODMR GUI:
        self._mw.show()
Exemplo n.º 19
0
class PoiManagerGui(GUIBase):
    """ This is the GUI Class for PoiManager """

    _modclass = 'PoiManagerGui'
    _modtype = 'gui'

    # declare connectors
    poimanagerlogic = Connector(interface='PoiManagerLogic')
    scannerlogic = Connector(interface='ConfocalLogic')

    # declare signals
    sigTrackPeriodChanged = QtCore.Signal(float)
    sigPoiNameChanged = QtCore.Signal(str)
    sigPoiNameTagChanged = QtCore.Signal(str)
    sigRoiNameChanged = QtCore.Signal(str)
    sigAddPoiByClick = QtCore.Signal(np.ndarray)

    def __init__(self, config, **kwargs):
        super().__init__(config=config, **kwargs)

        self._mw = None  # QMainWindow handle
        self.roi_image = None  # pyqtgraph PlotImage for ROI scan image
        self.roi_cb = None  # The qudi colorbar to use with roi_image
        self.x_shift_plot = None  # pyqtgraph PlotDataItem for ROI history plot
        self.y_shift_plot = None  # pyqtgraph PlotDataItem for ROI history plot
        self.z_shift_plot = None  # pyqtgraph PlotDataItem for ROI history plot

        self._markers = dict()  # dict to hold handles for the POI markers

        self._mouse_moved_proxy = None  # Signal proxy to limit mousMoved event rate

        self.__poi_selector_active = False  # Flag indicating if the poi selector is active
        return

    def on_activate(self):
        """
        Initializes the overall GUI, and establishes the connectors.

        This method executes the init methods for each of the GUIs.
        """
        self._markers = dict()

        self._mw = PoiManagerMainWindow()
        # Configuring the dock widgets.
        # All our gui elements are dockable, so there should be no "central" widget.
        self._mw.centralwidget.hide()
        self._mw.setDockNestingEnabled(True)

        # Add validator to LineEdits
        self._mw.roi_name_LineEdit.setValidator(NameValidator())
        self._mw.poi_name_LineEdit.setValidator(NameValidator())
        self._mw.poi_nametag_LineEdit.setValidator(
            NameValidator(empty_allowed=True))

        # Initialize plots
        self.__init_roi_scan_image()
        self.__init_roi_history_plot()

        # Initialize refocus timer
        self.update_refocus_timer(
            self.poimanagerlogic().module_state() == 'locked',
            self.poimanagerlogic().refocus_period,
            self.poimanagerlogic().refocus_period)
        # Initialize POIs
        self._update_pois(self.poimanagerlogic().poi_positions)
        # Initialize ROI name
        self._update_roi_name(self.poimanagerlogic().roi_name)
        # Initialize POI nametag
        self._update_poi_nametag(self.poimanagerlogic().poi_nametag)

        # Distance Measurement:
        # Introducing a SignalProxy will limit the rate of signals that get fired.
        self._mouse_moved_proxy = pg.SignalProxy(
            signal=self.roi_image.scene().sigMouseMoved,
            rateLimit=30,
            slot=self.mouse_moved_callback)

        # Connect signals
        self.__connect_internal_signals()
        self.__connect_update_signals_from_logic()
        self.__connect_control_signals_to_logic()

        self._mw.show()
        return

    def on_deactivate(self):
        """
        De-initialisation performed during deactivation of the module.
        """
        self.toggle_poi_selector(False)
        self.__disconnect_control_signals_to_logic()
        self.__disconnect_update_signals_from_logic()
        self.__disconnect_internal_signals()
        self._mw.close()

    def __init_roi_scan_image(self):
        # Get the color scheme
        my_colors = ColorScaleInferno()
        # Setting up display of ROI xy scan image
        self.roi_image = pg.ImageItem(axisOrder='row-major', lut=my_colors.lut)
        self._mw.roi_map_ViewWidget.addItem(self.roi_image)
        self._mw.roi_map_ViewWidget.setLabel('bottom', 'X position', units='m')
        self._mw.roi_map_ViewWidget.setLabel('left', 'Y position', units='m')
        self._mw.roi_map_ViewWidget.setAspectLocked(lock=True, ratio=1.0)
        # Set up color bar
        self.roi_cb = ColorBar(my_colors.cmap_normed, 100, 0, 100000)
        self._mw.roi_cb_ViewWidget.addItem(self.roi_cb)
        self._mw.roi_cb_ViewWidget.hideAxis('bottom')
        self._mw.roi_cb_ViewWidget.setLabel('left',
                                            'Fluorescence',
                                            units='c/s')
        self._mw.roi_cb_ViewWidget.setMouseEnabled(x=False, y=False)

        # Get scan image from logic and update initialize plot
        self._update_scan_image(self.poimanagerlogic().roi_scan_image,
                                self.poimanagerlogic().roi_scan_image_extent)
        return

    def __init_roi_history_plot(self):
        # Setting up display of sample shift plot
        self.x_shift_plot = pg.PlotDataItem(x=[0],
                                            y=[0],
                                            pen=pg.mkPen(
                                                palette.c1,
                                                style=QtCore.Qt.DotLine),
                                            symbol='o',
                                            symbolPen=palette.c1,
                                            symbolBrush=palette.c1,
                                            symbolSize=5,
                                            name='x')
        self.y_shift_plot = pg.PlotDataItem(x=[0],
                                            y=[0],
                                            pen=pg.mkPen(
                                                palette.c2,
                                                style=QtCore.Qt.DotLine),
                                            symbol='s',
                                            symbolPen=palette.c2,
                                            symbolBrush=palette.c2,
                                            symbolSize=5,
                                            name='y')
        self.z_shift_plot = pg.PlotDataItem(x=[0],
                                            y=[0],
                                            pen=pg.mkPen(
                                                palette.c3,
                                                style=QtCore.Qt.DotLine),
                                            symbol='t',
                                            symbolPen=palette.c3,
                                            symbolBrush=palette.c3,
                                            symbolSize=5,
                                            name='z')

        self._mw.sample_shift_ViewWidget.addLegend()

        # Add the plot to the ViewWidget defined in the UI file
        self._mw.sample_shift_ViewWidget.addItem(self.x_shift_plot)
        self._mw.sample_shift_ViewWidget.addItem(self.y_shift_plot)
        self._mw.sample_shift_ViewWidget.addItem(self.z_shift_plot)

        # Label axes
        self._mw.sample_shift_ViewWidget.setLabel('bottom', 'Time', units='s')
        self._mw.sample_shift_ViewWidget.setLabel('left',
                                                  'Sample shift',
                                                  units='m')

        self._update_roi_history(self.poimanagerlogic().roi_pos_history)
        return

    def __connect_update_signals_from_logic(self):
        self.poimanagerlogic().sigRefocusTimerUpdated.connect(
            self.update_refocus_timer, QtCore.Qt.QueuedConnection)
        self.poimanagerlogic().sigPoiUpdated.connect(
            self.update_poi, QtCore.Qt.QueuedConnection)
        self.poimanagerlogic().sigActivePoiUpdated.connect(
            self.update_active_poi, QtCore.Qt.QueuedConnection)
        self.poimanagerlogic().sigRoiUpdated.connect(
            self.update_roi, QtCore.Qt.QueuedConnection)
        self.poimanagerlogic().sigRefocusStateUpdated.connect(
            self.update_refocus_state, QtCore.Qt.QueuedConnection)
        return

    def __disconnect_update_signals_from_logic(self):
        self.poimanagerlogic().sigRefocusTimerUpdated.disconnect()
        self.poimanagerlogic().sigPoiUpdated.disconnect()
        self.poimanagerlogic().sigActivePoiUpdated.disconnect()
        self.poimanagerlogic().sigRoiUpdated.disconnect()
        self.poimanagerlogic().sigRefocusStateUpdated.disconnect()
        return

    def __connect_control_signals_to_logic(self):
        self._mw.new_poi_Action.triggered.connect(
            self.poimanagerlogic().add_poi, QtCore.Qt.QueuedConnection)
        self._mw.goto_poi_Action.triggered.connect(
            self.poimanagerlogic().go_to_poi, QtCore.Qt.QueuedConnection)
        self._mw.new_roi_Action.triggered.connect(
            self.poimanagerlogic().reset_roi, QtCore.Qt.QueuedConnection)
        self._mw.refind_poi_Action.triggered.connect(
            self.poimanagerlogic().optimise_poi_position,
            QtCore.Qt.QueuedConnection)
        self._mw.get_confocal_image_PushButton.clicked.connect(
            self.poimanagerlogic().set_scan_image, QtCore.Qt.QueuedConnection)
        self._mw.set_poi_PushButton.clicked.connect(
            self.poimanagerlogic().add_poi, QtCore.Qt.QueuedConnection)
        self._mw.delete_last_pos_Button.clicked.connect(
            self.poimanagerlogic().delete_history_entry,
            QtCore.Qt.QueuedConnection)
        self._mw.manual_update_poi_PushButton.clicked.connect(
            self.poimanagerlogic().move_roi_from_poi_position,
            QtCore.Qt.QueuedConnection)
        self._mw.move_poi_PushButton.clicked.connect(
            self.poimanagerlogic().set_poi_anchor_from_position,
            QtCore.Qt.QueuedConnection)
        self._mw.delete_poi_PushButton.clicked.connect(
            self.poimanagerlogic().delete_poi, QtCore.Qt.QueuedConnection)
        self._mw.active_poi_ComboBox.activated[str].connect(
            self.poimanagerlogic().set_active_poi, QtCore.Qt.QueuedConnection)
        self._mw.goto_poi_after_update_checkBox.stateChanged.connect(
            self.poimanagerlogic().set_move_scanner_after_optimise,
            QtCore.Qt.QueuedConnection)
        self._mw.track_poi_Action.triggered.connect(
            self.poimanagerlogic().toggle_periodic_refocus,
            QtCore.Qt.QueuedConnection)
        self.sigTrackPeriodChanged.connect(
            self.poimanagerlogic().set_refocus_period,
            QtCore.Qt.QueuedConnection)
        self.sigRoiNameChanged.connect(self.poimanagerlogic().rename_roi,
                                       QtCore.Qt.QueuedConnection)
        self.sigPoiNameChanged.connect(self.poimanagerlogic().rename_poi,
                                       QtCore.Qt.QueuedConnection)
        self.sigPoiNameTagChanged.connect(
            self.poimanagerlogic().set_poi_nametag, QtCore.Qt.QueuedConnection)
        self.sigAddPoiByClick.connect(self.poimanagerlogic().add_poi,
                                      QtCore.Qt.QueuedConnection)
        return

    def __disconnect_control_signals_to_logic(self):
        self._mw.new_poi_Action.triggered.disconnect()
        self._mw.goto_poi_Action.triggered.disconnect()
        self._mw.new_roi_Action.triggered.disconnect()
        self._mw.refind_poi_Action.triggered.disconnect()
        self._mw.get_confocal_image_PushButton.clicked.disconnect()
        self._mw.set_poi_PushButton.clicked.disconnect()
        self._mw.delete_last_pos_Button.clicked.disconnect()
        self._mw.manual_update_poi_PushButton.clicked.disconnect()
        self._mw.move_poi_PushButton.clicked.disconnect()
        self._mw.delete_poi_PushButton.clicked.disconnect()
        self._mw.active_poi_ComboBox.activated[str].disconnect()
        self._mw.goto_poi_after_update_checkBox.stateChanged.disconnect()
        self._mw.track_poi_Action.triggered.disconnect()
        self.sigTrackPeriodChanged.disconnect()
        self.sigRoiNameChanged.disconnect()
        self.sigPoiNameChanged.disconnect()
        self.sigPoiNameTagChanged.disconnect()
        self.sigAddPoiByClick.disconnect()
        for marker in self._markers.values():
            marker.sigPoiSelected.disconnect()
        return

    def __connect_internal_signals(self):
        self._mw.track_period_SpinBox.editingFinished.connect(
            self.track_period_changed)
        self._mw.roi_name_LineEdit.editingFinished.connect(
            self.roi_name_changed)
        self._mw.poi_name_LineEdit.returnPressed.connect(self.poi_name_changed)
        self._mw.poi_nametag_LineEdit.editingFinished.connect(
            self.poi_nametag_changed)
        self._mw.save_roi_Action.triggered.connect(self.save_roi)
        self._mw.load_roi_Action.triggered.connect(self.load_roi)
        self._mw.poi_selector_Action.toggled.connect(self.toggle_poi_selector)
        self._mw.roi_cb_centiles_RadioButton.toggled.connect(self.update_cb)
        self._mw.roi_cb_manual_RadioButton.toggled.connect(self.update_cb)
        self._mw.roi_cb_min_SpinBox.valueChanged.connect(
            self.update_cb_absolute)
        self._mw.roi_cb_max_SpinBox.valueChanged.connect(
            self.update_cb_absolute)
        self._mw.roi_cb_low_percentile_DoubleSpinBox.valueChanged.connect(
            self.update_cb_centiles)
        self._mw.roi_cb_high_percentile_DoubleSpinBox.valueChanged.connect(
            self.update_cb_centiles)
        return

    def __disconnect_internal_signals(self):
        self._mw.track_period_SpinBox.editingFinished.disconnect()
        self._mw.roi_name_LineEdit.editingFinished.disconnect()
        self._mw.poi_name_LineEdit.returnPressed.disconnect()
        self._mw.poi_nametag_LineEdit.editingFinished.disconnect()
        self._mw.save_roi_Action.triggered.disconnect()
        self._mw.load_roi_Action.triggered.disconnect()
        self._mw.poi_selector_Action.toggled.disconnect()
        self._mw.roi_cb_centiles_RadioButton.toggled.disconnect()
        self._mw.roi_cb_manual_RadioButton.toggled.disconnect()
        self._mw.roi_cb_min_SpinBox.valueChanged.disconnect()
        self._mw.roi_cb_max_SpinBox.valueChanged.disconnect()
        self._mw.roi_cb_low_percentile_DoubleSpinBox.valueChanged.disconnect()
        self._mw.roi_cb_high_percentile_DoubleSpinBox.valueChanged.disconnect()
        return

    def show(self):
        """Make main window visible and put it above all other windows. """
        QtWidgets.QMainWindow.show(self._mw)
        self._mw.activateWindow()
        self._mw.raise_()

    @QtCore.Slot(object)
    def mouse_moved_callback(self, event):
        """ Handles any mouse movements inside the image.

        @param event:   Event that signals the new mouse movement.
                        This should be of type QPointF.

        Gets the mouse position, converts it to a position scaled to the image axis
        and than calculates and updated the position to the current POI.
        """

        # converts the absolute mouse position to a position relative to the axis
        mouse_pos = self.roi_image.getViewBox().mapSceneToView(event[0])

        # only calculate distance, if a POI is selected
        active_poi = self.poimanagerlogic().active_poi
        if active_poi:
            poi_pos = self.poimanagerlogic().get_poi_position(active_poi)
            dx = ScaledFloat(mouse_pos.x() - poi_pos[0])
            dy = ScaledFloat(mouse_pos.y() - poi_pos[1])
            d_total = ScaledFloat(
                np.sqrt((mouse_pos.x() - poi_pos[0])**2 +
                        (mouse_pos.y() - poi_pos[1])**2))

            self._mw.poi_distance_label.setText(
                '{0:.2r}m ({1:.2r}m, {2:.2r}m)'.format(d_total, dx, dy))
        else:
            self._mw.poi_distance_label.setText('? (?, ?)')
        pass

    @QtCore.Slot(bool)
    def toggle_poi_selector(self, is_active):
        if is_active != self._mw.poi_selector_Action.isChecked():
            self._mw.poi_selector_Action.blockSignals(True)
            self._mw.poi_selector_Action.setChecked(is_active)
            self._mw.poi_selector_Action.blockSignals(False)
        if is_active != self.__poi_selector_active:
            if is_active:
                self.roi_image.scene().sigMouseClicked.connect(
                    self.create_poi_from_click)
                self.roi_image.setCursor(QtCore.Qt.CrossCursor)
            else:
                self.roi_image.scene().sigMouseClicked.disconnect()
                self.roi_image.setCursor(QtCore.Qt.ArrowCursor)
        self.__poi_selector_active = is_active
        return

    @QtCore.Slot(object)
    def create_poi_from_click(self, event):
        # Only create new POI if the mouse click event has not been accepted by some other means
        # In our case this is most likely the POI marker to select the active POI from.
        if not event.accepted:
            # Z position from ROI origin, X and Y positions from click event
            new_pos = self.poimanagerlogic().roi_origin
            cursor_pos = self.roi_image.getViewBox().mapSceneToView(
                event.scenePos())
            new_pos[0] = cursor_pos.x()
            new_pos[1] = cursor_pos.y()
            # Check if position lies within axis boundaries.
            x_axis_box = self._mw.roi_map_ViewWidget.getAxis(
                'bottom').sceneBoundingRect()
            y_axis_box = self._mw.roi_map_ViewWidget.getAxis(
                'left').sceneBoundingRect()
            min_x = self.roi_image.getViewBox().mapSceneToView(
                y_axis_box.bottomRight()).x()
            min_y = self.roi_image.getViewBox().mapSceneToView(
                x_axis_box.topLeft()).y()
            if new_pos[0] <= min_x or new_pos[1] <= min_y:
                return
            # Check if position is within scan image boundaries
            image_extent = self.poimanagerlogic().roi_scan_image_extent
            if image_extent is None:
                return
            if image_extent[0][0] > new_pos[0] or image_extent[0][1] < new_pos[
                    0]:
                return
            if image_extent[1][0] > new_pos[1] or image_extent[1][1] < new_pos[
                    1]:
                return
            event.accept()
            self.sigAddPoiByClick.emit(new_pos)
        return

    @QtCore.Slot(dict)
    def update_roi(self, roi_dict):
        if not isinstance(roi_dict, dict):
            self.log.error(
                'ROI parameters to update must be given in a single dictionary.'
            )
            return

        if 'name' in roi_dict:
            self._update_roi_name(name=roi_dict['name'])
        if 'poi_nametag' in roi_dict:
            self._update_poi_nametag(tag=roi_dict['poi_nametag'])
        if 'history' in roi_dict:
            self._update_roi_history(history=roi_dict['history'])
        if 'scan_image' in roi_dict and 'scan_image_extent' in roi_dict:
            self._update_scan_image(scan_image=roi_dict['scan_image'],
                                    image_extent=roi_dict['scan_image_extent'])
        if 'pois' in roi_dict:
            self._update_pois(poi_dict=roi_dict['pois'])
        return

    @QtCore.Slot(bool, float, float)
    def update_refocus_timer(self, is_active, period, time_until_refocus):
        if not self._mw.track_period_SpinBox.hasFocus():
            self._mw.track_period_SpinBox.blockSignals(True)
            self._mw.track_period_SpinBox.setValue(period)
            self._mw.track_period_SpinBox.blockSignals(False)

        self._mw.track_poi_Action.blockSignals(True)
        self._mw.time_till_next_update_ProgressBar.blockSignals(True)

        self._mw.track_poi_Action.setChecked(is_active)
        self._mw.time_till_next_update_ProgressBar.setMaximum(period)
        self._mw.time_till_next_update_ProgressBar.setValue(time_until_refocus)

        self._mw.time_till_next_update_ProgressBar.blockSignals(False)
        self._mw.track_poi_Action.blockSignals(False)
        return

    @QtCore.Slot(bool)
    def update_refocus_state(self, is_active):
        self._mw.refind_poi_Action.setEnabled(not is_active)
        return

    @QtCore.Slot(str, str, np.ndarray)
    def update_poi(self, old_name, new_name, position):
        # Handle changed names and deleted/added POIs
        if old_name != new_name:
            self._mw.active_poi_ComboBox.blockSignals(True)
            # Remember current text
            text_active_poi = self._mw.active_poi_ComboBox.currentText()
            # sort POI names and repopulate ComboBoxes
            self._mw.active_poi_ComboBox.clear()
            poi_names = natural_sort(self.poimanagerlogic().poi_names)
            self._mw.active_poi_ComboBox.addItems(poi_names)
            if text_active_poi == old_name:
                self._mw.active_poi_ComboBox.setCurrentText(new_name)
            else:
                self._mw.active_poi_ComboBox.setCurrentText(text_active_poi)
            self._mw.active_poi_ComboBox.blockSignals(False)

        # Delete/add/update POI marker to image
        if not old_name:
            # POI has been added
            self._add_poi_marker(name=new_name, position=position)
        elif not new_name:
            # POI has been deleted
            self._remove_poi_marker(name=old_name)
        else:
            # POI has been renamed and/or changed position
            size = self.poimanagerlogic().optimise_xy_size * np.sqrt(2)
            self._markers[old_name].set_name(new_name)
            self._markers[new_name] = self._markers.pop(old_name)
            self._markers[new_name].setSize((size, size))
            self._markers[new_name].set_position(position[:2])

        active_poi = self._mw.active_poi_ComboBox.currentText()
        if active_poi:
            self._markers[active_poi].select()
        return

    @QtCore.Slot(str)
    def update_active_poi(self, name):

        # Deselect current marker
        for marker in self._markers.values():
            if marker.selected:
                marker.deselect()
                break

        # Unselect POI if name is None or empty str
        self._mw.active_poi_ComboBox.blockSignals(True)
        if not name:
            self._mw.active_poi_ComboBox.setCurrentIndex(-1)
        else:
            self._mw.active_poi_ComboBox.setCurrentText(name)
        self._mw.active_poi_ComboBox.blockSignals(False)

        if name:
            active_poi_pos = self.poimanagerlogic().get_poi_position(name)
        else:
            active_poi_pos = np.zeros(3)
        self._mw.poi_coords_label.setText(
            '({0:.2r}m, {1:.2r}m, {2:.2r}m)'.format(
                ScaledFloat(active_poi_pos[0]), ScaledFloat(active_poi_pos[1]),
                ScaledFloat(active_poi_pos[2])))

        if name in self._markers:
            self._markers[name].set_radius(
                self.poimanagerlogic().optimise_xy_size / np.sqrt(2))
            self._markers[name].select()
        return

    @QtCore.Slot()
    def track_period_changed(self):
        self.sigTrackPeriodChanged.emit(self._mw.track_period_SpinBox.value())
        return

    @QtCore.Slot()
    def roi_name_changed(self):
        """ Set the name of the current ROI."""
        self.sigRoiNameChanged.emit(self._mw.roi_name_LineEdit.text())
        return

    @QtCore.Slot()
    def poi_name_changed(self):
        """ Change the name of the active poi."""
        new_name = self._mw.poi_name_LineEdit.text()
        if self._mw.active_poi_ComboBox.currentText(
        ) == new_name or not new_name:
            return

        self.sigPoiNameChanged.emit(new_name)

        # After POI name is changed, empty name field
        self._mw.poi_name_LineEdit.blockSignals(True)
        self._mw.poi_name_LineEdit.setText('')
        self._mw.poi_name_LineEdit.blockSignals(False)
        return

    @QtCore.Slot()
    def poi_nametag_changed(self):
        self.sigPoiNameTagChanged.emit(self._mw.poi_nametag_LineEdit.text())
        return

    @QtCore.Slot()
    def save_roi(self):
        """ Save ROI to file."""
        roi_name = self._mw.roi_name_LineEdit.text()
        self.poimanagerlogic().rename_roi(roi_name)
        self.poimanagerlogic().save_roi()
        return

    @QtCore.Slot()
    def load_roi(self):
        """ Load a saved ROI from file."""
        this_file = QtWidgets.QFileDialog.getOpenFileName(
            self._mw, 'Open ROI',
            self.poimanagerlogic().data_directory, 'Data files (*.dat)')[0]
        if this_file:
            self.poimanagerlogic().load_roi(complete_path=this_file)
        return

    @QtCore.Slot()
    def update_cb_centiles(self):
        if not self._mw.roi_cb_centiles_RadioButton.isChecked():
            self._mw.roi_cb_centiles_RadioButton.toggle()
        else:
            self.update_cb()
        return

    @QtCore.Slot()
    def update_cb_absolute(self):
        if not self._mw.roi_cb_manual_RadioButton.isChecked():
            self._mw.roi_cb_manual_RadioButton.toggle()
        else:
            self.update_cb()
        return

    @QtCore.Slot()
    def update_cb(self):
        image = self.poimanagerlogic().roi_scan_image
        if image is None:
            return
        cb_range = self.get_cb_range(image)
        self.roi_image.setLevels(cb_range)
        self.roi_cb.refresh_colorbar(*cb_range)
        return

    def _update_scan_image(self, scan_image, image_extent):
        """

        @param scan_image:
        @param image_extent:
        """
        if scan_image is None or image_extent is None:
            self._mw.roi_map_ViewWidget.removeItem(self.roi_image)
            return
        elif self.roi_image not in self._mw.roi_map_ViewWidget.items():
            self._mw.roi_map_ViewWidget.addItem(self.roi_image)
        self.roi_image.setImage(image=scan_image)
        (x_min, x_max), (y_min, y_max) = image_extent
        self.roi_image.getViewBox().enableAutoRange()
        self.roi_image.setRect(
            QtCore.QRectF(x_min, y_min, x_max - x_min, y_max - y_min))

        self.update_cb()
        return

    def _update_roi_name(self, name):
        self._mw.roi_name_LineEdit.blockSignals(True)
        self._mw.roi_name_LineEdit.setText(name)
        self._mw.roi_name_LineEdit.blockSignals(False)
        return

    def _update_poi_nametag(self, tag):
        if tag is None:
            tag = ''
        self._mw.poi_nametag_LineEdit.blockSignals(True)
        self._mw.poi_nametag_LineEdit.setText(tag)
        self._mw.poi_nametag_LineEdit.blockSignals(False)
        return

    def _update_roi_history(self, history=None):
        if history is None:
            history = self.poimanagerlogic().roi_pos_history

        if history.shape[1] != 4:
            self.log.error('ROI history must be an array of type float[][4].')
            return

        max_time = np.max(history[:, 0])
        if max_time < 300:
            self._mw.sample_shift_ViewWidget.setLabel('bottom',
                                                      'Time',
                                                      units='s')
            time_arr = history[:, 0]
        elif max_time < 7200:
            self._mw.sample_shift_ViewWidget.setLabel('bottom',
                                                      'Time',
                                                      units='min')
            time_arr = history[:, 0] / 60
        elif max_time < 172800:
            self._mw.sample_shift_ViewWidget.setLabel('bottom',
                                                      'Time',
                                                      units='h')
            time_arr = history[:, 0] / 3600
        else:
            self._mw.sample_shift_ViewWidget.setLabel('bottom',
                                                      'Time',
                                                      units='d')
            time_arr = history[:, 0] / 86400

        self.x_shift_plot.setData(time_arr, history[:, 1])
        self.y_shift_plot.setData(time_arr, history[:, 2])
        self.z_shift_plot.setData(time_arr, history[:, 3])
        return

    def _update_pois(self, poi_dict):
        """ Populate the dropdown box for selecting a poi. """
        self._mw.active_poi_ComboBox.blockSignals(True)

        self._mw.active_poi_ComboBox.clear()

        poi_names = natural_sort(poi_dict)
        self._mw.active_poi_ComboBox.addItems(poi_names)

        # Get two list of POI names. One of those to delete and one of those to add
        old_poi_names = set(self._markers)
        new_poi_names = set(poi_names)
        names_to_delete = list(old_poi_names.difference(new_poi_names))
        names_to_add = list(new_poi_names.difference(old_poi_names))

        # Delete markers accordingly
        for name in names_to_delete:
            self._remove_poi_marker(name)
        # Update positions of all remaining markers
        size = self.poimanagerlogic().optimise_xy_size * np.sqrt(2)
        for name, marker in self._markers.items():
            marker.setSize((size, size))
            marker.set_position(poi_dict[name])
        # Add new markers
        for name in names_to_add:
            self._add_poi_marker(name=name, position=poi_dict[name])

        # If there is no active POI, set the combobox to nothing (-1)
        active_poi = self.poimanagerlogic().active_poi
        if active_poi in poi_names:
            self._mw.active_poi_ComboBox.setCurrentText(active_poi)
            self._markers[active_poi].select()
            active_poi_pos = poi_dict[active_poi]
            self._mw.poi_coords_label.setText(
                '({0:.2r}m, {1:.2r}m, {2:.2r}m)'.format(
                    ScaledFloat(active_poi_pos[0]),
                    ScaledFloat(active_poi_pos[1]),
                    ScaledFloat(active_poi_pos[2])))
        else:
            self._mw.active_poi_ComboBox.setCurrentIndex(-1)

        self._mw.active_poi_ComboBox.blockSignals(False)
        return

    def get_cb_range(self, image):
        """ Process UI input to determine color bar range"""
        # If "Centiles" is checked, adjust colour scaling automatically to centiles.
        # Otherwise, take user-defined values.
        if self._mw.roi_cb_centiles_RadioButton.isChecked():
            low_centile = self._mw.roi_cb_low_percentile_DoubleSpinBox.value()
            high_centile = self._mw.roi_cb_high_percentile_DoubleSpinBox.value(
            )

            cb_min = np.percentile(image, low_centile)
            cb_max = np.percentile(image, high_centile)
        else:
            cb_min = self._mw.roi_cb_min_SpinBox.value()
            cb_max = self._mw.roi_cb_max_SpinBox.value()
        return cb_min, cb_max

    def _add_poi_marker(self, name, position):
        """ Add a circular POI marker to the ROI scan image. """
        if name:
            if name in self._markers:
                self.log.error(
                    'Unable to add POI marker to ROI image. POI marker already present.'
                )
                return
            marker = PoiMarker(position=position[:2],
                               view_widget=self._mw.roi_map_ViewWidget,
                               poi_name=name,
                               radius=self.poimanagerlogic().optimise_xy_size /
                               np.sqrt(2),
                               movable=False)
            # Add to the scan image widget
            marker.add_to_view_widget()
            marker.sigPoiSelected.connect(
                self.poimanagerlogic().set_active_poi,
                QtCore.Qt.QueuedConnection)
            self._markers[name] = marker
        return

    def _remove_poi_marker(self, name):
        """ Remove the POI marker for a POI that was deleted. """
        if name in self._markers:
            self._markers[name].delete_from_view_widget()
            self._markers[name].sigPoiSelected.disconnect()
            del self._markers[name]
        return
Exemplo n.º 20
0
class PoiManagerGui(GUIBase):

    """ This is the GUI Class for PoiManager """

    _modclass = 'PoiManagerGui'
    _modtype = 'gui'

    # declare connectors
    poimanagerlogic1 = Connector(interface='PoiManagerLogic')
    confocallogic1 = Connector(interface='ConfocalLogic')

    def __init__(self, config, **kwargs):
        super().__init__(config=config, **kwargs)

    def on_activate(self):
        """ Initializes the overall GUI, and establishes the connectors.

        This method executes the init methods for each of the GUIs.
        """

        # Connectors
        self._poi_manager_logic = self.get_connector('poimanagerlogic1')
        self._confocal_logic = self.get_connector('confocallogic1')
        self.log.debug("POI Manager logic is {0}".format(self._poi_manager_logic))
        self.log.debug("Confocal logic is {0}".format(self._confocal_logic))

        # Initializing the GUIs
        self.initMainUI()
        self.initReorientRoiDialogUI()

        # There could be POIs created in the logic already, so update lists and map
        self.populate_poi_list()
        self._redraw_sample_shift()
        self._redraw_poi_markers()

    def mouseMoved(self, event):
        """ Handles any mouse movements inside the image.

        @param event:   Event that signals the new mouse movement.
                        This should be of type QPointF.

        Gets the mouse position, converts it to a position scaled to the image axis
        and than calculates and updated the position to the current POI.
        """

        # converts the absolute mouse position to a position relative to the axis
        mouse_point=self.roi_map_image.mapFromScene(event.toPoint())
        #self.log.debug("Mouse at x = {0:0.2e}, y = {1:0.2e}".format(mouse_point.x(), mouse_point.y()))

        # only calculate distance, if a POI is selected
        if self._poi_manager_logic.active_poi is not None:
            cur_poi_pos = self._poi_manager_logic.get_poi_position(poikey=self._poi_manager_logic.active_poi.get_key())
            self._mw.poi_distance_label.setText('{0:.2e} ({1:.2e}, {2:.2e})'.format(
                np.sqrt((mouse_point.x() - cur_poi_pos[0])**2+(mouse_point.y() - cur_poi_pos[1])**2),
                mouse_point.x() - cur_poi_pos[0],
                mouse_point.y() - cur_poi_pos[1]))

    def initMainUI(self):
        """ Definition, configuration and initialisation of the POI Manager GUI.
        This init connects all the graphic modules, which were created in the
        *.ui file and configures the event handling between the modules.
        """

        # Use the inherited class 'Ui_PoiManagerGuiTemplate' to create now the
        # GUI element:
        self._mw = PoiManagerMainWindow()

        #####################
        # Configuring the dock widgets
        #####################

        # All our gui elements are dockable, and so there should be no "central" widget.
        self._mw.centralwidget.hide()
        self._mw.setDockNestingEnabled(True)

        self._mw.roi_cb_high_percentile_DoubleSpinBox.setOpts(step=0.01, decimals=5)
        self._mw.roi_cb_low_percentile_DoubleSpinBox.setOpts(step=0.01, decimals=2)
        #####################
        # Setting up display of ROI map xy image
        #####################

        # Get the image for the display from the logic:
        self.roi_xy_image_data = self._poi_manager_logic.roi_map_data[:, :, 3]

        # Load the image in the display:
        self.roi_map_image = pg.ImageItem(image=self.roi_xy_image_data, axisOrder='row-major')
        self.roi_map_image.setRect(
            QtCore.QRectF(
                self._confocal_logic.image_x_range[0],
                self._confocal_logic.image_y_range[0],
                self._confocal_logic.image_x_range[1] - self._confocal_logic.image_x_range[0],
                self._confocal_logic.image_y_range[1] - self._confocal_logic.image_y_range[0]))

        # Add the display item to the roi map ViewWidget defined in the UI file
        self._mw.roi_map_ViewWidget.addItem(self.roi_map_image)
        self._mw.roi_map_ViewWidget.setLabel('bottom', 'X position', units='m')
        self._mw.roi_map_ViewWidget.setLabel('left', 'Y position', units='m')

        # Set to fixed 1.0 aspect ratio, since the metaphor is a "map" of the sample
        self._mw.roi_map_ViewWidget.setAspectLocked(lock=True, ratio=1.0)

        # Get the colorscales and set LUT
        my_colors = ColorScaleInferno()

        self.roi_map_image.setLookupTable(my_colors.lut)

        # Add color bar:
        self.roi_cb = ColorBar(my_colors.cmap_normed, 100, 0, 100000)

        self._mw.roi_cb_ViewWidget.addItem(self.roi_cb)
        self._mw.roi_cb_ViewWidget.hideAxis('bottom')
        self._mw.roi_cb_ViewWidget.setLabel('left', 'Fluorescence', units='c/s')
        self._mw.roi_cb_ViewWidget.setMouseEnabled(x=False, y=False)

        #####################
        # Setting up display of sample shift plot
        #####################

        # Load image in the display
        self.x_shift_plot = pg.PlotDataItem(
            [0],
            [0],
            pen=pg.mkPen(palette.c1, style=QtCore.Qt.DotLine),
            symbol='o',
            symbolPen=palette.c1,
            symbolBrush=palette.c1,
            symbolSize=5,
            name='x'
            )
        self.y_shift_plot = pg.PlotDataItem(
            [0],
            [0],
            pen=pg.mkPen(palette.c2, style=QtCore.Qt.DotLine),
            symbol='s',
            symbolPen=palette.c2,
            symbolBrush=palette.c2,
            symbolSize=5,
            name='y'
            )
        self.z_shift_plot = pg.PlotDataItem(
            [0],
            [0],
            pen=pg.mkPen(palette.c3, style=QtCore.Qt.DotLine),
            symbol='t',
            symbolPen=palette.c3,
            symbolBrush=palette.c3,
            symbolSize=5,
            name='z'
            )

        self._mw.sample_shift_ViewWidget.addLegend()

        # Add the plot to the ViewWidget defined in the UI file
        self._mw.sample_shift_ViewWidget.addItem(self.x_shift_plot)
        self._mw.sample_shift_ViewWidget.addItem(self.y_shift_plot)
        self._mw.sample_shift_ViewWidget.addItem(self.z_shift_plot)

        # Label axes
        self._mw.sample_shift_ViewWidget.setLabel('bottom', 'Time', units='s')
        self._mw.sample_shift_ViewWidget.setLabel('left', 'Sample shift', units='m')

        #####################
        # Connect signals
        #####################

        # Distance Measurement:
        # Introducing a SignalProxy will limit the rate of signals that get fired.
        # Otherwise we will run into a heap of unhandled function calls.
        proxy = pg.SignalProxy(self.roi_map_image.scene().sigMouseMoved, rateLimit=60, slot=self.mouseMoved)
        # Connecting a Mouse Signal to trace to mouse movement function.
        self.roi_map_image.scene().sigMouseMoved.connect(self.mouseMoved)

        # Toolbar actions
        self._mw.new_roi_Action.triggered.connect(self.make_new_roi)
        self._mw.save_roi_Action.triggered.connect(self.save_roi)
        self._mw.load_roi_Action.triggered.connect(self.load_roi)
        self._mw.reorient_roi_Action.triggered.connect(self.open_reorient_roi_dialog)
        self._mw.autofind_pois_Action.triggered.connect(self.do_autofind_poi_procedure)
        self._mw.optimize_roi_Action.triggered.connect(self.optimize_roi)


        self._mw.new_poi_Action.triggered.connect(self.set_new_poi)
        self._mw.goto_poi_Action.triggered.connect(self.goto_poi)
        self._mw.refind_poi_Action.triggered.connect(self.update_poi_pos)
        self._mw.track_poi_Action.triggered.connect(self.toggle_tracking)

        # Interface controls
        self._mw.get_confocal_image_PushButton.clicked.connect(self.get_confocal_image)
        self._mw.set_poi_PushButton.clicked.connect(self.set_new_poi)
        self._mw.delete_last_pos_Button.clicked.connect(self.delete_last_point)
        self._mw.manual_update_poi_PushButton.clicked.connect(self.manual_update_poi)
        self._mw.move_poi_PushButton.clicked.connect(self.move_poi)
        self._mw.poi_name_LineEdit.returnPressed.connect(self.change_poi_name)
        self._mw.roi_name_LineEdit.editingFinished.connect(self.set_roi_name)
        self._mw.delete_poi_PushButton.clicked.connect(self.delete_poi)

        self._mw.goto_poi_after_update_checkBox.toggled.connect(self.toggle_follow)


        # This needs to be activated so that it only listens to user input, and ignores
        # algorithmic index changes
        self._mw.active_poi_ComboBox.activated.connect(self.handle_active_poi_ComboBox_index_change)
        self._mw.refind_method_ComboBox.currentIndexChanged.connect(self.change_refind_method)

        # Connect the buttons and inputs for the colorbar
        self._mw.roi_cb_centiles_RadioButton.toggled.connect(self.refresh_roi_colorscale)
        self._mw.roi_cb_manual_RadioButton.toggled.connect(self.refresh_roi_colorscale)
        self._mw.roi_cb_min_SpinBox.valueChanged.connect(self.shortcut_to_roi_cb_manual)
        self._mw.roi_cb_max_SpinBox.valueChanged.connect(self.shortcut_to_roi_cb_manual)
        self._mw.roi_cb_low_percentile_DoubleSpinBox.valueChanged.connect(self.shortcut_to_roi_cb_centiles)
        self._mw.roi_cb_high_percentile_DoubleSpinBox.valueChanged.connect(self.shortcut_to_roi_cb_centiles)

        self._mw.display_shift_vs_duration_RadioButton.toggled.connect(self._redraw_sample_shift)
        self._mw.display_shift_vs_clocktime_RadioButton.toggled.connect(self._redraw_sample_shift)

        self._markers = dict()

        # Signal at end of refocus
        self._poi_manager_logic.signal_timer_updated.connect(
            self._update_timer,
            QtCore.Qt.QueuedConnection
        )
        self._poi_manager_logic.signal_poi_updated.connect(
            self._redraw_sample_shift,
            QtCore.Qt.QueuedConnection
        )
        self._poi_manager_logic.signal_poi_updated.connect(
            self.populate_poi_list,
            QtCore.Qt.QueuedConnection
        )
        self._poi_manager_logic.signal_poi_updated.connect(
            self._redraw_poi_markers,
            QtCore.Qt.QueuedConnection
        )
        self._poi_manager_logic.signal_poi_deleted.connect(
            self._remove_poi_marker
        )
        self._poi_manager_logic.signal_confocal_image_updated.connect(
            self._redraw_roi_image
        )

        self._poi_manager_logic.signal_periodic_opt_duration_changed.connect(
            self._track_period_changed
        )
        self._poi_manager_logic.signal_periodic_opt_started.connect(
            self._tracking_started
        )
        self._poi_manager_logic.signal_periodic_opt_stopped.connect(
            self._tracking_stopped
        )

        # Connect track period after setting the GUI value from the logic
        initial_period = self._poi_manager_logic.timer_duration
        self._mw.track_period_SpinBox.setValue(initial_period)
        self._mw.time_till_next_update_ProgressBar.setMaximum(initial_period)
        self._mw.time_till_next_update_ProgressBar.setValue(initial_period)
        self._mw.track_period_SpinBox.valueChanged.connect(self.set_track_period)

        # Redraw the sample_shift axes if the range changes
        self._mw.sample_shift_ViewWidget.plotItem.sigRangeChanged.connect(self._redraw_sample_shift)

        self._mw.show()

    def initReorientRoiDialogUI(self):
        """ Definition, configuration and initialization fo the Reorient ROI Dialog GUI.

        This init connects all the graphic modules which were created in the
        *.ui file and configures event handling.
        """

        # Create the Reorient ROI Dialog window
        self._rrd = ReorientRoiDialog()

        # Connect the QDialog buttons to methods in the GUI
        self._rrd.accepted.connect(self.do_roi_reorientation)
        self._rrd.rejected.connect(self.reset_reorientation_dialog)

        # Connect the at_crosshair buttons
        self._rrd.ref_a_at_crosshair_PushButton.clicked.connect(self.ref_a_at_crosshair)
        self._rrd.ref_b_at_crosshair_PushButton.clicked.connect(self.ref_b_at_crosshair)
        self._rrd.ref_c_at_crosshair_PushButton.clicked.connect(self.ref_c_at_crosshair)

        # Connect input value changes to update the sanity-check values
        self._rrd.ref_a_poi_ComboBox.activated.connect(self.reorientation_sanity_check)
        self._rrd.ref_b_poi_ComboBox.activated.connect(self.reorientation_sanity_check)
        self._rrd.ref_c_poi_ComboBox.activated.connect(self.reorientation_sanity_check)
        self._rrd.ref_a_x_pos_DoubleSpinBox.valueChanged.connect(self.reorientation_sanity_check)
        self._rrd.ref_a_y_pos_DoubleSpinBox.valueChanged.connect(self.reorientation_sanity_check)
        self._rrd.ref_a_z_pos_DoubleSpinBox.valueChanged.connect(self.reorientation_sanity_check)
        self._rrd.ref_b_x_pos_DoubleSpinBox.valueChanged.connect(self.reorientation_sanity_check)
        self._rrd.ref_b_y_pos_DoubleSpinBox.valueChanged.connect(self.reorientation_sanity_check)
        self._rrd.ref_b_z_pos_DoubleSpinBox.valueChanged.connect(self.reorientation_sanity_check)
        self._rrd.ref_c_x_pos_DoubleSpinBox.valueChanged.connect(self.reorientation_sanity_check)
        self._rrd.ref_c_y_pos_DoubleSpinBox.valueChanged.connect(self.reorientation_sanity_check)
        self._rrd.ref_c_z_pos_DoubleSpinBox.valueChanged.connect(self.reorientation_sanity_check)

    def on_deactivate(self):
        """ Deinitialisation performed during deactivation of the module.
        """
        self._mw.close()

    def show(self):
        """Make main window visible and put it above all other windows. """
        QtWidgets.QMainWindow.show(self._mw)
        self._mw.activateWindow()
        self._mw.raise_()

    def get_confocal_image(self):
        """ Update the roi_map_data in poi manager logic, and use this updated
            data to redraw an image of the ROI.
        """

        # Make poi manager logic get the confocal data
        self._poi_manager_logic.get_confocal_image_data()

    def _redraw_roi_image(self):

        # the image data is the fluorescence part
        self.roi_xy_image_data = self._poi_manager_logic.roi_map_data[:, :, 3]

        # Also get the x and y range limits and hold them locally
        self.roi_map_xmin = np.min(self._poi_manager_logic.roi_map_data[:, :, 0])
        self.roi_map_xmax = np.max(self._poi_manager_logic.roi_map_data[:, :, 0])
        self.roi_map_ymin = np.min(self._poi_manager_logic.roi_map_data[:, :, 1])
        self.roi_map_ymax = np.max(self._poi_manager_logic.roi_map_data[:, :, 1])

        self.roi_map_image.getViewBox().enableAutoRange()
        self.roi_map_image.setRect(
            QtCore.QRectF(
                self.roi_map_xmin,
                self.roi_map_ymin,
                self.roi_map_xmax - self.roi_map_xmin,
                self.roi_map_ymax - self.roi_map_ymin))
        self.roi_map_image.setImage(image=self.roi_xy_image_data, autoLevels=True)

    def shortcut_to_roi_cb_manual(self):
        self._mw.roi_cb_manual_RadioButton.setChecked(True)
        self.refresh_roi_colorscale()

    def shortcut_to_roi_cb_centiles(self):
        self._mw.roi_cb_centiles_RadioButton.setChecked(True)
        self.refresh_roi_colorscale()

    def refresh_roi_colorscale(self):
        """ Adjust the colorbar in the ROI xy image, and update the image with the
        new color scale.

        Calls the refresh method from colorbar, which takes either the lowest
        and higherst value in the image or predefined ranges. Note that you can
        invert the colorbar if the lower border is bigger then the higher one.
        """

        cb_min, cb_max = self.determine_cb_range()

        self.roi_map_image.setImage(image=self.roi_xy_image_data, levels=(cb_min, cb_max))

        self.roi_cb.refresh_colorbar(cb_min, cb_max)
        self._mw.roi_cb_ViewWidget.update()

    def determine_cb_range(self):
        """ Process UI input to determine color bar range"""

        # If "Centiles" is checked, adjust colour scaling automatically to centiles.
        # Otherwise, take user-defined values.
        if self._mw.roi_cb_centiles_RadioButton.isChecked():
            low_centile = self._mw.roi_cb_low_percentile_DoubleSpinBox.value()
            high_centile = self._mw.roi_cb_high_percentile_DoubleSpinBox.value()

            cb_min = np.percentile(self.roi_xy_image_data, low_centile)
            cb_max = np.percentile(self.roi_xy_image_data, high_centile)

        else:
            cb_min = self._mw.roi_cb_min_SpinBox.value()
            cb_max = self._mw.roi_cb_max_SpinBox.value()

        return cb_min, cb_max

    def set_new_poi(self):
        """ This method sets a new poi from the current crosshair position."""
        key = self._poi_manager_logic.add_poi()

    def delete_last_point(self):
        """ Delete the last track position of a chosen poi. """
        if self._poi_manager_logic.active_poi is None:
            self.log.warning("No POI selected. No datapoint can be deleted")
        else:
            self._poi_manager_logic.delete_last_position(poikey=self._poi_manager_logic.active_poi.get_key())

    def delete_poi(self):
        """ Delete the active poi from the list of managed points. """
        if self._poi_manager_logic.active_poi is None:
            self.log.warning("No POI selected.")
        else:
            key = self._poi_manager_logic.active_poi.get_key()

            # todo: this needs to handle the case where the logic deletes a POI.

            self._poi_manager_logic.delete_poi(poikey=key)

    def _remove_poi_marker(self, poikey):
        """ Remove the POI marker for a POI that was deleted.
        """
        self._markers[poikey].delete_from_viewwidget()
        del self._markers[poikey]

    def manual_update_poi(self):
        """ Manually adds a point to the trace of a given poi without refocussing, and uses that information to update sample position.
        """
        if self._poi_manager_logic.active_poi is None:
            self.log.warning("No POI selected.")
        else:
            self._poi_manager_logic.set_new_position(poikey=self._poi_manager_logic.active_poi.get_key())

    def move_poi(self):
        """Manually move a POI to a new location in the sample map, but WITHOUT changing the sample position.  This moves a POI relative to all the others.
        """
        if self._poi_manager_logic.active_poi is None:
            self.log.warning("No POI selected.")
        else:
            self._poi_manager_logic.move_coords(poikey=self._poi_manager_logic.active_poi.get_key())

    def toggle_tracking(self):
        if self._poi_manager_logic.active_poi is None:
            self.log.warning("No POI selected.")
        else:
            if self._poi_manager_logic.timer is None:
                self._poi_manager_logic.start_periodic_refocus(poikey=self._poi_manager_logic.active_poi.get_key())

            else:
                self._poi_manager_logic.stop_periodic_refocus()

    def _tracking_started(self):
        self._mw.track_poi_Action.setChecked(True)

    def _tracking_stopped(self):
        self._mw.track_poi_Action.setChecked(False)

    def goto_poi(self, key):
        """ Go to the last known position of poi <key>."""
        if self._poi_manager_logic.active_poi is None:
            self.log.warning("No POI selected.")
        else:
            self._poi_manager_logic.go_to_poi(poikey=self._poi_manager_logic.active_poi.get_key())

    def populate_poi_list(self):
        """ Populate the dropdown box for selecting a poi. """
        self.log.debug('started populate_poi_list at {0}'.format(time.time()))
        self._mw.active_poi_ComboBox.clear()
        self._mw.offset_anchor_ComboBox.clear()
        self._rrd.ref_a_poi_ComboBox.clear()
        self._rrd.ref_b_poi_ComboBox.clear()
        self._rrd.ref_c_poi_ComboBox.clear()

        for key in self._poi_manager_logic.get_all_pois(abc_sort=True):
            if key is not 'crosshair' and key is not 'sample':
                poi_list_empty = False
                self._mw.active_poi_ComboBox.addItem(
                    self._poi_manager_logic.poi_list[key].get_name(), key)
                self._mw.offset_anchor_ComboBox.addItem(
                    self._poi_manager_logic.poi_list[key].get_name(), key)
                self._rrd.ref_a_poi_ComboBox.addItem(
                    self._poi_manager_logic.poi_list[key].get_name(), key)
                self._rrd.ref_b_poi_ComboBox.addItem(
                    self._poi_manager_logic.poi_list[key].get_name(), key)
                self._rrd.ref_c_poi_ComboBox.addItem(
                    self._poi_manager_logic.poi_list[key].get_name(), key)

        # If there is no active POI, set the combobox to nothing (-1)
        if self._poi_manager_logic.active_poi is None:
            self._mw.active_poi_ComboBox.setCurrentIndex(-1)

        # Otherwise, set it to the active POI
        else:
            self._mw.active_poi_ComboBox.setCurrentIndex(
                self._mw.active_poi_ComboBox.findData(
                    self._poi_manager_logic.active_poi.get_key()
                )
            )

        self.log.debug('finished populating at '.format(time.time()))

    def change_refind_method(self):
        """ Make appropriate changes in the GUI to reflect the newly chosen refind method."""

        if self._mw.refind_method_ComboBox.currentText() == 'position optimisation':
            self._mw.offset_anchor_ComboBox.setEnabled(False)
        elif self._mw.refind_method_ComboBox.currentText() == 'offset anchor':
            self.log.error("Anchor method not fully implemented yet. "
                           "Feel free to fix this method. Using position optimisation instead.")
            self._mw.offset_anchor_ComboBox.setEnabled(True)
        else:
            # TODO: throw an error
            self.log.debug('error 123')

    def set_roi_name(self):
        """ Set the name of a ROI (useful when saving)."""

        self._poi_manager_logic.roi_name = self._mw.roi_name_LineEdit.text().replace(" ", "_")

    def change_poi_name(self):
        """ Change the name of a poi."""

        newname = self._mw.poi_name_LineEdit.text()

        self._poi_manager_logic.rename_poi(poikey=self._poi_manager_logic.active_poi.get_key(), name=newname)

        # After POI name is changed, empty name field
        self._mw.poi_name_LineEdit.setText('')

    def handle_active_poi_ComboBox_index_change(self):
        """ Handle the change of index in the active POI combobox."""

        key = self._mw.active_poi_ComboBox.itemData(self._mw.active_poi_ComboBox.currentIndex())

        self._poi_manager_logic.set_active_poi(poikey = key)

        self._redraw_poi_markers() # todo when line 660 signal in logic is done, this is not necessary

    def select_poi_from_marker(self, poikey=None):
        """ Process the selection of a POI from click on POImark."""

        # Keep track of selected POI
        self._poi_manager_logic.set_active_poi(poikey=poikey)

#        # Set the selected POI in the combobox
#        self._mw.active_poi_ComboBox.setCurrentIndex(self._mw.active_poi_ComboBox.findData(poikey))
#        self._redraw_poi_markers()

    def update_poi_pos(self):
        if self._poi_manager_logic.active_poi is None:
            self.log.warning("No POI selected.")
        else:
            if self._mw.refind_method_ComboBox.currentText() == 'position optimisation':
                self._poi_manager_logic.optimise_poi(poikey=self._poi_manager_logic.active_poi.get_key())

            elif self._mw.refind_method_ComboBox.currentText() == 'offset anchor':
                anchor_key = self._mw.offset_anchor_ComboBox.itemData(
                    self._mw.offset_anchor_ComboBox.currentIndex())
                self._poi_manager_logic.optimise_poi(poikey=self._poi_manager_logic.active_poi.get_key(),
                                                     anchorkey=anchor_key)

    def toggle_follow(self):
        if self._mw.goto_poi_after_update_checkBox.isChecked():
            self._poi_manager_logic.go_to_crosshair_after_refocus = False
        else:
            self._poi_manager_logic.go_to_crosshair_after_refocus = True

    def _update_timer(self):
        self._mw.time_till_next_update_ProgressBar.setValue(self._poi_manager_logic.time_left)

    def set_track_period(self):
        """ Change the progress bar and update the timer duration."""

        new_track_period = self._mw.track_period_SpinBox.value()
        self._poi_manager_logic.set_periodic_optimize_duration(duration=new_track_period)

    def _track_period_changed(self):
        """ Reflect the changed track period in the GUI elements.
        """
        new_track_period = self._poi_manager_logic.timer_duration
        # Set the new maximum for the progress bar
        self._mw.time_till_next_update_ProgressBar.setMaximum(new_track_period)

        # If the tracker is not active, then set the value of the progress bar to the
        # new maximum
        if not self._mw.track_poi_Action.isChecked():
            self._mw.time_till_next_update_ProgressBar.setValue(new_track_period)

    def _redraw_clocktime_ticks(self):
        """If duration is displayed, reset ticks to default.
        Otherwise, create and update custom date/time ticks to the new axis range.
        """
        myAxisItem = self._mw.sample_shift_ViewWidget.plotItem.axes['bottom']['item']

        # if duration display, reset to default ticks
        if self._mw.display_shift_vs_duration_RadioButton.isChecked():
            myAxisItem.setTicks(None)

        # otherwise, convert tick strings to clock format
        else:

            # determine size of the sample shift bottom axis item in pixels
            bounds = myAxisItem.mapRectFromParent(myAxisItem.geometry())
            span = (bounds.topLeft(), bounds.topRight())
            lengthInPixels = (span[1] - span[0]).manhattanLength()

            if lengthInPixels == 0:
                return -1
            if myAxisItem.range[0] < 0:
                return -1

            default_ticks = myAxisItem.tickValues(
                myAxisItem.range[0], myAxisItem.range[1], lengthInPixels)

            newticks = []
            for i, tick_level in enumerate(default_ticks):
                newticks_this_level = []
                ticks = tick_level[1]
                for ii, tick in enumerate(ticks):
                    # For major ticks, include date
                    if i == 0:
                        string = time.strftime("%H:%M (%d.%m.)", time.localtime(tick * 3600))
                        # (the axis is plotted in hours to get naturally better placed ticks.)

                    # for middle and minor ticks, just display clock time
                    else:
                        string = time.strftime("%H:%M", time.localtime(tick * 3600))

                    newticks_this_level.append((tick, string))
                newticks.append(newticks_this_level)

            myAxisItem.setTicks(newticks)
            return 0

    def _redraw_sample_shift(self):

        # Get trace data and calculate shifts in x,y,z
        poi_trace = self._poi_manager_logic.poi_list['sample'].get_position_history()

        # If duration display is checked, subtract initial time and convert to
        # mins or hours as appropriate
        if self._mw.display_shift_vs_duration_RadioButton.isChecked():
            time_shift_data = (poi_trace[:, 0] - poi_trace[0, 0])

            if np.max(time_shift_data) < 300:
                self._mw.sample_shift_ViewWidget.setLabel('bottom', 'Time elapsed', units='s')
            elif np.max(time_shift_data) < 7200:
                time_shift_data = time_shift_data / 60.0
                self._mw.sample_shift_ViewWidget.setLabel('bottom', 'Time elapsed', units='min')
            else:
                time_shift_data = time_shift_data / 3600.0
                self._mw.sample_shift_ViewWidget.setLabel('bottom', 'Time elapsed', units='hr')

        # Otherwise, take the actual time but divide by 3600 so that tickmarks
        # automatically fall on whole hours
        else:
            time_shift_data = poi_trace[:, 0] / 3600.0
            self._mw.sample_shift_ViewWidget.setLabel('bottom', 'Time', units='')

        # Subtract initial position to get shifts
        x_shift_data = (poi_trace[:, 1] - poi_trace[0, 1])
        y_shift_data = (poi_trace[:, 2] - poi_trace[0, 2])
        z_shift_data = (poi_trace[:, 3] - poi_trace[0, 3])

        # Plot data
        self.x_shift_plot.setData(time_shift_data, x_shift_data)
        self.y_shift_plot.setData(time_shift_data, y_shift_data)
        self.z_shift_plot.setData(time_shift_data, z_shift_data)

        self._redraw_clocktime_ticks()

    def _redraw_poi_markers(self):

        self.log.debug('starting redraw_poi_markers {0}'.format(time.time()))

        for key in self._poi_manager_logic.get_all_pois():
            if key is not 'crosshair' and key is not 'sample':
                position = self._poi_manager_logic.get_poi_position(poikey=key)
                position = position[:2]

                if key in self._markers.keys():
                    self._markers[key].set_position(position)
                    self._markers[key].deselect()
                else:
                    # Create Region of Interest as marker:
                    marker = PoiMark(
                        position,
                        poi=self._poi_manager_logic.poi_list[key],
                        click_action=self.select_poi_from_marker,
                        movable=False,
                        scaleSnap=False,
                        snapSize=1.0e-6)

                    # Add to the Map Widget
                    marker.add_to_viewwidget(self._mw.roi_map_ViewWidget)
                    self._markers[key] = marker

        if self._poi_manager_logic.active_poi is not None:
            active_poi_key = self._poi_manager_logic.active_poi.get_key()

            self._markers[active_poi_key].select()
            cur_poi_pos = self._poi_manager_logic.get_poi_position(poikey=key)
            self._mw.poi_coords_label.setText(
                '({0:.2e}, {1:.2e}, {2:.2e})'.format(cur_poi_pos[0],
                                                     cur_poi_pos[1],
                                                     cur_poi_pos[2]
                                                     )
                )
        self.log.debug('finished redraw at {0}'.format(time.time()))

    def make_new_roi(self):
        """ Start new ROI by removing all POIs and resetting the sample history."""

        for key in self._poi_manager_logic.get_all_pois():
            if key is not 'crosshair' and key is not 'sample':
                self._markers[key].delete_from_viewwidget()

        del self._markers
        self._markers = dict()

        self._poi_manager_logic.reset_roi()

        self.populate_poi_list()

    def save_roi(self):
        """ Save ROI to file."""

        self._poi_manager_logic.save_poi_map_as_roi()

    def load_roi(self):
        """ Load a saved ROI from file."""

        this_file = QtWidgets.QFileDialog.getOpenFileName(
            self._mw,
            str("Open ROI"),
            None,
            str("Data files (*.dat)"))[0]

        self._poi_manager_logic.load_roi_from_file(filename=this_file)

        self.populate_poi_list()

    def open_reorient_roi_dialog(self):
        """ Open the dialog for reorienting the ROI. """
        self._rrd.show()

    def ref_a_at_crosshair(self):
        """ Set the newpos for ref A from the current crosshair position. """
        # TODO: get the range for these spinboxes from the hardware scanner range!
        self._rrd.ref_a_x_pos_DoubleSpinBox.setValue(self._confocal_logic.get_position()[0])
        self._rrd.ref_a_y_pos_DoubleSpinBox.setValue(self._confocal_logic.get_position()[1])
        self._rrd.ref_a_z_pos_DoubleSpinBox.setValue(self._confocal_logic.get_position()[2])

    def ref_b_at_crosshair(self):
        """ Set the newpos for ref B from the current crosshair position. """
        self._rrd.ref_b_x_pos_DoubleSpinBox.setValue(self._confocal_logic.get_position()[0])
        self._rrd.ref_b_y_pos_DoubleSpinBox.setValue(self._confocal_logic.get_position()[1])
        self._rrd.ref_b_z_pos_DoubleSpinBox.setValue(self._confocal_logic.get_position()[2])

    def ref_c_at_crosshair(self):
        """ Set the newpos for ref C from the current crosshair position. """
        self._rrd.ref_c_x_pos_DoubleSpinBox.setValue(self._confocal_logic.get_position()[0])
        self._rrd.ref_c_y_pos_DoubleSpinBox.setValue(self._confocal_logic.get_position()[1])
        self._rrd.ref_c_z_pos_DoubleSpinBox.setValue(self._confocal_logic.get_position()[2])

    def do_roi_reorientation(self):
        """Pass the old and new positions of refs A, B, C to PoiManager Logic to reorient every POI in the ROI.
        """

        ref_a_coords, ref_b_coords, ref_c_coords, ref_a_newpos, ref_b_newpos, ref_c_newpos = self._read_reorient_roi_dialog_values()

        self._poi_manager_logic.reorient_roi(ref_a_coords, ref_b_coords, ref_c_coords, ref_a_newpos, ref_b_newpos, ref_c_newpos)

        # Clear the values in the Reorient Roi Dialog in case it is needed again
        self.reset_reorientation_dialog()

    def _read_reorient_roi_dialog_values(self):
        """ This reads the values from reorient ROI Dialog, and returns them. """

        # Get POI keys for the chosen ref points
        ref_a_key = self._rrd.ref_a_poi_ComboBox.itemData(self._rrd.ref_a_poi_ComboBox.currentIndex())
        ref_b_key = self._rrd.ref_b_poi_ComboBox.itemData(self._rrd.ref_b_poi_ComboBox.currentIndex())
        ref_c_key = self._rrd.ref_c_poi_ComboBox.itemData(self._rrd.ref_c_poi_ComboBox.currentIndex())

        # Get the old coords for these refs
        ref_a_coords = np.array(self._poi_manager_logic.poi_list[ref_a_key].get_coords_in_sample())
        ref_b_coords = np.array(self._poi_manager_logic.poi_list[ref_b_key].get_coords_in_sample())
        ref_c_coords = np.array(self._poi_manager_logic.poi_list[ref_c_key].get_coords_in_sample())

        ref_a_newpos = np.array([self._rrd.ref_a_x_pos_DoubleSpinBox.value(),
                                 self._rrd.ref_a_y_pos_DoubleSpinBox.value(),
                                 self._rrd.ref_a_z_pos_DoubleSpinBox.value()])
        ref_b_newpos = np.array([self._rrd.ref_b_x_pos_DoubleSpinBox.value(),
                                 self._rrd.ref_b_y_pos_DoubleSpinBox.value(),
                                 self._rrd.ref_b_z_pos_DoubleSpinBox.value()])
        ref_c_newpos = np.array([self._rrd.ref_c_x_pos_DoubleSpinBox.value(),
                                 self._rrd.ref_c_y_pos_DoubleSpinBox.value(),
                                 self._rrd.ref_c_z_pos_DoubleSpinBox.value()])

        return ref_a_coords, ref_b_coords, ref_c_coords, ref_a_newpos*1e-6, ref_b_newpos*1e-6, ref_c_newpos*1e-6

    def reset_reorientation_dialog(self):
        """ Reset all the values in the reorient roi dialog. """

        self._rrd.ref_a_x_pos_DoubleSpinBox.setValue(0)
        self._rrd.ref_a_y_pos_DoubleSpinBox.setValue(0)
        self._rrd.ref_a_z_pos_DoubleSpinBox.setValue(0)

        self._rrd.ref_b_x_pos_DoubleSpinBox.setValue(0)
        self._rrd.ref_b_y_pos_DoubleSpinBox.setValue(0)
        self._rrd.ref_b_z_pos_DoubleSpinBox.setValue(0)

        self._rrd.ref_c_x_pos_DoubleSpinBox.setValue(0)
        self._rrd.ref_c_y_pos_DoubleSpinBox.setValue(0)
        self._rrd.ref_c_z_pos_DoubleSpinBox.setValue(0)

    def reorientation_sanity_check(self):
        """ Calculate the difference in length between edges of old triangle defined by refs A, B, C and the new triangle.
        """

        # Get set of positions from GUI
        ref_a_coords, ref_b_coords, ref_c_coords, ref_a_newpos, ref_b_newpos, ref_c_newpos = self._read_reorient_roi_dialog_values()

        # Calculate the difference in side lengths AB, BC, CA between the old triangle and the new triangle
        delta_ab = np.linalg.norm(ref_b_coords - ref_a_coords) - np.linalg.norm(ref_b_newpos - ref_a_newpos)
        delta_bc = np.linalg.norm(ref_c_coords - ref_b_coords) - np.linalg.norm(ref_c_newpos - ref_b_newpos)
        delta_ca = np.linalg.norm(ref_a_coords - ref_c_coords) - np.linalg.norm(ref_a_newpos - ref_c_newpos)

        # Write to the GUI
        self._rrd.length_difference_ab_Label.setText(str(delta_ab))
        self._rrd.length_difference_bc_Label.setText(str(delta_bc))
        self._rrd.length_difference_ca_Label.setText(str(delta_ca))

    def do_autofind_poi_procedure(self):
        """Run the autofind_pois procedure in the POI Manager Logic to get all the POIs in the current ROI image."""
        #Fixme: Add here the appropriate functionality

        self.log.error("Has to be implemented properly. Feel free to do it.")

        # # Get the thresholds from the user-chosen color bar range
        # cb_min, cb_max = self.determine_cb_range()
        #
        # this_min_threshold = cb_min + 0.3 * (cb_max - cb_min)
        # this_max_threshold = cb_max
        #
        # self._poi_manager_logic.autofind_pois(neighborhood_size=1, min_threshold=this_min_threshold, max_threshold=this_max_threshold)

    def optimize_roi(self):
        """Run the autofind_pois procedure in the POI Manager Logic to get all the POIs in the current ROI image."""
        #Fixme: Add here the appropriate functionality
        self.log.error("Not implemented yet. Feel free to help!")
Exemplo n.º 21
0
class ODMRGui(GUIBase):
    """
    This is the GUI Class for ODMR measurements
    """

    _modclass = 'ODMRGui'
    _modtype = 'gui'

    # declare connectors
    _connectors = {'odmrlogic1': 'ODMRLogic',
           'savelogic': 'SaveLogic'}

    sigStartOdmrScan = QtCore.Signal()
    sigStopOdmrScan = QtCore.Signal()
    sigContinueOdmrScan = QtCore.Signal()
    sigClearData = QtCore.Signal()
    sigCwMwOn = QtCore.Signal()
    sigMwOff = QtCore.Signal()
    sigMwPowerChanged = QtCore.Signal(float)
    sigMwCwParamsChanged = QtCore.Signal(float, float)
    sigMwSweepParamsChanged = QtCore.Signal(float, float, float, float)
    sigClockFreqChanged = QtCore.Signal(float)
    sigFitChanged = QtCore.Signal(str)
    sigNumberOfLinesChanged = QtCore.Signal(int)
    sigRuntimeChanged = QtCore.Signal(float)
    sigDoFit = QtCore.Signal(str)
    sigSaveMeasurement = QtCore.Signal(str, list, list)

    def __init__(self, config, **kwargs):
        super().__init__(config=config, **kwargs)

        self.log.info('The following configuration was found.')

        # checking for the right configuration
        for key in config.keys():
            self.log.info('{0}: {1}'.format(key, config[key]))

    def on_activate(self):
        """ Definition, configuration and initialisation of the ODMR GUI.

        This init connects all the graphic modules, which were created in the
        *.ui file and configures the event handling between the modules.
        """

        self._odmr_logic = self.get_connector('odmrlogic1')

        # Use the inherited class 'Ui_ODMRGuiUI' to create now the GUI element:
        self._mw = ODMRMainWindow()
        self._sd = ODMRSettingDialog()

        # Create a QSettings object for the mainwindow and store the actual GUI layout
        self.mwsettings = QtCore.QSettings("QUDI", "ODMR")
        self.mwsettings.setValue("geometry", self._mw.saveGeometry())
        self.mwsettings.setValue("windowState", self._mw.saveState())

        # Get hardware constraints to set limits for input widgets
        constraints = self._odmr_logic.get_hw_constraints()

        # Adjust range of scientific spinboxes above what is possible in Qt Designer
        self._mw.cw_frequency_DoubleSpinBox.setMaximum(constraints.max_frequency)
        self._mw.cw_frequency_DoubleSpinBox.setMinimum(constraints.min_frequency)
        self._mw.start_freq_DoubleSpinBox.setMaximum(constraints.max_frequency)
        self._mw.start_freq_DoubleSpinBox.setMinimum(constraints.min_frequency)
        self._mw.step_freq_DoubleSpinBox.setMaximum(100e9)
        self._mw.step_freq_DoubleSpinBox.setOpts(minStep=1.0)  # set the minimal step to 1Hz
        self._mw.stop_freq_DoubleSpinBox.setMaximum(constraints.max_frequency)
        self._mw.stop_freq_DoubleSpinBox.setMinimum(constraints.min_frequency)
        self._mw.cw_power_DoubleSpinBox.setMaximum(constraints.max_power)
        self._mw.cw_power_DoubleSpinBox.setMinimum(constraints.min_power)
        self._mw.cw_power_DoubleSpinBox.setOpts(minStep=0.1)
        self._mw.sweep_power_DoubleSpinBox.setMaximum(constraints.max_power)
        self._mw.sweep_power_DoubleSpinBox.setMinimum(constraints.min_power)
        self._mw.sweep_power_DoubleSpinBox.setOpts(minStep=0.1)

        # Add save file tag input box
        self._mw.save_tag_LineEdit = QtWidgets.QLineEdit(self._mw)
        self._mw.save_tag_LineEdit.setMaximumWidth(500)
        self._mw.save_tag_LineEdit.setMinimumWidth(200)
        self._mw.save_tag_LineEdit.setToolTip('Enter a nametag which will be\n'
                                              'added to the filename.')
        self._mw.save_ToolBar.addWidget(self._mw.save_tag_LineEdit)

        # add a clear button to clear the ODMR plots:
        self._mw.clear_odmr_PushButton = QtWidgets.QPushButton(self._mw)
        self._mw.clear_odmr_PushButton.setText('Clear ODMR')
        self._mw.clear_odmr_PushButton.setToolTip('Clear the data of the\n'
                                                  'current ODMR measurements.')
        self._mw.clear_odmr_PushButton.setEnabled(False)
        self._mw.toolBar.addWidget(self._mw.clear_odmr_PushButton)

        # Get the image from the logic
        self.odmr_matrix_image = pg.ImageItem(self._odmr_logic.odmr_plot_xy.transpose())
        self.odmr_matrix_image.setRect(QtCore.QRectF(
                self._odmr_logic.mw_start,
                0,
                self._odmr_logic.mw_stop - self._odmr_logic.mw_start,
                self._odmr_logic.number_of_lines
            ))

        self.odmr_image = pg.PlotDataItem(self._odmr_logic.odmr_plot_x,
                                          self._odmr_logic.odmr_plot_y,
                                          pen=pg.mkPen(palette.c1, style=QtCore.Qt.DotLine),
                                          symbol='o',
                                          symbolPen=palette.c1,
                                          symbolBrush=palette.c1,
                                          symbolSize=7)

        self.odmr_fit_image = pg.PlotDataItem(self._odmr_logic.odmr_fit_x,
                                              self._odmr_logic.odmr_fit_y,
                                              pen=pg.mkPen(palette.c2))

        # Add the display item to the xy and xz ViewWidget, which was defined in the UI file.
        self._mw.odmr_PlotWidget.addItem(self.odmr_image)
        self._mw.odmr_PlotWidget.setLabel(axis='left', text='Counts', units='Counts/s')
        self._mw.odmr_PlotWidget.setLabel(axis='bottom', text='Frequency', units='Hz')
        self._mw.odmr_PlotWidget.showGrid(x=True, y=True, alpha=0.8)

        self._mw.odmr_matrix_PlotWidget.addItem(self.odmr_matrix_image)
        self._mw.odmr_matrix_PlotWidget.setLabel(axis='left', text='Matrix Lines', units='#')
        self._mw.odmr_matrix_PlotWidget.setLabel(axis='bottom', text='Frequency', units='Hz')

        # Get the colorscales at set LUT
        my_colors = ColorScaleInferno()
        self.odmr_matrix_image.setLookupTable(my_colors.lut)

        ########################################################################
        #                  Configuration of the Colorbar                       #
        ########################################################################
        self.odmr_cb = ColorBar(my_colors.cmap_normed, 100, 0, 100000)

        # adding colorbar to ViewWidget
        self._mw.odmr_cb_PlotWidget.addItem(self.odmr_cb)
        self._mw.odmr_cb_PlotWidget.hideAxis('bottom')
        self._mw.odmr_cb_PlotWidget.hideAxis('left')
        self._mw.odmr_cb_PlotWidget.setLabel('right', 'Fluorescence', units='counts/s')

        ########################################################################
        #          Configuration of the various display Widgets                #
        ########################################################################
        # Take the default values from logic:
        self._mw.cw_frequency_DoubleSpinBox.setValue(self._odmr_logic.cw_mw_frequency)
        self._mw.start_freq_DoubleSpinBox.setValue(self._odmr_logic.mw_start)
        self._mw.stop_freq_DoubleSpinBox.setValue(self._odmr_logic.mw_stop)
        self._mw.step_freq_DoubleSpinBox.setValue(self._odmr_logic.mw_step)
        self._mw.cw_power_DoubleSpinBox.setValue(self._odmr_logic.cw_mw_power)
        self._mw.sweep_power_DoubleSpinBox.setValue(self._odmr_logic.sweep_mw_power)

        self._mw.runtime_DoubleSpinBox.setValue(self._odmr_logic.run_time)
        self._mw.elapsed_time_DisplayWidget.display(int(np.rint(self._odmr_logic.elapsed_time)))
        self._mw.elapsed_sweeps_DisplayWidget.display(self._odmr_logic.elapsed_sweeps)

        self._sd.matrix_lines_SpinBox.setValue(self._odmr_logic.number_of_lines)
        self._sd.clock_frequency_DoubleSpinBox.setValue(self._odmr_logic.clock_frequency)

        # fit settings
        self._fsd = FitSettingsDialog(self._odmr_logic.fc)
        self._fsd.sigFitsUpdated.connect(self._mw.fit_methods_ComboBox.setFitFunctions)
        self._fsd.applySettings()
        self._mw.action_FitSettings.triggered.connect(self._fsd.show)

        ########################################################################
        #                       Connect signals                                #
        ########################################################################
        # Internal user input changed signals
        self._mw.cw_frequency_DoubleSpinBox.editingFinished.connect(self.change_cw_params)
        self._mw.start_freq_DoubleSpinBox.editingFinished.connect(self.change_sweep_params)
        self._mw.step_freq_DoubleSpinBox.editingFinished.connect(self.change_sweep_params)
        self._mw.stop_freq_DoubleSpinBox.editingFinished.connect(self.change_sweep_params)
        self._mw.sweep_power_DoubleSpinBox.editingFinished.connect(self.change_sweep_params)
        self._mw.cw_power_DoubleSpinBox.editingFinished.connect(self.change_cw_params)
        self._mw.runtime_DoubleSpinBox.editingFinished.connect(self.change_runtime)
        self._mw.odmr_cb_max_DoubleSpinBox.valueChanged.connect(self.colorscale_changed)
        self._mw.odmr_cb_min_DoubleSpinBox.valueChanged.connect(self.colorscale_changed)
        self._mw.odmr_cb_high_percentile_DoubleSpinBox.valueChanged.connect(self.colorscale_changed)
        self._mw.odmr_cb_low_percentile_DoubleSpinBox.valueChanged.connect(self.colorscale_changed)
        # Internal trigger signals
        self._mw.odmr_cb_manual_RadioButton.clicked.connect(self.colorscale_changed)
        self._mw.odmr_cb_centiles_RadioButton.clicked.connect(self.colorscale_changed)
        self._mw.clear_odmr_PushButton.clicked.connect(self.clear_odmr_data)
        self._mw.action_run_stop.triggered.connect(self.run_stop_odmr)
        self._mw.action_resume_odmr.triggered.connect(self.resume_odmr)
        self._mw.action_toggle_cw.triggered.connect(self.toggle_cw_mode)
        self._mw.action_Save.triggered.connect(self.save_data)
        self._mw.action_RestoreDefault.triggered.connect(self.restore_defaultview)
        self._mw.do_fit_PushButton.clicked.connect(self.do_fit)

        # Control/values-changed signals to logic
        self.sigCwMwOn.connect(self._odmr_logic.mw_cw_on, QtCore.Qt.QueuedConnection)
        self.sigMwOff.connect(self._odmr_logic.mw_off, QtCore.Qt.QueuedConnection)
        self.sigClearData.connect(self._odmr_logic.clear_odmr_data, QtCore.Qt.QueuedConnection)
        self.sigStartOdmrScan.connect(self._odmr_logic.start_odmr_scan, QtCore.Qt.QueuedConnection)
        self.sigStopOdmrScan.connect(self._odmr_logic.stop_odmr_scan, QtCore.Qt.QueuedConnection)
        self.sigContinueOdmrScan.connect(self._odmr_logic.continue_odmr_scan,
                                         QtCore.Qt.QueuedConnection)
        self.sigDoFit.connect(self._odmr_logic.do_fit, QtCore.Qt.QueuedConnection)
        self.sigMwCwParamsChanged.connect(self._odmr_logic.set_cw_parameters,
                                          QtCore.Qt.QueuedConnection)
        self.sigMwSweepParamsChanged.connect(self._odmr_logic.set_sweep_parameters,
                                             QtCore.Qt.QueuedConnection)
        self.sigRuntimeChanged.connect(self._odmr_logic.set_runtime, QtCore.Qt.QueuedConnection)
        self.sigNumberOfLinesChanged.connect(self._odmr_logic.set_matrix_line_number,
                                             QtCore.Qt.QueuedConnection)
        self.sigSaveMeasurement.connect(self._odmr_logic.save_odmr_data, QtCore.Qt.QueuedConnection)

        # Update signals coming from logic:
        self._odmr_logic.sigParameterUpdated.connect(self.update_parameter,
                                                     QtCore.Qt.QueuedConnection)
        self._odmr_logic.sigOutputStateUpdated.connect(self.update_status,
                                                       QtCore.Qt.QueuedConnection)
        self._odmr_logic.sigOdmrPlotsUpdated.connect(self.update_plots, QtCore.Qt.QueuedConnection)
        self._odmr_logic.sigOdmrFitUpdated.connect(self.update_fit, QtCore.Qt.QueuedConnection)
        self._odmr_logic.sigOdmrElapsedTimeUpdated.connect(self.update_elapsedtime,
                                                           QtCore.Qt.QueuedConnection)

        # connect settings signals
        self._mw.action_Settings.triggered.connect(self._menu_settings)
        self._sd.accepted.connect(self.update_settings)
        self._sd.rejected.connect(self.reject_settings)
        self._sd.buttonBox.button(QtWidgets.QDialogButtonBox.Apply).clicked.connect(
            self.update_settings)
        self.reject_settings()

        # Show the Main ODMR GUI:
        self._show()

    def on_deactivate(self):
        """ Reverse steps of activation

        @return int: error code (0:OK, -1:error)
        """
        # Disconnect signals
        self._sd.buttonBox.button(QtWidgets.QDialogButtonBox.Apply).clicked.disconnect()
        self._sd.accepted.disconnect()
        self._sd.rejected.disconnect()
        self._mw.action_Settings.triggered.disconnect()
        self._odmr_logic.sigParameterUpdated.disconnect()
        self._odmr_logic.sigOutputStateUpdated.disconnect()
        self._odmr_logic.sigOdmrPlotsUpdated.disconnect()
        self._odmr_logic.sigOdmrFitUpdated.disconnect()
        self._odmr_logic.sigOdmrElapsedTimeUpdated.disconnect()
        self.sigCwMwOn.disconnect()
        self.sigMwOff.disconnect()
        self.sigClearData.disconnect()
        self.sigStartOdmrScan.disconnect()
        self.sigStopOdmrScan.disconnect()
        self.sigContinueOdmrScan.disconnect()
        self.sigDoFit.disconnect()
        self.sigMwCwParamsChanged.disconnect()
        self.sigMwSweepParamsChanged.disconnect()
        self.sigRuntimeChanged.disconnect()
        self.sigNumberOfLinesChanged.disconnect()
        self.sigSaveMeasurement.disconnect()
        self._mw.odmr_cb_manual_RadioButton.clicked.disconnect()
        self._mw.odmr_cb_centiles_RadioButton.clicked.disconnect()
        self._mw.clear_odmr_PushButton.clicked.disconnect()
        self._mw.action_run_stop.triggered.disconnect()
        self._mw.action_resume_odmr.triggered.disconnect()
        self._mw.action_Save.triggered.disconnect()
        self._mw.action_toggle_cw.triggered.disconnect()
        self._mw.action_RestoreDefault.triggered.disconnect()
        self._mw.do_fit_PushButton.clicked.disconnect()
        self._mw.cw_frequency_DoubleSpinBox.editingFinished.disconnect()
        self._mw.start_freq_DoubleSpinBox.editingFinished.disconnect()
        self._mw.step_freq_DoubleSpinBox.editingFinished.disconnect()
        self._mw.stop_freq_DoubleSpinBox.editingFinished.disconnect()
        self._mw.cw_power_DoubleSpinBox.editingFinished.disconnect()
        self._mw.sweep_power_DoubleSpinBox.editingFinished.disconnect()
        self._mw.runtime_DoubleSpinBox.editingFinished.disconnect()
        self._mw.odmr_cb_max_DoubleSpinBox.valueChanged.disconnect()
        self._mw.odmr_cb_min_DoubleSpinBox.valueChanged.disconnect()
        self._mw.odmr_cb_high_percentile_DoubleSpinBox.valueChanged.disconnect()
        self._mw.odmr_cb_low_percentile_DoubleSpinBox.valueChanged.disconnect()
        self._fsd.sigFitsUpdated.disconnect()
        self._mw.action_FitSettings.triggered.disconnect()
        self._mw.close()
        return 0

    def _show(self):
        """Make window visible and put it above all other windows. """
        self._mw.show()
        self._mw.activateWindow()
        self._mw.raise_()
        return

    def _menu_settings(self):
        """ Open the settings menu """
        self._sd.exec_()

    def run_stop_odmr(self, is_checked):
        """ Manages what happens if odmr scan is started/stopped. """
        if is_checked:
            # change the axes appearance according to input values:
            self._mw.action_run_stop.setEnabled(False)
            self._mw.action_resume_odmr.setEnabled(False)
            self._mw.action_toggle_cw.setEnabled(False)
            self._mw.odmr_PlotWidget.removeItem(self.odmr_fit_image)
            self._mw.cw_power_DoubleSpinBox.setEnabled(False)
            self._mw.sweep_power_DoubleSpinBox.setEnabled(False)
            self._mw.cw_frequency_DoubleSpinBox.setEnabled(False)
            self._mw.start_freq_DoubleSpinBox.setEnabled(False)
            self._mw.step_freq_DoubleSpinBox.setEnabled(False)
            self._mw.stop_freq_DoubleSpinBox.setEnabled(False)
            self._mw.runtime_DoubleSpinBox.setEnabled(False)
            self._sd.clock_frequency_DoubleSpinBox.setEnabled(False)
            self.sigStartOdmrScan.emit()
        else:
            self._mw.action_run_stop.setEnabled(False)
            self._mw.action_resume_odmr.setEnabled(False)
            self._mw.action_toggle_cw.setEnabled(False)
            self.sigStopOdmrScan.emit()
        return

    def resume_odmr(self, is_checked):
        if is_checked:
            self._mw.action_run_stop.setEnabled(False)
            self._mw.action_resume_odmr.setEnabled(False)
            self._mw.action_toggle_cw.setEnabled(False)
            self._mw.cw_power_DoubleSpinBox.setEnabled(False)
            self._mw.sweep_power_DoubleSpinBox.setEnabled(False)
            self._mw.cw_frequency_DoubleSpinBox.setEnabled(False)
            self._mw.start_freq_DoubleSpinBox.setEnabled(False)
            self._mw.step_freq_DoubleSpinBox.setEnabled(False)
            self._mw.stop_freq_DoubleSpinBox.setEnabled(False)
            self._mw.runtime_DoubleSpinBox.setEnabled(False)
            self._sd.clock_frequency_DoubleSpinBox.setEnabled(False)
            self.sigContinueOdmrScan.emit()
        else:
            self._mw.action_run_stop.setEnabled(False)
            self._mw.action_resume_odmr.setEnabled(False)
            self._mw.action_toggle_cw.setEnabled(False)
            self.sigStopOdmrScan.emit()
        return

    def toggle_cw_mode(self, is_checked):
        """ Starts or stops CW microwave output if no measurement is running. """
        if is_checked:
            self._mw.action_run_stop.setEnabled(False)
            self._mw.action_resume_odmr.setEnabled(False)
            self._mw.action_toggle_cw.setEnabled(False)
            self._mw.cw_power_DoubleSpinBox.setEnabled(False)
            self._mw.cw_frequency_DoubleSpinBox.setEnabled(False)
            self.sigCwMwOn.emit()
        else:
            self._mw.action_toggle_cw.setEnabled(False)
            self.sigMwOff.emit()
        return

    def update_status(self, mw_mode, is_running):
        """ 
        Update the display for a change in the microwave status (mode and output).

        @param str mw_mode: is the microwave output active?
        @param bool is_running: is the microwave output active?
        """
        # Block signals from firing
        self._mw.action_run_stop.blockSignals(True)
        self._mw.action_resume_odmr.blockSignals(True)
        self._mw.action_toggle_cw.blockSignals(True)

        # Update measurement status (activate/deactivate widgets/actions)
        if is_running:
            self._mw.action_resume_odmr.setEnabled(False)
            self._mw.cw_power_DoubleSpinBox.setEnabled(False)
            self._mw.cw_frequency_DoubleSpinBox.setEnabled(False)
            if mw_mode != 'cw':
                self._mw.clear_odmr_PushButton.setEnabled(True)
                self._mw.action_run_stop.setEnabled(True)
                self._mw.action_toggle_cw.setEnabled(False)
                self._mw.start_freq_DoubleSpinBox.setEnabled(False)
                self._mw.step_freq_DoubleSpinBox.setEnabled(False)
                self._mw.stop_freq_DoubleSpinBox.setEnabled(False)
                self._mw.sweep_power_DoubleSpinBox.setEnabled(False)
                self._mw.runtime_DoubleSpinBox.setEnabled(False)
                self._sd.clock_frequency_DoubleSpinBox.setEnabled(False)
                self._mw.action_run_stop.setChecked(True)
                self._mw.action_resume_odmr.setChecked(True)
                self._mw.action_toggle_cw.setChecked(False)
            else:
                self._mw.clear_odmr_PushButton.setEnabled(False)
                self._mw.action_run_stop.setEnabled(False)
                self._mw.action_toggle_cw.setEnabled(True)
                self._mw.start_freq_DoubleSpinBox.setEnabled(True)
                self._mw.step_freq_DoubleSpinBox.setEnabled(True)
                self._mw.stop_freq_DoubleSpinBox.setEnabled(True)
                self._mw.sweep_power_DoubleSpinBox.setEnabled(True)
                self._mw.runtime_DoubleSpinBox.setEnabled(True)
                self._sd.clock_frequency_DoubleSpinBox.setEnabled(True)
                self._mw.action_run_stop.setChecked(False)
                self._mw.action_resume_odmr.setChecked(False)
                self._mw.action_toggle_cw.setChecked(True)
        else:
            self._mw.action_resume_odmr.setEnabled(True)
            self._mw.cw_power_DoubleSpinBox.setEnabled(True)
            self._mw.sweep_power_DoubleSpinBox.setEnabled(True)
            self._mw.cw_frequency_DoubleSpinBox.setEnabled(True)
            self._mw.clear_odmr_PushButton.setEnabled(False)
            self._mw.action_run_stop.setEnabled(True)
            self._mw.action_toggle_cw.setEnabled(True)
            self._mw.start_freq_DoubleSpinBox.setEnabled(True)
            self._mw.step_freq_DoubleSpinBox.setEnabled(True)
            self._mw.stop_freq_DoubleSpinBox.setEnabled(True)
            self._mw.runtime_DoubleSpinBox.setEnabled(True)
            self._sd.clock_frequency_DoubleSpinBox.setEnabled(True)
            self._mw.action_run_stop.setChecked(False)
            self._mw.action_resume_odmr.setChecked(False)
            self._mw.action_toggle_cw.setChecked(False)

        # Unblock signal firing
        self._mw.action_run_stop.blockSignals(False)
        self._mw.action_resume_odmr.blockSignals(False)
        self._mw.action_toggle_cw.blockSignals(False)
        return

    def clear_odmr_data(self):
        """ Clear the ODMR data. """
        self.sigClearData.emit()
        return

    def update_plots(self, odmr_data_x, odmr_data_y, odmr_matrix):
        """ Refresh the plot widgets with new data. """
        # Update mean signal plot
        self.odmr_image.setData(odmr_data_x, odmr_data_y)
        # Update raw data matrix plot
        cb_range = self.get_matrix_cb_range()
        self.update_colorbar(cb_range)
        self.odmr_matrix_image.setRect(QtCore.QRectF(odmr_data_x[0],
                                                     0,
                                                     np.abs(odmr_data_x[-1] - odmr_data_x[0]),
                                                     odmr_matrix.shape[0]))
        self.odmr_matrix_image.setImage(image=odmr_matrix.transpose(),
                                        levels=(cb_range[0], cb_range[1]))

        return

    def colorscale_changed(self):
        """
        Updates the range of the displayed colorscale in both the colorbar and the matrix plot.
        """
        cb_range = self.get_matrix_cb_range()
        self.update_colorbar(cb_range)
        matrix_image = self.odmr_matrix_image.image
        self.odmr_matrix_image.setImage(image=matrix_image, levels=(cb_range[0], cb_range[1]))
        return

    def update_colorbar(self, cb_range):
        """ 
        Update the colorbar to a new range.
        
        @param list cb_range: List or tuple containing the min and max values for the cb range
        """
        self.odmr_cb.refresh_colorbar(cb_range[0], cb_range[1])
        return

    def get_matrix_cb_range(self):
        """ 
        Determines the cb_min and cb_max values for the matrix plot
        """
        matrix_image = self.odmr_matrix_image.image

        # If "Manual" is checked or the image is empty (all zeros), then take manual cb range.
        # Otherwise, calculate cb range from percentiles.
        if self._mw.odmr_cb_manual_RadioButton.isChecked() or np.max(matrix_image) < 0.1:
            cb_min = self._mw.odmr_cb_min_DoubleSpinBox.value()
            cb_max = self._mw.odmr_cb_max_DoubleSpinBox.value()
        else:
            # Exclude any zeros (which are typically due to unfinished scan)
            matrix_image_nonzero = matrix_image[np.nonzero(matrix_image)]

            # Read centile range
            low_centile = self._mw.odmr_cb_low_percentile_DoubleSpinBox.value()
            high_centile = self._mw.odmr_cb_high_percentile_DoubleSpinBox.value()

            cb_min = np.percentile(matrix_image_nonzero, low_centile)
            cb_max = np.percentile(matrix_image_nonzero, high_centile)

        cb_range = [cb_min, cb_max]
        return cb_range

    def restore_defaultview(self):
        self._mw.restoreGeometry(self.mwsettings.value("geometry", ""))
        self._mw.restoreState(self.mwsettings.value("windowState", ""))

    def update_elapsedtime(self, elapsed_time, scanned_lines):
        """ Updates current elapsed measurement time and completed frequency sweeps """
        self._mw.elapsed_time_DisplayWidget.display(int(np.rint(elapsed_time)))
        self._mw.elapsed_sweeps_DisplayWidget.display(scanned_lines)
        return

    def update_settings(self):
        """ Write the new settings from the gui to the file. """
        number_of_lines = self._sd.matrix_lines_SpinBox.value()
        clock_frequency = self._sd.clock_frequency_DoubleSpinBox.value()
        self.sigClockFreqChanged.emit(clock_frequency)
        self.sigNumberOfLinesChanged.emit(number_of_lines)
        return

    def reject_settings(self):
        """ Keep the old settings and restores the old settings in the gui. """
        self._sd.matrix_lines_SpinBox.setValue(self._odmr_logic.number_of_lines)
        self._sd.clock_frequency_DoubleSpinBox.setValue(self._odmr_logic.clock_frequency)
        return

    def do_fit(self):
        fit_function  = self._mw.fit_methods_ComboBox.getCurrentFit()[0]
        self.sigDoFit.emit(fit_function)
        return

    def update_fit(self, x_data, y_data, result_str_dict, current_fit):
        """ Update the shown fit. """
        if current_fit != 'No Fit':
            # display results as formatted text
            self._mw.odmr_fit_results_DisplayWidget.clear()
            try:
                formated_results = units.create_formatted_output(result_str_dict)
            except:
                formated_results = 'this fit does not return formatted results'
            self._mw.odmr_fit_results_DisplayWidget.setPlainText(formated_results)

        self._mw.fit_methods_ComboBox.blockSignals(True)
        self._mw.fit_methods_ComboBox.setCurrentFit(current_fit)
        self._mw.fit_methods_ComboBox.blockSignals(False)

        # check which Fit method is used and remove or add again the
        # odmr_fit_image, check also whether a odmr_fit_image already exists.
        if current_fit != 'No Fit':
            self.odmr_fit_image.setData(x=x_data, y=y_data)
            if self.odmr_fit_image not in self._mw.odmr_PlotWidget.listDataItems():
                self._mw.odmr_PlotWidget.addItem(self.odmr_fit_image)
        else:
            if self.odmr_fit_image in self._mw.odmr_PlotWidget.listDataItems():
                self._mw.odmr_PlotWidget.removeItem(self.odmr_fit_image)

        self._mw.odmr_PlotWidget.getViewBox().updateAutoRange()
        return

    def update_parameter(self, param_dict):
        """ Update the parameter display in the GUI.

        @param param_dict:
        @return:

        Any change event from the logic should call this update function.
        The update will block the GUI signals from emitting a change back to the
        logic.
        """
        param = param_dict.get('mw_power')
        if param is not None:
            self._mw.power_DoubleSpinBox.blockSignals(True)
            self._mw.power_DoubleSpinBox.setValue(param)
            self._mw.power_DoubleSpinBox.blockSignals(False)

        param = param_dict.get('mw_frequency')
        if param is not None:
            self._mw.frequency_DoubleSpinBox.blockSignals(True)
            self._mw.frequency_DoubleSpinBox.setValue(param)
            self._mw.frequency_DoubleSpinBox.blockSignals(False)

        param = param_dict.get('mw_start')
        if param is not None:
            self._mw.start_freq_DoubleSpinBox.blockSignals(True)
            self._mw.start_freq_DoubleSpinBox.setValue(param)
            self._mw.start_freq_DoubleSpinBox.blockSignals(False)

        param = param_dict.get('mw_step')
        if param is not None:
            self._mw.step_freq_DoubleSpinBox.blockSignals(True)
            self._mw.step_freq_DoubleSpinBox.setValue(param)
            self._mw.step_freq_DoubleSpinBox.blockSignals(False)

        param = param_dict.get('mw_stop')
        if param is not None:
            self._mw.stop_freq_DoubleSpinBox.blockSignals(True)
            self._mw.stop_freq_DoubleSpinBox.setValue(param)
            self._mw.stop_freq_DoubleSpinBox.blockSignals(False)

        param = param_dict.get('run_time')
        if param is not None:
            self._mw.runtime_DoubleSpinBox.blockSignals(True)
            self._mw.runtime_DoubleSpinBox.setValue(param)
            self._mw.runtime_DoubleSpinBox.blockSignals(False)

        param = param_dict.get('number_of_lines')
        if param is not None:
            self._sd.matrix_lines_SpinBox.blockSignals(True)
            self._sd.matrix_lines_SpinBox.setValue(param)
            self._sd.matrix_lines_SpinBox.blockSignals(False)

        param = param_dict.get('clock_frequency')
        if param is not None:
            self._sd.clock_frequency_DoubleSpinBox.blockSignals(True)
            self._sd.clock_frequency_DoubleSpinBox.setValue(param)
            self._sd.clock_frequency_DoubleSpinBox.blockSignals(False)
        return

    ############################################################################
    #                           Change Methods                                 #
    ############################################################################

    def change_cw_params(self):
        """ Change CW frequency and power of microwave source """
        frequency = self._mw.cw_frequency_DoubleSpinBox.value()
        power = self._mw.cw_power_DoubleSpinBox.value()
        self.sigMwCwParamsChanged.emit(frequency, power)
        return

    def change_sweep_params(self):
        """ Change start, stop and step frequency of frequency sweep """
        start = self._mw.start_freq_DoubleSpinBox.value()
        stop = self._mw.stop_freq_DoubleSpinBox.value()
        step = self._mw.step_freq_DoubleSpinBox.value()
        power = self._mw.sweep_power_DoubleSpinBox.value()
        self.sigMwSweepParamsChanged.emit(start, stop, step, power)
        return

    def change_runtime(self):
        """ Change time after which microwave sweep is stopped """
        runtime = self._mw.runtime_DoubleSpinBox.value()
        self.sigRuntimeChanged.emit(runtime)
        return

    def save_data(self):
        """ Save the sum plot, the scan marix plot and the scan data """
        filetag = self._mw.save_tag_LineEdit.text()
        cb_range = self.get_matrix_cb_range()

        # Percentile range is None, unless the percentile scaling is selected in GUI.
        pcile_range = None
        if self._mw.odmr_cb_centiles_RadioButton.isChecked():
            low_centile = self._mw.odmr_cb_low_percentile_DoubleSpinBox.value()
            high_centile = self._mw.odmr_cb_high_percentile_DoubleSpinBox.value()
            pcile_range = [low_centile, high_centile]

        self.sigSaveMeasurement.emit(filetag, cb_range, pcile_range)
        return
Exemplo n.º 22
0
    def initMainUI(self):
        """ Definition, configuration and initialisation of the POI Manager GUI.
        This init connects all the graphic modules, which were created in the
        *.ui file and configures the event handling between the modules.
        """

        # Use the inherited class 'Ui_PoiManagerGuiTemplate' to create now the
        # GUI element:
        self._mw = PoiManagerMainWindow()

        #####################
        # Configuring the dock widgets
        #####################

        # All our gui elements are dockable, and so there should be no "central" widget.
        self._mw.centralwidget.hide()
        self._mw.setDockNestingEnabled(True)

        self._mw.roi_cb_high_percentile_DoubleSpinBox.setOpts(step=0.01, decimals=5)
        self._mw.roi_cb_low_percentile_DoubleSpinBox.setOpts(step=0.01, decimals=2)
        #####################
        # Setting up display of ROI map xy image
        #####################

        # Get the image for the display from the logic:
        self.roi_xy_image_data = self._poi_manager_logic.roi_map_data[:, :, 3]

        # Load the image in the display:
        self.roi_map_image = pg.ImageItem(image=self.roi_xy_image_data, axisOrder='row-major')
        self.roi_map_image.setRect(
            QtCore.QRectF(
                self._confocal_logic.image_x_range[0],
                self._confocal_logic.image_y_range[0],
                self._confocal_logic.image_x_range[1] - self._confocal_logic.image_x_range[0],
                self._confocal_logic.image_y_range[1] - self._confocal_logic.image_y_range[0]))

        # Add the display item to the roi map ViewWidget defined in the UI file
        self._mw.roi_map_ViewWidget.addItem(self.roi_map_image)
        self._mw.roi_map_ViewWidget.setLabel('bottom', 'X position', units='m')
        self._mw.roi_map_ViewWidget.setLabel('left', 'Y position', units='m')

        # Set to fixed 1.0 aspect ratio, since the metaphor is a "map" of the sample
        self._mw.roi_map_ViewWidget.setAspectLocked(lock=True, ratio=1.0)

        # Get the colorscales and set LUT
        my_colors = ColorScaleInferno()

        self.roi_map_image.setLookupTable(my_colors.lut)

        # Add color bar:
        self.roi_cb = ColorBar(my_colors.cmap_normed, 100, 0, 100000)

        self._mw.roi_cb_ViewWidget.addItem(self.roi_cb)
        self._mw.roi_cb_ViewWidget.hideAxis('bottom')
        self._mw.roi_cb_ViewWidget.setLabel('left', 'Fluorescence', units='c/s')
        self._mw.roi_cb_ViewWidget.setMouseEnabled(x=False, y=False)

        #####################
        # Setting up display of sample shift plot
        #####################

        # Load image in the display
        self.x_shift_plot = pg.PlotDataItem(
            [0],
            [0],
            pen=pg.mkPen(palette.c1, style=QtCore.Qt.DotLine),
            symbol='o',
            symbolPen=palette.c1,
            symbolBrush=palette.c1,
            symbolSize=5,
            name='x'
            )
        self.y_shift_plot = pg.PlotDataItem(
            [0],
            [0],
            pen=pg.mkPen(palette.c2, style=QtCore.Qt.DotLine),
            symbol='s',
            symbolPen=palette.c2,
            symbolBrush=palette.c2,
            symbolSize=5,
            name='y'
            )
        self.z_shift_plot = pg.PlotDataItem(
            [0],
            [0],
            pen=pg.mkPen(palette.c3, style=QtCore.Qt.DotLine),
            symbol='t',
            symbolPen=palette.c3,
            symbolBrush=palette.c3,
            symbolSize=5,
            name='z'
            )

        self._mw.sample_shift_ViewWidget.addLegend()

        # Add the plot to the ViewWidget defined in the UI file
        self._mw.sample_shift_ViewWidget.addItem(self.x_shift_plot)
        self._mw.sample_shift_ViewWidget.addItem(self.y_shift_plot)
        self._mw.sample_shift_ViewWidget.addItem(self.z_shift_plot)

        # Label axes
        self._mw.sample_shift_ViewWidget.setLabel('bottom', 'Time', units='s')
        self._mw.sample_shift_ViewWidget.setLabel('left', 'Sample shift', units='m')

        #####################
        # Connect signals
        #####################

        # Distance Measurement:
        # Introducing a SignalProxy will limit the rate of signals that get fired.
        # Otherwise we will run into a heap of unhandled function calls.
        proxy = pg.SignalProxy(self.roi_map_image.scene().sigMouseMoved, rateLimit=60, slot=self.mouseMoved)
        # Connecting a Mouse Signal to trace to mouse movement function.
        self.roi_map_image.scene().sigMouseMoved.connect(self.mouseMoved)

        # Toolbar actions
        self._mw.new_roi_Action.triggered.connect(self.make_new_roi)
        self._mw.save_roi_Action.triggered.connect(self.save_roi)
        self._mw.load_roi_Action.triggered.connect(self.load_roi)
        self._mw.reorient_roi_Action.triggered.connect(self.open_reorient_roi_dialog)
        self._mw.autofind_pois_Action.triggered.connect(self.do_autofind_poi_procedure)
        self._mw.optimize_roi_Action.triggered.connect(self.optimize_roi)


        self._mw.new_poi_Action.triggered.connect(self.set_new_poi)
        self._mw.goto_poi_Action.triggered.connect(self.goto_poi)
        self._mw.refind_poi_Action.triggered.connect(self.update_poi_pos)
        self._mw.track_poi_Action.triggered.connect(self.toggle_tracking)

        # Interface controls
        self._mw.get_confocal_image_PushButton.clicked.connect(self.get_confocal_image)
        self._mw.set_poi_PushButton.clicked.connect(self.set_new_poi)
        self._mw.delete_last_pos_Button.clicked.connect(self.delete_last_point)
        self._mw.manual_update_poi_PushButton.clicked.connect(self.manual_update_poi)
        self._mw.move_poi_PushButton.clicked.connect(self.move_poi)
        self._mw.poi_name_LineEdit.returnPressed.connect(self.change_poi_name)
        self._mw.roi_name_LineEdit.editingFinished.connect(self.set_roi_name)
        self._mw.delete_poi_PushButton.clicked.connect(self.delete_poi)

        self._mw.goto_poi_after_update_checkBox.toggled.connect(self.toggle_follow)


        # This needs to be activated so that it only listens to user input, and ignores
        # algorithmic index changes
        self._mw.active_poi_ComboBox.activated.connect(self.handle_active_poi_ComboBox_index_change)
        self._mw.refind_method_ComboBox.currentIndexChanged.connect(self.change_refind_method)

        # Connect the buttons and inputs for the colorbar
        self._mw.roi_cb_centiles_RadioButton.toggled.connect(self.refresh_roi_colorscale)
        self._mw.roi_cb_manual_RadioButton.toggled.connect(self.refresh_roi_colorscale)
        self._mw.roi_cb_min_SpinBox.valueChanged.connect(self.shortcut_to_roi_cb_manual)
        self._mw.roi_cb_max_SpinBox.valueChanged.connect(self.shortcut_to_roi_cb_manual)
        self._mw.roi_cb_low_percentile_DoubleSpinBox.valueChanged.connect(self.shortcut_to_roi_cb_centiles)
        self._mw.roi_cb_high_percentile_DoubleSpinBox.valueChanged.connect(self.shortcut_to_roi_cb_centiles)

        self._mw.display_shift_vs_duration_RadioButton.toggled.connect(self._redraw_sample_shift)
        self._mw.display_shift_vs_clocktime_RadioButton.toggled.connect(self._redraw_sample_shift)

        self._markers = dict()

        # Signal at end of refocus
        self._poi_manager_logic.signal_timer_updated.connect(
            self._update_timer,
            QtCore.Qt.QueuedConnection
        )
        self._poi_manager_logic.signal_poi_updated.connect(
            self._redraw_sample_shift,
            QtCore.Qt.QueuedConnection
        )
        self._poi_manager_logic.signal_poi_updated.connect(
            self.populate_poi_list,
            QtCore.Qt.QueuedConnection
        )
        self._poi_manager_logic.signal_poi_updated.connect(
            self._redraw_poi_markers,
            QtCore.Qt.QueuedConnection
        )
        self._poi_manager_logic.signal_poi_deleted.connect(
            self._remove_poi_marker
        )
        self._poi_manager_logic.signal_confocal_image_updated.connect(
            self._redraw_roi_image
        )

        self._poi_manager_logic.signal_periodic_opt_duration_changed.connect(
            self._track_period_changed
        )
        self._poi_manager_logic.signal_periodic_opt_started.connect(
            self._tracking_started
        )
        self._poi_manager_logic.signal_periodic_opt_stopped.connect(
            self._tracking_stopped
        )

        # Connect track period after setting the GUI value from the logic
        initial_period = self._poi_manager_logic.timer_duration
        self._mw.track_period_SpinBox.setValue(initial_period)
        self._mw.time_till_next_update_ProgressBar.setMaximum(initial_period)
        self._mw.time_till_next_update_ProgressBar.setValue(initial_period)
        self._mw.track_period_SpinBox.valueChanged.connect(self.set_track_period)

        # Redraw the sample_shift axes if the range changes
        self._mw.sample_shift_ViewWidget.plotItem.sigRangeChanged.connect(self._redraw_sample_shift)

        self._mw.show()
Exemplo n.º 23
0
    def on_activate(self):
        """ Initializes all needed UI files and establishes the connectors.
        """

        self._logic = self.camera_logic()
        self._save_logic = self.savelogic()

        # Windows
        self._mw = CameraWindow()
        self._mw.centralwidget.hide()
        self._mw.setDockNestingEnabled(True)
        self.initSettingsUI()

        self._mw.start_video_Action.setEnabled(True)
        self._mw.start_video_Action.setChecked(self._logic.enabled)
        self._mw.start_video_Action.triggered.connect(self.start_video_clicked)

        self._mw.start_image_Action.setEnabled(True)
        self._mw.start_image_Action.setChecked(self._logic.enabled)
        self._mw.start_image_Action.triggered.connect(self.start_image_clicked)

        self._logic.sigUpdateDisplay.connect(self.update_data)
        self._logic.sigAcquisitionFinished.connect(self.acquisition_finished)
        self._logic.sigVideoFinished.connect(self.enable_start_image_action)

        # starting the physical measurement
        self.sigVideoStart.connect(self._logic.start_loop)
        self.sigVideoStop.connect(self._logic.stop_loop)
        self.sigImageStart.connect(self._logic.start_single_acquistion)

        # connect Settings action under Options menu
        self._mw.actionSettings.triggered.connect(self.menu_settings)
        # connect save action to save function
        self._mw.actionSave_XY_Scan.triggered.connect(self.save_xy_scan_data)

        raw_data_image = self._logic.get_last_image()
        self._image = pg.ImageItem(image=raw_data_image, axisOrder='row-major')
        self._mw.image_PlotWidget.addItem(self._image)
        self._mw.image_PlotWidget.setAspectLocked(True)

        # Get the colorscale and set the LUTs
        self.my_colors = ColorScaleInferno()

        self._image.setLookupTable(self.my_colors.lut)

        # Connect the buttons and inputs for the colorbar
        self._mw.xy_cb_manual_RadioButton.clicked.connect(self.update_xy_cb_range)
        self._mw.xy_cb_centiles_RadioButton.clicked.connect(self.update_xy_cb_range)

        self._mw.xy_cb_min_DoubleSpinBox.valueChanged.connect(self.shortcut_to_xy_cb_manual)
        self._mw.xy_cb_max_DoubleSpinBox.valueChanged.connect(self.shortcut_to_xy_cb_manual)
        self._mw.xy_cb_low_percentile_DoubleSpinBox.valueChanged.connect(self.shortcut_to_xy_cb_centiles)
        self._mw.xy_cb_high_percentile_DoubleSpinBox.valueChanged.connect(self.shortcut_to_xy_cb_centiles)

        # create color bar
        self.xy_cb = ColorBar(self.my_colors.cmap_normed, width=100, cb_min=0, cb_max=100)
        self.depth_cb = ColorBar(self.my_colors.cmap_normed, width=100, cb_min=0, cb_max=100)
        self._mw.xy_cb_ViewWidget.addItem(self.xy_cb)
        self._mw.xy_cb_ViewWidget.hideAxis('bottom')
        self._mw.xy_cb_ViewWidget.setLabel('left', 'Fluorescence', units='c')
        self._mw.xy_cb_ViewWidget.setMouseEnabled(x=False, y=False)
Exemplo n.º 24
0
class VoltScanGui(GUIBase):
    """

    """
    _modclass = 'VoltScanGui'
    _modtype = 'gui'
    
    ## declare connectors
    voltagescannerlogic1 = Connector(interface='VoltageScannerLogic')
    savelogic = Connector(interface='SaveLogic')

    sigStartScan = QtCore.Signal()
    sigStopScan = QtCore.Signal()
    sigChangeVoltage = QtCore.Signal(float)
    sigChangeRange = QtCore.Signal(list)
    sigChangeResolution = QtCore.Signal(float)
    sigChangeSpeed = QtCore.Signal(float)
    sigChangeLines = QtCore.Signal(int)
    sigSaveMeasurement = QtCore.Signal(str, list, list)

    def on_deactivate(self):
        """ Reverse steps of activation

        @return int: error code (0:OK, -1:error)
        """
        self._mw.close()
        return 0

    def on_activate(self):
        """ 

        """
        self._voltscan_logic = self.get_connector('voltagescannerlogic1')
        self._savelogic = self.get_connector('savelogic')

        # Use the inherited class 'Ui_VoltagescannerGuiUI' to create now the
        # GUI element:
        self._mw = VoltScanMainWindow()

        # Add save file tag input box
        self._mw.save_tag_LineEdit = QtWidgets.QLineEdit(self._mw)
        self._mw.save_tag_LineEdit.setMaximumWidth(500)
        self._mw.save_tag_LineEdit.setMinimumWidth(200)
        self._mw.save_tag_LineEdit.setToolTip('Enter a nametag which will be\n'
                                              'added to the filename.')
        self._mw.toolBar.addWidget(self._mw.save_tag_LineEdit)

        # Get the image from the logic
        self.scan_matrix_image = pg.ImageItem(
            self._voltscan_logic.scan_matrix,
            axisOrder='row-major')

        self.scan_matrix_image.setRect(
            QtCore.QRectF(
                self._voltscan_logic.scan_range[0],
                0,
                self._voltscan_logic.scan_range[1] - self._voltscan_logic.scan_range[0],
                self._voltscan_logic.number_of_repeats)
        )

        self.scan_matrix_image2 = pg.ImageItem(
            self._voltscan_logic.scan_matrix2,
            axisOrder='row-major')

        self.scan_matrix_image2.setRect(
            QtCore.QRectF(
                self._voltscan_logic.scan_range[0],
                0,
                self._voltscan_logic.scan_range[1] - self._voltscan_logic.scan_range[0],
                self._voltscan_logic.number_of_repeats)
        )

        self.scan_image = pg.PlotDataItem(
            self._voltscan_logic.plot_x,
            self._voltscan_logic.plot_y)

        self.scan_image2 = pg.PlotDataItem(
            self._voltscan_logic.plot_x,
            self._voltscan_logic.plot_y2)

        self.scan_fit_image = pg.PlotDataItem(
            self._voltscan_logic.fit_x,
            self._voltscan_logic.fit_y,
            pen=QtGui.QPen(QtGui.QColor(255, 255, 255, 255)))

        # Add the display item to the xy and xz VieWidget, which was defined in
        # the UI file.
        self._mw.voltscan_ViewWidget.addItem(self.scan_image)
        #self._mw.voltscan_ViewWidget.addItem(self.scan_fit_image)
        self._mw.voltscan_ViewWidget.showGrid(x=True, y=True, alpha=0.8)
        self._mw.voltscan_matrix_ViewWidget.addItem(self.scan_matrix_image)

        self._mw.voltscan2_ViewWidget.addItem(self.scan_image2)
        #self._mw.voltscan2_ViewWidget.addItem(self.scan_fit_image)
        self._mw.voltscan2_ViewWidget.showGrid(x=True, y=True, alpha=0.8)
        self._mw.voltscan_matrix2_ViewWidget.addItem(self.scan_matrix_image2)

        # Get the colorscales at set LUT
        my_colors = ColorScaleInferno()

        self.scan_matrix_image.setLookupTable(my_colors.lut)
        self.scan_matrix_image2.setLookupTable(my_colors.lut)

        # Configuration of the Colorbar
        self.scan_cb = ColorBar(my_colors.cmap_normed, 100, 0, 100000)

        #adding colorbar to ViewWidget
        self._mw.voltscan_cb_ViewWidget.addItem(self.scan_cb)
        self._mw.voltscan_cb_ViewWidget.hideAxis('bottom')
        self._mw.voltscan_cb_ViewWidget.hideAxis('left')
        self._mw.voltscan_cb_ViewWidget.setLabel('right', 'Fluorescence', units='c/s')

        # Connect the buttons and inputs for colorbar
        self._mw.voltscan_cb_manual_RadioButton.clicked.connect(self.refresh_matrix)
        self._mw.voltscan_cb_centiles_RadioButton.clicked.connect(self.refresh_matrix)

        # set initial values
        self._mw.startDoubleSpinBox.setValue(self._voltscan_logic.scan_range[0])
        self._mw.speedDoubleSpinBox.setValue(self._voltscan_logic._scan_speed)
        self._mw.stopDoubleSpinBox.setValue(self._voltscan_logic.scan_range[1])
        self._mw.constDoubleSpinBox.setValue(self._voltscan_logic._static_v)
        self._mw.resolutionSpinBox.setValue(self._voltscan_logic.resolution)
        self._mw.linesSpinBox.setValue(self._voltscan_logic.number_of_repeats)

        # Update the inputed/displayed numbers if the cursor has left the field:
        self._mw.startDoubleSpinBox.editingFinished.connect(self.change_start_volt)
        self._mw.speedDoubleSpinBox.editingFinished.connect(self.change_speed)
        self._mw.stopDoubleSpinBox.editingFinished.connect(self.change_stop_volt)
        self._mw.resolutionSpinBox.editingFinished.connect(self.change_resolution)
        self._mw.linesSpinBox.editingFinished.connect(self.change_lines)
        self._mw.constDoubleSpinBox.editingFinished.connect(self.change_voltage)

        #
        self._mw.voltscan_cb_max_InputWidget.valueChanged.connect(self.refresh_matrix)
        self._mw.voltscan_cb_min_InputWidget.valueChanged.connect(self.refresh_matrix)
        self._mw.voltscan_cb_high_centile_InputWidget.valueChanged.connect(self.refresh_matrix)
        self._mw.voltscan_cb_low_centile_InputWidget.valueChanged.connect(self.refresh_matrix)

        # Connect signals
        self._voltscan_logic.sigUpdatePlots.connect(self.refresh_matrix)
        self._voltscan_logic.sigUpdatePlots.connect(self.refresh_plot)
        self._voltscan_logic.sigUpdatePlots.connect(self.refresh_lines)
        self._voltscan_logic.sigScanFinished.connect(self.scan_stopped)
        self._voltscan_logic.sigScanStarted.connect(self.scan_started)

        self.sigStartScan.connect(self._voltscan_logic.start_scanning)
        self.sigStopScan.connect(self._voltscan_logic.stop_scanning)
        self.sigChangeVoltage.connect(self._voltscan_logic.set_voltage)
        self.sigChangeRange.connect(self._voltscan_logic.set_scan_range)
        self.sigChangeSpeed.connect(self._voltscan_logic.set_scan_speed)
        self.sigChangeLines.connect(self._voltscan_logic.set_scan_lines)
        self.sigChangeResolution.connect(self._voltscan_logic.set_resolution)
        self.sigSaveMeasurement.connect(self._voltscan_logic.save_data)

        self._mw.action_run_stop.triggered.connect(self.run_stop)
        self._mw.action_Save.triggered.connect(self.save_data)
        self._mw.show()

    def show(self):
        """Make window visible and put it above all other windows. """
        self._mw.show()
        self._mw.activateWindow()
        self._mw.raise_()

    def run_stop(self, is_checked):
        """ Manages what happens if scan is started/stopped """
        self._mw.action_run_stop.setEnabled(False)
        if is_checked:
            self.sigStartScan.emit()
            self._mw.voltscan_ViewWidget.removeItem(self.scan_fit_image)
            self._mw.voltscan2_ViewWidget.removeItem(self.scan_fit_image)
        else:
            self.sigStopScan.emit()

    def scan_started(self):
        self._mw.action_run_stop.setEnabled(True)

    def scan_stopped(self):
        self._mw.action_run_stop.setEnabled(True)
        self._mw.action_run_stop.setChecked(False)
        self.refresh_plot()
        self.refresh_matrix()
        self.refresh_lines()

    def refresh_plot(self):
        """ Refresh the xy-plot image """
        self.scan_image.setData(self._voltscan_logic.plot_x, self._voltscan_logic.plot_y)
        self.scan_image2.setData(self._voltscan_logic.plot_x, self._voltscan_logic.plot_y2)

    def refresh_matrix(self):
        """ Refresh the xy-matrix image """
        self.scan_matrix_image.setImage(self._voltscan_logic.scan_matrix, axisOrder='row-major')
        self.scan_matrix_image.setRect(
            QtCore.QRectF(
                self._voltscan_logic.scan_range[0],
                0,
                self._voltscan_logic.scan_range[1] - self._voltscan_logic.scan_range[0],
                self._voltscan_logic.number_of_repeats)
            )
        self.scan_matrix_image2.setImage(self._voltscan_logic.scan_matrix2, axisOrder='row-major')
        self.scan_matrix_image2.setRect(
            QtCore.QRectF(
                self._voltscan_logic.scan_range[0],
                0,
                self._voltscan_logic.scan_range[1] - self._voltscan_logic.scan_range[0],
                self._voltscan_logic.number_of_repeats)
        )
        self.refresh_scan_colorbar()

        scan_image_data = self._voltscan_logic.scan_matrix

        # If "Centiles" is checked, adjust colour scaling automatically to centiles.
        # Otherwise, take user-defined values.
        if self._mw.voltscan_cb_centiles_RadioButton.isChecked():
            low_centile = self._mw.voltscan_cb_low_centile_InputWidget.value()
            high_centile = self._mw.voltscan_cb_high_centile_InputWidget.value()

            cb_min = np.percentile(scan_image_data, low_centile)
            cb_max = np.percentile(scan_image_data, high_centile)
        else:
            cb_min = self._mw.voltscan_cb_min_InputWidget.value()
            cb_max = self._mw.voltscan_cb_max_InputWidget.value()

        # Now update image with new color scale, and update colorbar
        self.scan_matrix_image.setImage(
            image=scan_image_data,
            levels=(cb_min, cb_max),
            axisOrder='row-major')

        scan_image_data2 = self._voltscan_logic.scan_matrix2
        # Now update image with new color scale, and update colorbar
        self.scan_matrix_image2.setImage(
            image=scan_image_data2,
            levels=(cb_min, cb_max),
            axisOrder='row-major')

        self.refresh_scan_colorbar()

    def refresh_scan_colorbar(self):
        """ Update the colorbar to a new scaling."""

        # If "Centiles" is checked, adjust colour scaling automatically to centiles.
        # Otherwise, take user-defined values.
        if self._mw.voltscan_cb_centiles_RadioButton.isChecked():
            low_centile = self._mw.voltscan_cb_low_centile_InputWidget.value()
            high_centile = self._mw.voltscan_cb_high_centile_InputWidget.value()

            cb_min = np.percentile(self.scan_matrix_image.image, low_centile)
            cb_max = np.percentile(self.scan_matrix_image.image, high_centile)
        else:
            cb_min = self._mw.voltscan_cb_min_InputWidget.value()
            cb_max = self._mw.voltscan_cb_max_InputWidget.value()

        self.scan_cb.refresh_colorbar(cb_min, cb_max)
        self._mw.voltscan_cb_ViewWidget.update()

    def refresh_lines(self):
        self._mw.elapsed_lines_DisplayWidget.display(self._voltscan_logic._scan_counter_up)

    def change_voltage(self):
        self.sigChangeVoltage.emit(self._mw.constDoubleSpinBox.value())

    def change_start_volt(self):
        self.sigChangeRange.emit([
            self._mw.startDoubleSpinBox.value(),
            self._mw.stopDoubleSpinBox.value()
        ])

    def change_speed(self):
        self.sigChangeSpeed.emit(self._mw.speedDoubleSpinBox.value())

    def change_stop_volt(self):
        self.sigChangeRange.emit([
            self._mw.startDoubleSpinBox.value(),
            self._mw.stopDoubleSpinBox.value()
        ])

    def change_lines(self):
        self.sigChangeLines.emit(self._mw.linesSpinBox.value())

    def change_resolution(self):
        self.sigChangeResolution.emit(self._mw.resolutionSpinBox.value())

    def get_matrix_cb_range(self):
        """
        Determines the cb_min and cb_max values for the matrix plot
        """
        matrix_image = self.scan_matrix_image.image

        # If "Manual" is checked or the image is empty (all zeros), then take manual cb range.
        # Otherwise, calculate cb range from percentiles.
        if self._mw.voltscan_cb_manual_RadioButton.isChecked() or np.max(matrix_image) < 0.1:
            cb_min = self._mw.voltscan_cb_min_InputWidget.value()
            cb_max = self._mw.voltscan_cb_max_InputWidget.value()
        else:
            # Exclude any zeros (which are typically due to unfinished scan)
            matrix_image_nonzero = matrix_image[np.nonzero(matrix_image)]

            # Read centile range
            low_centile = self._mw.voltscan_cb_low_centile_InputWidget.value()
            high_centile = self._mw.voltscan_cb_high_centile_InputWidget.value()

            cb_min = np.percentile(matrix_image_nonzero, low_centile)
            cb_max = np.percentile(matrix_image_nonzero, high_centile)

        cb_range = [cb_min, cb_max]
        return cb_range

    def save_data(self):
        """ Save the sum plot, the scan marix plot and the scan data """
        filetag = self._mw.save_tag_LineEdit.text()
        cb_range = self.get_matrix_cb_range()

        # Percentile range is None, unless the percentile scaling is selected in GUI.
        pcile_range = None
        if self._mw.voltscan_cb_centiles_RadioButton.isChecked():
            low_centile = self._mw.voltscan_cb_low_centile_InputWidget.value()
            high_centile = self._mw.voltscan_cb_high_centile_InputWidget.value()
            pcile_range = [low_centile, high_centile]

        self.sigSaveMeasurement.emit(filetag, cb_range, pcile_range)
Exemplo n.º 25
0
    def initMainUI(self):
        """ Definition, configuration and initialisation of the POI Manager GUI.
        This init connects all the graphic modules, which were created in the
        *.ui file and configures the event handling between the modules.
        """

        # Use the inherited class 'Ui_PoiManagerGuiTemplate' to create now the
        # GUI element:
        self._mw = PoiManagerMainWindow()

        #####################
        # Configuring the dock widgets
        #####################

        # All our gui elements are dockable, and so there should be no "central" widget.
        self._mw.centralwidget.hide()
        self._mw.setDockNestingEnabled(True)
        #####################
        # Setting up display of ROI map xy image
        #####################

        # Get the image for the display from the logic:
        self.roi_xy_image_data = self._poi_manager_logic.roi_map_data[:, :, 3]

        # Load the image in the display:
        self.roi_map_image = pg.ImageItem(image=self.roi_xy_image_data,
                                          axisOrder='row-major')
        self.roi_map_image.setRect(
            QtCore.QRectF(
                self._confocal_logic.image_x_range[0],
                self._confocal_logic.image_y_range[0],
                self._confocal_logic.image_x_range[1] -
                self._confocal_logic.image_x_range[0],
                self._confocal_logic.image_y_range[1] -
                self._confocal_logic.image_y_range[0]))

        # Add the display item to the roi map ViewWidget defined in the UI file
        self._mw.roi_map_ViewWidget.addItem(self.roi_map_image)
        self._mw.roi_map_ViewWidget.setLabel('bottom', 'X position', units='m')
        self._mw.roi_map_ViewWidget.setLabel('left', 'Y position', units='m')

        # Set to fixed 1.0 aspect ratio, since the metaphor is a "map" of the sample
        self._mw.roi_map_ViewWidget.setAspectLocked(lock=True, ratio=1.0)

        # Get the colorscales and set LUT
        my_colors = ColorScaleInferno()

        self.roi_map_image.setLookupTable(my_colors.lut)

        # Add color bar:
        self.roi_cb = ColorBar(my_colors.cmap_normed, 100, 0, 100000)

        self._mw.roi_cb_ViewWidget.addItem(self.roi_cb)
        self._mw.roi_cb_ViewWidget.hideAxis('bottom')
        self._mw.roi_cb_ViewWidget.setLabel('left',
                                            'Fluorescence',
                                            units='c/s')
        self._mw.roi_cb_ViewWidget.setMouseEnabled(x=False, y=False)

        #####################
        # Setting up display of sample shift plot
        #####################

        # Load image in the display
        self.x_shift_plot = pg.PlotDataItem([0], [0],
                                            pen=pg.mkPen(
                                                palette.c1,
                                                style=QtCore.Qt.DotLine),
                                            symbol='o',
                                            symbolPen=palette.c1,
                                            symbolBrush=palette.c1,
                                            symbolSize=5,
                                            name='x')
        self.y_shift_plot = pg.PlotDataItem([0], [0],
                                            pen=pg.mkPen(
                                                palette.c2,
                                                style=QtCore.Qt.DotLine),
                                            symbol='s',
                                            symbolPen=palette.c2,
                                            symbolBrush=palette.c2,
                                            symbolSize=5,
                                            name='y')
        self.z_shift_plot = pg.PlotDataItem([0], [0],
                                            pen=pg.mkPen(
                                                palette.c3,
                                                style=QtCore.Qt.DotLine),
                                            symbol='t',
                                            symbolPen=palette.c3,
                                            symbolBrush=palette.c3,
                                            symbolSize=5,
                                            name='z')

        self._mw.sample_shift_ViewWidget.addLegend()

        # Add the plot to the ViewWidget defined in the UI file
        self._mw.sample_shift_ViewWidget.addItem(self.x_shift_plot)
        self._mw.sample_shift_ViewWidget.addItem(self.y_shift_plot)
        self._mw.sample_shift_ViewWidget.addItem(self.z_shift_plot)

        # Label axes
        self._mw.sample_shift_ViewWidget.setLabel('bottom', 'Time', units='s')
        self._mw.sample_shift_ViewWidget.setLabel('left',
                                                  'Sample shift',
                                                  units='m')

        #####################
        # Connect signals
        #####################

        # Distance Measurement:
        # Introducing a SignalProxy will limit the rate of signals that get fired.
        # Otherwise we will run into a heap of unhandled function calls.
        proxy = pg.SignalProxy(self.roi_map_image.scene().sigMouseMoved,
                               rateLimit=60,
                               slot=self.mouseMoved)
        # Connecting a Mouse Signal to trace to mouse movement function.
        self.roi_map_image.scene().sigMouseMoved.connect(self.mouseMoved)

        # Toolbar actions
        self._mw.new_roi_Action.triggered.connect(self.make_new_roi)
        self._mw.save_roi_Action.triggered.connect(self.save_roi)
        self._mw.load_roi_Action.triggered.connect(self.load_roi)
        self._mw.reorient_roi_Action.triggered.connect(
            self.open_reorient_roi_dialog)
        self._mw.autofind_pois_Action.triggered.connect(
            self.do_autofind_poi_procedure)
        self._mw.optimize_roi_Action.triggered.connect(self.optimize_roi)

        self._mw.new_poi_Action.triggered.connect(self.set_new_poi)
        self._mw.goto_poi_Action.triggered.connect(self.goto_poi)
        self._mw.refind_poi_Action.triggered.connect(self.update_poi_pos)
        self._mw.track_poi_Action.triggered.connect(self.toggle_tracking)

        # Interface controls
        self._mw.get_confocal_image_PushButton.clicked.connect(
            self.get_confocal_image)
        self._mw.set_poi_PushButton.clicked.connect(self.set_new_poi)
        self._mw.delete_last_pos_Button.clicked.connect(self.delete_last_point)
        self._mw.manual_update_poi_PushButton.clicked.connect(
            self.manual_update_poi)
        self._mw.move_poi_PushButton.clicked.connect(self.move_poi)
        self._mw.poi_name_LineEdit.returnPressed.connect(self.change_poi_name)
        self._mw.roi_name_LineEdit.editingFinished.connect(self.set_roi_name)
        self._mw.delete_poi_PushButton.clicked.connect(self.delete_poi)

        self._mw.goto_poi_after_update_checkBox.toggled.connect(
            self.toggle_follow)

        # This needs to be activated so that it only listens to user input, and ignores
        # algorithmic index changes
        self._mw.active_poi_ComboBox.activated.connect(
            self.handle_active_poi_ComboBox_index_change)
        self._mw.refind_method_ComboBox.currentIndexChanged.connect(
            self.change_refind_method)

        # Connect the buttons and inputs for the colorbar
        self._mw.roi_cb_centiles_RadioButton.toggled.connect(
            self.refresh_roi_colorscale)
        self._mw.roi_cb_manual_RadioButton.toggled.connect(
            self.refresh_roi_colorscale)
        self._mw.roi_cb_min_SpinBox.valueChanged.connect(
            self.shortcut_to_roi_cb_manual)
        self._mw.roi_cb_max_SpinBox.valueChanged.connect(
            self.shortcut_to_roi_cb_manual)
        self._mw.roi_cb_low_percentile_DoubleSpinBox.valueChanged.connect(
            self.shortcut_to_roi_cb_centiles)
        self._mw.roi_cb_high_percentile_DoubleSpinBox.valueChanged.connect(
            self.shortcut_to_roi_cb_centiles)

        self._mw.display_shift_vs_duration_RadioButton.toggled.connect(
            self._redraw_sample_shift)
        self._mw.display_shift_vs_clocktime_RadioButton.toggled.connect(
            self._redraw_sample_shift)

        self._markers = dict()

        # Signal at end of refocus
        self._poi_manager_logic.signal_timer_updated.connect(
            self._update_timer, QtCore.Qt.QueuedConnection)
        self._poi_manager_logic.signal_poi_updated.connect(
            self._redraw_sample_shift, QtCore.Qt.QueuedConnection)
        self._poi_manager_logic.signal_poi_updated.connect(
            self.populate_poi_list, QtCore.Qt.QueuedConnection)
        self._poi_manager_logic.signal_poi_updated.connect(
            self._redraw_poi_markers, QtCore.Qt.QueuedConnection)
        self._poi_manager_logic.signal_poi_deleted.connect(
            self._remove_poi_marker)
        self._poi_manager_logic.signal_confocal_image_updated.connect(
            self._redraw_roi_image)

        self._poi_manager_logic.signal_periodic_opt_duration_changed.connect(
            self._track_period_changed)
        self._poi_manager_logic.signal_periodic_opt_started.connect(
            self._tracking_started)
        self._poi_manager_logic.signal_periodic_opt_stopped.connect(
            self._tracking_stopped)

        # Connect track period after setting the GUI value from the logic
        initial_period = self._poi_manager_logic.timer_duration
        self._mw.track_period_SpinBox.setValue(initial_period)
        self._mw.time_till_next_update_ProgressBar.setMaximum(initial_period)
        self._mw.time_till_next_update_ProgressBar.setValue(initial_period)
        self._mw.track_period_SpinBox.valueChanged.connect(
            self.set_track_period)

        # Redraw the sample_shift axes if the range changes
        self._mw.sample_shift_ViewWidget.plotItem.sigRangeChanged.connect(
            self._redraw_sample_shift)

        self._mw.show()
Exemplo n.º 26
0
class ColorbarWidget(QtWidgets.QWidget):
    """ Create the widget, based on the corresponding *.ui file."""
    def __init__(self, image_widget, unit='c/s'):
        # Get the path to the *.ui file
        this_dir = os.path.dirname(__file__)
        ui_file = os.path.join(this_dir, 'ui_colorbar.ui')

        # Load it
        super(ColorbarWidget, self).__init__()
        uic.loadUi(ui_file, self)

        self._cb_min = 0
        self._cb_max = 100
        self.unit = unit

        self.init_spin_box()
        self.init_colorbar()

        self.set_image(image_widget)

        self.percentile.clicked.emit()
        self.percentile.setChecked(True)

    def init_spin_box(self):
        """ Initialize all the spinboxes """
        self._min_percentile = ScienDSpinBox()
        self._min_manual = ScienDSpinBox()
        self._max_percentile = ScienDSpinBox()
        self._max_manual = ScienDSpinBox()

        self._min_percentile.setSuffix('%')
        self._min_percentile.setMinimum(0)
        self._min_percentile.setMaximum(100)
        self._min_percentile.setValue(0)

        self._min_manual.setSuffix(self.unit)

        self._max_percentile.setSuffix('%')
        self._max_percentile.setMinimum(0)
        self._max_percentile.setMaximum(100)
        self._max_percentile.setValue(100)

        self._max_manual.setSuffix(self.unit)

        self.min.addWidget(self._min_manual)
        self.min.addWidget(self._min_percentile)
        self.max.addWidget(self._max_percentile)
        self.max.addWidget(self._max_manual)

        self._min_percentile.valueChanged.connect(self.shortcut_to_cb_centiles)
        self._min_manual.valueChanged.connect(self.shortcut_to_cb_manual)
        self._max_percentile.valueChanged.connect(self.shortcut_to_cb_centiles)
        self._max_manual.valueChanged.connect(self.shortcut_to_cb_manual)

        self.manual.clicked.connect(self.update_cb_range)
        self.percentile.clicked.connect(self.update_cb_range)

    def init_colorbar(self):
        """ Create the colorbar """
        self.my_colors = ColorScaleInferno()
        self._color_map = ColorScaleMagma()
        self._cb = ColorBar(self.my_colors.cmap_normed,
                            width=100,
                            cb_min=self._cb_min,
                            cb_max=self._cb_max)
        self.colorbar.addItem(self._cb)
        self.colorbar.hideAxis('bottom')
        self.colorbar.setLabel('left', 'Intensity', units=self.unit)
        self.colorbar.setMouseEnabled(x=False, y=False)

    def set_image(self, image_widget):
        """ Set the image widget associated to the colorbar """
        self._image = image_widget
        self._min_manual.setValue(np.min(self._image.image))
        self._min_percentile.setValue(0)
        self._max_manual.setValue(np.max(self._image.image))
        self._max_percentile.setValue(100)
        self.refresh_colorbar()

    def get_cb_range(self):
        """ Determines the cb_min and cb_max values for the image """
        # If "Manual" is checked, or the image data is empty (all zeros), then take manual cb range.
        if self.manual.isChecked() or np.count_nonzero(self._image.image) < 1:
            cb_min = self._min_manual.value()
            cb_max = self._max_manual.value()

        # Otherwise, calculate cb range from percentiles.
        else:
            # Exclude any zeros (which are typically due to unfinished scan)
            image_nonzero = self._image.image[np.nonzero(self._image.image)]

            # Read centile range
            low_centile = self._min_percentile.value()
            high_centile = self._max_percentile.value()

            cb_min = np.percentile(image_nonzero, low_centile)
            cb_max = np.percentile(image_nonzero, high_centile)

        cb_range = [cb_min, cb_max]

        return cb_range

    def refresh_colorbar(self):
        """ Adjust the colorbar. """
        cb_range = self.get_cb_range()
        self._cb.refresh_colorbar(cb_range[0], cb_range[1])

    def refresh_image(self):
        """ Update the image colors range."""

        image_data = self._image.image
        cb_range = self.get_cb_range()
        self._image.setImage(image=image_data,
                             levels=(cb_range[0], cb_range[1]))
        self.refresh_colorbar()

    def update_cb_range(self):
        """ Redraw colour bar and image."""
        self.refresh_colorbar()
        self.refresh_image()

    def shortcut_to_cb_manual(self):
        """ Someone edited the absolute counts range for the colour bar, better update."""
        self.manual.setChecked(True)
        self.update_cb_range()

    def shortcut_to_cb_centiles(self):
        """Someone edited the centiles range for the colour bar, better update."""
        self.percentile.setChecked(True)
        self.update_cb_range()