class DisplayThread(QtCore.QThread): spectrum_ready = QtCore.Signal(np.ndarray) spectra_ready = QtCore.Signal(list) def __init__(self, parent): super(DisplayThread, self).__init__() self.parent = parent self.single_shot = False self.refresh_rate = 30. def run(self): t0 = time.time() while self.parent.live_button.isChecked() or self.single_shot: read_processed_spectrum = self.parent.spectrometer.read_processed_spectra \ if isinstance(self.parent.spectrometer, Spectrometers) \ else self.parent.spectrometer.read_processed_spectrum spectrum = read_processed_spectrum() if time.time() - t0 < 1. / self.refresh_rate: continue else: t0 = time.time() if type(spectrum) == np.ndarray: self.spectrum_ready.emit(spectrum) elif type(spectrum) == list: self.spectra_ready.emit(spectrum) if self.single_shot: break self.finished.emit()
class CameraPreviewWidget(pg.GraphicsView): """A Qt Widget to display the live feed from a camera.""" update_data_signal = QtCore.Signal(np.ndarray) def __init__(self): super(CameraPreviewWidget, self).__init__() self.image_item = PreviewImageItem() self.view_box = PreviewViewBox(lockAspect=1.0, invertY=True) self.view_box.addItem(self.image_item) self.view_box.setBackgroundColor([128, 128, 128, 255]) self.setCentralWidget(self.view_box) self.crosshair = { 'h_line': pg.InfiniteLine(pos=0, angle=0), 'v_line': pg.InfiniteLine(pos=0, angle=90), } for item in self.crosshair.values(): self.view_box.addItem(item) self._image_shape = () # We want to make sure we always update the data in the GUI thread. # This is done using the signal/slot mechanism self.update_data_signal.connect(self.update_widget, type=QtCore.Qt.QueuedConnection) def update_widget(self, newimage): """Set the image, but do so in the Qt main loop to avoid threading nasties.""" # I've explicitly dealt with the datatype of the source image, to avoid # a bug in the way pyqtgraph interacts with numpy 1.10. This means # scaling the display values will fail for integer data. I've thus # forced floating-point for anything that isn't a u8, and assumed u8 # wants to be displayed raw. You can always use filter_function to # tweak the brightness/contrast. if len(newimage.shape) == 2: newimage = newimage.transpose() elif len(newimage.shape) == 3: newimage = newimage.transpose((1, 0, 2)) if newimage.dtype == "uint8": self.image_item.setImage(newimage, autoLevels=False) else: self.image_item.setImage(newimage.astype(float)) if newimage.shape != self._image_shape: self._image_shape = newimage.shape self.set_crosshair_centre( (newimage.shape[1] / 2.0, newimage.shape[0] / 2.0)) def update_image(self, newimage): """Update the image displayed in the preview widget.""" # NB compared to previous versions, pyqtgraph flips in y, hence the # funny slice on the next line. self.update_data_signal.emit(newimage) def add_legacy_click_callback(self, function): """Add an old-style (coordinates in fractions-of-an-image) callback.""" self.image_item.legacy_click_callback = function def set_crosshair_centre(self, pos): """Move the crosshair to centre on a given pixel coordinate.""" self.crosshair['h_line'].setValue(pos[0]) self.crosshair['v_line'].setValue(pos[1])
class PowerMeterUI(QtWidgets.QWidget, UiTools): update_data_signal = QtCore.Signal(np.ndarray) def __init__(self, pm): super(PowerMeterUI, self).__init__() uic.loadUi(os.path.join(os.path.dirname(__file__), 'power_meter.ui'), self) self.pm = pm self.update_condition = threading.Condition() self.display_thread = DisplayThread(self) self.SetupSignals() register_for_property_changes(self.pm, 'live', self.live_changed) def SetupSignals(self): self.read_pushButton.clicked.connect(self.button_pressed) self.live_button.clicked.connect(self.button_pressed) self.display_thread.ready.connect(self.update_display) def button_pressed(self): if self.sender() == self.read_pushButton: self.display_thread.single_shot = True elif self.sender() == self.live_button: self.pm.live = self.live_button.isChecked() self.display_thread.start() def update_display(self, power): self.power_lcdNumber.display(float(power)) def live_changed(self, new): if self.live_button.isChecked() is not self.pm.live: self.live_button.setChecked(new) self.display_thread.start()
class OxfordITCUI(QtWidgets.QWidget): updateGUI = QtCore.Signal() def __init__(self, itc): assert isinstance(itc, OxfordITC), "instrument must be an Oxford ITC" super(OxfordITCUI, self).__init__() self.ITC = itc uic.loadUi(os.path.join(os.path.dirname(__file__), 'OxfordITC.ui'), self) self.lineEditSetT.returnPressed.connect(self.setT) self.updateGUI.connect(self.SentUpdateGUI) self.SentUpdateGUI() def SentUpdateGUI(self): self.textEditT.setText(str(self.ITC.params['T'])) self.lineEditSetT.setText(str(self.ITC.params['SetT'])) self.lineEditP.setText(str(self.ITC.params['PID'][0])) self.lineEditI.setText(str(self.ITC.params['PID'][1])) self.lineEditD.setText(str(self.ITC.params['PID'][2])) return def setT(self): temp = float(self.lineEditSetT.text()) self.ITC.setSetTemperature(temp)
def __init__(self, solstis): QtCore.QThread.__init__(self) self.SolsTiS = solstis self.signal = QtCore.SIGNAL("SolsTiS_status_update") self.setTerminationEnabled() self.SolsTiS.system_status()
def parent(self, index=None): """Find the index of the parent of the item at a given index.""" try: parent = self._index_to_item(index).parent return self.createIndex(parent.row, 0, parent) except: # Something went wrong with finding the parent so return an invalid index return QtCore.QModelIndex()
def __init__(self, solstis): QtCore.QThread.__init__(self) self.SolsTiS = solstis self.signal = QtCore.SIGNAL("laser_unlocked") self.setTerminationEnabled() self.SolsTiS.system_status() if self.SolsTiS.laser_status['etalon_lock'] != 'on': self.SolsTiS.etalon_lock('on')
def index(self, row, column, parent_index): """Return the index of the <row>th child of parent :type row: int :type column: int :type parent: QtCore.QModelIndex """ try: parent = self._index_to_item(parent_index) return self.createIndex(row, column, parent.children[row]) except: return QtCore.QModelIndex()
class QProgressDialogWithDeferredUpdate(QtWidgets.QProgressDialog): """A QProcessDialog that can have its value updated from a background thread.""" set_new_value = QtCore.Signal(int) def __init__(self, *args, **kwargs): QtWidgets.QProgressDialog.__init__(self, *args, **kwargs) self.set_new_value.connect(self.setValue, type=QtCore.Qt.QueuedConnection) def setValueLater(self, progress): """Update the progress bar - but do it in a thread-safe way.""" self.set_new_value.emit(progress)
class FigureCanvasWithDeferredDraw(FigureCanvas): # This class allows us to use Qt's event loop to draw the canvas from # the GUI thread, even if the call comes from outside the GUI thread. # this is necessary if you want to plot from a background thread. ask_for_redraw = QtCore.Signal() def __init__(self, figure): FigureCanvas.__init__(self, figure) # We connect the ask_for_redraw signal to the FigureCanvas's draw() method. # using a QueuedConnection ensures that draw() is correctly called in the # application's main GUI thread. self.ask_for_redraw.connect(self.draw, type=QtCore.Qt.QueuedConnection) def draw_in_main_loop(self): """Draw the canvas, but do so in the Qt main loop to avoid threading nasties.""" self.ask_for_redraw.emit()
class PreviewImageItem(pg.ImageItem): legacy_click_callback = None click_callback_signal = QtCore.Signal(np.ndarray) def mouseClickEvent(self, ev): """Handle a mouse click on the image.""" if ev.button() == QtCore.Qt.LeftButton: pos = np.array(ev.pos()) if self.legacy_click_callback is not None: # size = np.array(self.image.shape[:2]) # point = pos/size # self.legacy_click_callback(point[1], point[0]) self.legacy_click_callback(int(pos[1]), int(pos[0])) print pos[1], pos[0] ev.accept() else: pass else: super(PreviewImageItem, self).mouseClickEvent(ev)
def __init__(self, solstis): assert isinstance(solstis, SolsTiS), "instrument must be a SolsTiS" super(SolsTiSUI, self).__init__() self.SolsTiS = solstis self.signal = QtCore.SIGNAL('SolsTiSGUIupdate') self.SolsTiSMonitorThread = None uic.loadUi(os.path.join(os.path.dirname(__file__), 'SolsTiS.ui'), self) self.checkBoxSolsTiSLockMonitor.stateChanged.connect( self.SolsTiSLockMonitor) self.checkBoxSolsTiSEtalonLock.stateChanged.connect( self.SolsTiSLockEtalon) self.checkBoxSolsTiSCavityLock.stateChanged.connect( self.SolsTiSLockCavity) self.lineEditSolsTiSWL.returnPressed.connect(self.SolsTiSWL) self.pushButtonSolsTiSstatusMonitor.clicked.connect( self.SolsTiSMonitor) self.pushButtonSolsTiSstopMonitor.clicked.connect( self.SolsTiSMonitorStop)
class DisplayThread(QtCore.QThread): ready = QtCore.Signal(float) def __init__(self, parent): super(DisplayThread, self).__init__() self.parent = parent self.single_shot = False self.refresh_rate = 4. def run(self): t0 = time.time() while self.parent.pm.live or self.single_shot: p = self.parent.pm.power if time.time() - t0 < 1. / self.refresh_rate: continue else: t0 = time.time() self.ready.emit(p) if self.single_shot: self.single_shot = False break self.finished.emit()
class DisplayThread(QtCore.QThread): '''for displaying the temperature''' ready = QtCore.Signal(float) def __init__(self, parent): super(DisplayThread, self).__init__() self.parent = parent self.single_shot = False self.refresh_rate = 1. # every second def run(self): t0 = time.time() while self.parent.live_temperature_checkBox.isChecked( ) or self.single_shot: T = self.parent.get_temperature() if time.time() - t0 < 1. / self.refresh_rate: continue else: t0 = time.time() self.ready.emit(T) if self.single_shot: self.single_shot = False break self.finished.emit()
class CounterPreviewWidget(QtWidgets.QWidget): """A Qt Widget to display the live feed from a camera.""" update_data_signal = QtCore.Signal(np.ndarray) def __init__(self, counter): super(CounterPreviewWidget, self).__init__() # self.plot_item = pg.pl self.plot_widget = pg.PlotWidget(labels={'bottom': 'Time'}) self.plot = self.plot_widget.getPlotItem() self.setLayout(QtWidgets.QGridLayout()) self.layout().addWidget(self.plot_widget) self.counter = counter # We want to make sure we always update the data in the GUI thread. # This is done using the signal/slot mechanism self.update_data_signal.connect(self.update_widget, type=QtCore.Qt.QueuedConnection) def update_widget(self, new_data): """Set the data to the latest""" # print 'update',new_data self.plot.clear() self.plot.plot(new_data[:, 1] - new_data[0, 1], new_data[:, 0])
class AndorUI(QtWidgets.QWidget, UiTools): ImageUpdated = QtCore.Signal() def __init__(self, andor): assert isinstance(andor, Andor), "instrument must be an Andor" super(AndorUI, self).__init__() self.Andor = andor self.DisplayWidget = None self.temperature_display_thread = DisplayThread(self) uic.loadUi((os.path.dirname(__file__) + '/andor.ui'), self) self._setup_signals() self.init_gui() self.binning() self.data_file = None self.save_all_parameters = False self.gui_params = [ 'ReadMode', 'Exposure', 'AcquisitionMode', 'OutAmp', 'TriggerMode' ] self._func_dict = {} for param in self.gui_params: func = self.callback_to_update_prop(param) self._func_dict[param] = func register_for_property_changes(self.Andor, param, self._func_dict[param]) if self.Andor.SingleTrack is not None: c_row, n_rows = self.Andor.SingleTrack self.spinBoxCenterRow.setValue(c_row) self.spinBoxNumRows.setValue(n_rows) def __del__(self): self._stopTemperatureThread = True if self.DisplayWidget is not None: self.DisplayWidget.hide() self.DisplayWidget.close() def _setup_signals(self): self.comboBoxAcqMode.activated.connect(self.acquisition_mode) self.comboBoxBinning.activated.connect(self.binning) self.comboBoxReadMode.activated.connect(self.read_mode) self.comboBoxTrigMode.activated.connect(self.trigger) self.spinBoxNumFrames.valueChanged.connect(self.number_frames) self.spinBoxNumFrames.setRange(1, 1000000) self.spinBoxNumAccum.valueChanged.connect(self.number_accumulations) self.spinBoxNumRows.valueChanged.connect(self.number_rows) self.spinBoxCenterRow.valueChanged.connect(self.number_rows) self.checkBoxROI.stateChanged.connect(self.ROI) self.checkBoxCrop.stateChanged.connect(self.isolated_crop) self.checkBoxCooler.stateChanged.connect(self.cooler) self.checkBoxEMMode.stateChanged.connect(self.output_amplifier) self.spinBoxEMGain.valueChanged.connect(self.em_gain) self.lineEditExpT.editingFinished.connect(self.exposure) self.lineEditExpT.setValidator(QtGui.QDoubleValidator()) self.pushButtonDiv5.clicked.connect(lambda: self.exposure('/')) self.pushButtonTimes5.clicked.connect(lambda: self.exposure('x')) self.pushButtonCapture.clicked.connect(self.Capture) self.pushButtonLive.clicked.connect(self.Live) self.pushButtonAbort.clicked.connect(self.Abort) self.save_pushButton.clicked.connect(self.Save) self.pushButtonTakeBG.clicked.connect(self.take_background) self.checkBoxRemoveBG.stateChanged.connect(self.remove_background) self.referesh_groups_pushButton.clicked.connect(self.update_groups_box) self.keep_shutter_open_checkBox.stateChanged.connect( self.update_shutter_mode) self.read_temperature_pushButton.clicked.connect(self.temperature_gui) self.live_temperature_checkBox.clicked.connect(self.temperature_gui) self.temperature_display_thread.ready.connect( self.update_temperature_display) def init_gui(self): trig_modes = {0: 0, 1: 1, 6: 2} self.comboBoxAcqMode.setCurrentIndex( self.Andor._parameters['AcquisitionMode'] - 1) self.acquisition_mode() self.comboBoxReadMode.setCurrentIndex( self.Andor._parameters['ReadMode']) self.read_mode() self.comboBoxTrigMode.setCurrentIndex( trig_modes[self.Andor._parameters['TriggerMode']]) self.trigger() self.comboBoxBinning.setCurrentIndex( np.log2(self.Andor._parameters['Image'][0])) self.binning() self.spinBoxNumFrames.setValue(self.Andor._parameters['NKin']) self.checkBoxEMMode.setChecked(not bool(self.Andor.OutAmp)) if len(self.Andor.capabilities['EMGainCapability']) == 0: self.checkBoxEMMode.hide() self.spinBoxEMGain.hide() self.Andor.get_camera_parameter('AcquisitionTimings') self.lineEditExpT.setText( str(float( '%#e' % self.Andor._parameters['AcquisitionTimings'][0])).rstrip('0')) def cooler(self): self.Andor.cooler = self.checkBoxCooler.isChecked() def temperature_gui(self): if self.sender() == self.read_temperature_pushButton: self.temperature_display_thread.single_shot = True self.temperature_display_thread.start() def update_temperature_display(self, temperature): self.temperature_lcdNumber.display(float(temperature)) def get_temperature(self): return self.Andor.CurrentTemperature def update_shutter_mode(self): self.Andor.keep_shutter_open = self.keep_shutter_open_checkBox.isChecked( ) def acquisition_mode(self): available_modes = ['Single', 'Accumulate', 'Kinetic', 'Fast Kinetic'] currentMode = self.comboBoxAcqMode.currentText() self.Andor.set_camera_parameter('AcquisitionMode', available_modes.index(currentMode) + 1) if currentMode == 'Fast Kinetic': self.spinBoxNumRows.show() self.labelNumRows.show() elif currentMode != 'Single track': self.spinBoxNumRows.hide() self.labelNumRows.hide() if currentMode == 'Accumulate': self.spinBoxNumAccum.show() self.labelNumAccum.show() else: self.spinBoxNumAccum.hide() self.labelNumAccum.hide() if (currentMode == 'Fast Kinetic') or (currentMode == 'Kinetic'): self.keep_shutter_open_checkBox.show() else: self.keep_shutter_open_checkBox.hide() def read_mode(self): available_modes = [ 'FVB', 'Multi-track', 'Random track', 'Single track', 'Image' ] currentMode = self.comboBoxReadMode.currentText() self.Andor.set_camera_parameter('ReadMode', available_modes.index(currentMode)) if currentMode == 'Single track': self.spinBoxNumRows.show() self.labelNumRows.show() self.spinBoxCenterRow.show() self.labelCenterRow.show() elif self.comboBoxAcqMode.currentText() != 'Fast Kinetic': self.spinBoxNumRows.hide() self.labelNumRows.hide() self.spinBoxCenterRow.hide() self.labelCenterRow.hide() else: self.spinBoxCenterRow.hide() self.labelCenterRow.hide() def update_ReadMode(self, index): self.comboBoxReadMode.setCurrentIndex(index) def update_TriggerMode(self, value): available_modes = {0: 0, 1: 1, 6: 2} index = available_modes[value] self.comboBoxTrigMode.setCurrentIndex(index) def update_Exposure(self, value): self.lineEditExpT.setText(str(value)) def callback_to_update_prop(self, propname): """Return a callback function that refreshes the named parameter.""" def callback(value=None): getattr(self, 'update_' + propname)(value) return callback def trigger(self): available_modes = {'Internal': 0, 'External': 1, 'ExternalStart': 6} currentMode = self.comboBoxTrigMode.currentText() self.Andor.set_camera_parameter('TriggerMode', available_modes[currentMode]) def output_amplifier(self): self.Andor.OutAmp = int(not self.checkBoxEMMode.isChecked()) self.checkBoxCrop.setChecked(False) def binning(self): current_binning = int(self.comboBoxBinning.currentText()[0]) self.Andor.binning = current_binning self.Andor.FVBHBin = current_binning def number_frames(self): num_frames = self.spinBoxNumFrames.value() self.Andor.set_camera_parameter('NKin', num_frames) def number_accumulations(self): num_frames = self.spinBoxNumAccum.value() self.Andor.set_camera_parameter('NAccum', num_frames) def number_rows(self): num_rows = self.spinBoxNumRows.value() if self.Andor._parameters['AcquisitionMode'] == 4: self.Andor.set_fast_kinetics(num_rows) elif self.Andor._parameters['ReadMode'] == 3: center_row = self.spinBoxCenterRow.value() if center_row - num_rows < 0: self.Andor._logger.info( 'Too many rows provided for Single Track mode. Using %g rows instead' % center_row) num_rows = center_row self.Andor.set_camera_parameter('SingleTrack', center_row, num_rows) else: self.Andor._logger.info( 'Changing the rows only works in Fast Kinetic or in Single Track mode' ) def exposure(self, input=None): if input is None: expT = float(self.lineEditExpT.text()) elif input == 'x': expT = float(self.lineEditExpT.text()) * 5 elif input == '/': expT = float(self.lineEditExpT.text()) / 5 self.Andor.Exposure = expT def em_gain(self): gain = self.spinBoxEMGain.value() self.Andor.set_camera_parameter('EMGain', gain) def isolated_crop(self): current_binning = self.Andor.binning gui_roi = self.Andor.gui_roi maxy = gui_roi[3] if self.checkBoxEMMode.isChecked(): maxx = gui_roi[1] else: shape = self.Andor.DetectorShape maxx = shape[0] - gui_roi[1] if self.checkBoxCrop.isChecked(): self.checkBoxROI.setEnabled(False) self.Andor.IsolatedCropMode = (1, maxy, maxx, current_binning[0], current_binning[1]) self.Andor.Image = (current_binning[0], current_binning[1], 1, maxx, 1, maxy) else: self.checkBoxROI.setEnabled(True) self.Andor.IsolatedCropMode = (0, maxy, maxx, current_binning[0], current_binning[1]) shape = self.Andor.DetectorShape self.Andor.Image = (current_binning[0], current_binning[1], 1, shape[0], 1, shape[1]) def take_background(self): self.Andor.background = self.Andor.raw_snapshot()[1] self.Andor.backgrounded = True self.checkBoxRemoveBG.setChecked(True) def remove_background(self): if self.checkBoxRemoveBG.isChecked(): self.Andor.backgrounded = True else: self.Andor.backgrounded = False def Save(self): if self.data_file is None: self.data_file = df.current() data = self.Andor.CurImage if self.filename_lineEdit.text() != 'Filename....': filename = self.filename_lineEdit.text() else: filename = 'Andor_data' if self.group_comboBox.currentText() == 'AndorData': if df._use_current_group == True and df._current_group is not None: group = df._current_group elif 'AndorData' in list(self.data_file.keys()): group = self.data_file['AndorData'] else: group = self.data_file.create_group('AndorData') else: group = self.data_file[self.group_comboBox.currentText()] if np.shape(data)[0] == 1: data = data[0] if self.save_all_parameters: attrs = self.Andor.get_andor_parameters() else: attrs = dict() attrs['Description'] = self.description_plainTextEdit.toPlainText() if hasattr(self.Andor, 'x_axis'): attrs['wavelengths'] = self.Andor.x_axis try: data_set = group.create_dataset(name=filename, data=data) except Exception as e: self.Andor._logger.info(e) df.attributes_from_dict(data_set, attrs) if self.Andor.backgrounded == False and 'background' in list( data_set.attrs.keys()): del data_set.attrs['background'] def update_groups_box(self): if self.data_file is None: self.data_file = df.current() self.group_comboBox.clear() if 'AndorData' not in list(self.data_file.values()): self.group_comboBox.addItem('AndorData') for group in list(self.data_file.values()): if type(group) == df.Group: self.group_comboBox.addItem(group.name[1:], group) def ROI(self): if self.checkBoxROI.isChecked(): self.checkBoxCrop.setEnabled(False) self.Andor.roi = self.Andor.gui_roi # binning + params else: self.checkBoxCrop.setEnabled(True) self.Andor.roi = (0, self.Andor._parameters['DetectorShape'][0] - 1, 0, self.Andor._parameters['DetectorShape'][1] - 1) def Capture(self): self.Andor.raw_image(update_latest_frame=True) def Live(self): self.Andor.live_view = True def Abort(self): self.Andor.live_view = False
class DisplayWidgetRoiScale(ExtendedImageView): _max_num_line_plots = 4 update_data_signal = QtCore.Signal(np.ndarray) def __init__(self, scale=(1, 1), offset=(0, 0)): super(DisplayWidgetRoiScale, self).__init__() self._pxl_scale = scale self._pxl_offset = offset self.LineDisplay = self.ui.roiPlot self.LineDisplay.showGrid(x=True, y=True) self.ui.splitter.setHandleWidth(10) self.getHistogramWidget().gradient.restoreState( list(Gradients.values())[1]) self.imageItem.setTransform(QtGui.QTransform()) self.LineDisplay.show() self.plot = () for ii in range(self._max_num_line_plots): self.plot += (self.LineDisplay.plot( pen=pyqtgraph.intColor(ii, self._max_num_line_plots)), ) self.toggle_displays() self.checkbox_autorange = QtWidgets.QCheckBox('Autorange') self.tools.gridLayout.addWidget(self.checkbox_autorange, 0, 3, 1, 1) @property def x_axis(self): """Convenience wrapper for integration with spectrometer code""" return self.axis_values['bottom'] @x_axis.setter def x_axis(self, value): self.axis_values['bottom'] = value @property def y_axis(self): """Convenience wrapper for integration with spectrometer code""" return self.axis_values['left'] @y_axis.setter def y_axis(self, value): self.axis_values['left'] = value def update_axes(self): gui_axes = self.get_axes() for ax, name in zip(gui_axes, ["bottom", "left", "top", "right"]): if self.axis_values[name] is not None: setattr(ax, 'axis_values', self.axis_values[name]) if self.axis_units[name] is not None: ax.setLabel(self.axis_units[name]) # This is kept in case subclasses overwrite the x_axis or y_axis properties for ax, value in zip(gui_axes[:2], [self.x_axis, self.y_axis]): if value is not None: setattr(ax, 'axis_values', value) def toggle_displays(self, boolean=False): """Toggle between an Image display and a Plot widget for Line displays :param boolean: if True, display lines. If False, display images :return: """ if boolean: self.LineDisplay.show() self.LineDisplay.showAxis('left') self.ui.splitter.setSizes([0, self.height() - 35, 35]) else: self.ui.splitter.setSizes([self.height() - 35, 0, 35]) def update_image(self, newimage): scale = self._pxl_scale offset = self._pxl_offset if len(newimage.shape) == 1: self.toggle_displays(True) self.plot[0].setData(x=self.x_axis, y=newimage) elif len(newimage.shape) == 2: if newimage.shape[0] > self._max_num_line_plots: self.toggle_displays(False) # levels = [np.percentile(newimage, x) for x in self.levels()] self.setImage( newimage, pos=offset, autoRange=self.checkbox_autorange.isChecked(), # levels=levels, scale=scale) else: self.toggle_displays(True) for ii, ydata in enumerate(newimage): self.plot[ii].setData(x=self.x_axis, y=ydata) elif len(newimage.shape) == 3: self.toggle_displays(False) zvals = 0.99 * np.linspace(0, newimage.shape[0] - 1, newimage.shape[0]) if newimage.shape[0] == 1: newimage = newimage[0] # levels = [np.percentile(newimage, x) for x in self.levels()] self.setImage( newimage, xvals=zvals, pos=offset, autoRange=self.checkbox_autorange.isChecked(), # levels=levels, scale=scale) else: raise ValueError('Cannot display. Array shape unrecognised')
class StreakUI(QtWidgets.QWidget): ImageUpdated = QtCore.Signal() def __init__(self, streak): super(StreakUI, self).__init__() self.Streak = streak uic.loadUi((os.path.dirname(__file__) + '/Streak.ui'), self) self.comboBoxGateMode.activated.connect(self.gate_mode) self.comboBoxReadMode.activated.connect(self.read_mode) self.comboBoxShutter.activated.connect(self.shutter) self.comboBoxTrigMode.activated.connect(self.trigger) self.spinBox_MCPGain.valueChanged.connect(self.mcp_gain) self.lineEditTimeRange.returnPressed.connect(self.time_range) self.comboBoxTimeUnit.activated.connect(self.time_range) self.pushButtonLess.clicked.connect(lambda: self.time_range('-')) self.pushButtonMore.clicked.connect(lambda: self.time_range('+')) self.pushButtonCapture.clicked.connect( lambda: self.Streak.raw_image(update_latest_frame=True)) def gate_mode(self): mode = str(self.comboBoxGateMode.currentText()) self.Streak.set_parameter('Devices', 'TD', 'Gate Mode', mode) def read_mode(self): mode = str(self.comboBoxReadMode.currentText()) self.Streak.set_parameter('Devices', 'TD', 'Mode', mode) def shutter(self): mode = str(self.comboBoxShutter.currentText()) self.Streak.set_parameter('Devices', 'TD', 'Shutter', mode) def trigger(self): mode = str(self.comboBoxTrigMode.currentText()) self.Streak.set_parameter('Devices', 'TD', 'Trig. Mode', mode) def mcp_gain(self): gain = int(self.spinBox_MCPGain.value()) self.Streak.set_parameter('Devices', 'TD', 'MCP Gain', gain) def time_range(self, direction=None): allowed_times = { 'ns': [5, 10, 20, 50, 100, 200, 500], 'us': [1, 2, 5, 10, 20, 50, 100, 200, 500], 'ms': [1] } unit = str(self.comboBoxTimeUnit.currentText()) given_number = int(self.lineEditTimeRange.text()) if direction is '+': if not (unit == 'ms' and given_number == 1): next_unit = str(unit) if given_number != 500: next_number = allowed_times[unit][ allowed_times[unit].index(given_number) + 1] else: next_number = 1 if unit == 'ns': self.comboBoxTimeUnit.setCurrentIndex(1) next_unit = 'us' elif unit == 'us': self.comboBoxTimeUnit.setCurrentIndex(2) next_unit = 'ms' self.lineEditTimeRange.setText(str(next_number)) unit = str(next_unit) else: self.Streak._logger.info( 'Tried increasing the maximum time range') return elif direction is '-': if not (unit == 'ns' and given_number == 5): next_unit = str(unit) if given_number != 1: next_number = allowed_times[unit][ allowed_times[unit].index(given_number) - 1] else: next_number = 500 if unit == 'ms': self.comboBoxTimeUnit.setCurrentIndex(1) next_unit = 'us' elif unit == 'us': self.comboBoxTimeUnit.setCurrentIndex(0) next_unit = 'ns' self.lineEditTimeRange.setText(str(next_number)) unit = str(next_unit) else: self.Streak._logger.info( 'Tried decreasing the minimum time range') return else: next_number = min(allowed_times[unit], key=lambda x: abs(x - given_number)) self.lineEditTimeRange.setText(str(next_number)) # Some camera models don't give you direct access to the time range, but rather you preset a finite number of # settings that you then switch between try: self.Streak.set_parameter('Devices', 'TD', 'Time Range', str(next_number) + ' ' + unit) except StreakError: self.Streak.set_parameter('Devices', 'TD', 'Time Range', str(next_number))
class Frequency_counter_F390(SerialInstrument): port_settings = dict(baudrate=115200, bytesize=serial.EIGHTBITS, parity=serial.PARITY_NONE, xonxoff=True, timeout=1.0) termination_character = "\n" update_data_signal = QtCore.Signal(np.ndarray) def __init__(self, port=None, integration_time=1): SerialInstrument.__init__(self, port=port) self.live_window = 100 self._live_view = False self.int_time = integration_time self.write('FO') #do not apply low pass filter self.write('Z5') #for 50 Ohms impedance function_dict = { '0': 'B Input Period', '1': 'A Input Period', '2': 'A Input Frequency', '3': 'B Input Frequency', '4': 'Frequency Ratio B:A', '5': 'A Input Width High', '6': 'A Input Width Low', '7': 'A Input Count', '8': 'A Input Ratio H:L', '9': 'A Input Duty Cycle', 'C': 'C Input Frequency', 'D': 'C Input Period' } def get_function(self): '''A property to set the required function of the frequency counter Args: f: the a string value of the function shown in the table below and in self.function_dict 0 B Input Period 1 A Input Period 2 A Input Frequency 3 B Input Frequency 4 Frequency Ratio B:A 5 A Input Width High 6 A Input Width Low 7 A Input Count 8 A Input Ratio H:L 9 A Input Duty Cycle C C Input Frequency D C Input Period returns: the current function ''' return self.function_dict(self._function) def set_function(self, f): self._function = str(f) self.write('F' + str(f)) function = property(fget=get_function, fset=set_function) def get_identity(self): '''Returns the device id (good for testing comms) ''' return self.query('*IDN?') def test_communications(self): '''A command to allow autodetection to work ''' if self.get_identity().split(',')[0] == 'Thurlby-Thandar': return True def measure_next(self): '''Return the next valid measurement''' try: return float(self.query('N?')[:-2]) except: print(self.query('N?')[:-2]) def measure_next_fast(self): '''Return the invalid measurement (i.e. refereshs at LCD refresh rate, not the measreument rate)''' try: return float(self.query('?')[:-2]) except: print(self.query('?')[:-2]) # def start_countinous_fast(self): # '''Starts fast streaming of values at the LCD refresh rate ''' # self.write('C?') # def start_countinous_single(self): # '''Starts continuous streaming of values at the rate of the measurement time''' # self.write('E?') # def stop_countinous(self): # self.write('STOP') def get_live_view_window(self): return self._live_window def set_live_view_window(self, window_length): self._live_window = window_length '''Set the number of the stored values in the deque ''' self.live_deque = deque(maxlen=window_length) live_window = NotifiedProperty(get_live_view_window, set_live_view_window) int_times = {0.3: '1', 1: '2', 10: '3', 100: '4'} impedances = {'50': 'Z5', '1M': 'Z1'} def get_int_time(self): '''A property for the integration time possible values are: 0.3 s, 1s, 10s,100s ''' return self._int_time def set_int_time(self, integration_time): self._int_time = integration_time try: self.write('M' + self.int_times[integration_time]) except KeyError: self.log('Invalid integration time', level='WARN') int_time = NotifiedProperty(get_int_time, set_int_time) def get_qt_ui(self): self.ui = CounterUI(self) self.display_ui = self.ui.preview_widget self.control_ui = self.ui.control_widget return self.ui def get_preview_widget(self): self.display_ui = CounterPreviewWidget(self) return self.display_ui def get_control_widget(self): self.control_ui = CounterControlUI(self) return self.control_ui def _live_view_function(self): '''The function that is run within the live preview thread ''' while self._live_view: data = None data = self.measure_next_fast() # while data == None: time.sleep(self.int_time) self.live_deque.append([data, time.time()]) self.display_ui.update_data_signal.emit(np.array(self.live_deque)) def get_live_view(self): '''Setting up the notificed property live view to allow live view to be switch on and off ''' return self._live_view def set_live_view(self, enabled): if enabled == True: try: self._live_view = True self._live_view_stop_event = threading.Event() self._live_view_thread = threading.Thread( target=self._live_view_function) self._live_view_thread.start() except AttributeError as e: #if any of the attributes aren't there print("Error:", e) else: if not self._live_view: return # do nothing if it's not running. print("stopping live view thread") try: self._live_view = False self._live_view_stop_event.set() self._live_view_thread.join() del (self._live_view_stop_event, self._live_view_thread) except AttributeError: raise Exception( "Tried to stop live view but it doesn't appear to be running!" ) live_view = NotifiedProperty(get_live_view, set_live_view)
def sizeHint(self): return QtCore.QSize(1024, 768)