def get_scan_info(self): # print('get_scan_info called in gui') finerates = [ 20, 10, 5, 2, 1, .5, .2, .1, .05, .02, .01, .005, .002, .001 ] # in GHz/s mediumrates = [100, 50, 20, 15, 10, 5, 2, 1] # in GHz/s typebox = self._mw.scanType_comboBox.currentText() if typebox == 'Fine': scanrate = finerates[int( self._mw.scanRate_comboBox.currentText())] * 10**9 # in Hz/s else: indx = int(self._mw.scanRate_comboBox.currentText()) #handle if index is too high for medium scan if indx >= len(mediumrates): error_dialog = QtWidgets.QErrorMessage() error_dialog.showMessage( 'ERROR: index given for medium rates is too high') error_dialog.exec() self._mw.scanRate_comboBox.setCurrentIndex(7) return #alternatively (Todo?) change number of scanRate options based on whether we are on Fine or Medium else: scanrate = mediumrates[int(self._mw.scanRate_comboBox. currentText())] * 10**9 # in Hz/s startwvln = self._mw.startWvln_doubleSpinBox.value() * 10**-9 # in m stopwvln = self._mw.stopWvln_doubleSpinBox.value() * 10**-9 #in m numscans = self._mw.numScans_spinBox.value() return startwvln, stopwvln, typebox.lower(), scanrate, numscans
def run(self): if self.main_widget.dev: self.main_widget.data_handler = DataHandler( data_path=self.data_path, trials=self.trials, save_dir_path=self.save_dir_path, save_dir_already_created=self.save_dir_already_created, load_into_mem=self.load_into_mem) self.main_widget.data_handler.calculate_filters( self.reportProgress, auto_crop=self.auto_crop) self.signal.sig.emit(True) else: try: self.main_widget.data_handler = DataHandler( data_path=self.data_path, trials=self.trials, save_dir_path=self.save_dir_path, save_dir_already_created=self.save_dir_already_created, load_into_mem=self.load_into_mem) self.main_widget.data_handler.calculate_filters( self.reportProgress, auto_crop=self.auto_crop) self.signal.sig.emit(True) except Exception as e: logger.error(e) print("Unexpected error:", sys.exc_info()[0]) self.main_widget.console.updateText("Unexpected error: " + sys.exc_info()[0]) error_dialog = QtWidgets.QErrorMessage() error_dialog.showMessage("Unexpected error: " + str(e)) self.signal.sig.emit(False)
def on_error(message=None): em = QtWidgets.QErrorMessage(self.ui) msg = tr("An error occurred during decomposition") if message: msg += ":\n" + message em.setWindowTitle(tr("Decomposition error")) em.showMessage(msg)
def demoDownload(save_path): url = "https://github.com/Mishne-Lab/CIDAN/blob/master/demo/demo_dataset_1.tif?raw=true" if not os.path.isdir(save_path) and save_path != "": error_dialog = QtWidgets.QErrorMessage() error_dialog.showMessage("Please Select a valid folder") demo_folder_path = os.path.join(save_path, "CIDAN_Demo/") if not os.path.isdir(demo_folder_path): os.mkdir(demo_folder_path) r = requests.get(url) demo_dataset_path = os.path.join(demo_folder_path, "demo_dataset_1.tif") with open(demo_dataset_path, 'wb') as f: f.write(r.content) return True
def run(self): if self.main_widget.dev: self.data_handler.calculate_roi_extraction(self.reportProgress) print("Finished ROI extraction") self.signal.sig.emit(True) else: try: self.data_handler.calculate_roi_extraction(self.reportProgress) print("Finished ROI extraction") self.signal.sig.emit(True) except Exception as e: if (type(e) == AssertionError): error_dialog = QtWidgets.QErrorMessage() error_dialog.showMessage("Unexpected error: " + str(e.args[0])) else: error_dialog = QtWidgets.QErrorMessage() error_dialog.showMessage( "Something weird happened please reload and try again") self.main_widget.data_handler.global_params[ "need_recalc_eigen_params"] = True logger.error(str(e)) self.signal.sig.emit(False)
def run(self): if self.main_widget.dev: self.data_handler.calculate_filters() self.signal.sig.emit(True) else: try: self.data_handler.calculate_filters() self.signal.sig.emit(True) except Exception as e: logger.error(e) print("Unexpected error:", sys.exc_info()[0]) error_dialog = QtWidgets.QErrorMessage() error_dialog.showMessage("Unexpected error: " + str(e)) self.signal.sig.emit(False)
def run(self): if self.main_widget.dev: self.signal.sig.emit(demoDownload(self.path)) else: try: self.signal.sig.emit(demoDownload(self.path)) except Exception as e: logger.error(e) print("Unexpected error:", sys.exc_info()[0]) self.main_widget.console.updateText("Unexpected error: " + sys.exc_info()[0]) error_dialog = QtWidgets.QErrorMessage() error_dialog.showMessage("Unexpected error: " + str(e)) self.signal.sig.emit(False)
def start_roi(self): """create a new ROI for the image""" if not len(self.images) > 0: error = QtWidgets.QErrorMessage() error.showMessage( 'You must a load a series of images before drawing the ROI') error.exec_() return roi_style = self.combo_roi_style.currentText().lower() # style names are lowercase in ROI.py self.clear_roi() # create an ROI object for both images, keep the one that calls the # complete callback first self.grey_activeROI = ROI.new_ROI(self.plot_im.mpl_im, self.plot_im.axes, self.plot_im.figure, roi_style, 'red', self.grey_roi_complete_callback)
def run(self): if self.main_widget.dev: self.data_handler.calculate_time_traces(self.reportProgress) self.signal.sig.emit(True) else: try: self.data_handler.calculate_time_traces(self.reportProgress) self.signal.sig.emit(True) except Exception as e: ex_info = sys.exc_info()[0] logger.error(e) logger.error(ex_info) print("Unexpected error:", sys.exc_info()[0]) self.main_widget.console.updateText("Unexpected error: " + ex_info) error_dialog = QtWidgets.QErrorMessage() error_dialog.showMessage("Unexpected error: " + str(e)) self.signal.sig.emit(False)
def _allowRabbitMQchanged(self, checked): PX_FACTOR = QtWidgets.QApplication.instance().PX_FACTOR if checked: try: self.rabbitMQServer.start() except Exception as ex: # maybe rabbitMQ is not installed # needs to assign to self, otherwise garbage collected self._errm = QtWidgets.QErrorMessage() self._errm.showMessage("""Could not load RabbitMQ %s: %s Have you installed it? https://www.rabbitmq.com""" % (type(ex).__name__, ex.args)) self.cb_allowRabbit.setChecked(False) self.cb_allowRabbit.setEnabled(False) return # update size tt = self.gui.menuBar().file_preferences s = tt.minimumSize() h, w = s.height(), s.width() tt.setMinimumSize(w + 600 * PX_FACTOR, h + 600 * PX_FACTOR) else: self.rabbitMQServer.stop() # update size tt = self.gui.menuBar().file_preferences s = tt.minimumSize() h, w = s.height(), s.width() if h: tt.setMinimumSize(w - 600 * PX_FACTOR, h - 600 * PX_FACTOR) self._rab_opts.setVisible(checked) self.cb_confirm.setVisible(checked)
def process_data(self, *event): """Gets the prep times and populates the T1/T2 plot""" # check that user has drawn all of the required ROIs for ii, fn in enumerate(self.image_filename_list): if self.included_slices[ii] and not fn in self.image_ROIs: error = QtWidgets.QErrorMessage() error.showMessage( "You must draw an ROI on every included slice before you can fit the data. Use the 'All Slices' option if the ROIs are conincident accross the slices" ) error.exec_() return roi_list = [] for image_filename in self.image_filename_list: roi_list.append(self.image_ROIs[image_filename]) if not len(self.images) > 0: error = QtWidgets.QErrorMessage() error.showMessage( 'You must load a series of dicom images before fitting the data' ) error.exec_() return # todo add error message if images or ROI not loaded relaxation_type = self.combo_relax.currentText() axes = self.plot_graph.axes axes.clear() fit_type = self.combo_type.currentText() if relaxation_type == 'T1': self.t2 = 0 ti, signal, stddev = get_T1_decay_signal(self.image_attributes, self.images, roi_list, self.included_slices) if not len(ti) or ti[0] == 0: error = QtWidgets.QErrorMessage() error.showMessage( 'Failed to find T1 recovery times for this dataset, ensure that this is a T1 series' ) error.exec_() return axes.errorbar(ti, signal, stddev, fmt='o') axes.set_xlabel('inversion time (ms)') axes.set_ylabel('signal intensity') # inversion_recovery = fitting.model( # 'abs(M0*(1-2*aa*exp(-x/T1)))', {'M0': signal.max(), 'aa': 1, 'T1': 1000}) inversion_recovery = fitting.model('abs(A-B*exp(-x/T1))', { 'A': signal.max(), 'B': 0.5 * signal.max(), 'T1': 1000 }) # Initial T1 guess based on null time ti = np.array(ti) # necessary for the next line to work if 20000 not in ti: T1_guess = -ti[np.where(signal == signal.min())] / np.log(0.5) inversion_recovery['T1'] = T1_guess[0] inversion_recovery['B'] = 2 * signal.max() bootstrap_signals = bootstrap_decay_signal(self.image_attributes, self.images, roi_list, self.included_slices, iterations=100) inversion_recovery.fit(ti, signal, stddev) par_uncertainties = fit_bootstrap(ti, bootstrap_signals, inversion_recovery) fix_x_points = np.arange(0, 1.3 * np.max(ti), 1) axes.plot(fix_x_points, inversion_recovery(fix_x_points), 'b') # T1_corr = inversion_recovery['T1'].value * \ # (2 * inversion_recovery['aa'].value - 1) T1_corr = inversion_recovery['T1'].value * ( inversion_recovery['B'].value / inversion_recovery['A'].value - 1) # Use error propagation to obtain uncertainty in LL corrected T1 # temp = np.sqrt((par_uncertainties['aa'] / inversion_recovery['aa'].value)**2 + ( # par_uncertainties['T1'] / inversion_recovery['T1'].value)**2) # T1_corr_unc = np.sqrt(temp**2 + par_uncertainties['T1']**2) T1_corr_unc = T1_corr * np.sqrt( (par_uncertainties['A'] / inversion_recovery['A'].value)**2 + (par_uncertainties['B'] / inversion_recovery['B'].value)**2 + (par_uncertainties['T1'] / inversion_recovery['T1'].value)**2) resids = (inversion_recovery(ti) - np.array(signal))**2 / np.array(signal)**2 RMSD = 100 * np.sqrt(np.mean(resids)) str1 = r'$\rm{T_1=%.0f \pm %.0f\ ms}$' % ( inversion_recovery['T1'].value, par_uncertainties['T1']) if 20000 in ti: str2 = '' else: str2 = r'$\rm{T_1\ (LL\ corr)=%.0f \pm %.0f\ ms}$' % ( T1_corr, T1_corr_unc) str3 = r'$\rm{RMSD=%.1f \%%}$' % (RMSD) #axes.text(0.5, 0.5, "T1 value, LL corrected : {}ms".format(round(T1_corr),0), transform=axes.transAxes) axes.text(0.4, 0.2, str1, transform=axes.transAxes, fontsize=16) axes.text(0.4, 0.1, str2, transform=axes.transAxes, fontsize=16) axes.set_title(str3, fontsize=16) elif relaxation_type == 'T2': te, signal, stddev = get_T2_decay_signal(self.dicom_list, self.images, roi_list, self.included_slices) # throw an error if no T2 prep times found in the dicom header if not len(te): error = QtWidgets.QErrorMessage() error.showMessage( 'Failed to find prep times for this dataset, ensure that this is a T2 series' ) error.exec_() return axes.errorbar(te, signal, stddev, fmt='o') axes.set_xlabel('TE time (ms)') axes.set_ylabel('signal intensity') start, stop = 0.5 * np.min(te), 1.25 * np.max(te) fit_x_points = np.linspace(start, stop, 1000) if fit_type == '2': spin_echo = fitting.model('M0*exp(-x/T2)', { 'M0': np.max(signal), 'T2': 150 }) elif fit_type == '3': spin_echo = fitting.model('M0*exp(-x/T2) + B', { 'M0': np.max(signal), 'T2': 150, 'B': signal[0] }) #spin_echo.fit(te, signal, stddev) spin_echo.fit(te, signal, np.ones_like(signal)) axes.plot(fit_x_points, spin_echo(fit_x_points), 'b') resids = (spin_echo(np.array(te)) - np.array(signal))**2 / np.array(signal)**2 RMSD = 100 * np.sqrt(np.mean(resids)) bootstrap_signals = bootstrap_decay_signal(self.image_attributes, self.images, roi_list, self.included_slices, iterations=100) par_uncertainties = fit_bootstrap(te, bootstrap_signals, spin_echo) str1 = r'$\rm{T_2=%.0f \pm %.0f\ ms, RMSD=%.1f \%%}$' % ( spin_echo['T2'].value, par_uncertainties['T2'], RMSD) #axes.text(0.3, 0.9, str1, transform=axes.transAxes, fontsize=16) axes.set_title(str1, fontsize=16) else: raise NotImplementedError( "This mapping type's fitting algorithm has not been implemented yet" ) axes.set_xlim(xmin=-5) self.plot_graph.figure.canvas.draw()
def choose_dir(self, *event): """opens a directory choose dialog box, allows the user to select their dicom series of interest and loads that series.""" self.plot_graph.axes.clear() self.plot_graph.figure.canvas.draw() if self.directory: out = QtWidgets.QFileDialog.getExistingDirectory( directory=os.path.split(self.directory)[0], caption='MRI Data Directory') else: out = QtWidgets.QFileDialog.getExistingDirectory( caption='MRI Data Directory') if out: self.image_index = 0 self.t2 = 0 # is it a T2 series? self.image_filename = None self.image_ROIs = {} self.image_filename_list = [] self.grey_activeROI = None self.color_activeROI = None self.roi_path = None self.images, self.image_attributes = [], [] self.plot_graph.axes.clear() self.clear_roi() self.directory = out self.roi_path = os.path.join(self.directory, '.ROIs') self.images, self.image_attributes, self.dicom_list = blood_tools.read_dicoms( out, ['InversionTime', 'PixelSpacing']) VB17_prep_times = blood_tools.get_T2_prep_times_VB17( self.dicom_list) VE11_prep_times = blood_tools.get_T2_prep_times_VE11( self.dicom_list) VD13_prep_times = blood_tools.get_T2_prep_times_VD13A( self.dicom_list) if VE11_prep_times: self.prep_times = VE11_prep_times if VB17_prep_times: self.prep_times = VB17_prep_times if VD13_prep_times: self.prep_times = VD13_prep_times #for some reason, zero prep time image gets no prep time, assign it TE=2000 if len(self.prep_times) < len(self.dicom_list): self.prep_times = np.concatenate( [np.array([2000]), self.prep_times]) if not self.images: error = QtWidgets.QErrorMessage() error.showMessage( 'The selected directory does not contain a DICOM series ' 'which this widget is capable of loading') error.exec_() return if len(self.prep_times) == len(self.images): self.t2 = 1 self.image_index = np.argsort(self.prep_times)[0] self.combo_relax.setCurrentIndex(1) self.image_pixel_spacing = self.image_attributes[0]['PixelSpacing'] # initiate included slices to be all True self.included_slices = [True for _ in range(len(self.images))] for attributes in self.image_attributes: self.image_filename_list.append(attributes['filename']) self.image_filename = self.image_filename_list[self.image_index] colormap = self.combo_colormap.currentText() self.plot_im.make_image(self.images[self.image_index], colormap, self.vmin, self.vmax) axes = self.plot_im.axes if self.t2: title_str = 'TE=%.0f ms' % self.prep_times[self.image_index] else: inversion_times = [ att['InversionTime'] for att in self.image_attributes ] title_str = 'TI=%.0f ms' % inversion_times[self.image_index] axes.set_title(title_str) self.controls_enabled(True) num, demon = '01', str(len(self.images)).rjust(2, '0') self.slice_label.setText("{}/{}".format(num, demon)) else: # user hit the cancel or x button to leave the dialog pass
def start_clicked( self ): #todo: move the logic elements of this function to the logic module """ Handling the Start button to stop and restart the counter. """ # print('start_clicked called in gui') if self._laser_logic.module_state() == 'locked': print('STOP TERASCAN') # Disable/enable buttons as appropriate, update gui self._mw.replot_pushButton.setEnabled(True) self._mw.run_scan_Action.setEnabled(False) self._mw.status_disp.setText( 'stopping scan') #is not being seen.? fixme self._laser_logic.current_state = 'stopping scan' #is not being seen fixme self._mw.run_scan_Action.setText( 'Start counter' ) #this also isn't working as far as I can tell fixme # Stop the counter self.sigStopCounter.emit() # Enable the "start/stop scan" button Todo maybe wait for signal before enable? self._mw.run_scan_Action.setEnabled(True) else: print('START TERASCAN') # Disable/enable buttons as appropriate, update gui #self._laser_logic.current_state = 'starting scan' self._mw.status_disp.setText('starting scan') self._mw.replot_pushButton.setEnabled(False) self._mw.run_scan_Action.setEnabled(False) self._mw.run_scan_Action.setText( 'Stop counter') #not sure if this is working fixme # Grab terascan parameters startWvln, stopWvln, scantype, scanrate, numScans = self.get_scan_info( ) # More update gui self._mw.scanNumber_label.setText( str(self._laser_logic.repetition_count)) self._mw.scanNumber_label.setText("Scan {0:d} of {1:d}".format( self._laser_logic.repetition_count + 1, numScans)) # Check for input parameter errors. E.G., stop_wavelength should be less than start_wavelength if startWvln >= stopWvln: error_dialog = QtWidgets.QErrorMessage() error_dialog.showMessage( 'ERROR: start wavelength must be less than stop wavelength' ) error_dialog.exec() return self._laser_logic.module_state() # save terascan parameters to laser module self._laser_logic.scanParams = { "scanbounds": (startWvln, stopWvln), "scantype": scantype, "scanrate": scanrate, "numScans": numScans } # Start the counter self.sigStartCounter.emit() # Enable clicking of "start/stop" button self._mw.run_scan_Action.setEnabled(True) # print('start_clicked finished in gui') return self._laser_logic.module_state()
def load_new_dataset(main_widget, file_path, save_dir_path, trials=None, single=False, load_into_mem=True, override_load_warning=False): """ Function to load a initialize a new DataHandler object and the GUI with the data Parameters ---------- main_widget : MainWidget The main widget for the GUI file_path : str Either the folder that contains the trials or the file to load save_dir_path : str The path to the save directory trials : List[str] A list of trials either paths to files or folders single Whether to load the list of trials as a single one, ie like they are each only one time point so load the entire folder as one. override_many_files : bool Whether to give user dialog to choose whether to rearange files if there are over 250 Returns ------- Nothing """ if (main_widget.checkThreadRunning()): if main_widget.data_handler is not None: main_widget.data_handler.__del__() main_widget.data_handler = None pass if single: try: dir_path = os.path.dirname(file_path) main_widget.data_handler = DataHandler( data_path=dir_path, trials=[os.path.basename(file_path)], save_dir_path=save_dir_path, save_dir_already_created=False, load_into_mem=load_into_mem) main_widget.init_w_data() except Exception as e: logger1.error(e) error_dialog = QtWidgets.QErrorMessage(main_widget.main_window) error_dialog.showMessage( "Loading Failed please make sure it is a valid file") # error_dialog.exec_() elif not trials: try: dir_path = os.path.dirname(file_path) main_widget.data_handler = DataHandler( data_path=dir_path, trials=[os.path.basename(file_path)], save_dir_path=save_dir_path, save_dir_already_created=False, load_into_mem=load_into_mem) main_widget.init_w_data() except Exception as e: logger1.error(e) error_dialog = QtWidgets.QErrorMessage() error_dialog.showMessage( "Loading Failed please make sure it is a valid file") elif trials: logger1.debug("Trials:" + str(trials)) if len(trials) == 0: error_dialog = QtWidgets.QErrorMessage() error_dialog.showMessage("Please select at least one trial") try: main_widget.data_handler = DataHandler( data_path=file_path, trials=trials, save_dir_path=save_dir_path, save_dir_already_created=False, load_into_mem=load_into_mem) main_widget.init_w_data() except Exception as e: logger1.error(e) error_dialog = QtWidgets.QErrorMessage() error_dialog.showMessage( "Loading Failed please make sure it is a valid folder and all trials" + " are valid files")