class Stack(QtGui.QWidget): def __init__(self,main_widget): super(Stack,self).__init__() self.counter = 0 self.database_path = '' self.num_captures = 0 self.time_interval = 0 self.main_widget = main_widget self.initUI() self.crop_image.setChecked(True) self.update_plots.setChecked(True) self.adjust_exposure.setChecked(True) self.toggle_move_to_mologram() self.toggle_reference_mologram() def initUI(self): # algorithm names self.algo_names = [] self.algo_names.append('sum over background plus 3 sigma') # different types of stacks self.stack_type_list = [] self.stack_type_list.append('time') self.stack_type_list.append('z-position (um)') self.stack_type_list.append('TE-position (deg)') self.stack_type_list.append('exposure') self.mologram_sides = ['left','right'] self.time_unit_list = ['s','min'] # declare widgets # labels for the form self.editFolder_lbl = QtGui.QLabel('Experiment Folder') self.mologram_lbl = QtGui.QLabel('Move to Mologram') self.time_int_lbl = QtGui.QLabel('Time Interval') self.num_caps_lbl = QtGui.QLabel('Number of Captures') self.algorithm_lbl = QtGui.QLabel('Intensity Algorithm') self.stack_type_lbl = QtGui.QLabel('Stack Type') self.stack_incr_lbl = QtGui.QLabel('Stack Increment (down)') self.start_lbl = QtGui.QLabel('') self.stop_lbl = QtGui.QLabel('') self.pause_lbl = QtGui.QLabel('') self.move_to_lbl = QtGui.QLabel('Enable Move to Mologram') self.cap_laser_lbl = QtGui.QLabel('Record Laser Intensity') self.ref_molo_lbl = QtGui.QLabel('Reference Mologram') self.num_avg_lbl = QtGui.QLabel('Number of Avg per capture') self.crop_image_lbl = QtGui.QLabel('') self.update_plots_lbl = QtGui.QLabel('Update Plots') self.adjust_exposure_lbl= QtGui.QLabel('Adjust Exposure when saturated') # line edits and selectors self.editFolder = QtGui.QLineEdit() self.mologram_pos = MologramSelector() self.time_int_sbox = QtGui.QDoubleSpinBox(value = 3) self.stack_incr_sbox = QtGui.QDoubleSpinBox() self.number_caps = QtGui.QSpinBox(value = 1) self.time_units = QtGui.QComboBox() self.algorithms = QtGui.QComboBox() self.stack_type = QtGui.QComboBox() self.stack_unit = QtGui.QComboBox() self.mologram_side = QtGui.QComboBox() self.num_avg = QtGui.QSpinBox(value = 1) self.crop_image = QtGui.QCheckBox('Crop image to 60 x 60 um') self.update_plots = QtGui.QCheckBox('') self.adjust_exposure = QtGui.QCheckBox('') for name in self.mologram_sides: self.mologram_side.addItem(name) for name in self.algo_names: self.algorithms.addItem(name) for name in self.stack_type_list: self.stack_type.addItem(name) for name in self.time_unit_list: self.time_units.addItem(name) self.set_stack_unit() self.number_caps.setRange(0,100000) # Create and connect buttons self.start = QtGui.QPushButton('Start Experiment') self.start.clicked.connect(self.start_f) self.start.resize(self.start.sizeHint()) self.browse = QtGui.QPushButton('browse') self.browse.clicked.connect(self.browse_f) self.browse.resize(self.browse.sizeHint()) self.stop = QtGui.QPushButton('Stop Experiment') self.pause = QtGui.QPushButton('Pause/Continue Experiment') self.stack_type.activated[str].connect(self.set_stack_unit) self.move_to_mologram_btn = QtGui.QCheckBox('Enable') self.move_to_mologram_btn.clicked.connect(self.toggle_move_to_mologram) self.reference_mologram = QtGui.QCheckBox('Enable') self.reference_mologram.clicked.connect(self.toggle_reference_mologram) self.record_laser_btn = QtGui.QCheckBox('') #self.record_laser_btn.clicked.connect(self.toggle_capture_laser) # layout hbox_folder = QtGui.QHBoxLayout() hbox_time = QtGui.QHBoxLayout() hbox_stack = QtGui.QHBoxLayout() hbox_mologram = QtGui.QHBoxLayout() hbox_ref = QtGui.QHBoxLayout() hbox_folder.addWidget(self.editFolder) hbox_folder.addWidget(self.browse) hbox_time.addWidget(self.time_int_sbox) hbox_time.addWidget(self.time_units) hbox_stack.addWidget(self.stack_incr_sbox) hbox_stack.addWidget(self.stack_unit) hbox_ref.addWidget(self.reference_mologram) hbox_ref.addWidget(self.mologram_side) hbox_mologram.addWidget(self.move_to_mologram_btn) hbox_mologram.addLayout(self.mologram_pos) fbox = QtGui.QFormLayout() fbox.addRow(self.editFolder_lbl, hbox_folder) fbox.addRow(self.mologram_lbl, hbox_mologram) fbox.addRow(self.crop_image_lbl,self.crop_image) fbox.addRow(self.stack_type_lbl, self.stack_type) fbox.addRow(self.time_int_lbl, hbox_time) fbox.addRow(self.stack_incr_lbl, hbox_stack) fbox.addRow(self.num_caps_lbl, self.number_caps) fbox.addRow(self.num_avg_lbl,self.num_avg) fbox.addRow(self.ref_molo_lbl, hbox_ref) fbox.addRow(self.algorithm_lbl, self.algorithms) fbox.addRow(self.cap_laser_lbl, self.record_laser_btn) fbox.addRow(self.update_plots_lbl,self.update_plots) fbox.addRow(self.adjust_exposure_lbl,self.adjust_exposure) fbox.addRow(self.start_lbl, self.start) fbox.addRow(self.stop_lbl, self.stop) fbox.addRow(self.pause_lbl, self.pause) hbox = QtGui.QHBoxLayout() hbox.addLayout(fbox) self.setLayout(hbox) def set_stack_unit(self,str = None): """ Depending on the current stack type, set the right units for the stack units QComboBox. Also disables and enables other widgets in the stack selector box.""" curr_stack_type = self.stack_type.currentText() self.stack_unit.setEnabled(True) self.stack_incr_sbox.setEnabled(True) self.stack_unit.clear() if curr_stack_type == self.stack_type_list[1]: self.num_avg.setEnabled(True) else: self.num_avg.setEnabled(False) if curr_stack_type == self.stack_type_list[0]: self.stack_unit.setEnabled(False) self.stack_incr_sbox.setEnabled(False) return elif curr_stack_type == self.stack_type_list[1]: units_list = ['um'] elif curr_stack_type == self.stack_type_list[2]: units_list = ['deg'] elif curr_stack_type == self.stack_type_list[3]: units_list = ['ms'] for unit in units_list: self.stack_unit.addItem(unit) def fetch_mologram_data(self,database_path = None): """ Fetch all the rows in the SQL database for the given path and return all of the data as a numpy array """ # Check if datapase path was passed if database_path == None: database_path = self.database_path if database_path == '': return None # Connect to database con = sqlite3.connect(database_path + '/mologram_data.db') cur = con.cursor() # fetch all rows from database rows = [] for row in cur.execute('SELECT * FROM mologram_data ORDER BY key'): rows.append(row) # Close connection with SQL databse con.close() # extract data rows = np.array(rows) print(rows.shape) print(type(rows)) time = rows[:,1] intensity = rows[:,7] return time,intensity def confirm_user_input(self,experiment_folder_path,num_captures): # Test for incorrect user input if experiment_folder_path == '': msg = QtGui.QMessageBox() msg.setWindowTitle("Folder name") msg.setIcon(QtGui.QMessageBox.Warning) msg.setStandardButtons(QtGui.QMessageBox.Ok) msg.setText("Please select a valid experiment folder") msg.exec_() return -1 if num_captures == 0: msg = QtGui.QMessageBox() msg.setWindowTitle("Experiment Length") msg.setIcon(QtGui.QMessageBox.Warning) msg.setStandardButtons(QtGui.QMessageBox.Ok) msg.setText("Please a valib experiment length") msg.exec_() return -1 # Clear existing data in selected directory and create necessary directories if os.listdir(experiment_folder_path) != []: msg = QtGui.QMessageBox() msg.setWindowTitle("Question") msg.setIcon(QtGui.QMessageBox.Warning) msg.setStandardButtons(QMessageBox.Yes | QMessageBox.No) msg.setText("Are you sure you want to delete the existing data?") retval = msg.exec_() if retval == QtGui.QMessageBox.No: return -1 # Clear previous results os.system('sudo rm -rf ' + experiment_folder_path + '/*') return 0 """ Fetch all parameters for experiment from GUI and launch the experiment in a seperate thread """ def start_f(self): # Determine where to store results experiment_folder_path = self.editFolder.text() image_path = experiment_folder_path + '/images' self.database_path = experiment_folder_path + '/database' # Confirm user input and delete experiment information if it is already there. if self.confirm_user_input(experiment_folder_path,self.number_caps.value()) == -1: return self.main_widget.set_experiment_folder_path(experiment_folder_path) # Create directories if non-existent directories = [experiment_folder_path,image_path,self.database_path] for directory in directories: if not os.path.exists(directory): os.makedirs(directory) # Thread for recording the Experiment self.experiment = Experiment(self.main_widget,self.database_path) self.connect( self.experiment, QtCore.SIGNAL("database_updated"), self.main_widget.updateAllStack ) self.connect( self.experiment, QtCore.SIGNAL("done_experiment"), self.done_experiment ) self.stop.clicked.connect(self.experiment.stop) self.pause.clicked.connect(self.experiment.pause) try: self.main_widget.plotTab.set_current_plot('time_stack') except Exception: pass # Adjust time_interval depending on time unit if self.time_units.currentText() == 'ms': time_interval /= 1000 elif self.time_units.currentText() == 'min': time_interval *= 60 elif self.time_units.currentText() == 's': pass # If user wished so, move to mologram automatically if self.move_to_mologram_btn.isChecked(): position = self.mologram_pos.position() print('Moving to mologram ' + position) self.main_widget.setup.chip.move_to(position) # Create file with experiment parameters for easier analysis later on self.create_info_file() # Start experiment self.experiment.record_data( image_path = image_path, database_path = self.database_path, num_captures = self.number_caps.value(), num_avg = self.num_avg.value(), time_interval = self.time_int_sbox.value(), stack_type = self.stack_type.currentText(), stack_incr = self.stack_incr_sbox.value(), stack_type_list = self.stack_type_list, current_algo = self.algorithms.currentText(), algo_names = self.algo_names, record_laser = self.record_laser_btn.isChecked(), reference_mologram = self.reference_mologram.isChecked(), mologram_side = self.mologram_side.currentText(), crop_image = self.crop_image.isChecked(), update_plots = self.update_plots.isChecked(), adjust_exposure = self.adjust_exposure.isChecked()) """ Create file with experiment parameters for easier analysis later on """ def create_info_file(self): info = dict({}) # Add all parameters to a dictionary info['Experiment Folder'] = self.database_path info['Number of Captures'] = self.number_caps.value() info['Time Interval'] = self.time_int_sbox.value() info['Number of Averages'] = self.num_avg.value() info['Stack Type'] = self.stack_type.currentText() info['Stack Increment'] = self.stack_incr_sbox.value() info['Recorded Algorithms'] = self.algorithms.currentText() info['Record Laser'] = self.record_laser_btn.isChecked() info['Mologram Name'] = self.main_widget.setup.chip.file_name() info['Reference Mologram'] = self.reference_mologram.isChecked() info['Mologram Side'] = self.mologram_side.currentText() # Store dictionary as JSON data in an info file file = open(self.editFolder.text() + '/experiment.info','w') json.dump(info,file) file.close() """ Once experiment is done or if it stopped unexpectedly, show appropriate message box and update GUI """ def done_experiment(self): # Indicate experiment is complete msg = QtGui.QMessageBox() msg.setWindowTitle("Experiment") msg.setIcon(QtGui.QMessageBox.Information) msg.setStandardButtons(QtGui.QMessageBox.Ok) msg.setText("Experiment is complete") msg.exec_() # Update all displays self.main_widget.updateAll() def browse_f(self): folder = QtGui.QFileDialog.getExistingDirectory(self, 'Open file', '/home') self.editFolder.setText(folder) def toggle_move_to_mologram(self): self.mologram_pos.setEnabled(self.move_to_mologram_btn.isChecked()) def toggle_reference_mologram(self): self.mologram_side.setEnabled(self.reference_mologram.isChecked())
class CalibrationTab(QtGui.QWidget): def __init__(self,main_widget): super(CalibrationTab,self).__init__() self.main_widget = main_widget self.heights = self.read_heights() self.initUI() def initUI(self): # Define buttons self.calibrate = QtGui.QPushButton('Calibrate') self.set_position = QtGui.QPushButton('Set Position') self.setSurfaceHeight = QtGui.QPushButton('Set Surface Height') self.setMoloHeight = QtGui.QPushButton('Set Mologram Height') self.goToSurfaceHeight = QtGui.QPushButton('Go To Surface Height') self.goToMoloHeight = QtGui.QPushButton('Go To Mologram Height') self.mologram_pos = MologramSelector() # connect buttons self.calibrate.clicked.connect(self.onCalibrateClicked) self.set_position.clicked.connect(self.onSetPositionClicked) self.setSurfaceHeight.clicked.connect(self.onSetSurfaceHeightClicked) self.setMoloHeight.clicked.connect(self.onSetMologramHeightClicked) self.goToSurfaceHeight.clicked.connect(self.onGoToSurfaceHeightClicked) self.goToMoloHeight.clicked.connect(self.onGoToMologramHeightClicked) # Layout vbox = QtGui.QVBoxLayout() self.setLayout(vbox) hbox = QtGui.QHBoxLayout() hbox.addLayout(self.mologram_pos) hbox.addWidget(self.set_position) vbox.addWidget(self.calibrate) vbox.addLayout(hbox) vbox.addWidget(self.setSurfaceHeight) vbox.addWidget(self.setMoloHeight) vbox.addWidget(self.goToSurfaceHeight) vbox.addWidget(self.goToMoloHeight) self.calibrate.resize(self.calibrate.sizeHint()) self.set_position.resize(self.set_position.sizeHint()) self.setSurfaceHeight.resize(self.setSurfaceHeight.sizeHint()) self.setMoloHeight.resize(self.setMoloHeight.sizeHint()) self.goToSurfaceHeight.resize(self.goToSurfaceHeight.sizeHint()) self.goToMoloHeight.resize(self.goToMoloHeight.sizeHint()) def onCalibrateClicked(self): self.main_widget.calib() def onSetPositionClicked(self): pos = self.mologram_pos.position() x,y = self.main_widget.setup.chip.cartesian_position(pos) self.main_widget.setup.motors.x.set_position(x,'mm') self.main_widget.setup.motors.y.set_position(y,'mm') # update position and images self.main_widget.updateAll() def write_heights(self,heights): file = open('heights.txt','w') json.dump(heights,file) file.close() def read_heights(self): file = open('heights.txt','r') heights = json.load(file) file.close() return heights def onSetSurfaceHeightClicked(self): self.heights["surface_height"] = self.main_widget.setup.motors.z.pos('mm') self.write_heights(self.heights) def onGoToSurfaceHeightClicked(self): self.main_widget.axisControl.z.start_moving( distance = self.heights["surface_height"], unit = 'mm', relative = False ) def onSetMologramHeightClicked(self): self.heights["mologram_height"] = self.main_widget.setup.motors.z.pos('mm') self.write_heights(self.heights) def onGoToMologramHeightClicked(self): self.main_widget.axisControl.z.start_moving( distance = self.heights["mologram_height"], unit = 'mm', relative = False )