From c1002fbcd0765a264c646e770b5666d91bd2ca44 Mon Sep 17 00:00:00 2001 From: "LAKESIDE\\LindaT18" Date: Wed, 7 Aug 2019 16:22:57 -0700 Subject: [PATCH 01/25] load data from h5, spec scan: init work on handling pkl w/o scan params --- PythonGUI_apps/FLIM_analysis/FLIM_plot.py | 75 +++++----- .../Spectrum_analysis/Spectra_plot_fit.py | 130 +++++++++++------- .../Spectrum_analysis/scan_params_input.ui | 68 +++++++++ 3 files changed, 187 insertions(+), 86 deletions(-) create mode 100644 PythonGUI_apps/Spectrum_analysis/scan_params_input.ui diff --git a/PythonGUI_apps/FLIM_analysis/FLIM_plot.py b/PythonGUI_apps/FLIM_analysis/FLIM_plot.py index a17c7c5..8ba8d49 100644 --- a/PythonGUI_apps/FLIM_analysis/FLIM_plot.py +++ b/PythonGUI_apps/FLIM_analysis/FLIM_plot.py @@ -33,7 +33,7 @@ def __init__(self): self.ui.setupUi(self) #set up ui signals - self.ui.load_scan_pushButton.clicked.connect(self.open_pkl_file) + self.ui.load_scan_pushButton.clicked.connect(self.open_file) self.ui.plot_intensity_sums_pushButton.clicked.connect(self.plot_intensity_sums) self.ui.plot_raw_hist_data_pushButton.clicked.connect(self.plot_raw_scan) self.ui.save_intensities_image_pushButton.clicked.connect(self.save_intensities_image) @@ -45,11 +45,18 @@ def __init__(self): self.show() - def open_pkl_file(self): + def open_file(self): """ Open FLIM scan file """ try: - self.filename = QtWidgets.QFileDialog.getOpenFileName(self) - self.pkl_file = pickle.load(open(self.filename[0], 'rb')) + self.filename = QtWidgets.QFileDialog.getOpenFileName(self, filter="Scan files (*.pkl *.h5)") + if ".pkl" in self.filename[0]: + self.flim_scan_file = pickle.load(open(self.filename[0], 'rb')) + self.scan_file_type = "pkl" + elif ".h5" in self.filename[0]: + self.flim_scan_file = h5py.File(self.filename[0], 'r') + self.scan_file_type = "h5" + self.get_data_params() + # self.pkl_file = pickle.load(open(self.filename[0], 'rb')) except Exception as err: print(format(err)) @@ -61,24 +68,37 @@ def import_pkl_to_convert(self): except: pass + def get_data_params(self): + + data = self.flim_scan_file + if self.scan_file_type == "pkl": + self.x_scan_size = data['Scan Parameters']['X scan size (um)'] + self.y_scan_size = data['Scan Parameters']['Y scan size (um)'] + self.x_step_size = data['Scan Parameters']['X step size (um)'] + self.y_step_size = data['Scan Parameters']['Y step size (um)'] + self.hist_data = data['Histogram data'] + self.time_data = data['Time data'] + else: #run this if scan file is h5 + self.x_scan_size = data['Scan Parameters'].attrs['X scan size (um)'] + self.y_scan_size = data['Scan Parameters'].attrs['Y scan size (um)'] + self.x_step_size = data['Scan Parameters'].attrs['X step size (um)'] + self.y_step_size = data['Scan Parameters'].attrs['Y step size (um)'] + self.hist_data = data['Histogram data'][()] #get dataset values + self.time_data = data['Time data'][()] + + self.numb_x_pixels = int(self.x_scan_size/self.x_step_size) + self.numb_y_pixels = int(self.y_scan_size/self.y_step_size) + + def plot_intensity_sums(self): try: - data = self.pkl_file - self.numb_pixels_X = int((data['Scan Parameters']['X scan size (um)'])/(data['Scan Parameters']['X step size (um)'])) - self.numb_pixels_Y = int((data['Scan Parameters']['Y scan size (um)'])/(data['Scan Parameters']['Y step size (um)'])) - self.x_step_size = float(data['Scan Parameters']['X step size (um)']) - self.x_scan_size = float(data['Scan Parameters']['X scan size (um)']) - self.y_step_size = float(data['Scan Parameters']['Y step size (um)']) - self.y_scan_size = float(data['Scan Parameters']['Y scan size (um)']) - - hist_data = data["Histogram data"] - hist_data = np.reshape(hist_data, newshape=(hist_data.shape[0], self.numb_pixels_X*self.numb_pixels_Y)) - self.intensity_sums = np.sum(hist_data, axis=0) #sum intensities for each pixel - self.intensity_sums = np.reshape(self.intensity_sums, newshape=(self.numb_pixels_X, self.numb_pixels_Y)) + self.hist_data = np.reshape(self.hist_data, newshape=(self.hist_data.shape[0], self.numb_x_pixels*self.numb_y_pixels)) + self.intensity_sums = np.sum(self.hist_data, axis=0) #sum intensities for each pixel + self.intensity_sums = np.reshape(self.intensity_sums, newshape=(self.numb_x_pixels, self.numb_y_pixels)) self.ui.intensity_sums_viewBox.view.invertY(False) # stop y axis invert self.ui.intensity_sums_viewBox.setImage(self.intensity_sums, scale= - (data['Scan Parameters']['X step size (um)'], - data['Scan Parameters']['Y step size (um)'])) + (self.x_step_size, + self.y_step_size)) self.ui.intensity_sums_viewBox.roi.setSize([self.x_scan_size, self.y_step_size]) #line roi scale = pg.ScaleBar(size=1,suffix='um') scale.setParentItem(self.ui.intensity_sums_viewBox.view) @@ -112,23 +132,12 @@ def line_profile_update_plot(self): def plot_raw_scan(self): try: - data = self.pkl_file - self.numb_pixels_X = int((data['Scan Parameters']['X scan size (um)'])/(data['Scan Parameters']['X step size (um)'])) - self.numb_pixels_Y = int((data['Scan Parameters']['Y scan size (um)'])/(data['Scan Parameters']['Y step size (um)'])) - self.x_step_size = float(data['Scan Parameters']['X step size (um)']) - self.x_scan_size = float(data['Scan Parameters']['X scan size (um)']) - self.y_step_size = float(data['Scan Parameters']['Y step size (um)']) - self.y_scan_size = float(data['Scan Parameters']['Y scan size (um)']) - # TODO test line scan plots - hist_data = data['Histogram data'] - - self.hist_image = np.reshape(hist_data, newshape=(hist_data.shape[0],self.numb_pixels_X,self.numb_pixels_Y)) - time_data = data['Time data'] - self.times = time_data[:, 0, 0]*1e-3 + self.hist_image = np.reshape(self.hist_data, newshape=(self.hist_data.shape[0],self.numb_x_pixels,self.numb_y_pixels)) + self.times = self.time_data[:, 0, 0]*1e-3 self.ui.raw_hist_data_viewBox.view.invertY(False) # stops y-axis invert self.ui.raw_hist_data_viewBox.setImage(self.hist_image, scale= - (data['Scan Parameters']['X step size (um)'], - data['Scan Parameters']['Y step size (um)']), xvals=self.times) + (self.x_step_size, + self.y_step_size), xvals=self.times) self.ui.raw_hist_data_viewBox.roi.setSize([self.x_scan_size, self.y_scan_size]) # if self.ui.compare_checkBox.isChecked(): # self.ui.imv2.setImage(self.hist_image, scale= (data['Scan Parameters']['X step size (um)'], diff --git a/PythonGUI_apps/Spectrum_analysis/Spectra_plot_fit.py b/PythonGUI_apps/Spectrum_analysis/Spectra_plot_fit.py index 005746a..8960bf1 100644 --- a/PythonGUI_apps/Spectrum_analysis/Spectra_plot_fit.py +++ b/PythonGUI_apps/Spectrum_analysis/Spectra_plot_fit.py @@ -60,6 +60,7 @@ def __init__(self): self.ui.importSpec_pushButton.clicked.connect(self.open_file) self.ui.importBck_pushButton.clicked.connect(self.open_bck_file) self.ui.importWLRef_pushButton.clicked.connect(self.open_wlref_file) + self.ui.load_spectra_scan_pushButton.clicked.connect(self.open_spectra_scan_file) self.ui.load_bck_file_pushButton.clicked.connect(self.open_spectra_bck_file) self.ui.load_fitted_scan_pushButton.clicked.connect(self.open_fit_scan_file) @@ -137,8 +138,14 @@ def open_wlref_file(self): """Open Scan Files""" def open_spectra_scan_file(self): try: - filename = QtWidgets.QFileDialog.getOpenFileName(self) - self.spec_scan_file = pickle.load(open(filename[0], 'rb')) + filename = QtWidgets.QFileDialog.getOpenFileName(self, filter="Scan files (*.pkl *.h5)") + if ".pkl" in filename[0]: + self.spec_scan_file = pickle.load(open(filename[0], 'rb')) + self.scan_file_type = "pkl" + elif ".h5" in filename[0]: + self.spec_scan_file = h5py.File(filename[0], 'r') + self.scan_file_type = "h5" + self.get_data_params() self.ui.result_textBrowser2.append("Done Loading - Spectra Scan File") except Exception as e: self.ui.result_textBrowser2.append(str(e)) @@ -262,13 +269,13 @@ def clear_check(self): return False """Open param window and get peak center range values and assign it to variables to use later""" - # def configure_fit_params(self): - # self.param_window = ParamWindow() + def configure_scan_params(self): + self.param_window = ParamWindow() # self.param_window.peak_range.connect(self.peak_range) - def peak_range(self, peaks): - self.center_min = peaks[0] - self.center_max = peaks[1] + # def peak_range(self, peaks): + # self.center_min = peaks[0] + # self.center_max = peaks[1] def fit_and_plot(self): @@ -409,12 +416,41 @@ def pub_ready_plot_export(self): """ Scan spectra functions """ + def get_data_params(self): + data = self.spec_scan_file + if self.scan_file_type == "pkl": + self.intensities = data['Intensities'] + self.wavelengths = data['Wavelengths'] + try: + self.x_scan_size = data['Scan Parameters']['X scan size (um)'] + self.y_scan_size = data['Scan Parameters']['Y scan size (um)'] + self.x_step_size = data['Scan Parameters']['X step size (um)'] + self.y_step_size = data['Scan Parameters']['Y step size (um)'] + except: # TODO test and debug loading pkl file w/o scan parameters + self.configure_scan_params() + while not hasattr(self, "scan_params_entered"): + pass + self.x_scan_size = self.param_window.ui.x_scan_size_spinBox.value() + self.y_scan_size = self.param_window.ui.y_scan_size_spinBox.value() + self.x_step_size = self.param_window.ui.x_step_size_spinBox.value() + self.y_step_size = self.param_window.ui.y_step_size_spinBox.value() + + else: #run this if scan file is h5 + self.x_scan_size = data['Scan Parameters'].attrs['X scan size (um)'] + self.y_scan_size = data['Scan Parameters'].attrs['Y scan size (um)'] + self.x_step_size = data['Scan Parameters'].attrs['X step size (um)'] + self.y_step_size = data['Scan Parameters'].attrs['Y step size (um)'] + self.intensities = data['Intensities'][()] #get dataset values + self.wavelengths = data['Wavelengths'][()] + + self.numb_x_pixels = int(self.x_scan_size/self.x_step_size) + self.numb_y_pixels = int(self.y_scan_size/self.y_step_size) + def plot_fit_scan(self): try: if self.ui.use_raw_scan_settings.isChecked(): - data = self.spec_scan_file - num_x = int((data['Scan Parameters']['X scan size (um)'])/(data['Scan Parameters']['X step size (um)'])) - num_y = int((data['Scan Parameters']['Y scan size (um)'])/(data['Scan Parameters']['Y step size (um)'])) + num_x = self.numb_x_pixels + num_y =self.numb_y_pixels else: num_x = self.ui.num_x_spinBox.value() num_y = self.ui.num_y_spinBox.value() @@ -441,8 +477,8 @@ def plot_fit_scan(self): if self.ui.use_raw_scan_settings.isChecked(): self.ui.fit_scan_viewbox.setImage(self.img, scale= - (data['Scan Parameters']['X step size (um)'], - data['Scan Parameters']['Y step size (um)'])) + (self.x_step_size, + self.y_step_size)) scale = pg.ScaleBar(size=2,suffix='um') scale.setParentItem(self.ui.fit_scan_viewbox.view) scale.anchor((1, 1), (1, 1), offset=(-30, -30)) @@ -457,21 +493,16 @@ def plot_fit_scan(self): def plot_raw_scan(self): try: - data = self.spec_scan_file - numb_pixels_X = int((data['Scan Parameters']['X scan size (um)'])/(data['Scan Parameters']['X step size (um)'])) - numb_pixels_Y = int((data['Scan Parameters']['Y scan size (um)'])/(data['Scan Parameters']['Y step size (um)'])) # TODO test line scan plots - intensities = data['Intensities'].T #this is only there because of how we are saving the data in the app + intensities = self.intensities.T #this is only there because of how we are saving the data in the app - intensities = np.reshape(intensities, newshape=(2048,numb_pixels_X,numb_pixels_Y)) - - wavelengths = data['Wavelengths'] + intensities = np.reshape(intensities, newshape=(2048,self.numb_x_pixels, self.numb_y_pixels)) self.ui.raw_scan_viewbox.view.invertY(False) self.ui.raw_scan_viewbox.setImage(intensities, scale= - (data['Scan Parameters']['X step size (um)'], - data['Scan Parameters']['Y step size (um)']), xvals=wavelengths) + (self.x_step_size, + self.y_step_size), xvals=self.wavelengths) #roi_plot = self.ui.raw_scan_viewBox.getRoiPlot() @@ -485,21 +516,16 @@ def plot_raw_scan(self): def plot_intensity_sums(self): try: - data = self.spec_scan_file - numb_pixels_X = int((data['Scan Parameters']['X scan size (um)'])/(data['Scan Parameters']['X step size (um)'])) - numb_pixels_Y = int((data['Scan Parameters']['Y scan size (um)'])/(data['Scan Parameters']['Y step size (um)'])) # TODO test line scan plots - intensities = data['Intensities'] - #intensities = np.reshape(intensities, newshape=(2048, numb_pixels_X*numb_pixels_Y)) - sums = np.sum(intensities, axis=-1) - sums = np.reshape(sums, newshape=(numb_pixels_X, numb_pixels_Y)) + sums = np.sum(self.intensities, axis=-1) + sums = np.reshape(sums, newshape=(self.numb_x_pixels, self.numb_y_pixels)) self.ui.intensity_sums_viewBox.setImage(sums, scale= - (data['Scan Parameters']['X step size (um)'], - data['Scan Parameters']['Y step size (um)'])) + (self.x_step_size, + self.y_step_size)) self.ui.intensity_sums_viewBox.view.invertY(False) scale = pg.ScaleBar(size=2,suffix='um') @@ -522,10 +548,10 @@ def fit_and_plot_scan(self): ref = self.bck_file index = (ref[:,0]>start_nm) & (ref[:,0] + + Form + + + + 0 + 0 + 542 + 211 + + + + Form + + + + + + X scan size + + + + + + + + + + Y scan size + + + + + + + + + + X step size + + + + + + + + + + Y step size + + + + + + + + + + Done + + + + + + + + From 9099bc8202611aa4f23086bb6060340a8aebd06c Mon Sep 17 00:00:00 2001 From: "LAKESIDE\\LindaT18" Date: Mon, 12 Aug 2019 10:55:16 -0700 Subject: [PATCH 02/25] lifetime: added prompt for skip rows, can now load csv --- .../Lifetime_analysis/Lifetime_plot_fit.py | 38 +++++++++++++++-- PythonGUI_apps/Lifetime_analysis/skip_rows.ui | 42 +++++++++++++++++++ 2 files changed, 76 insertions(+), 4 deletions(-) create mode 100644 PythonGUI_apps/Lifetime_analysis/skip_rows.ui diff --git a/PythonGUI_apps/Lifetime_analysis/Lifetime_plot_fit.py b/PythonGUI_apps/Lifetime_analysis/Lifetime_plot_fit.py index ec792f2..6416eca 100644 --- a/PythonGUI_apps/Lifetime_analysis/Lifetime_plot_fit.py +++ b/PythonGUI_apps/Lifetime_analysis/Lifetime_plot_fit.py @@ -87,20 +87,29 @@ def __init__(self): self.out = None # output file after fitting self.data_list = [] self.show() + def open_file(self): """ Open data file """ # try: self.filename = QtWidgets.QFileDialog.getOpenFileName(self) try: - self.file = np.loadtxt(self.filename[0], skiprows=10) -# except ValueError: -# self.file = np.loadtxt(filename[0], skiprows=10) + if ".csv" in self.filename[0] or ".txt" in self.filename[0]: #if txt or csv, prompt user to enter # of rows to skip + self.skip_rows_window = SkipRowsWindow() + self.skip_rows_window.skip_rows_signal.connect(self.open_with_skip_rows_window) except UnicodeDecodeError: self.file = read_picoharp_phd(self.filename[0]) except: pass + def open_with_skip_rows_window(self): + """ Prompts user to enter how many rows to skip """ + self.skip_rows = self.skip_rows_window.ui.skip_rows_spinBox.value() + if ".txt" in self.filename[0]: + self.file = np.loadtxt(self.filename[0], skiprows=self.skip_rows) + elif ".csv" in self.filename[0]: + self.file = np.genfromtxt(self.filename[0], skip_header=self.skip_rows, delimiter=",") + def open_irf_file(self): """ Open file with irf - enabled if 'load separate irf' is checled """ filename = QtWidgets.QFileDialog.getOpenFileName(self) @@ -465,7 +474,6 @@ def export_data(self): self.data_list = [] file.close() - def pub_ready_plot_export(self): try: filename = QtWidgets.QFileDialog.getSaveFileName(self,caption="Filename with EXTENSION") @@ -497,6 +505,28 @@ def close_application(self): else: pass +"""Skip rows GUI""" +ui_file_path = (base_path / "skip_rows.ui").resolve() +skiprows_WindowTemplate, skiprows_TemplateBaseClass = pg.Qt.loadUiType(ui_file_path) + +class SkipRowsWindow(skiprows_TemplateBaseClass): + + skip_rows_signal = QtCore.pyqtSignal() #signal to help with pass info back to MainWindow + + def __init__(self): + skiprows_TemplateBaseClass.__init__(self) + + # Create the param window + self.ui = skiprows_WindowTemplate() + self.ui.setupUi(self) + self.ui.done_pushButton.clicked.connect(self.done) + self.setWindowFlag(QtCore.Qt.WindowCloseButtonHint, False) + self.show() + + def done(self): + self.skip_rows_signal.emit() + self.close() + def run(): win = MainWindow() QtGui.QApplication.instance().exec_() diff --git a/PythonGUI_apps/Lifetime_analysis/skip_rows.ui b/PythonGUI_apps/Lifetime_analysis/skip_rows.ui new file mode 100644 index 0000000..35a4e6b --- /dev/null +++ b/PythonGUI_apps/Lifetime_analysis/skip_rows.ui @@ -0,0 +1,42 @@ + + + Form + + + + 0 + 0 + 413 + 94 + + + + Enter rows to skip + + + + + + Rows to skip + + + + + + + 10 + + + + + + + Done + + + + + + + + From 6a0406ca42ee9d3fa36178a4e084a075888e031e Mon Sep 17 00:00:00 2001 From: "LAKESIDE\\LindaT18" Date: Mon, 12 Aug 2019 14:03:59 -0700 Subject: [PATCH 03/25] added skip rows prompt for irf --- .../Lifetime_analysis/Lifetime_plot_fit.py | 970 +++++++++--------- 1 file changed, 489 insertions(+), 481 deletions(-) diff --git a/PythonGUI_apps/Lifetime_analysis/Lifetime_plot_fit.py b/PythonGUI_apps/Lifetime_analysis/Lifetime_plot_fit.py index 6416eca..d0c5741 100644 --- a/PythonGUI_apps/Lifetime_analysis/Lifetime_plot_fit.py +++ b/PythonGUI_apps/Lifetime_analysis/Lifetime_plot_fit.py @@ -18,13 +18,13 @@ # local module imports try: - from Lifetime_analysis.Fit_functions import stretch_exp_fit, double_exp_fit, single_exp_fit - from Lifetime_analysis.picoharp_phd import read_picoharp_phd - from Lifetime_analysis.Fit_functions_with_irf import fit_exp_stretch_diffev, fit_exp_stretch_fmin_tnc, fit_multi_exp_diffev, fit_multi_exp_fmin_tnc + from Lifetime_analysis.Fit_functions import stretch_exp_fit, double_exp_fit, single_exp_fit + from Lifetime_analysis.picoharp_phd import read_picoharp_phd + from Lifetime_analysis.Fit_functions_with_irf import fit_exp_stretch_diffev, fit_exp_stretch_fmin_tnc, fit_multi_exp_diffev, fit_multi_exp_fmin_tnc except: - from Fit_functions import stretch_exp_fit, double_exp_fit, single_exp_fit - from Fit_functions_with_irf import fit_exp_stretch_diffev, fit_exp_stretch_fmin_tnc, fit_multi_exp_diffev, fit_multi_exp_fmin_tnc - from picoharp_phd import read_picoharp_phd + from Fit_functions import stretch_exp_fit, double_exp_fit, single_exp_fit + from Fit_functions_with_irf import fit_exp_stretch_diffev, fit_exp_stretch_fmin_tnc, fit_multi_exp_diffev, fit_multi_exp_fmin_tnc + from picoharp_phd import read_picoharp_phd """Recylce params for plotting""" plt.rc('xtick', labelsize = 20) @@ -46,491 +46,499 @@ WindowTemplate, TemplateBaseClass = pg.Qt.loadUiType(uiFile) class MainWindow(TemplateBaseClass): - - def __init__(self): - TemplateBaseClass.__init__(self) - - # Create the main window - self.ui = WindowTemplate() - self.ui.setupUi(self) - self.ui.Res_comboBox.addItems(["0.004","0.008","0.016","0.032","0.064","0.128","0.256","0.512"]) - self.ui.FittingFunc_comboBox.addItems(["Stretched Exponential","Double Exponential", "Single Exponential"]) - self.ui.FittingMethod_comboBox.addItems(["diff_ev", "fmin_tnc"]) - - #set up file menu - self.ui.actionOpen.triggered.connect(self.open_file) - self.ui.actionOpen_IRF_File.triggered.connect(self.open_irf_file) - self.ui.actionSave.triggered.connect(self.save_file) - self.ui.actionExit.triggered.connect(self.close_application) - - #set up ui signals - self.ui.plot_pushButton.clicked.connect(self.plot) - self.ui.fit_pushButton.clicked.connect(self.call_fit_and_plot) - self.ui.clear_pushButton.clicked.connect(self.clear_plot) - self.ui.export_plot_pushButton.clicked.connect(self.pub_ready_plot_export) - self.ui.calculate_srv_pushButton.clicked.connect(self.calculate_srv) - - self.ui.log_checkBox.stateChanged.connect(self.make_semilog) - self.ui.fit_with_irf_checkBox.stateChanged.connect(self.switch_fit_settings) - self.ui.FittingFunc_comboBox.currentTextChanged.connect(self.switch_function_tab) - self.ui.FittingMethod_comboBox.currentTextChanged.connect(self.switch_init_params_groupBox) - self.ui.separate_irf_checkBox.stateChanged.connect(self.switch_open_irf) - self.ui.export_data_pushButton.clicked.connect(self.export_data) - - #set up plot color button - self.plot_color_button = pg.ColorButton(color=(255,0,0)) - self.ui.plot_color_button_container.layout().addWidget(self.plot_color_button) - self.plot_color = self.plot_color_button.color() - self.plot_color_button.sigColorChanged.connect(self.plot_color_changed) - - self.file = None - self.out = None # output file after fitting - self.data_list = [] - self.show() - - - def open_file(self): - """ Open data file """ + + def __init__(self): + TemplateBaseClass.__init__(self) + + # Create the main window + self.ui = WindowTemplate() + self.ui.setupUi(self) + self.ui.Res_comboBox.addItems(["0.004","0.008","0.016","0.032","0.064","0.128","0.256","0.512"]) + self.ui.FittingFunc_comboBox.addItems(["Stretched Exponential","Double Exponential", "Single Exponential"]) + self.ui.FittingMethod_comboBox.addItems(["diff_ev", "fmin_tnc"]) + + #set up file menu + self.ui.actionOpen.triggered.connect(self.open_file) + self.ui.actionOpen_IRF_File.triggered.connect(self.open_irf_file) + self.ui.actionSave.triggered.connect(self.save_file) + self.ui.actionExit.triggered.connect(self.close_application) + + #set up ui signals + self.ui.plot_pushButton.clicked.connect(self.plot) + self.ui.fit_pushButton.clicked.connect(self.call_fit_and_plot) + self.ui.clear_pushButton.clicked.connect(self.clear_plot) + self.ui.export_plot_pushButton.clicked.connect(self.pub_ready_plot_export) + self.ui.calculate_srv_pushButton.clicked.connect(self.calculate_srv) + + self.ui.log_checkBox.stateChanged.connect(self.make_semilog) + self.ui.fit_with_irf_checkBox.stateChanged.connect(self.switch_fit_settings) + self.ui.FittingFunc_comboBox.currentTextChanged.connect(self.switch_function_tab) + self.ui.FittingMethod_comboBox.currentTextChanged.connect(self.switch_init_params_groupBox) + self.ui.separate_irf_checkBox.stateChanged.connect(self.switch_open_irf) + self.ui.export_data_pushButton.clicked.connect(self.export_data) + + #set up plot color button + self.plot_color_button = pg.ColorButton(color=(255,0,0)) + self.ui.plot_color_button_container.layout().addWidget(self.plot_color_button) + self.plot_color = self.plot_color_button.color() + self.plot_color_button.sigColorChanged.connect(self.plot_color_changed) + + self.file = None + self.out = None # output file after fitting + self.data_list = [] + self.show() + + def open_file(self): + """ Open data file """ # try: - self.filename = QtWidgets.QFileDialog.getOpenFileName(self) - try: - if ".csv" in self.filename[0] or ".txt" in self.filename[0]: #if txt or csv, prompt user to enter # of rows to skip - self.skip_rows_window = SkipRowsWindow() - self.skip_rows_window.skip_rows_signal.connect(self.open_with_skip_rows_window) - except UnicodeDecodeError: - self.file = read_picoharp_phd(self.filename[0]) - except: - pass - - def open_with_skip_rows_window(self): - """ Prompts user to enter how many rows to skip """ - self.skip_rows = self.skip_rows_window.ui.skip_rows_spinBox.value() - if ".txt" in self.filename[0]: - self.file = np.loadtxt(self.filename[0], skiprows=self.skip_rows) - elif ".csv" in self.filename[0]: - self.file = np.genfromtxt(self.filename[0], skip_header=self.skip_rows, delimiter=",") - - def open_irf_file(self): - """ Open file with irf - enabled if 'load separate irf' is checled """ - filename = QtWidgets.QFileDialog.getOpenFileName(self) - try: - self.irf_file = np.loadtxt(filename[0], skiprows=10) - except UnicodeDecodeError: - self.irf_file = read_picoharp_phd(filename[0]) - except: - pass - - def save_file(self): - try: - filename = QtWidgets.QFileDialog.getSaveFileName(self) - np.savetxt(filename[0], self.out, fmt = '%.5f', header = 'Time, Raw_PL, Sim_PL', delimiter = ' ') - except: - pass - - def switch_open_irf(self): - """ Handle 'load separate irf' checkbox """ - self.ui.actionOpen_IRF_File.setEnabled(self.ui.separate_irf_checkBox.isChecked()) - - def switch_fit_settings(self): - """ Enable bounds/initial guess groupboxes only when 'Fit with IRF' is checked """ - checked = self.ui.fit_with_irf_checkBox.isChecked() - for func in "str de se".split(" "): - boundsGb = eval("self.ui."+func+"_bounds_groupBox") - #initGb = eval("self.ui."+func+"_init_groupBox") - boundsGb.setEnabled(checked) - #initGb.setEnabled(checked) - if checked == True: - self.switch_init_params_groupBox() - else: - initGb = eval("self.ui."+func+"_init_groupBox") - initGb.setEnabled(checked) - self.ui.FittingMethod_comboBox.setEnabled(checked) - - def switch_function_tab(self): - """ Switch bounds groupbox contents depending on selected fit function """ - fitting_func = self.ui.FittingFunc_comboBox.currentText() - if fitting_func == "Stretched Exponential": - self.ui.fitting_params_stackedWidget.setCurrentIndex(0) - elif fitting_func == "Double Exponential": - self.ui.fitting_params_stackedWidget.setCurrentIndex(1) - elif fitting_func == "Single Exponential": - self.ui.fitting_params_stackedWidget.setCurrentIndex(2) - - def switch_init_params_groupBox(self): - """ Enable initial guess groupbox only when fmin_tnc fit method selected """ - if self.ui.FittingMethod_comboBox.currentText() == "diff_ev": - for func in "str de se".split(" "): - initGb = eval("self.ui."+func+"_init_groupBox") - initGb.setEnabled(False) - #initGb.setEnabled(checked) - elif self.ui.FittingMethod_comboBox.currentText() == "fmin_tnc": - for func in "str de se".split(" "): - initGb = eval("self.ui."+func+"_init_groupBox") - initGb.setEnabled(True) - - def plot_color_changed(self): - """ Grab new plot_color when color button value is changed """ - self.plot_color = self.plot_color_button.color() - - def acquire_settings(self, mode="data"): - """ - Acquire data or irf from channel specified in spinbox. - - mode -- string specifying whether to use data or irf channel (default "data") - """ - self.resolution = float(self.ui.Res_comboBox.currentText()) - if mode == "data": - channel = int(self.ui.Data_channel_spinBox.value()) - elif mode == "irf": - channel = int(self.ui.irf_channel_spinBox.value()) - try: - try: # - if self.ui.separate_irf_checkBox.isChecked() and mode=="irf": #if separate irf, get from irf file - try: - y = self.irf_file[:,channel] - except: - y = self.irf_file.get_curve(channel)[1] - else: #otherwise, get data/irf from data file - y = self.file[:,channel] - except: - res, y = self.file.get_curve(channel) - # TO DO - check if res read in is the same as selected - time_window = int(np.floor(self.file.get_time_window_in_ns(channel))) - y = y[0:time_window] - - length = np.shape(y)[0] - x = np.arange(0, length, 1) * self.resolution - return x,y - - except Exception as e: - self.ui.Result_textBrowser.setText(str(e)) - - def plot(self): - try: - x,y = self.acquire_settings() #get data - if self.ui.normalize_checkBox.isChecked(): - y = y / np.amax(y) - - self.ui.plot.plot(x, y, clear=self.ui.clear_plot_checkBox.isChecked(), pen=pg.mkPen(self.plot_color)) - - try: - self.ui.Result_textBrowser.setText("Integral Counts :\n" "{:.2E}".format( - self.file.get_integral_counts(int(self.ui.Channel_spinBox.value())))) - except: - self.ui.Result_textBrowser.setText("Integral Counts :\n" "{:.2E}".format(np.sum(y))) - except: - pass - self.ui.plot.setLabel('left', 'Intensity', units='a.u.') - self.ui.plot.setLabel('bottom', 'Time (ns)') - - def make_semilog(self): - """ Switch y-log on/off """ - self.ui.plot.setLogMode(False,self.ui.log_checkBox.isChecked()) - - def clear_plot(self): - self.ui.plot.clear() - self.ui.Result_textBrowser.clear() - - def fit_and_plot(self): - """ Fit and plot without IRF """ - try: - x,y = self.acquire_settings() #get data - y_norm = y/np.max(y) #normalized y - - # find the max intensity in the array and start things from there - find_max_int = np.nonzero(y_norm == 1) - y = y[np.asscalar(find_max_int[0]):] - x = x[np.asscalar(find_max_int[0]):] - - t = x - time_fit = t - TRPL_interp = np.interp(time_fit, t, y) - - fit_func = self.ui.FittingFunc_comboBox.currentText() - self.ui.plot.plot(t, y, clear=self.ui.clear_plot_checkBox.isChecked(), pen=pg.mkPen(self.plot_color)) - - if fit_func == "Stretched Exponential": #stretch exponential tab - tc, beta, a, avg_tau, PL_fit = stretch_exp_fit(TRPL_interp, t) - self.out = np.empty((len(t), 3)) - self.out[:,0] = t #time - self.out[:,1] = TRPL_interp #Raw PL - self.out[:,2] = PL_fit # PL fit - self.ui.plot.plot(t, PL_fit, clear=self.ui.clear_plot_checkBox.isChecked(), pen='k') - self.ui.Result_textBrowser.setText("Fit Results:\n\nFit Function: Stretched Exponential" - "\nFit Method: " + "diff_ev" + #TODO : change when diff_ev and fmin_tnc implemented for non-irf - "\nAverage Lifetime = " + str(avg_tau)+ " ns" - "\nCharacteristic Tau = " + str(tc)+" ns" - "\nBeta = "+str(beta)) - self.ui.average_lifetime_spinBox.setValue(avg_tau) - - elif fit_func == "Double Exponential": #double exponential tab - tau1, a1, tau2, a2, avg_tau, PL_fit = double_exp_fit(TRPL_interp, t) - self.out = np.empty((len(t), 3)) - self.out[:,0] = t #time - self.out[:,1] = TRPL_interp #Raw PL - self.out[:,2] = PL_fit # PL fit - self.ui.plot.plot(t, PL_fit, clear=self.ui.clear_plot_checkBox.isChecked(), pen='k') - self.ui.Result_textBrowser.setText("Fit Results:\n\nFit Function: Double Exponential" - "\nFit Method: " + "diff_ev" + - "\nAverage Lifetime = " + str(avg_tau)+ " ns" - "\nTau 1 = " + str(tau1)+" ns" - "\nA 1 = " + str(a1)+ - "\nTau 2 = " + str(tau2)+" ns" - "\nA 2 = " + str(a2)) - #TODO - once tau_avg implemented, set average lifetime spinbox to tau_avg value - - elif fit_func == "Single Exponential": #single exponential tab - tau, a, PL_fit = single_exp_fit(TRPL_interp, t) - self.out = np.empty((len(t), 3)) - self.out[:,0] = t #time - self.out[:,1] = TRPL_interp #Raw PL - self.out[:,2] = PL_fit # PL fit - self.ui.plot.plot(t, PL_fit, clear=self.ui.clear_plot_checkBox.isChecked(), pen='k') - self.ui.Result_textBrowser.setText("Fit Results:\n\nFit Function: Single Exponential" - "\nFit Method: " + "diff_ev" + - "\nLifetime = " + str(tau)+ " ns" - "\nA = " + str(a)) - self.ui.average_lifetime_spinBox.setValue(tau) - - #add fit params to data_list - self.data_list.append("Data Channel: " + str(self.ui.Data_channel_spinBox.value()) + "\n" + self.ui.Result_textBrowser.toPlainText()) - - self.ui.plot.setLabel('left', 'Intensity', units='a.u.') - self.ui.plot.setLabel('bottom', 'Time (ns)') - return self.out - - except Exception as err: - exc_type, exc_obj, exc_tb = sys.exc_info() - print(exc_type, exc_tb.tb_lineno) - - def fit_and_plot_with_irf(self): - """ Fit and plot with IRF """ - try: - x,y = self.acquire_settings() #get data - _, irf_counts = self.acquire_settings(mode="irf") #get irf counts - - #make sure Irf and data have the same length - if len(y) != len(irf_counts): - y = y[0:min(len(y), len(irf_counts))] - irf_counts = irf_counts[0:min(len(y), len(irf_counts))] - x = x[0:min(len(y), len(irf_counts))] - - y_norm = y/np.max(y) #normalized y - irf_norm = irf_counts/np.amax(irf_counts) #normalized irf - - t = x - time_fit = t - y = y_norm - irf_counts = irf_norm - - TRPL_interp = np.interp(time_fit, t, y) - - fit_func = self.ui.FittingFunc_comboBox.currentText() - self.ui.plot.plot(t, y, clear=self.ui.clear_plot_checkBox.isChecked(), pen=pg.mkPen(self.plot_color)) - if fit_func == "Stretched Exponential": #stretched exponential tab - tc_bounds = (self.ui.str_tc_min_spinBox.value(), self.ui.str_tc_max_spinBox.value()) #(0, 10000) - a_bounds = (self.ui.str_a_min_spinBox.value(), self.ui.str_a_max_spinBox.value())#(0.9, 1.1) - beta_bounds = (self.ui.str_beta_min_spinBox.value(), self.ui.str_beta_max_spinBox.value())#(0,1) - noise_bounds = (self.ui.str_noise_min_spinBox.value(), self.ui.str_noise_max_spinBox.value())#(0, 1e4) - stretch_exp_bounds = [tc_bounds, beta_bounds, a_bounds, noise_bounds] - stretch_exp_init_params = [self.ui.str_tc_init_spinBox.value(), self.ui.str_a_init_spinBox.value(), self.ui.str_beta_init_spinBox.value(), self.ui.str_noise_init_spinBox.value()] - - #tc, beta, a, avg_tau, PL_fit = stretch_exp_fit(TRPL_interp, t) + self.filename = QtWidgets.QFileDialog.getOpenFileName(self) + try: + if ".csv" in self.filename[0] or ".txt" in self.filename[0]: #if txt or csv, prompt user to enter # of rows to skip + self.skip_rows_window = SkipRowsWindow() + self.skip_rows_window.skip_rows_signal.connect(self.open_with_skip_rows_window) + except UnicodeDecodeError: + self.file = read_picoharp_phd(self.filename[0]) + except: + pass + + def open_with_skip_rows_window(self): + """ Prompts user to enter how many rows to skip """ + skip_rows = self.skip_rows_window.ui.skip_rows_spinBox.value() + if ".txt" in self.filename[0]: + self.file = np.loadtxt(self.filename[0], skiprows=skip_rows) + elif ".csv" in self.filename[0]: + self.file = np.genfromtxt(self.filename[0], skip_header=skip_rows, delimiter=",") + + def open_irf_file(self): + """ Open file with irf - enabled if 'load separate irf' is checled """ + self.irf_filename = QtWidgets.QFileDialog.getOpenFileName(self) + try: + if ".txt" in self.irf_filename[0] or ".csv" in self.irf_filename[0]: + self.irf_skip_rows_window = SkipRowsWindow() + self.irf_skip_rows_window.skip_rows_signal.connect(self.open_irf_with_skip_rows_window) + except UnicodeDecodeError: + self.irf_file = read_picoharp_phd(self.irf_filename[0]) + except: + pass + + def open_irf_with_skip_rows_window(self): + irf_skip_rows = self.irf_skip_rows_window.ui.skip_rows_spinBox.value() + if ".txt" in self.irf_filename[0]: + self.irf_file = np.loadtxt(self.irf_filename[0], skiprows=irf_skip_rows) + elif ".csv" in self.irf_filename[0]: + self.irf_file = np.genfrontxt(self.irf_filename[0], skip_header=irf_skip_rows, delimiter=",") + + def save_file(self): + try: + filename = QtWidgets.QFileDialog.getSaveFileName(self) + np.savetxt(filename[0], self.out, fmt = '%.5f', header = 'Time, Raw_PL, Sim_PL', delimiter = ' ') + except: + pass + + def switch_open_irf(self): + """ Handle 'load separate irf' checkbox """ + self.ui.actionOpen_IRF_File.setEnabled(self.ui.separate_irf_checkBox.isChecked()) + + def switch_fit_settings(self): + """ Enable bounds/initial guess groupboxes only when 'Fit with IRF' is checked """ + checked = self.ui.fit_with_irf_checkBox.isChecked() + for func in "str de se".split(" "): + boundsGb = eval("self.ui."+func+"_bounds_groupBox") + #initGb = eval("self.ui."+func+"_init_groupBox") + boundsGb.setEnabled(checked) + #initGb.setEnabled(checked) + if checked == True: + self.switch_init_params_groupBox() + else: + initGb = eval("self.ui."+func+"_init_groupBox") + initGb.setEnabled(checked) + self.ui.FittingMethod_comboBox.setEnabled(checked) + + def switch_function_tab(self): + """ Switch bounds groupbox contents depending on selected fit function """ + fitting_func = self.ui.FittingFunc_comboBox.currentText() + if fitting_func == "Stretched Exponential": + self.ui.fitting_params_stackedWidget.setCurrentIndex(0) + elif fitting_func == "Double Exponential": + self.ui.fitting_params_stackedWidget.setCurrentIndex(1) + elif fitting_func == "Single Exponential": + self.ui.fitting_params_stackedWidget.setCurrentIndex(2) + + def switch_init_params_groupBox(self): + """ Enable initial guess groupbox only when fmin_tnc fit method selected """ + if self.ui.FittingMethod_comboBox.currentText() == "diff_ev": + for func in "str de se".split(" "): + initGb = eval("self.ui."+func+"_init_groupBox") + initGb.setEnabled(False) + #initGb.setEnabled(checked) + elif self.ui.FittingMethod_comboBox.currentText() == "fmin_tnc": + for func in "str de se".split(" "): + initGb = eval("self.ui."+func+"_init_groupBox") + initGb.setEnabled(True) + + def plot_color_changed(self): + """ Grab new plot_color when color button value is changed """ + self.plot_color = self.plot_color_button.color() + + def acquire_settings(self, mode="data"): + """ + Acquire data or irf from channel specified in spinbox. + + mode -- string specifying whether to use data or irf channel (default "data") + """ + self.resolution = float(self.ui.Res_comboBox.currentText()) + if mode == "data": + channel = int(self.ui.Data_channel_spinBox.value()) + elif mode == "irf": + channel = int(self.ui.irf_channel_spinBox.value()) + try: + try: # + if self.ui.separate_irf_checkBox.isChecked() and mode=="irf": #if separate irf, get from irf file + try: + y = self.irf_file[:,channel] + except: + y = self.irf_file.get_curve(channel)[1] + else: #otherwise, get data/irf from data file + y = self.file[:,channel] + except: + res, y = self.file.get_curve(channel) + # TO DO - check if res read in is the same as selected + time_window = int(np.floor(self.file.get_time_window_in_ns(channel))) + y = y[0:time_window] + + length = np.shape(y)[0] + x = np.arange(0, length, 1) * self.resolution + return x,y + + except Exception as e: + self.ui.Result_textBrowser.setText(str(e)) + + def plot(self): + try: + x,y = self.acquire_settings() #get data + if self.ui.normalize_checkBox.isChecked(): + y = y / np.amax(y) + + self.ui.plot.plot(x, y, clear=self.ui.clear_plot_checkBox.isChecked(), pen=pg.mkPen(self.plot_color)) + + try: + self.ui.Result_textBrowser.setText("Integral Counts :\n" "{:.2E}".format( + self.file.get_integral_counts(int(self.ui.Channel_spinBox.value())))) + except: + self.ui.Result_textBrowser.setText("Integral Counts :\n" "{:.2E}".format(np.sum(y))) + except: + pass + self.ui.plot.setLabel('left', 'Intensity', units='a.u.') + self.ui.plot.setLabel('bottom', 'Time (ns)') + + def make_semilog(self): + """ Switch y-log on/off """ + self.ui.plot.setLogMode(False,self.ui.log_checkBox.isChecked()) + + def clear_plot(self): + self.ui.plot.clear() + self.ui.Result_textBrowser.clear() + + def fit_and_plot(self): + """ Fit and plot without IRF """ + try: + x,y = self.acquire_settings() #get data + y_norm = y/np.max(y) #normalized y + + # find the max intensity in the array and start things from there + find_max_int = np.nonzero(y_norm == 1) + y = y[np.asscalar(find_max_int[0]):] + x = x[np.asscalar(find_max_int[0]):] + + t = x + time_fit = t + TRPL_interp = np.interp(time_fit, t, y) + + fit_func = self.ui.FittingFunc_comboBox.currentText() + self.ui.plot.plot(t, y, clear=self.ui.clear_plot_checkBox.isChecked(), pen=pg.mkPen(self.plot_color)) + + if fit_func == "Stretched Exponential": #stretch exponential tab + tc, beta, a, avg_tau, PL_fit = stretch_exp_fit(TRPL_interp, t) + self.out = np.empty((len(t), 3)) + self.out[:,0] = t #time + self.out[:,1] = TRPL_interp #Raw PL + self.out[:,2] = PL_fit # PL fit + self.ui.plot.plot(t, PL_fit, clear=self.ui.clear_plot_checkBox.isChecked(), pen='k') + self.ui.Result_textBrowser.setText("Fit Results:\n\nFit Function: Stretched Exponential" + "\nFit Method: " + "diff_ev" + #TODO : change when diff_ev and fmin_tnc implemented for non-irf + "\nAverage Lifetime = " + str(avg_tau)+ " ns" + "\nCharacteristic Tau = " + str(tc)+" ns" + "\nBeta = "+str(beta)) + self.ui.average_lifetime_spinBox.setValue(avg_tau) + + elif fit_func == "Double Exponential": #double exponential tab + tau1, a1, tau2, a2, avg_tau, PL_fit = double_exp_fit(TRPL_interp, t) + self.out = np.empty((len(t), 3)) + self.out[:,0] = t #time + self.out[:,1] = TRPL_interp #Raw PL + self.out[:,2] = PL_fit # PL fit + self.ui.plot.plot(t, PL_fit, clear=self.ui.clear_plot_checkBox.isChecked(), pen='k') + self.ui.Result_textBrowser.setText("Fit Results:\n\nFit Function: Double Exponential" + "\nFit Method: " + "diff_ev" + + "\nAverage Lifetime = " + str(avg_tau)+ " ns" + "\nTau 1 = " + str(tau1)+" ns" + "\nA 1 = " + str(a1)+ + "\nTau 2 = " + str(tau2)+" ns" + "\nA 2 = " + str(a2)) + #TODO - once tau_avg implemented, set average lifetime spinbox to tau_avg value + + elif fit_func == "Single Exponential": #single exponential tab + tau, a, PL_fit = single_exp_fit(TRPL_interp, t) + self.out = np.empty((len(t), 3)) + self.out[:,0] = t #time + self.out[:,1] = TRPL_interp #Raw PL + self.out[:,2] = PL_fit # PL fit + self.ui.plot.plot(t, PL_fit, clear=self.ui.clear_plot_checkBox.isChecked(), pen='k') + self.ui.Result_textBrowser.setText("Fit Results:\n\nFit Function: Single Exponential" + "\nFit Method: " + "diff_ev" + + "\nLifetime = " + str(tau)+ " ns" + "\nA = " + str(a)) + self.ui.average_lifetime_spinBox.setValue(tau) + + #add fit params to data_list + self.data_list.append("Data Channel: " + str(self.ui.Data_channel_spinBox.value()) + "\n" + self.ui.Result_textBrowser.toPlainText()) + + self.ui.plot.setLabel('left', 'Intensity', units='a.u.') + self.ui.plot.setLabel('bottom', 'Time (ns)') + return self.out + + except Exception as err: + exc_type, exc_obj, exc_tb = sys.exc_info() + print(exc_type, exc_tb.tb_lineno) + + def fit_and_plot_with_irf(self): + """ Fit and plot with IRF """ + try: + x,y = self.acquire_settings() #get data + _, irf_counts = self.acquire_settings(mode="irf") #get irf counts + + #make sure Irf and data have the same length + if len(y) != len(irf_counts): + y = y[0:min(len(y), len(irf_counts))] + irf_counts = irf_counts[0:min(len(y), len(irf_counts))] + x = x[0:min(len(y), len(irf_counts))] + + y_norm = y/np.max(y) #normalized y + irf_norm = irf_counts/np.amax(irf_counts) #normalized irf + + t = x + time_fit = t + y = y_norm + irf_counts = irf_norm + + TRPL_interp = np.interp(time_fit, t, y) + + fit_func = self.ui.FittingFunc_comboBox.currentText() + self.ui.plot.plot(t, y, clear=self.ui.clear_plot_checkBox.isChecked(), pen=pg.mkPen(self.plot_color)) + if fit_func == "Stretched Exponential": #stretched exponential tab + tc_bounds = (self.ui.str_tc_min_spinBox.value(), self.ui.str_tc_max_spinBox.value()) #(0, 10000) + a_bounds = (self.ui.str_a_min_spinBox.value(), self.ui.str_a_max_spinBox.value())#(0.9, 1.1) + beta_bounds = (self.ui.str_beta_min_spinBox.value(), self.ui.str_beta_max_spinBox.value())#(0,1) + noise_bounds = (self.ui.str_noise_min_spinBox.value(), self.ui.str_noise_max_spinBox.value())#(0, 1e4) + stretch_exp_bounds = [tc_bounds, beta_bounds, a_bounds, noise_bounds] + stretch_exp_init_params = [self.ui.str_tc_init_spinBox.value(), self.ui.str_a_init_spinBox.value(), self.ui.str_beta_init_spinBox.value(), self.ui.str_noise_init_spinBox.value()] + + #tc, beta, a, avg_tau, PL_fit = stretch_exp_fit(TRPL_interp, t) # resolution = float(self.ui.Res_comboBox.currentText()) - if self.ui.FittingMethod_comboBox.currentText() == "diff_ev": - bestfit_params, t_avg, bestfit_model, data_array, time_array, irf = fit_exp_stretch_diffev(t, self.resolution, TRPL_interp, irf_counts, stretch_exp_bounds) - else: #if fmin_tnc fitting method selected - bestfit_params, t_avg, bestfit_model, data_array, time_array, irf = fit_exp_stretch_fmin_tnc(t, self.resolution, TRPL_interp, irf_counts, stretch_exp_init_params, stretch_exp_bounds) - self.out = np.empty((len(t), 3)) - self.out[:,0] = t #time - self.out[:,1] = TRPL_interp #Raw PL - self.out[:,2] = bestfit_model # PL fit - self.ui.plot.plot(t, bestfit_model, clear=self.ui.clear_plot_checkBox.isChecked(), pen='k') - self.ui.Result_textBrowser.setText("Fit Results:\n\nFit Function: Stretched Exponential with IRF" - "\nFit Method: "+ self.ui.FittingMethod_comboBox.currentText() + - "\ntau_avg = %.5f ns" - "\nbeta = %.5f" - "\ntau_c = %.5f ns" - "\na = %.5f \nnoise = %.5f counts" %(t_avg, bestfit_params[1], bestfit_params[0], bestfit_params[2], bestfit_params[3])) - #self.effective_lifetime = t_avg - self.ui.average_lifetime_spinBox.setValue(t_avg) - - elif fit_func == "Double Exponential": #double exponential tab - a1_bounds = (self.ui.de_a1_min_spinBox.value(), self.ui.de_a1_max_spinBox.value()) - tau1_bounds = (self.ui.de_tau1_min_spinBox.value(), self.ui.de_tau1_max_spinBox.value()) - a2_bounds = (self.ui.de_a2_min_spinBox.value(), self.ui.de_a2_max_spinBox.value()) - tau2_bounds = (self.ui.de_tau2_min_spinBox.value(), self.ui.de_tau2_max_spinBox.value()) - noise_bounds = (self.ui.de_noise_min_spinBox.value(), self.ui.de_noise_max_spinBox.value()) - double_exp_bounds = [a1_bounds, tau1_bounds, a2_bounds, tau2_bounds, noise_bounds] - double_exp_init_params = [self.ui.de_a1_init_spinBox.value(), self.ui.de_tau1_init_spinBox.value(), self.ui.de_a2_init_spinBox.value(), - self.ui.de_tau2_init_spinBox.value(), self.ui.de_noise_init_spinBox.value()] - - if self.ui.FittingMethod_comboBox.currentText() == "diff_ev": - bestfit_params, bestfit_model, data_array, time_array, irf = fit_multi_exp_diffev(t, self.resolution, TRPL_interp, irf_counts, double_exp_bounds, 2) - #bestfit_params, bestfit_model, data_array, time_array, irf = fit_multi_exp_diffev(t, resolution, TRPL_interp, irf_counts, double_exp_init_bounds, 2) - else: - bestfit_params, bestfit_model, data_array, time_array, irf = fit_multi_exp_fmin_tnc(t, self.resolution, TRPL_interp, irf_counts, double_exp_init_params, double_exp_bounds, 2) - self.out = np.empty((len(t), 3)) - self.out[:,0] = t #time - self.out[:,1] = TRPL_interp #Raw PL - self.out[:,2] = bestfit_model # PL fit - self.ui.plot.plot(t, bestfit_model, clear=self.ui.clear_plot_checkBox.isChecked(), pen='k') - self.ui.Result_textBrowser.setText("Fit Results:\n\nFit Function: Double Exponential with IRF" - "\nFit Method: "+ self.ui.FittingMethod_comboBox.currentText() + - "\na1 = %.5f" - "\ntau1 = %.5f ns" - "\na2 = %.5f" - "\ntau2 = %.5f ns" - "\nnoise = %.5f counts" %(bestfit_params[0], bestfit_params[1], bestfit_params[2], bestfit_params[3], bestfit_params[4])) - #TODO - once tau_avg implemented, set average lifetime spinbox to tau_avg value - - elif fit_func == "Single Exponential": #single exponential tab - a_bounds = (self.ui.se_a_min_spinBox.value(), self.ui.se_a_max_spinBox.value()) - tau_bounds = (self.ui.se_tau_min_spinBox.value(), self.ui.se_tau_max_spinBox.value()) - noise_bounds = (self.ui.se_noise_min_spinBox.value(), self.ui.se_noise_max_spinBox.value()) - single_exp_bounds = [a_bounds, tau_bounds, noise_bounds] - single_exp_init_params = [self.ui.se_a_init_spinBox.value(), self.ui.se_tau_init_spinBox.value(), self.ui.se_noise_init_spinBox.value()] - - if self.ui.FittingMethod_comboBox.currentText() == "diff_ev": - bestfit_params, bestfit_model, data_array, time_array, irf = fit_multi_exp_diffev(t, self.resolution, TRPL_interp, irf_counts, single_exp_bounds, 1) - else: - bestfit_params, bestfit_model, data_array, time_array, irf = fit_multi_exp_fmin_tnc(t, self.resolution, TRPL_interp, irf_counts, single_exp_init_params, single_exp_bounds, 1) - self.out = np.empty((len(t), 3)) - self.out[:,0] = t #time - self.out[:,1] = TRPL_interp #Raw PL - self.out[:,2] = bestfit_model # PL fit - self.ui.plot.plot(t, bestfit_model, clear=self.ui.clear_plot_checkBox.isChecked(), pen='k') - self.ui.Result_textBrowser.setText("Fit Results:\n\nFit Function: Single Exponential with IRF" - "\nFit Method: "+ self.ui.FittingMethod_comboBox.currentText() + - "\na = %.5f" - "\ntau = %.5f ns" - "\nnoise = %.5f counts" %(bestfit_params[0], bestfit_params[1], bestfit_params[2])) - self.ui.average_lifetime_spinBox.setValue(bestfit_params[1]) #set spinbox to tau value - - #add fit params to data_list - self.data_list.append("Data Channel: " + str(self.ui.Data_channel_spinBox.value()) + "\n" + self.ui.Result_textBrowser.toPlainText()) - - except Exception as err: - exc_type, exc_obj, exc_tb = sys.exc_info() - print(exc_type, exc_tb.tb_lineno) - - def call_fit_and_plot(self): - if self.ui.fit_with_irf_checkBox.isChecked(): - self.fit_and_plot_with_irf() - else: - self.fit_and_plot() - if self.ui.calculate_srv_groupBox.isChecked(): - self.calculate_srv() #calculate srv on plot - self.data_list.append(self.get_srv_string()) #add srv params to data_list - - def calculate_surface_lifetime(self): - effective_lifetime = self.ui.average_lifetime_spinBox.value() - self.bulk_lifetime = self.ui.bulk_lifetime_spinBox.value() # in ns - self.surface_lifetime = (effective_lifetime * self.bulk_lifetime)/(self.bulk_lifetime - effective_lifetime) - self.ui.surface_lifetime_label.setText(str(self.surface_lifetime)) - - def calculate_srv (self): - self.calculate_surface_lifetime() - self.thickness = self.ui.thickness_spinBox.value()*1e-7 # convert to cm - self.diffusion_coeffecient = self.ui.diffusion_coefficient_spinBox.value() # in cm2/s - - if self.ui.srv1_srv2_checkBox.isChecked(): - self.srv = self.thickness / (2*((1e-9*self.surface_lifetime) - ((1/self.diffusion_coeffecient)*((self.thickness/np.pi)**2)) )) - else: - self.srv = self.thickness / ((1e-9*self.surface_lifetime) - ((4/self.diffusion_coeffecient)*((self.thickness/np.pi)**2)) ) - - self.ui.srv_label.setText(str(self.srv)) - - def get_srv_string(self): - """ Get info from SRV Calculation groupbox as string """ - srv_string = "SRV Calculation:"\ - + "\nAverage Lifetime (ns): " + str(self.ui.average_lifetime_spinBox.value()) \ - + "\nBulk Lifetime (ns): " + str(self.ui.bulk_lifetime_spinBox.value()) \ - + "\nThickness (nm): " + str(self.ui.thickness_spinBox.value()) \ - + "\nDiffusion Coefficient (cm2/s): " + str(self.ui.diffusion_coefficient_spinBox.value()) - if self.ui.srv1_srv2_checkBox.isChecked(): - srv_string += "\nSRV1 = SRV2" - else: - srv_string += "\nSRV1 = 0" - srv_string += "\nSurface Lifetime (ns): " + self.ui.surface_lifetime_label.text() \ - + "\nSRV (cm/s): " + self.ui.srv_label.text() - return srv_string - - def export_data(self): - """ Save fit params and srv calculations stored in data_list as .txt """ - folder = os.path.dirname(self.filename[0]) - filename_ext = os.path.basename(self.filename[0]) - filename = os.path.splitext(filename_ext)[0] #get filename without extension - - path = folder + "/" + filename + "_fit_results.txt" - if not os.path.exists(path): - file = open(path, "w+") - else: - file = open(path, "a+") - - for i in range(len(self.data_list)): - file.write(self.data_list[i] + "\n\n") - - self.data_list = [] - file.close() - - def pub_ready_plot_export(self): - try: - filename = QtWidgets.QFileDialog.getSaveFileName(self,caption="Filename with EXTENSION") - - plt.figure(figsize=(8,6)) - plt.tick_params(direction='out', length=8, width=3.5) - if self.ui.save_w_fit_checkBox.isChecked(): - plt.plot(self.out[:,0],self.out[:,1]/np.max(self.out[:,1])) - plt.plot(self.out[:,0],self.out[:,2]/np.max(self.out[:,1]),'k') - else: - plt.plot(self.acquire_settings()[0],self.acquire_settings()[1]/np.max(self.acquire_settings()[1])) - plt.yscale('log') - plt.xlabel("Time (ns)", fontsize=20, fontweight='bold') - plt.ylabel("Intensity (norm.)", fontsize=20, fontweight='bold') - plt.tight_layout() - - plt.savefig(filename[0],bbox_inches='tight', dpi=300) - plt.close() - - except: - pass - - def close_application(self): - choice = QtGui.QMessageBox.question(self, 'EXIT!', - "Do you want to exit the app?", - QtGui.QMessageBox.Yes | QtGui.QMessageBox.No) - if choice == QtGui.QMessageBox.Yes: - sys.exit() - else: - pass + if self.ui.FittingMethod_comboBox.currentText() == "diff_ev": + bestfit_params, t_avg, bestfit_model, data_array, time_array, irf = fit_exp_stretch_diffev(t, self.resolution, TRPL_interp, irf_counts, stretch_exp_bounds) + else: #if fmin_tnc fitting method selected + bestfit_params, t_avg, bestfit_model, data_array, time_array, irf = fit_exp_stretch_fmin_tnc(t, self.resolution, TRPL_interp, irf_counts, stretch_exp_init_params, stretch_exp_bounds) + self.out = np.empty((len(t), 3)) + self.out[:,0] = t #time + self.out[:,1] = TRPL_interp #Raw PL + self.out[:,2] = bestfit_model # PL fit + self.ui.plot.plot(t, bestfit_model, clear=self.ui.clear_plot_checkBox.isChecked(), pen='k') + self.ui.Result_textBrowser.setText("Fit Results:\n\nFit Function: Stretched Exponential with IRF" + "\nFit Method: "+ self.ui.FittingMethod_comboBox.currentText() + + "\ntau_avg = %.5f ns" + "\nbeta = %.5f" + "\ntau_c = %.5f ns" + "\na = %.5f \nnoise = %.5f counts" %(t_avg, bestfit_params[1], bestfit_params[0], bestfit_params[2], bestfit_params[3])) + #self.effective_lifetime = t_avg + self.ui.average_lifetime_spinBox.setValue(t_avg) + + elif fit_func == "Double Exponential": #double exponential tab + a1_bounds = (self.ui.de_a1_min_spinBox.value(), self.ui.de_a1_max_spinBox.value()) + tau1_bounds = (self.ui.de_tau1_min_spinBox.value(), self.ui.de_tau1_max_spinBox.value()) + a2_bounds = (self.ui.de_a2_min_spinBox.value(), self.ui.de_a2_max_spinBox.value()) + tau2_bounds = (self.ui.de_tau2_min_spinBox.value(), self.ui.de_tau2_max_spinBox.value()) + noise_bounds = (self.ui.de_noise_min_spinBox.value(), self.ui.de_noise_max_spinBox.value()) + double_exp_bounds = [a1_bounds, tau1_bounds, a2_bounds, tau2_bounds, noise_bounds] + double_exp_init_params = [self.ui.de_a1_init_spinBox.value(), self.ui.de_tau1_init_spinBox.value(), self.ui.de_a2_init_spinBox.value(), + self.ui.de_tau2_init_spinBox.value(), self.ui.de_noise_init_spinBox.value()] + + if self.ui.FittingMethod_comboBox.currentText() == "diff_ev": + bestfit_params, bestfit_model, data_array, time_array, irf = fit_multi_exp_diffev(t, self.resolution, TRPL_interp, irf_counts, double_exp_bounds, 2) + #bestfit_params, bestfit_model, data_array, time_array, irf = fit_multi_exp_diffev(t, resolution, TRPL_interp, irf_counts, double_exp_init_bounds, 2) + else: + bestfit_params, bestfit_model, data_array, time_array, irf = fit_multi_exp_fmin_tnc(t, self.resolution, TRPL_interp, irf_counts, double_exp_init_params, double_exp_bounds, 2) + self.out = np.empty((len(t), 3)) + self.out[:,0] = t #time + self.out[:,1] = TRPL_interp #Raw PL + self.out[:,2] = bestfit_model # PL fit + self.ui.plot.plot(t, bestfit_model, clear=self.ui.clear_plot_checkBox.isChecked(), pen='k') + self.ui.Result_textBrowser.setText("Fit Results:\n\nFit Function: Double Exponential with IRF" + "\nFit Method: "+ self.ui.FittingMethod_comboBox.currentText() + + "\na1 = %.5f" + "\ntau1 = %.5f ns" + "\na2 = %.5f" + "\ntau2 = %.5f ns" + "\nnoise = %.5f counts" %(bestfit_params[0], bestfit_params[1], bestfit_params[2], bestfit_params[3], bestfit_params[4])) + #TODO - once tau_avg implemented, set average lifetime spinbox to tau_avg value + + elif fit_func == "Single Exponential": #single exponential tab + a_bounds = (self.ui.se_a_min_spinBox.value(), self.ui.se_a_max_spinBox.value()) + tau_bounds = (self.ui.se_tau_min_spinBox.value(), self.ui.se_tau_max_spinBox.value()) + noise_bounds = (self.ui.se_noise_min_spinBox.value(), self.ui.se_noise_max_spinBox.value()) + single_exp_bounds = [a_bounds, tau_bounds, noise_bounds] + single_exp_init_params = [self.ui.se_a_init_spinBox.value(), self.ui.se_tau_init_spinBox.value(), self.ui.se_noise_init_spinBox.value()] + + if self.ui.FittingMethod_comboBox.currentText() == "diff_ev": + bestfit_params, bestfit_model, data_array, time_array, irf = fit_multi_exp_diffev(t, self.resolution, TRPL_interp, irf_counts, single_exp_bounds, 1) + else: + bestfit_params, bestfit_model, data_array, time_array, irf = fit_multi_exp_fmin_tnc(t, self.resolution, TRPL_interp, irf_counts, single_exp_init_params, single_exp_bounds, 1) + self.out = np.empty((len(t), 3)) + self.out[:,0] = t #time + self.out[:,1] = TRPL_interp #Raw PL + self.out[:,2] = bestfit_model # PL fit + self.ui.plot.plot(t, bestfit_model, clear=self.ui.clear_plot_checkBox.isChecked(), pen='k') + self.ui.Result_textBrowser.setText("Fit Results:\n\nFit Function: Single Exponential with IRF" + "\nFit Method: "+ self.ui.FittingMethod_comboBox.currentText() + + "\na = %.5f" + "\ntau = %.5f ns" + "\nnoise = %.5f counts" %(bestfit_params[0], bestfit_params[1], bestfit_params[2])) + self.ui.average_lifetime_spinBox.setValue(bestfit_params[1]) #set spinbox to tau value + + #add fit params to data_list + self.data_list.append("Data Channel: " + str(self.ui.Data_channel_spinBox.value()) + "\n" + self.ui.Result_textBrowser.toPlainText()) + + except Exception as err: + exc_type, exc_obj, exc_tb = sys.exc_info() + print(exc_type, exc_tb.tb_lineno) + + def call_fit_and_plot(self): + if self.ui.fit_with_irf_checkBox.isChecked(): + self.fit_and_plot_with_irf() + else: + self.fit_and_plot() + if self.ui.calculate_srv_groupBox.isChecked(): + self.calculate_srv() #calculate srv on plot + self.data_list.append(self.get_srv_string()) #add srv params to data_list + + def calculate_surface_lifetime(self): + effective_lifetime = self.ui.average_lifetime_spinBox.value() + self.bulk_lifetime = self.ui.bulk_lifetime_spinBox.value() # in ns + self.surface_lifetime = (effective_lifetime * self.bulk_lifetime)/(self.bulk_lifetime - effective_lifetime) + self.ui.surface_lifetime_label.setText(str(self.surface_lifetime)) + + def calculate_srv (self): + self.calculate_surface_lifetime() + self.thickness = self.ui.thickness_spinBox.value()*1e-7 # convert to cm + self.diffusion_coeffecient = self.ui.diffusion_coefficient_spinBox.value() # in cm2/s + + if self.ui.srv1_srv2_checkBox.isChecked(): + self.srv = self.thickness / (2*((1e-9*self.surface_lifetime) - ((1/self.diffusion_coeffecient)*((self.thickness/np.pi)**2)) )) + else: + self.srv = self.thickness / ((1e-9*self.surface_lifetime) - ((4/self.diffusion_coeffecient)*((self.thickness/np.pi)**2)) ) + + self.ui.srv_label.setText(str(self.srv)) + + def get_srv_string(self): + """ Get info from SRV Calculation groupbox as string """ + srv_string = "SRV Calculation:"\ + + "\nAverage Lifetime (ns): " + str(self.ui.average_lifetime_spinBox.value()) \ + + "\nBulk Lifetime (ns): " + str(self.ui.bulk_lifetime_spinBox.value()) \ + + "\nThickness (nm): " + str(self.ui.thickness_spinBox.value()) \ + + "\nDiffusion Coefficient (cm2/s): " + str(self.ui.diffusion_coefficient_spinBox.value()) + if self.ui.srv1_srv2_checkBox.isChecked(): + srv_string += "\nSRV1 = SRV2" + else: + srv_string += "\nSRV1 = 0" + srv_string += "\nSurface Lifetime (ns): " + self.ui.surface_lifetime_label.text() \ + + "\nSRV (cm/s): " + self.ui.srv_label.text() + return srv_string + + def export_data(self): + """ Save fit params and srv calculations stored in data_list as .txt """ + folder = os.path.dirname(self.filename[0]) + filename_ext = os.path.basename(self.filename[0]) + filename = os.path.splitext(filename_ext)[0] #get filename without extension + + path = folder + "/" + filename + "_fit_results.txt" + if not os.path.exists(path): + file = open(path, "w+") + else: + file = open(path, "a+") + + for i in range(len(self.data_list)): + file.write(self.data_list[i] + "\n\n") + + self.data_list = [] + file.close() + + def pub_ready_plot_export(self): + try: + filename = QtWidgets.QFileDialog.getSaveFileName(self,caption="Filename with EXTENSION") + + plt.figure(figsize=(8,6)) + plt.tick_params(direction='out', length=8, width=3.5) + if self.ui.save_w_fit_checkBox.isChecked(): + plt.plot(self.out[:,0],self.out[:,1]/np.max(self.out[:,1])) + plt.plot(self.out[:,0],self.out[:,2]/np.max(self.out[:,1]),'k') + else: + plt.plot(self.acquire_settings()[0],self.acquire_settings()[1]/np.max(self.acquire_settings()[1])) + plt.yscale('log') + plt.xlabel("Time (ns)", fontsize=20, fontweight='bold') + plt.ylabel("Intensity (norm.)", fontsize=20, fontweight='bold') + plt.tight_layout() + + plt.savefig(filename[0],bbox_inches='tight', dpi=300) + plt.close() + + except: + pass + + def close_application(self): + choice = QtGui.QMessageBox.question(self, 'EXIT!', + "Do you want to exit the app?", + QtGui.QMessageBox.Yes | QtGui.QMessageBox.No) + if choice == QtGui.QMessageBox.Yes: + sys.exit() + else: + pass """Skip rows GUI""" ui_file_path = (base_path / "skip_rows.ui").resolve() skiprows_WindowTemplate, skiprows_TemplateBaseClass = pg.Qt.loadUiType(ui_file_path) class SkipRowsWindow(skiprows_TemplateBaseClass): - - skip_rows_signal = QtCore.pyqtSignal() #signal to help with pass info back to MainWindow - - def __init__(self): - skiprows_TemplateBaseClass.__init__(self) - - # Create the param window - self.ui = skiprows_WindowTemplate() - self.ui.setupUi(self) - self.ui.done_pushButton.clicked.connect(self.done) - self.setWindowFlag(QtCore.Qt.WindowCloseButtonHint, False) - self.show() - - def done(self): - self.skip_rows_signal.emit() - self.close() + + skip_rows_signal = QtCore.pyqtSignal() #signal to help with pass info back to MainWindow + + def __init__(self): + skiprows_TemplateBaseClass.__init__(self) + + # Create the param window + self.ui = skiprows_WindowTemplate() + self.ui.setupUi(self) + self.ui.done_pushButton.clicked.connect(self.done) + self.setWindowFlag(QtCore.Qt.WindowCloseButtonHint, False) + self.show() + + def done(self): + self.skip_rows_signal.emit() + self.close() def run(): - win = MainWindow() - QtGui.QApplication.instance().exec_() - return win + win = MainWindow() + QtGui.QApplication.instance().exec_() + return win #Uncomment below if you want to run this as standalone #run() \ No newline at end of file From 959d317f29de1c1c527cf60498b24794ca6730d9 Mon Sep 17 00:00:00 2001 From: "LAKESIDE\\LindaT18" Date: Mon, 12 Aug 2019 14:38:49 -0700 Subject: [PATCH 04/25] fix load phd --- PythonGUI_apps/FLIM_analysis/flim_plot_gui.ui | 7 +++++++ PythonGUI_apps/Lifetime_analysis/Lifetime_plot_fit.py | 8 ++++---- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/PythonGUI_apps/FLIM_analysis/flim_plot_gui.ui b/PythonGUI_apps/FLIM_analysis/flim_plot_gui.ui index 5daa01e..4b35cb8 100644 --- a/PythonGUI_apps/FLIM_analysis/flim_plot_gui.ui +++ b/PythonGUI_apps/FLIM_analysis/flim_plot_gui.ui @@ -111,6 +111,13 @@ + + + + Analyze lifetime + + + diff --git a/PythonGUI_apps/Lifetime_analysis/Lifetime_plot_fit.py b/PythonGUI_apps/Lifetime_analysis/Lifetime_plot_fit.py index d0c5741..bebd665 100644 --- a/PythonGUI_apps/Lifetime_analysis/Lifetime_plot_fit.py +++ b/PythonGUI_apps/Lifetime_analysis/Lifetime_plot_fit.py @@ -96,8 +96,8 @@ def open_file(self): if ".csv" in self.filename[0] or ".txt" in self.filename[0]: #if txt or csv, prompt user to enter # of rows to skip self.skip_rows_window = SkipRowsWindow() self.skip_rows_window.skip_rows_signal.connect(self.open_with_skip_rows_window) - except UnicodeDecodeError: - self.file = read_picoharp_phd(self.filename[0]) + else: + self.file = read_picoharp_phd(self.filename[0]) except: pass @@ -116,8 +116,8 @@ def open_irf_file(self): if ".txt" in self.irf_filename[0] or ".csv" in self.irf_filename[0]: self.irf_skip_rows_window = SkipRowsWindow() self.irf_skip_rows_window.skip_rows_signal.connect(self.open_irf_with_skip_rows_window) - except UnicodeDecodeError: - self.irf_file = read_picoharp_phd(self.irf_filename[0]) + else: + self.irf_file = read_picoharp_phd(self.irf_filename[0]) except: pass From 051c756b0baeac4b943d1229617949c1cf96bbd0 Mon Sep 17 00:00:00 2001 From: "LAKESIDE\\LindaT18" Date: Tue, 13 Aug 2019 12:27:26 -0700 Subject: [PATCH 05/25] added analyze lifetime/spectrum from flim, clear lifetime export data, user checking --- PythonGUI_apps/FLIM_analysis/FLIM_plot.py | 37 +- PythonGUI_apps/FLIM_analysis/flim_plot_gui.ui | 7 + .../Lifetime_analysis_gui_layout.ui | 23 +- .../Lifetime_analysis/Lifetime_plot_fit.py | 366 ++++++++++-------- .../Spectrum_analysis/Spectra_plot_fit.py | 166 ++++---- .../Spectrum_analysis/Spectra_plot_fit_gui.ui | 79 ++-- 6 files changed, 397 insertions(+), 281 deletions(-) diff --git a/PythonGUI_apps/FLIM_analysis/FLIM_plot.py b/PythonGUI_apps/FLIM_analysis/FLIM_plot.py index 8ba8d49..ad1eaad 100644 --- a/PythonGUI_apps/FLIM_analysis/FLIM_plot.py +++ b/PythonGUI_apps/FLIM_analysis/FLIM_plot.py @@ -10,6 +10,11 @@ import time from lmfit.models import GaussianModel import customplotting.mscope as cpm + +sys.path.append(os.path.abspath('../Lifetime_analysis')) +sys.path.append(os.path.abspath('../Spectrum_analysis')) +from Lifetime_analysis import Lifetime_plot_fit +from Spectrum_analysis import Spectra_plot_fit # local modules pg.mkQApp() @@ -24,7 +29,9 @@ WindowTemplate, TemplateBaseClass = pg.Qt.loadUiType(uiFile) class MainWindow(TemplateBaseClass): - + + hist_data_signal = QtCore.pyqtSignal() + def __init__(self): super(TemplateBaseClass, self).__init__() @@ -42,6 +49,8 @@ def __init__(self): self.ui.intensity_sums_viewBox.roi.sigRegionChanged.connect(self.line_profile_update_plot) self.ui.import_pkl_pushButton.clicked.connect(self.import_pkl_to_convert) self.ui.pkl_to_h5_pushButton.clicked.connect(self.pkl_to_h5) + self.ui.analyze_lifetime_pushButton.clicked.connect(self.on_analyze_lifetime) + self.ui.analyze_spectrum_pushButton.clicked.connect(self.on_analyze_spectrum) self.show() @@ -130,6 +139,15 @@ def line_profile_update_plot(self): except: pass + def on_analyze_spectrum(self): + self.spectrum_window = Spectra_plot_fit.MainWindow() + self.spectrum_window.show() + self.spectrum_window.opened_from_flim = True + sum_data = self.ui.intensity_sums_viewBox.getRoiPlot().getPlotItem().curves[0].getData() + self.spectrum_window.sum_data_from_flim = np.asarray(sum_data) + self.spectrum_window.ui.plot_without_bck_radioButton.setChecked(True) + self.spectrum_window.ui.result_textBrowser.setText("Data successfully loaded from FLIM analysis.") + def plot_raw_scan(self): try: self.hist_image = np.reshape(self.hist_data, newshape=(self.hist_data.shape[0],self.numb_x_pixels,self.numb_y_pixels)) @@ -191,10 +209,25 @@ def update_roi2_plot(self): # Average data within entire ROI for each frame data = data.mean(axis=max(axes)).mean(axis=min(axes)) xvals = self.ui.raw_hist_data_viewBox.tVals - if hasattr(self, "roi2_plot"): + if hasattr(self, "roi2_plot"): #make sure second plot is properly cleared everytime self.roi2_plot.clear() + c = self.ui.raw_hist_data_viewBox.getRoiPlot().getPlotItem().curves.pop() + c.scene().removeItem(c) self.roi2_plot = self.ui.raw_hist_data_viewBox.getRoiPlot().plot(xvals, data, pen='r') + def get_raw_hist_curve(self, curve_index): + #curve_index = 0 for original roi + #curve_index = 1 for second comparison roi + curves = self.ui.raw_hist_data_viewBox.getRoiPlot().getPlotItem().curves + return curves[curve_index].getData() + + def on_analyze_lifetime(self): + self.lifetime_window = Lifetime_plot_fit.MainWindow() + self.lifetime_window.show() + self.lifetime_window.opened_from_flim = True + self.lifetime_window.hist_data_from_flim = np.asarray(self.get_raw_hist_curve(0)) + self.lifetime_window.ui.Result_textBrowser.setText("Data successfully loaded from FLIM analysis.") + def save_intensities_image(self): try: folder = os.path.dirname(self.filename[0]) diff --git a/PythonGUI_apps/FLIM_analysis/flim_plot_gui.ui b/PythonGUI_apps/FLIM_analysis/flim_plot_gui.ui index 4b35cb8..65c1e92 100644 --- a/PythonGUI_apps/FLIM_analysis/flim_plot_gui.ui +++ b/PythonGUI_apps/FLIM_analysis/flim_plot_gui.ui @@ -56,6 +56,13 @@ + + + + Analyze spectrum + + + diff --git a/PythonGUI_apps/Lifetime_analysis/Lifetime_analysis_gui_layout.ui b/PythonGUI_apps/Lifetime_analysis/Lifetime_analysis_gui_layout.ui index b4fc950..945c672 100644 --- a/PythonGUI_apps/Lifetime_analysis/Lifetime_analysis_gui_layout.ui +++ b/PythonGUI_apps/Lifetime_analysis/Lifetime_analysis_gui_layout.ui @@ -1038,6 +1038,13 @@ Export Settings + + + + Export data + + + @@ -1053,7 +1060,14 @@ - + + + + Clear export data + + + + @@ -1067,13 +1081,6 @@ - - - - Export data - - - diff --git a/PythonGUI_apps/Lifetime_analysis/Lifetime_plot_fit.py b/PythonGUI_apps/Lifetime_analysis/Lifetime_plot_fit.py index bebd665..8e27f7d 100644 --- a/PythonGUI_apps/Lifetime_analysis/Lifetime_plot_fit.py +++ b/PythonGUI_apps/Lifetime_analysis/Lifetime_plot_fit.py @@ -76,6 +76,7 @@ def __init__(self): self.ui.FittingMethod_comboBox.currentTextChanged.connect(self.switch_init_params_groupBox) self.ui.separate_irf_checkBox.stateChanged.connect(self.switch_open_irf) self.ui.export_data_pushButton.clicked.connect(self.export_data) + self.ui.clear_export_data_pushButton.clicked.connect(self.clear_export_data) #set up plot color button self.plot_color_button = pg.ColorButton(color=(255,0,0)) @@ -86,6 +87,11 @@ def __init__(self): self.file = None self.out = None # output file after fitting self.data_list = [] + + #variables accounting for data received from FLIM analysis + self.opened_from_flim = False #switched to True in FLIM_plot when "analyze lifetime" clicked + self.hist_data_from_flim = [] #container for flim roi data + self.show() def open_file(self): @@ -98,6 +104,7 @@ def open_file(self): self.skip_rows_window.skip_rows_signal.connect(self.open_with_skip_rows_window) else: self.file = read_picoharp_phd(self.filename[0]) + self.opened_from_flim = False except: pass @@ -215,7 +222,10 @@ def acquire_settings(self, mode="data"): def plot(self): try: - x,y = self.acquire_settings() #get data + if self.opened_from_flim: + x, y = self.hist_data_from_flim + else: + x,y = self.acquire_settings() #get data if self.ui.normalize_checkBox.isChecked(): y = y / np.amax(y) @@ -242,185 +252,198 @@ def clear_plot(self): def fit_and_plot(self): """ Fit and plot without IRF """ try: - x,y = self.acquire_settings() #get data - y_norm = y/np.max(y) #normalized y + if not hasattr(self, "file"): + self.ui.Result_textBrowser.setText("You need to load a data file.") + else: + if self.opened_from_flim: + x, y = self.hist_data_from_flim + else: + x,y = self.acquire_settings() #get data + y_norm = y/np.max(y) #normalized y - # find the max intensity in the array and start things from there - find_max_int = np.nonzero(y_norm == 1) - y = y[np.asscalar(find_max_int[0]):] - x = x[np.asscalar(find_max_int[0]):] + # find the max intensity in the array and start things from there + find_max_int = np.nonzero(y_norm == 1) + y = y[np.asscalar(find_max_int[0]):] + x = x[np.asscalar(find_max_int[0]):] - t = x - time_fit = t - TRPL_interp = np.interp(time_fit, t, y) - - fit_func = self.ui.FittingFunc_comboBox.currentText() - self.ui.plot.plot(t, y, clear=self.ui.clear_plot_checkBox.isChecked(), pen=pg.mkPen(self.plot_color)) - - if fit_func == "Stretched Exponential": #stretch exponential tab - tc, beta, a, avg_tau, PL_fit = stretch_exp_fit(TRPL_interp, t) - self.out = np.empty((len(t), 3)) - self.out[:,0] = t #time - self.out[:,1] = TRPL_interp #Raw PL - self.out[:,2] = PL_fit # PL fit - self.ui.plot.plot(t, PL_fit, clear=self.ui.clear_plot_checkBox.isChecked(), pen='k') - self.ui.Result_textBrowser.setText("Fit Results:\n\nFit Function: Stretched Exponential" - "\nFit Method: " + "diff_ev" + #TODO : change when diff_ev and fmin_tnc implemented for non-irf - "\nAverage Lifetime = " + str(avg_tau)+ " ns" - "\nCharacteristic Tau = " + str(tc)+" ns" - "\nBeta = "+str(beta)) - self.ui.average_lifetime_spinBox.setValue(avg_tau) - - elif fit_func == "Double Exponential": #double exponential tab - tau1, a1, tau2, a2, avg_tau, PL_fit = double_exp_fit(TRPL_interp, t) - self.out = np.empty((len(t), 3)) - self.out[:,0] = t #time - self.out[:,1] = TRPL_interp #Raw PL - self.out[:,2] = PL_fit # PL fit - self.ui.plot.plot(t, PL_fit, clear=self.ui.clear_plot_checkBox.isChecked(), pen='k') - self.ui.Result_textBrowser.setText("Fit Results:\n\nFit Function: Double Exponential" - "\nFit Method: " + "diff_ev" + - "\nAverage Lifetime = " + str(avg_tau)+ " ns" - "\nTau 1 = " + str(tau1)+" ns" - "\nA 1 = " + str(a1)+ - "\nTau 2 = " + str(tau2)+" ns" - "\nA 2 = " + str(a2)) - #TODO - once tau_avg implemented, set average lifetime spinbox to tau_avg value - - elif fit_func == "Single Exponential": #single exponential tab - tau, a, PL_fit = single_exp_fit(TRPL_interp, t) - self.out = np.empty((len(t), 3)) - self.out[:,0] = t #time - self.out[:,1] = TRPL_interp #Raw PL - self.out[:,2] = PL_fit # PL fit - self.ui.plot.plot(t, PL_fit, clear=self.ui.clear_plot_checkBox.isChecked(), pen='k') - self.ui.Result_textBrowser.setText("Fit Results:\n\nFit Function: Single Exponential" - "\nFit Method: " + "diff_ev" + - "\nLifetime = " + str(tau)+ " ns" - "\nA = " + str(a)) - self.ui.average_lifetime_spinBox.setValue(tau) - - #add fit params to data_list - self.data_list.append("Data Channel: " + str(self.ui.Data_channel_spinBox.value()) + "\n" + self.ui.Result_textBrowser.toPlainText()) - - self.ui.plot.setLabel('left', 'Intensity', units='a.u.') - self.ui.plot.setLabel('bottom', 'Time (ns)') - return self.out + t = x + time_fit = t + TRPL_interp = np.interp(time_fit, t, y) + + fit_func = self.ui.FittingFunc_comboBox.currentText() + self.ui.plot.plot(t, y, clear=self.ui.clear_plot_checkBox.isChecked(), pen=pg.mkPen(self.plot_color)) + + if fit_func == "Stretched Exponential": #stretch exponential tab + tc, beta, a, avg_tau, PL_fit = stretch_exp_fit(TRPL_interp, t) + self.out = np.empty((len(t), 3)) + self.out[:,0] = t #time + self.out[:,1] = TRPL_interp #Raw PL + self.out[:,2] = PL_fit # PL fit + self.ui.plot.plot(t, PL_fit, clear=self.ui.clear_plot_checkBox.isChecked(), pen='k') + self.ui.Result_textBrowser.setText("Fit Results:\n\nFit Function: Stretched Exponential" + "\nFit Method: " + "diff_ev" + #TODO : change when diff_ev and fmin_tnc implemented for non-irf + "\nAverage Lifetime = " + str(avg_tau)+ " ns" + "\nCharacteristic Tau = " + str(tc)+" ns" + "\nBeta = "+str(beta)) + self.ui.average_lifetime_spinBox.setValue(avg_tau) + + elif fit_func == "Double Exponential": #double exponential tab + tau1, a1, tau2, a2, avg_tau, PL_fit = double_exp_fit(TRPL_interp, t) + self.out = np.empty((len(t), 3)) + self.out[:,0] = t #time + self.out[:,1] = TRPL_interp #Raw PL + self.out[:,2] = PL_fit # PL fit + self.ui.plot.plot(t, PL_fit, clear=self.ui.clear_plot_checkBox.isChecked(), pen='k') + self.ui.Result_textBrowser.setText("Fit Results:\n\nFit Function: Double Exponential" + "\nFit Method: " + "diff_ev" + + "\nAverage Lifetime = " + str(avg_tau)+ " ns" + "\nTau 1 = " + str(tau1)+" ns" + "\nA 1 = " + str(a1)+ + "\nTau 2 = " + str(tau2)+" ns" + "\nA 2 = " + str(a2)) + #TODO - once tau_avg implemented, set average lifetime spinbox to tau_avg value + + elif fit_func == "Single Exponential": #single exponential tab + tau, a, PL_fit = single_exp_fit(TRPL_interp, t) + self.out = np.empty((len(t), 3)) + self.out[:,0] = t #time + self.out[:,1] = TRPL_interp #Raw PL + self.out[:,2] = PL_fit # PL fit + self.ui.plot.plot(t, PL_fit, clear=self.ui.clear_plot_checkBox.isChecked(), pen='k') + self.ui.Result_textBrowser.setText("Fit Results:\n\nFit Function: Single Exponential" + "\nFit Method: " + "diff_ev" + + "\nLifetime = " + str(tau)+ " ns" + "\nA = " + str(a)) + self.ui.average_lifetime_spinBox.setValue(tau) + + #add fit params to data_list + self.data_list.append("Data Channel: " + str(self.ui.Data_channel_spinBox.value()) + "\n" + self.ui.Result_textBrowser.toPlainText()) + + self.ui.plot.setLabel('left', 'Intensity', units='a.u.') + self.ui.plot.setLabel('bottom', 'Time (ns)') + return self.out - except Exception as err: - exc_type, exc_obj, exc_tb = sys.exc_info() - print(exc_type, exc_tb.tb_lineno) + except Exception as e: + self.ui.Result_textBrowser.append(format(e)) def fit_and_plot_with_irf(self): """ Fit and plot with IRF """ try: - x,y = self.acquire_settings() #get data - _, irf_counts = self.acquire_settings(mode="irf") #get irf counts + self.ui.Result_textBrowser.clear() + if not hasattr(self, "file"): + self.ui.Result_textBrowser.append("You need to load a data file.") + if not hasattr(self, "irf_file") and self.ui.separate_irf_checkBox.isChecked(): + self.ui.Result_textBrowser.append("You need to load an IRF file.") + else: + if self.opened_from_flim: + x,y = self.hist_data_from_flim + else: + x,y = self.acquire_settings() #get data + _, irf_counts = self.acquire_settings(mode="irf") #get irf counts - #make sure Irf and data have the same length - if len(y) != len(irf_counts): - y = y[0:min(len(y), len(irf_counts))] - irf_counts = irf_counts[0:min(len(y), len(irf_counts))] - x = x[0:min(len(y), len(irf_counts))] + #make sure Irf and data have the same length + if len(y) != len(irf_counts): + y = y[0:min(len(y), len(irf_counts))] + irf_counts = irf_counts[0:min(len(y), len(irf_counts))] + x = x[0:min(len(y), len(irf_counts))] - y_norm = y/np.max(y) #normalized y - irf_norm = irf_counts/np.amax(irf_counts) #normalized irf - - t = x - time_fit = t - y = y_norm - irf_counts = irf_norm - - TRPL_interp = np.interp(time_fit, t, y) - - fit_func = self.ui.FittingFunc_comboBox.currentText() - self.ui.plot.plot(t, y, clear=self.ui.clear_plot_checkBox.isChecked(), pen=pg.mkPen(self.plot_color)) - if fit_func == "Stretched Exponential": #stretched exponential tab - tc_bounds = (self.ui.str_tc_min_spinBox.value(), self.ui.str_tc_max_spinBox.value()) #(0, 10000) - a_bounds = (self.ui.str_a_min_spinBox.value(), self.ui.str_a_max_spinBox.value())#(0.9, 1.1) - beta_bounds = (self.ui.str_beta_min_spinBox.value(), self.ui.str_beta_max_spinBox.value())#(0,1) - noise_bounds = (self.ui.str_noise_min_spinBox.value(), self.ui.str_noise_max_spinBox.value())#(0, 1e4) - stretch_exp_bounds = [tc_bounds, beta_bounds, a_bounds, noise_bounds] - stretch_exp_init_params = [self.ui.str_tc_init_spinBox.value(), self.ui.str_a_init_spinBox.value(), self.ui.str_beta_init_spinBox.value(), self.ui.str_noise_init_spinBox.value()] - - #tc, beta, a, avg_tau, PL_fit = stretch_exp_fit(TRPL_interp, t) -# resolution = float(self.ui.Res_comboBox.currentText()) - if self.ui.FittingMethod_comboBox.currentText() == "diff_ev": - bestfit_params, t_avg, bestfit_model, data_array, time_array, irf = fit_exp_stretch_diffev(t, self.resolution, TRPL_interp, irf_counts, stretch_exp_bounds) - else: #if fmin_tnc fitting method selected - bestfit_params, t_avg, bestfit_model, data_array, time_array, irf = fit_exp_stretch_fmin_tnc(t, self.resolution, TRPL_interp, irf_counts, stretch_exp_init_params, stretch_exp_bounds) - self.out = np.empty((len(t), 3)) - self.out[:,0] = t #time - self.out[:,1] = TRPL_interp #Raw PL - self.out[:,2] = bestfit_model # PL fit - self.ui.plot.plot(t, bestfit_model, clear=self.ui.clear_plot_checkBox.isChecked(), pen='k') - self.ui.Result_textBrowser.setText("Fit Results:\n\nFit Function: Stretched Exponential with IRF" - "\nFit Method: "+ self.ui.FittingMethod_comboBox.currentText() + - "\ntau_avg = %.5f ns" - "\nbeta = %.5f" - "\ntau_c = %.5f ns" - "\na = %.5f \nnoise = %.5f counts" %(t_avg, bestfit_params[1], bestfit_params[0], bestfit_params[2], bestfit_params[3])) - #self.effective_lifetime = t_avg - self.ui.average_lifetime_spinBox.setValue(t_avg) + y_norm = y/np.max(y) #normalized y + irf_norm = irf_counts/np.amax(irf_counts) #normalized irf + + t = x + time_fit = t + y = y_norm + irf_counts = irf_norm + + TRPL_interp = np.interp(time_fit, t, y) + + fit_func = self.ui.FittingFunc_comboBox.currentText() + self.ui.plot.plot(t, y, clear=self.ui.clear_plot_checkBox.isChecked(), pen=pg.mkPen(self.plot_color)) + if fit_func == "Stretched Exponential": #stretched exponential tab + tc_bounds = (self.ui.str_tc_min_spinBox.value(), self.ui.str_tc_max_spinBox.value()) #(0, 10000) + a_bounds = (self.ui.str_a_min_spinBox.value(), self.ui.str_a_max_spinBox.value())#(0.9, 1.1) + beta_bounds = (self.ui.str_beta_min_spinBox.value(), self.ui.str_beta_max_spinBox.value())#(0,1) + noise_bounds = (self.ui.str_noise_min_spinBox.value(), self.ui.str_noise_max_spinBox.value())#(0, 1e4) + stretch_exp_bounds = [tc_bounds, beta_bounds, a_bounds, noise_bounds] + stretch_exp_init_params = [self.ui.str_tc_init_spinBox.value(), self.ui.str_a_init_spinBox.value(), self.ui.str_beta_init_spinBox.value(), self.ui.str_noise_init_spinBox.value()] + + #tc, beta, a, avg_tau, PL_fit = stretch_exp_fit(TRPL_interp, t) + # resolution = float(self.ui.Res_comboBox.currentText()) + if self.ui.FittingMethod_comboBox.currentText() == "diff_ev": + bestfit_params, t_avg, bestfit_model, data_array, time_array, irf = fit_exp_stretch_diffev(t, self.resolution, TRPL_interp, irf_counts, stretch_exp_bounds) + else: #if fmin_tnc fitting method selected + bestfit_params, t_avg, bestfit_model, data_array, time_array, irf = fit_exp_stretch_fmin_tnc(t, self.resolution, TRPL_interp, irf_counts, stretch_exp_init_params, stretch_exp_bounds) + self.out = np.empty((len(t), 3)) + self.out[:,0] = t #time + self.out[:,1] = TRPL_interp #Raw PL + self.out[:,2] = bestfit_model # PL fit + self.ui.plot.plot(t, bestfit_model, clear=self.ui.clear_plot_checkBox.isChecked(), pen='k') + self.ui.Result_textBrowser.setText("Fit Results:\n\nFit Function: Stretched Exponential with IRF" + "\nFit Method: "+ self.ui.FittingMethod_comboBox.currentText() + + "\ntau_avg = %.5f ns" + "\nbeta = %.5f" + "\ntau_c = %.5f ns" + "\na = %.5f \nnoise = %.5f counts" %(t_avg, bestfit_params[1], bestfit_params[0], bestfit_params[2], bestfit_params[3])) + #self.effective_lifetime = t_avg + self.ui.average_lifetime_spinBox.setValue(t_avg) + + elif fit_func == "Double Exponential": #double exponential tab + a1_bounds = (self.ui.de_a1_min_spinBox.value(), self.ui.de_a1_max_spinBox.value()) + tau1_bounds = (self.ui.de_tau1_min_spinBox.value(), self.ui.de_tau1_max_spinBox.value()) + a2_bounds = (self.ui.de_a2_min_spinBox.value(), self.ui.de_a2_max_spinBox.value()) + tau2_bounds = (self.ui.de_tau2_min_spinBox.value(), self.ui.de_tau2_max_spinBox.value()) + noise_bounds = (self.ui.de_noise_min_spinBox.value(), self.ui.de_noise_max_spinBox.value()) + double_exp_bounds = [a1_bounds, tau1_bounds, a2_bounds, tau2_bounds, noise_bounds] + double_exp_init_params = [self.ui.de_a1_init_spinBox.value(), self.ui.de_tau1_init_spinBox.value(), self.ui.de_a2_init_spinBox.value(), + self.ui.de_tau2_init_spinBox.value(), self.ui.de_noise_init_spinBox.value()] + + if self.ui.FittingMethod_comboBox.currentText() == "diff_ev": + bestfit_params, bestfit_model, data_array, time_array, irf = fit_multi_exp_diffev(t, self.resolution, TRPL_interp, irf_counts, double_exp_bounds, 2) + #bestfit_params, bestfit_model, data_array, time_array, irf = fit_multi_exp_diffev(t, resolution, TRPL_interp, irf_counts, double_exp_init_bounds, 2) + else: + bestfit_params, bestfit_model, data_array, time_array, irf = fit_multi_exp_fmin_tnc(t, self.resolution, TRPL_interp, irf_counts, double_exp_init_params, double_exp_bounds, 2) + self.out = np.empty((len(t), 3)) + self.out[:,0] = t #time + self.out[:,1] = TRPL_interp #Raw PL + self.out[:,2] = bestfit_model # PL fit + self.ui.plot.plot(t, bestfit_model, clear=self.ui.clear_plot_checkBox.isChecked(), pen='k') + self.ui.Result_textBrowser.setText("Fit Results:\n\nFit Function: Double Exponential with IRF" + "\nFit Method: "+ self.ui.FittingMethod_comboBox.currentText() + + "\na1 = %.5f" + "\ntau1 = %.5f ns" + "\na2 = %.5f" + "\ntau2 = %.5f ns" + "\nnoise = %.5f counts" %(bestfit_params[0], bestfit_params[1], bestfit_params[2], bestfit_params[3], bestfit_params[4])) + #TODO - once tau_avg implemented, set average lifetime spinbox to tau_avg value + + elif fit_func == "Single Exponential": #single exponential tab + a_bounds = (self.ui.se_a_min_spinBox.value(), self.ui.se_a_max_spinBox.value()) + tau_bounds = (self.ui.se_tau_min_spinBox.value(), self.ui.se_tau_max_spinBox.value()) + noise_bounds = (self.ui.se_noise_min_spinBox.value(), self.ui.se_noise_max_spinBox.value()) + single_exp_bounds = [a_bounds, tau_bounds, noise_bounds] + single_exp_init_params = [self.ui.se_a_init_spinBox.value(), self.ui.se_tau_init_spinBox.value(), self.ui.se_noise_init_spinBox.value()] + + if self.ui.FittingMethod_comboBox.currentText() == "diff_ev": + bestfit_params, bestfit_model, data_array, time_array, irf = fit_multi_exp_diffev(t, self.resolution, TRPL_interp, irf_counts, single_exp_bounds, 1) + else: + bestfit_params, bestfit_model, data_array, time_array, irf = fit_multi_exp_fmin_tnc(t, self.resolution, TRPL_interp, irf_counts, single_exp_init_params, single_exp_bounds, 1) + self.out = np.empty((len(t), 3)) + self.out[:,0] = t #time + self.out[:,1] = TRPL_interp #Raw PL + self.out[:,2] = bestfit_model # PL fit + self.ui.plot.plot(t, bestfit_model, clear=self.ui.clear_plot_checkBox.isChecked(), pen='k') + self.ui.Result_textBrowser.setText("Fit Results:\n\nFit Function: Single Exponential with IRF" + "\nFit Method: "+ self.ui.FittingMethod_comboBox.currentText() + + "\na = %.5f" + "\ntau = %.5f ns" + "\nnoise = %.5f counts" %(bestfit_params[0], bestfit_params[1], bestfit_params[2])) + self.ui.average_lifetime_spinBox.setValue(bestfit_params[1]) #set spinbox to tau value + + #add fit params to data_list + self.data_list.append("Data Channel: " + str(self.ui.Data_channel_spinBox.value()) + "\n" + self.ui.Result_textBrowser.toPlainText()) - elif fit_func == "Double Exponential": #double exponential tab - a1_bounds = (self.ui.de_a1_min_spinBox.value(), self.ui.de_a1_max_spinBox.value()) - tau1_bounds = (self.ui.de_tau1_min_spinBox.value(), self.ui.de_tau1_max_spinBox.value()) - a2_bounds = (self.ui.de_a2_min_spinBox.value(), self.ui.de_a2_max_spinBox.value()) - tau2_bounds = (self.ui.de_tau2_min_spinBox.value(), self.ui.de_tau2_max_spinBox.value()) - noise_bounds = (self.ui.de_noise_min_spinBox.value(), self.ui.de_noise_max_spinBox.value()) - double_exp_bounds = [a1_bounds, tau1_bounds, a2_bounds, tau2_bounds, noise_bounds] - double_exp_init_params = [self.ui.de_a1_init_spinBox.value(), self.ui.de_tau1_init_spinBox.value(), self.ui.de_a2_init_spinBox.value(), - self.ui.de_tau2_init_spinBox.value(), self.ui.de_noise_init_spinBox.value()] - - if self.ui.FittingMethod_comboBox.currentText() == "diff_ev": - bestfit_params, bestfit_model, data_array, time_array, irf = fit_multi_exp_diffev(t, self.resolution, TRPL_interp, irf_counts, double_exp_bounds, 2) - #bestfit_params, bestfit_model, data_array, time_array, irf = fit_multi_exp_diffev(t, resolution, TRPL_interp, irf_counts, double_exp_init_bounds, 2) - else: - bestfit_params, bestfit_model, data_array, time_array, irf = fit_multi_exp_fmin_tnc(t, self.resolution, TRPL_interp, irf_counts, double_exp_init_params, double_exp_bounds, 2) - self.out = np.empty((len(t), 3)) - self.out[:,0] = t #time - self.out[:,1] = TRPL_interp #Raw PL - self.out[:,2] = bestfit_model # PL fit - self.ui.plot.plot(t, bestfit_model, clear=self.ui.clear_plot_checkBox.isChecked(), pen='k') - self.ui.Result_textBrowser.setText("Fit Results:\n\nFit Function: Double Exponential with IRF" - "\nFit Method: "+ self.ui.FittingMethod_comboBox.currentText() + - "\na1 = %.5f" - "\ntau1 = %.5f ns" - "\na2 = %.5f" - "\ntau2 = %.5f ns" - "\nnoise = %.5f counts" %(bestfit_params[0], bestfit_params[1], bestfit_params[2], bestfit_params[3], bestfit_params[4])) - #TODO - once tau_avg implemented, set average lifetime spinbox to tau_avg value - - elif fit_func == "Single Exponential": #single exponential tab - a_bounds = (self.ui.se_a_min_spinBox.value(), self.ui.se_a_max_spinBox.value()) - tau_bounds = (self.ui.se_tau_min_spinBox.value(), self.ui.se_tau_max_spinBox.value()) - noise_bounds = (self.ui.se_noise_min_spinBox.value(), self.ui.se_noise_max_spinBox.value()) - single_exp_bounds = [a_bounds, tau_bounds, noise_bounds] - single_exp_init_params = [self.ui.se_a_init_spinBox.value(), self.ui.se_tau_init_spinBox.value(), self.ui.se_noise_init_spinBox.value()] - - if self.ui.FittingMethod_comboBox.currentText() == "diff_ev": - bestfit_params, bestfit_model, data_array, time_array, irf = fit_multi_exp_diffev(t, self.resolution, TRPL_interp, irf_counts, single_exp_bounds, 1) - else: - bestfit_params, bestfit_model, data_array, time_array, irf = fit_multi_exp_fmin_tnc(t, self.resolution, TRPL_interp, irf_counts, single_exp_init_params, single_exp_bounds, 1) - self.out = np.empty((len(t), 3)) - self.out[:,0] = t #time - self.out[:,1] = TRPL_interp #Raw PL - self.out[:,2] = bestfit_model # PL fit - self.ui.plot.plot(t, bestfit_model, clear=self.ui.clear_plot_checkBox.isChecked(), pen='k') - self.ui.Result_textBrowser.setText("Fit Results:\n\nFit Function: Single Exponential with IRF" - "\nFit Method: "+ self.ui.FittingMethod_comboBox.currentText() + - "\na = %.5f" - "\ntau = %.5f ns" - "\nnoise = %.5f counts" %(bestfit_params[0], bestfit_params[1], bestfit_params[2])) - self.ui.average_lifetime_spinBox.setValue(bestfit_params[1]) #set spinbox to tau value - - #add fit params to data_list - self.data_list.append("Data Channel: " + str(self.ui.Data_channel_spinBox.value()) + "\n" + self.ui.Result_textBrowser.toPlainText()) - - except Exception as err: - exc_type, exc_obj, exc_tb = sys.exc_info() - print(exc_type, exc_tb.tb_lineno) + except Exception as e: + self.ui.Result_textBrowser.append(format(e)) def call_fit_and_plot(self): if self.ui.fit_with_irf_checkBox.isChecked(): @@ -482,6 +505,9 @@ def export_data(self): self.data_list = [] file.close() + def clear_export_data(self): + self.data_list = [] + def pub_ready_plot_export(self): try: filename = QtWidgets.QFileDialog.getSaveFileName(self,caption="Filename with EXTENSION") diff --git a/PythonGUI_apps/Spectrum_analysis/Spectra_plot_fit.py b/PythonGUI_apps/Spectrum_analysis/Spectra_plot_fit.py index 8960bf1..c826937 100644 --- a/PythonGUI_apps/Spectrum_analysis/Spectra_plot_fit.py +++ b/PythonGUI_apps/Spectrum_analysis/Spectra_plot_fit.py @@ -100,6 +100,10 @@ def __init__(self): # Peak parameters if adjust params is selected self.center_min = None self.center_max = None + + #variables accounting for data received from FLIM analysis + self.opened_from_flim = False #switched to True in FLIM_plot when "analyze lifetime" clicked + self.sum_data_from_flim = [] self.show() @@ -111,6 +115,7 @@ def open_file(self): self.file = np.loadtxt(filename[0], skiprows = 16, delimiter='\t') except: self.file = np.genfromtxt(filename[0], skip_header=1, skip_footer=3, delimiter='\t') + self.opened_from_flim = False except: pass @@ -226,23 +231,42 @@ def switch_adjust_param(self): self.ui.bounds_groupBox.setEnabled(checked) self.ui.guess_groupBox.setEnabled(checked) + def check_loaded_files(self): + """ + Check if 'subtract background' or 'white light correction' is checked + and if required files have been loaded. + """ + if self.ui.subtract_bck_radioButton.isChecked() and self.bck_file is None: + self.ui.result_textBrowser.setText("You need to load a background file.") + elif self.wlref_file is not None and self.ui.WLRef_checkBox.isChecked() == False: + self.ui.result_textBrowser.setText("You need to check the White Light Correction option!") + elif self.wlref_file is None and self.ui.WLRef_checkBox.isChecked(): + self.ui.result_textBrowser.setText("You need to load a White Light Ref file.") + else: + return True + def plot(self): try: - self.x = self.file[:,0] - self.y = self.file[:,1] - - if self.ui.subtract_bck_checkBox.isChecked() == True and self.ui.WLRef_checkBox.isChecked() == False: - bck_y = self.bck_file[:,1] - self.y = self.y - bck_y - - elif self.ui.subtract_bck_checkBox.isChecked() == False and self.ui.WLRef_checkBox.isChecked() == True: - wlref_y = self.wlref_file[:,1] - self.y = (self.y)/wlref_y - - elif self.ui.subtract_bck_checkBox.isChecked() == True and self.ui.WLRef_checkBox.isChecked() == True: - bck_y = self.bck_file[:,1] - wlref_y = self.wlref_file[:,1] - self.y = (self.y-bck_y)/wlref_y + if self.opened_from_flim: + self.x, self.y = self.sum_data_from_flim + elif self.file is None: + self.ui.result_textBrowser.setText("You need to load a data file.") + else: + self.x = self.file[:,0] + self.y = self.file[:,1] + + if self.check_loaded_files == True: #check the following conditions if all required files have been provided + if self.ui.subtract_bck_radioButton.isChecked() == True and self.ui.WLRef_checkBox.isChecked() == False: + bck_y = self.bck_file[:,1] + self.y = self.y - bck_y + elif self.ui.subtract_bck_radioButton.isChecked() == False and self.ui.WLRef_checkBox.isChecked() == True: + wlref_y = self.wlref_file[:,1] + self.y = (self.y)/wlref_y + + elif self.ui.subtract_bck_radioButton.isChecked() == True and self.ui.WLRef_checkBox.isChecked() == True: + bck_y = self.bck_file[:,1] + wlref_y = self.wlref_file[:,1] + self.y = (self.y-bck_y)/wlref_y if self.ui.norm_checkBox.isChecked(): @@ -267,30 +291,25 @@ def clear_check(self): return True elif self.ui.clear_checkBox.isChecked() == False: return False - - """Open param window and get peak center range values and assign it to variables to use later""" - def configure_scan_params(self): - self.param_window = ParamWindow() - # self.param_window.peak_range.connect(self.peak_range) - - # def peak_range(self, peaks): - # self.center_min = peaks[0] - # self.center_max = peaks[1] - - + def fit_and_plot(self): fit_func = self.ui.fitFunc_comboBox.currentText() try: - - if self.ui.subtract_bck_checkBox.isChecked() == False: - self.ui.result_textBrowser.setText("You need to check the subtract background option!") - - elif self.wlref_file is not None and self.ui.WLRef_checkBox.isChecked() == False: - self.ui.result_textBrowser.setText("You need to check the White Light Correction option!") - + self.plot() + if self.opened_from_flim: + self.file = self.sum_data_from_flim.T + if self.ui.plot_without_bck_radioButton.isChecked(): #if plot w/o bck, create dummy bck_file + self.bck_file = np.zeros(shape=(self.file.shape[0], 2)) + self.bck_file[:,0] = self.file[:,0] + + # if self.ui.subtract_bck_radioButton.isChecked() == False: + # self.ui.result_textBrowser.setText("You need to check the subtract background option!") + if self.check_loaded_files is None: + pass else: - if fit_func == "Single Gaussian" and self.ui.subtract_bck_checkBox.isChecked() == True: + + if fit_func == "Single Gaussian": #and self.ui.subtract_bck_radioButton.isChecked() == True: single_gauss = Single_Gaussian(self.file, self.bck_file, wlref=self.wlref_file) if self.ui.adjust_param_checkBox.isChecked(): center1_min = self.ui.single_peakcenter1_min_spinBox.value() @@ -305,7 +324,7 @@ def fit_and_plot(self): self.ui.plot.plot(self.x, self.result.best_fit, clear=False, pen='k') self.ui.result_textBrowser.setText(self.result.fit_report()) - elif fit_func == "Single Lorentzian" and self.ui.subtract_bck_checkBox.isChecked() == True: + elif fit_func == "Single Lorentzian": #and self.ui.subtract_bck_radioButton.isChecked() == True: single_lorentzian = Single_Lorentzian(self.file, self.bck_file, wlref=self.wlref_file) if self.ui.adjust_param_checkBox.isChecked(): @@ -321,7 +340,7 @@ def fit_and_plot(self): self.ui.plot.plot(self.x, self.result.best_fit, clear=False, pen='k') self.ui.result_textBrowser.setText(self.result.fit_report()) - elif fit_func == "Double Gaussian" and self.ui.subtract_bck_checkBox.isChecked() == True: + elif fit_func == "Double Gaussian": #and self.ui.subtract_bck_radioButton.isChecked() == True: double_gauss = Double_Gaussian(self.file, self.bck_file, wlref=self.wlref_file) if self.ui.adjust_param_checkBox.isChecked(): center1_min = self.ui.double_peakcenter1_min_spinBox.value() @@ -350,7 +369,7 @@ def fit_and_plot(self): self.ui.result_textBrowser.setText(self.result.fit_report()) - elif fit_func == "Triple Gaussians" and self.ui.subtract_bck_checkBox.isChecked() == True: + elif fit_func == "Triple Gaussian": #and self.ui.subtract_bck_radioButton.isChecked() == True: #currently only works for triple gaussian (n=3) multiple_gauss = Multi_Gaussian(self.file, self.bck_file, 3, wlref=self.wlref_file) if self.ui.adjust_param_checkBox.isChecked(): @@ -386,7 +405,7 @@ def fit_and_plot(self): except Exception as e: - self.ui.result_textBrowser.setText(str(e)) + self.ui.result_textBrowser.append(str(e)) def pub_ready_plot_export(self): filename = QtWidgets.QFileDialog.getSaveFileName(self,caption="Filename with EXTENSION") @@ -421,19 +440,19 @@ def get_data_params(self): if self.scan_file_type == "pkl": self.intensities = data['Intensities'] self.wavelengths = data['Wavelengths'] - try: - self.x_scan_size = data['Scan Parameters']['X scan size (um)'] - self.y_scan_size = data['Scan Parameters']['Y scan size (um)'] - self.x_step_size = data['Scan Parameters']['X step size (um)'] - self.y_step_size = data['Scan Parameters']['Y step size (um)'] - except: # TODO test and debug loading pkl file w/o scan parameters - self.configure_scan_params() - while not hasattr(self, "scan_params_entered"): - pass - self.x_scan_size = self.param_window.ui.x_scan_size_spinBox.value() - self.y_scan_size = self.param_window.ui.y_scan_size_spinBox.value() - self.x_step_size = self.param_window.ui.x_step_size_spinBox.value() - self.y_step_size = self.param_window.ui.y_step_size_spinBox.value() + # try: + self.x_scan_size = data['Scan Parameters']['X scan size (um)'] + self.y_scan_size = data['Scan Parameters']['Y scan size (um)'] + self.x_step_size = data['Scan Parameters']['X step size (um)'] + self.y_step_size = data['Scan Parameters']['Y step size (um)'] + # except: # TODO test and debug loading pkl file w/o scan parameters + # self.configure_scan_params() + # while not hasattr(self, "scan_params_entered"): + # pass + # self.x_scan_size = self.param_window.ui.x_scan_size_spinBox.value() + # self.y_scan_size = self.param_window.ui.y_scan_size_spinBox.value() + # self.x_step_size = self.param_window.ui.x_step_size_spinBox.value() + # self.y_step_size = self.param_window.ui.y_step_size_spinBox.value() else: #run this if scan file is h5 self.x_scan_size = data['Scan Parameters'].attrs['X scan size (um)'] @@ -446,6 +465,15 @@ def get_data_params(self): self.numb_x_pixels = int(self.x_scan_size/self.x_step_size) self.numb_y_pixels = int(self.y_scan_size/self.y_step_size) + """Open param window and get peak center range values and assign it to variables to use later""" + # def configure_scan_params(self): + # self.param_window = ParamWindow() + # self.param_window.peak_range.connect(self.peak_range) + + # def peak_range(self, peaks): + # self.center_min = peaks[0] + # self.center_max = peaks[1] + def plot_fit_scan(self): try: if self.ui.use_raw_scan_settings.isChecked(): @@ -679,35 +707,35 @@ def close_application(self): """Parameter Window GUI and Functions""" -param_file_path = (base_path / "scan_params_input.ui").resolve() +# param_file_path = (base_path / "scan_params_input.ui").resolve() -param_uiFile = param_file_path +# param_uiFile = param_file_path -param_WindowTemplate, param_TemplateBaseClass = pg.Qt.loadUiType(param_uiFile) +# param_WindowTemplate, param_TemplateBaseClass = pg.Qt.loadUiType(param_uiFile) -class ParamWindow(param_TemplateBaseClass): +# class ParamWindow(param_TemplateBaseClass): - #peak_range = QtCore.pyqtSignal(list) +# #peak_range = QtCore.pyqtSignal(list) - def __init__(self): -# super(param_TemplateBaseClass, self).__init__() - param_TemplateBaseClass.__init__(self) +# def __init__(self): +# # super(param_TemplateBaseClass, self).__init__() +# param_TemplateBaseClass.__init__(self) - # Create the param window - self.pui = param_WindowTemplate() - self.pui.setupUi(self) +# # Create the param window +# self.pui = param_WindowTemplate() +# self.pui.setupUi(self) - self.pui.done_pushButton.clicked.connect(self.done) +# self.pui.done_pushButton.clicked.connect(self.done) - self.show() +# self.show() - def done(self): - #center_min, center_max = self.current_peak_range() - #self.peak_range.emit([center_min, center_max]) - self.close() - self.scan_params_entered = True +# def done(self): +# #center_min, center_max = self.current_peak_range() +# #self.peak_range.emit([center_min, center_max]) +# self.close() +# self.scan_params_entered = True """Run the Main Window""" def run(): diff --git a/PythonGUI_apps/Spectrum_analysis/Spectra_plot_fit_gui.ui b/PythonGUI_apps/Spectrum_analysis/Spectra_plot_fit_gui.ui index ca867d6..fb7721a 100644 --- a/PythonGUI_apps/Spectrum_analysis/Spectra_plot_fit_gui.ui +++ b/PythonGUI_apps/Spectrum_analysis/Spectra_plot_fit_gui.ui @@ -758,8 +758,8 @@ Load Settings - - + + @@ -771,7 +771,7 @@ - + @@ -784,7 +784,7 @@ File - + @@ -797,7 +797,7 @@ File - + @@ -810,43 +810,61 @@ Ref File - - + + 10 - Subtract Background + Normalize - - + + 10 - Correct for White Light + Clear Plots Everytime + + + true - - + + 10 - Normalize + Subtract Background + + + true - + + + + + 10 + + + + Correct for White Light + + + + @@ -860,22 +878,20 @@ Ref File - - + + 10 - Clear Plots Everytime - - - true + Export Publication +Ready Figure - + @@ -888,26 +904,25 @@ Ref File - - + + 10 - - Export Publication -Ready Figure - - - + + 10 + + Plot without Background + @@ -1330,12 +1345,12 @@ File - PlotWidget + ImageView QGraphicsView
pyqtgraph
- ImageView + PlotWidget QGraphicsView
pyqtgraph
From fc8cbbbab16ed4281e4be9b96db268dfd922192e Mon Sep 17 00:00:00 2001 From: "LAKESIDE\\LindaT18" Date: Tue, 13 Aug 2019 14:15:28 -0700 Subject: [PATCH 06/25] ui changes, fix FLIM image direction --- PythonGUI_apps/FLIM_analysis/FLIM_plot.py | 10 +++++----- PythonGUI_apps/FLIM_analysis/flim_plot_gui.ui | 4 ++-- .../Lifetime_analysis/Lifetime_analysis_gui_layout.ui | 6 +++--- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/PythonGUI_apps/FLIM_analysis/FLIM_plot.py b/PythonGUI_apps/FLIM_analysis/FLIM_plot.py index ad1eaad..79a8032 100644 --- a/PythonGUI_apps/FLIM_analysis/FLIM_plot.py +++ b/PythonGUI_apps/FLIM_analysis/FLIM_plot.py @@ -50,7 +50,7 @@ def __init__(self): self.ui.import_pkl_pushButton.clicked.connect(self.import_pkl_to_convert) self.ui.pkl_to_h5_pushButton.clicked.connect(self.pkl_to_h5) self.ui.analyze_lifetime_pushButton.clicked.connect(self.on_analyze_lifetime) - self.ui.analyze_spectrum_pushButton.clicked.connect(self.on_analyze_spectrum) + self.ui.analyze_psf_pushButton.clicked.connect(self.on_analyze_psf) self.show() @@ -139,7 +139,7 @@ def line_profile_update_plot(self): except: pass - def on_analyze_spectrum(self): + def on_analyze_psf(self): self.spectrum_window = Spectra_plot_fit.MainWindow() self.spectrum_window.show() self.spectrum_window.opened_from_flim = True @@ -234,10 +234,10 @@ def save_intensities_image(self): filename_ext = os.path.basename(self.filename[0]) filename = os.path.splitext(filename_ext)[0] #get filename without extension save_to = folder + "\\" + filename + "_intensity_sums.png" - cpm.plot_confocal(self.intensity_sums, stepsize=np.abs(self.pkl_file['Scan Parameters']['X step size (um)'])) + cpm.plot_confocal(self.intensity_sums, FLIM_adjust=False, stepsize=np.abs(self.x_step_size)) plt.savefig(save_to, bbox_inches='tight', dpi=300) - except: - pass + except Exception as e: + print(format(e)) def save_intensities_array(self): try: diff --git a/PythonGUI_apps/FLIM_analysis/flim_plot_gui.ui b/PythonGUI_apps/FLIM_analysis/flim_plot_gui.ui index 65c1e92..2cd9a32 100644 --- a/PythonGUI_apps/FLIM_analysis/flim_plot_gui.ui +++ b/PythonGUI_apps/FLIM_analysis/flim_plot_gui.ui @@ -57,9 +57,9 @@
- + - Analyze spectrum + Analyze PSF diff --git a/PythonGUI_apps/Lifetime_analysis/Lifetime_analysis_gui_layout.ui b/PythonGUI_apps/Lifetime_analysis/Lifetime_analysis_gui_layout.ui index 945c672..d6f6cb6 100644 --- a/PythonGUI_apps/Lifetime_analysis/Lifetime_analysis_gui_layout.ui +++ b/PythonGUI_apps/Lifetime_analysis/Lifetime_analysis_gui_layout.ui @@ -6,8 +6,8 @@ 0 0 - 1985 - 1470 + 1490 + 1201 @@ -1261,7 +1261,7 @@ 0 0 - 1985 + 1490 31 From e5aad832314f21658a442d89872a3f8a2d112e05 Mon Sep 17 00:00:00 2001 From: "LAKESIDE\\LindaT18" Date: Tue, 13 Aug 2019 15:52:42 -0700 Subject: [PATCH 07/25] added export fig for spectra scan, added export data for single spectrum --- .../Spectrum_analysis/Spectra_plot_fit.py | 37 +++++- .../Spectrum_analysis/Spectra_plot_fit_gui.ui | 111 ++++++++++++------ 2 files changed, 107 insertions(+), 41 deletions(-) diff --git a/PythonGUI_apps/Spectrum_analysis/Spectra_plot_fit.py b/PythonGUI_apps/Spectrum_analysis/Spectra_plot_fit.py index c826937..ace143a 100644 --- a/PythonGUI_apps/Spectrum_analysis/Spectra_plot_fit.py +++ b/PythonGUI_apps/Spectrum_analysis/Spectra_plot_fit.py @@ -74,7 +74,8 @@ def __init__(self): self.ui.fit_scan_pushButton.clicked.connect(self.fit_and_plot_scan) # self.ui.config_fit_params_pushButton.clicked.connect(self.configure_fit_params) self.ui.clear_pushButton.clicked.connect(self.clear_plot) - self.ui.export_fig_pushButton.clicked.connect(self.pub_ready_plot_export) + self.ui.export_single_figure_pushButton.clicked.connect(self.pub_ready_plot_export) + self.ui.export_scan_figure_pushButton.clicked.connect(self.pub_ready_plot_export) self.ui.import_pkl_pushButton.clicked.connect(self.open_pkl_file) self.ui.data_txt_pushButton.clicked.connect(self.pkl_data_to_txt) @@ -86,6 +87,9 @@ def __init__(self): self.ui.fitFunc_comboBox.currentTextChanged.connect(self.switch_bounds_and_guess_tab) self.ui.adjust_param_checkBox.stateChanged.connect(self.switch_adjust_param) + self.ui.export_data_pushButton.clicked.connect(self.export_data) + self.ui.clear_export_data_pushButton.clicked.connect(self.clear_export_data) + # for i in reversed(range(self.ui.bounds_groupBox.layout().count())): # self.ui.bounds_groupBox.layout().itemAt(i).widget().deleteLater() #self.ui.single_bounds_page.layout().addWidget(QtWidgets.QPushButton("test")) @@ -104,17 +108,20 @@ def __init__(self): #variables accounting for data received from FLIM analysis self.opened_from_flim = False #switched to True in FLIM_plot when "analyze lifetime" clicked self.sum_data_from_flim = [] + + #container for data to append to txt file + self.data_list = [] self.show() """ Open Single Spectrum files """ def open_file(self): try: - filename = QtWidgets.QFileDialog.getOpenFileName(self) + self.single_spec_filename = QtWidgets.QFileDialog.getOpenFileName(self) try: - self.file = np.loadtxt(filename[0], skiprows = 16, delimiter='\t') + self.file = np.loadtxt(self.single_spec_filename[0], skiprows = 16, delimiter='\t') except: - self.file = np.genfromtxt(filename[0], skip_header=1, skip_footer=3, delimiter='\t') + self.file = np.genfromtxt(self.single_spec_filename[0], skip_header=1, skip_footer=3, delimiter='\t') self.opened_from_flim = False except: pass @@ -403,6 +410,7 @@ def fit_and_plot(self): self.ui.plot.plot(self.x, comps['g3_'], pen='c', clear=False) self.ui.result_textBrowser.setText(self.result.fit_report()) + self.data_list.append(self.ui.result_textBrowser.toPlainText()) except Exception as e: self.ui.result_textBrowser.append(str(e)) @@ -433,6 +441,27 @@ def pub_ready_plot_export(self): except AttributeError: self.ui.result_textBrowser.setText("Need to fit the data first!") + def export_data(self): + """ Save fit params and srv calculations stored in data_list as .txt """ + folder = os.path.dirname(self.single_spec_filename[0]) + filename_ext = os.path.basename(self.single_spec_filename[0]) + filename = os.path.splitext(filename_ext)[0] #get filename without extension + + path = folder + "/" + filename + "_fit_results.txt" + if not os.path.exists(path): + file = open(path, "w+") + else: + file = open(path, "a+") + + for i in range(len(self.data_list)): + file.write(self.data_list[i] + "\n\n") + + self.data_list = [] + file.close() + + def clear_export_data(self): + self.data_list = [] + """ Scan spectra functions """ def get_data_params(self): diff --git a/PythonGUI_apps/Spectrum_analysis/Spectra_plot_fit_gui.ui b/PythonGUI_apps/Spectrum_analysis/Spectra_plot_fit_gui.ui index fb7721a..273d006 100644 --- a/PythonGUI_apps/Spectrum_analysis/Spectra_plot_fit_gui.ui +++ b/PythonGUI_apps/Spectrum_analysis/Spectra_plot_fit_gui.ui @@ -759,81 +759,80 @@ Load Settings - - + + 10 - For Single Spectrum + Background +File - - + + 10 - Spectrum -File + Normalize - - + + 10 - Background -File + Clear Plots Everytime + + + true - - + + 10 - White Light -Ref File + Correct for White Light - - + + 10 - Normalize + For Single Spectrum - - + + 10 - Clear Plots Everytime - - - true + White Light +Ref File @@ -852,15 +851,37 @@ Ref File - - + + 10 - Correct for White Light + Spectrum +File + + + + + + + + 10 + + + + Export data + + + + + + + + 10 + @@ -879,7 +900,7 @@ Ref File - + 10 @@ -891,37 +912,40 @@ Ready Figure - - + + 10 - false - Clear Plot + Plot without Background - - + + 10 + false + + Clear Plot + - - + + 10 - Plot without Background + Clear export data @@ -1226,6 +1250,19 @@ File + + + + + 12 + + + + Export Fitted +Scan + + + From b65a73896af7406956a98d5eb423ea64afaf35cf Mon Sep 17 00:00:00 2001 From: SarthakJariwala Date: Wed, 14 Aug 2019 13:46:02 -0700 Subject: [PATCH 08/25] window title changes, minor ui changes in MainDataBrowser --- PythonGUI_apps/DataBrowser.py | 90 +- PythonGUI_apps/DataBrowser_GUI.ui | 17 +- PythonGUI_apps/FLIM_analysis/flim_plot_gui.ui | 2 +- PythonGUI_apps/H5_Pkl/h5_pkl_view_gui.ui | 4 +- PythonGUI_apps/H5_Pkl/h5_view_and_plot_gui.ui | 6 +- .../Lifetime_analysis_gui_layout.ui | 4 +- .../Lifetime_analysis/Lifetime_plot_fit.py | 1036 ++++++++--------- .../PLQE_analysis/plqe_analysis_gui.ui | 2 +- .../Spectrum_analysis/Spectra_plot_fit_gui.ui | 4 +- .../UV_Vis_analysis/uv_vis_analysis_gui.ui | 4 +- 10 files changed, 587 insertions(+), 582 deletions(-) diff --git a/PythonGUI_apps/DataBrowser.py b/PythonGUI_apps/DataBrowser.py index 2ab2b25..d77f8c9 100644 --- a/PythonGUI_apps/DataBrowser.py +++ b/PythonGUI_apps/DataBrowser.py @@ -10,7 +10,7 @@ from pathlib import Path import pyqtgraph as pg -from pyqtgraph.Qt import QtGui +from pyqtgraph.Qt import QtGui, QtCore from Lifetime_analysis import Lifetime_plot_fit from Spectrum_analysis import Spectra_plot_fit @@ -20,7 +20,7 @@ from H5_Pkl import h5_pkl_view, h5_view_and_plot pg.mkQApp() -pg.setConfigOption('background', 'w') +#pg.setConfigOption('background', 'w') base_path = Path(__file__).parent file_path = (base_path / "DataBrowser_GUI.ui").resolve() @@ -29,50 +29,52 @@ WindowTemplate, TemplateBaseClass = pg.Qt.loadUiType(uiFile) -class MainWindow(TemplateBaseClass): - - def __init__(self): - TemplateBaseClass.__init__(self) - - # Create the main window - self.ui = WindowTemplate() - self.ui.setupUi(self) - self.ui.select_comboBox.addItems(["Lifetime Analysis", "Spectrum Analysis", "FLIM Analysis", - "UV-Vis Analysis", "PLQE Analysis", "H5 View/Plot", "H5/PKL Viewer"]) - self.ui.load_pushButton.clicked.connect(self.load_app) - - self.show() +class MainWindow(TemplateBaseClass): + + def __init__(self): + TemplateBaseClass.__init__(self) + + # Create the main window + self.ui = WindowTemplate() + self.ui.setupUi(self) + self.ui.select_comboBox.addItems(["Lifetime Analysis", "Spectrum Analysis", "FLIM Analysis", + "UV-Vis Analysis", "PLQE Analysis", "H5 View/Plot", "H5/PKL Viewer"]) + self.ui.load_pushButton.clicked.connect(self.load_app) + + self.show() - - def load_app(self): - - analysis_software = self.ui.select_comboBox.currentText() - - if analysis_software == "Lifetime Analysis": - self.lifetime_window = Lifetime_plot_fit.MainWindow() - self.lifetime_window.show() - elif analysis_software == "Spectrum Analysis": - self.spectrum_window = Spectra_plot_fit.MainWindow() - self.spectrum_window.show() - elif analysis_software == "FLIM Analysis": - self.flim_window = FLIM_plot.MainWindow() - self.flim_window.show() - elif analysis_software == "UV-Vis Analysis": - self.uv_vis_window = uv_vis_analysis.MainWindow() - self.uv_vis_window.show() - elif analysis_software == "PLQE Analysis": - self.plqe_window = plqe_analysis.MainWindow() - self.plqe_window.show() - elif analysis_software == "H5 View/Plot": - app = h5_view_and_plot.H5ViewPlot(sys.argv) - #sys.exit(app.exec_()) - elif analysis_software == "H5/PKL Viewer": - app = h5_pkl_view.H5PklView(sys.argv) - #sys.exit(app.exec_()) + + def load_app(self): + + analysis_software = self.ui.select_comboBox.currentText() + + if analysis_software == "Lifetime Analysis": + self.lifetime_window = Lifetime_plot_fit.MainWindow() + self.lifetime_window.show() + elif analysis_software == "Spectrum Analysis": + self.spectrum_window = Spectra_plot_fit.MainWindow() + self.spectrum_window.show() + elif analysis_software == "FLIM Analysis": + self.flim_window = FLIM_plot.MainWindow() + self.flim_window.show() + elif analysis_software == "UV-Vis Analysis": + self.uv_vis_window = uv_vis_analysis.MainWindow() + self.uv_vis_window.show() + elif analysis_software == "PLQE Analysis": + self.plqe_window = plqe_analysis.MainWindow() + self.plqe_window.show() + elif analysis_software == "H5 View/Plot": + app = h5_view_and_plot.H5ViewPlot(sys.argv) + #sys.exit(app.exec_()) + elif analysis_software == "H5/PKL Viewer": + app = h5_pkl_view.H5PklView(sys.argv) + #sys.exit(app.exec_()) + + def run(): - win = MainWindow() - QtGui.QApplication.instance().exec_() - return + win = MainWindow() + QtGui.QApplication.instance().exec_() + return run() \ No newline at end of file diff --git a/PythonGUI_apps/DataBrowser_GUI.ui b/PythonGUI_apps/DataBrowser_GUI.ui index 3b55990..054b4ef 100644 --- a/PythonGUI_apps/DataBrowser_GUI.ui +++ b/PythonGUI_apps/DataBrowser_GUI.ui @@ -6,12 +6,12 @@ 0 0 - 684 - 403 + 435 + 221 - MainWindow + GLabViz - DataBrowser @@ -19,13 +19,16 @@ - 20 + 30 75 true - Welcome to the GLabViz + GLabViz + + + Qt::AlignCenter @@ -82,8 +85,8 @@ 0 0 - 684 - 38 + 435 + 21 diff --git a/PythonGUI_apps/FLIM_analysis/flim_plot_gui.ui b/PythonGUI_apps/FLIM_analysis/flim_plot_gui.ui index 2cd9a32..bbfef2a 100644 --- a/PythonGUI_apps/FLIM_analysis/flim_plot_gui.ui +++ b/PythonGUI_apps/FLIM_analysis/flim_plot_gui.ui @@ -11,7 +11,7 @@ - Form + FLIM Analysis diff --git a/PythonGUI_apps/H5_Pkl/h5_pkl_view_gui.ui b/PythonGUI_apps/H5_Pkl/h5_pkl_view_gui.ui index 08ec7ff..d147ddc 100644 --- a/PythonGUI_apps/H5_Pkl/h5_pkl_view_gui.ui +++ b/PythonGUI_apps/H5_Pkl/h5_pkl_view_gui.ui @@ -11,7 +11,7 @@ - ScopeFoundry Data Browser + H5/pkl View @@ -78,7 +78,7 @@ 0 0 856 - 31 + 21 diff --git a/PythonGUI_apps/H5_Pkl/h5_view_and_plot_gui.ui b/PythonGUI_apps/H5_Pkl/h5_view_and_plot_gui.ui index de399cb..a7bcc01 100644 --- a/PythonGUI_apps/H5_Pkl/h5_view_and_plot_gui.ui +++ b/PythonGUI_apps/H5_Pkl/h5_view_and_plot_gui.ui @@ -11,7 +11,7 @@ - ScopeFoundry Data Browser + H5 View and Plot @@ -257,7 +257,7 @@ 0 0 856 - 31 + 21 @@ -267,7 +267,7 @@ PlotWidget QGraphicsView -
pyqtgraph
+
pyqtgraph
ImageView diff --git a/PythonGUI_apps/Lifetime_analysis/Lifetime_analysis_gui_layout.ui b/PythonGUI_apps/Lifetime_analysis/Lifetime_analysis_gui_layout.ui index d6f6cb6..e80df57 100644 --- a/PythonGUI_apps/Lifetime_analysis/Lifetime_analysis_gui_layout.ui +++ b/PythonGUI_apps/Lifetime_analysis/Lifetime_analysis_gui_layout.ui @@ -11,7 +11,7 @@ - MainWindow + Lifetime Analysis @@ -1262,7 +1262,7 @@ 0 0 1490 - 31 + 21 diff --git a/PythonGUI_apps/Lifetime_analysis/Lifetime_plot_fit.py b/PythonGUI_apps/Lifetime_analysis/Lifetime_plot_fit.py index 8e27f7d..fb9bca5 100644 --- a/PythonGUI_apps/Lifetime_analysis/Lifetime_plot_fit.py +++ b/PythonGUI_apps/Lifetime_analysis/Lifetime_plot_fit.py @@ -18,13 +18,13 @@ # local module imports try: - from Lifetime_analysis.Fit_functions import stretch_exp_fit, double_exp_fit, single_exp_fit - from Lifetime_analysis.picoharp_phd import read_picoharp_phd - from Lifetime_analysis.Fit_functions_with_irf import fit_exp_stretch_diffev, fit_exp_stretch_fmin_tnc, fit_multi_exp_diffev, fit_multi_exp_fmin_tnc + from Lifetime_analysis.Fit_functions import stretch_exp_fit, double_exp_fit, single_exp_fit + from Lifetime_analysis.picoharp_phd import read_picoharp_phd + from Lifetime_analysis.Fit_functions_with_irf import fit_exp_stretch_diffev, fit_exp_stretch_fmin_tnc, fit_multi_exp_diffev, fit_multi_exp_fmin_tnc except: - from Fit_functions import stretch_exp_fit, double_exp_fit, single_exp_fit - from Fit_functions_with_irf import fit_exp_stretch_diffev, fit_exp_stretch_fmin_tnc, fit_multi_exp_diffev, fit_multi_exp_fmin_tnc - from picoharp_phd import read_picoharp_phd + from Fit_functions import stretch_exp_fit, double_exp_fit, single_exp_fit + from Fit_functions_with_irf import fit_exp_stretch_diffev, fit_exp_stretch_fmin_tnc, fit_multi_exp_diffev, fit_multi_exp_fmin_tnc + from picoharp_phd import read_picoharp_phd """Recylce params for plotting""" plt.rc('xtick', labelsize = 20) @@ -36,7 +36,7 @@ pg.mkQApp() pg.setConfigOption('background', 'w') -#pg.setConfigOption('crashWarning', True) +##pg.setConfigOption('crashWarning', True) base_path = Path(__file__).parent file_path = (base_path / "Lifetime_analysis_gui_layout.ui").resolve() @@ -45,526 +45,526 @@ WindowTemplate, TemplateBaseClass = pg.Qt.loadUiType(uiFile) -class MainWindow(TemplateBaseClass): - - def __init__(self): - TemplateBaseClass.__init__(self) - - # Create the main window - self.ui = WindowTemplate() - self.ui.setupUi(self) - self.ui.Res_comboBox.addItems(["0.004","0.008","0.016","0.032","0.064","0.128","0.256","0.512"]) - self.ui.FittingFunc_comboBox.addItems(["Stretched Exponential","Double Exponential", "Single Exponential"]) - self.ui.FittingMethod_comboBox.addItems(["diff_ev", "fmin_tnc"]) - - #set up file menu - self.ui.actionOpen.triggered.connect(self.open_file) - self.ui.actionOpen_IRF_File.triggered.connect(self.open_irf_file) - self.ui.actionSave.triggered.connect(self.save_file) - self.ui.actionExit.triggered.connect(self.close_application) - - #set up ui signals - self.ui.plot_pushButton.clicked.connect(self.plot) - self.ui.fit_pushButton.clicked.connect(self.call_fit_and_plot) - self.ui.clear_pushButton.clicked.connect(self.clear_plot) - self.ui.export_plot_pushButton.clicked.connect(self.pub_ready_plot_export) - self.ui.calculate_srv_pushButton.clicked.connect(self.calculate_srv) - - self.ui.log_checkBox.stateChanged.connect(self.make_semilog) - self.ui.fit_with_irf_checkBox.stateChanged.connect(self.switch_fit_settings) - self.ui.FittingFunc_comboBox.currentTextChanged.connect(self.switch_function_tab) - self.ui.FittingMethod_comboBox.currentTextChanged.connect(self.switch_init_params_groupBox) - self.ui.separate_irf_checkBox.stateChanged.connect(self.switch_open_irf) - self.ui.export_data_pushButton.clicked.connect(self.export_data) - self.ui.clear_export_data_pushButton.clicked.connect(self.clear_export_data) - - #set up plot color button - self.plot_color_button = pg.ColorButton(color=(255,0,0)) - self.ui.plot_color_button_container.layout().addWidget(self.plot_color_button) - self.plot_color = self.plot_color_button.color() - self.plot_color_button.sigColorChanged.connect(self.plot_color_changed) - - self.file = None - self.out = None # output file after fitting - self.data_list = [] - - #variables accounting for data received from FLIM analysis - self.opened_from_flim = False #switched to True in FLIM_plot when "analyze lifetime" clicked - self.hist_data_from_flim = [] #container for flim roi data - - self.show() - - def open_file(self): - """ Open data file """ +class MainWindow(TemplateBaseClass): + + def __init__(self): + TemplateBaseClass.__init__(self) + + # Create the main window + self.ui = WindowTemplate() + self.ui.setupUi(self) + self.ui.Res_comboBox.addItems(["0.004","0.008","0.016","0.032","0.064","0.128","0.256","0.512"]) + self.ui.FittingFunc_comboBox.addItems(["Stretched Exponential","Double Exponential", "Single Exponential"]) + self.ui.FittingMethod_comboBox.addItems(["diff_ev", "fmin_tnc"]) + + #set up file menu + self.ui.actionOpen.triggered.connect(self.open_file) + self.ui.actionOpen_IRF_File.triggered.connect(self.open_irf_file) + self.ui.actionSave.triggered.connect(self.save_file) + self.ui.actionExit.triggered.connect(self.close_application) + + #set up ui signals + self.ui.plot_pushButton.clicked.connect(self.plot) + self.ui.fit_pushButton.clicked.connect(self.call_fit_and_plot) + self.ui.clear_pushButton.clicked.connect(self.clear_plot) + self.ui.export_plot_pushButton.clicked.connect(self.pub_ready_plot_export) + self.ui.calculate_srv_pushButton.clicked.connect(self.calculate_srv) + + self.ui.log_checkBox.stateChanged.connect(self.make_semilog) + self.ui.fit_with_irf_checkBox.stateChanged.connect(self.switch_fit_settings) + self.ui.FittingFunc_comboBox.currentTextChanged.connect(self.switch_function_tab) + self.ui.FittingMethod_comboBox.currentTextChanged.connect(self.switch_init_params_groupBox) + self.ui.separate_irf_checkBox.stateChanged.connect(self.switch_open_irf) + self.ui.export_data_pushButton.clicked.connect(self.export_data) + self.ui.clear_export_data_pushButton.clicked.connect(self.clear_export_data) + + #set up plot color button + self.plot_color_button = pg.ColorButton(color=(255,0,0)) + self.ui.plot_color_button_container.layout().addWidget(self.plot_color_button) + self.plot_color = self.plot_color_button.color() + self.plot_color_button.sigColorChanged.connect(self.plot_color_changed) + + self.file = None + self.out = None # output file after fitting + self.data_list = [] + + #variables accounting for data received from FLIM analysis + self.opened_from_flim = False #switched to True in FLIM_plot when "analyze lifetime" clicked + self.hist_data_from_flim = [] #container for flim roi data + + self.show() + + def open_file(self): + """ Open data file """ # try: - self.filename = QtWidgets.QFileDialog.getOpenFileName(self) - try: - if ".csv" in self.filename[0] or ".txt" in self.filename[0]: #if txt or csv, prompt user to enter # of rows to skip - self.skip_rows_window = SkipRowsWindow() - self.skip_rows_window.skip_rows_signal.connect(self.open_with_skip_rows_window) - else: - self.file = read_picoharp_phd(self.filename[0]) - self.opened_from_flim = False - except: - pass - - def open_with_skip_rows_window(self): - """ Prompts user to enter how many rows to skip """ - skip_rows = self.skip_rows_window.ui.skip_rows_spinBox.value() - if ".txt" in self.filename[0]: - self.file = np.loadtxt(self.filename[0], skiprows=skip_rows) - elif ".csv" in self.filename[0]: - self.file = np.genfromtxt(self.filename[0], skip_header=skip_rows, delimiter=",") - - def open_irf_file(self): - """ Open file with irf - enabled if 'load separate irf' is checled """ - self.irf_filename = QtWidgets.QFileDialog.getOpenFileName(self) - try: - if ".txt" in self.irf_filename[0] or ".csv" in self.irf_filename[0]: - self.irf_skip_rows_window = SkipRowsWindow() - self.irf_skip_rows_window.skip_rows_signal.connect(self.open_irf_with_skip_rows_window) - else: - self.irf_file = read_picoharp_phd(self.irf_filename[0]) - except: - pass - - def open_irf_with_skip_rows_window(self): - irf_skip_rows = self.irf_skip_rows_window.ui.skip_rows_spinBox.value() - if ".txt" in self.irf_filename[0]: - self.irf_file = np.loadtxt(self.irf_filename[0], skiprows=irf_skip_rows) - elif ".csv" in self.irf_filename[0]: - self.irf_file = np.genfrontxt(self.irf_filename[0], skip_header=irf_skip_rows, delimiter=",") - - def save_file(self): - try: - filename = QtWidgets.QFileDialog.getSaveFileName(self) - np.savetxt(filename[0], self.out, fmt = '%.5f', header = 'Time, Raw_PL, Sim_PL', delimiter = ' ') - except: - pass - - def switch_open_irf(self): - """ Handle 'load separate irf' checkbox """ - self.ui.actionOpen_IRF_File.setEnabled(self.ui.separate_irf_checkBox.isChecked()) - - def switch_fit_settings(self): - """ Enable bounds/initial guess groupboxes only when 'Fit with IRF' is checked """ - checked = self.ui.fit_with_irf_checkBox.isChecked() - for func in "str de se".split(" "): - boundsGb = eval("self.ui."+func+"_bounds_groupBox") - #initGb = eval("self.ui."+func+"_init_groupBox") - boundsGb.setEnabled(checked) - #initGb.setEnabled(checked) - if checked == True: - self.switch_init_params_groupBox() - else: - initGb = eval("self.ui."+func+"_init_groupBox") - initGb.setEnabled(checked) - self.ui.FittingMethod_comboBox.setEnabled(checked) - - def switch_function_tab(self): - """ Switch bounds groupbox contents depending on selected fit function """ - fitting_func = self.ui.FittingFunc_comboBox.currentText() - if fitting_func == "Stretched Exponential": - self.ui.fitting_params_stackedWidget.setCurrentIndex(0) - elif fitting_func == "Double Exponential": - self.ui.fitting_params_stackedWidget.setCurrentIndex(1) - elif fitting_func == "Single Exponential": - self.ui.fitting_params_stackedWidget.setCurrentIndex(2) - - def switch_init_params_groupBox(self): - """ Enable initial guess groupbox only when fmin_tnc fit method selected """ - if self.ui.FittingMethod_comboBox.currentText() == "diff_ev": - for func in "str de se".split(" "): - initGb = eval("self.ui."+func+"_init_groupBox") - initGb.setEnabled(False) - #initGb.setEnabled(checked) - elif self.ui.FittingMethod_comboBox.currentText() == "fmin_tnc": - for func in "str de se".split(" "): - initGb = eval("self.ui."+func+"_init_groupBox") - initGb.setEnabled(True) - - def plot_color_changed(self): - """ Grab new plot_color when color button value is changed """ - self.plot_color = self.plot_color_button.color() - - def acquire_settings(self, mode="data"): - """ - Acquire data or irf from channel specified in spinbox. - - mode -- string specifying whether to use data or irf channel (default "data") - """ - self.resolution = float(self.ui.Res_comboBox.currentText()) - if mode == "data": - channel = int(self.ui.Data_channel_spinBox.value()) - elif mode == "irf": - channel = int(self.ui.irf_channel_spinBox.value()) - try: - try: # - if self.ui.separate_irf_checkBox.isChecked() and mode=="irf": #if separate irf, get from irf file - try: - y = self.irf_file[:,channel] - except: - y = self.irf_file.get_curve(channel)[1] - else: #otherwise, get data/irf from data file - y = self.file[:,channel] - except: - res, y = self.file.get_curve(channel) - # TO DO - check if res read in is the same as selected - time_window = int(np.floor(self.file.get_time_window_in_ns(channel))) - y = y[0:time_window] - - length = np.shape(y)[0] - x = np.arange(0, length, 1) * self.resolution - return x,y - - except Exception as e: - self.ui.Result_textBrowser.setText(str(e)) - - def plot(self): - try: - if self.opened_from_flim: - x, y = self.hist_data_from_flim - else: - x,y = self.acquire_settings() #get data - if self.ui.normalize_checkBox.isChecked(): - y = y / np.amax(y) - - self.ui.plot.plot(x, y, clear=self.ui.clear_plot_checkBox.isChecked(), pen=pg.mkPen(self.plot_color)) - - try: - self.ui.Result_textBrowser.setText("Integral Counts :\n" "{:.2E}".format( - self.file.get_integral_counts(int(self.ui.Channel_spinBox.value())))) - except: - self.ui.Result_textBrowser.setText("Integral Counts :\n" "{:.2E}".format(np.sum(y))) - except: - pass - self.ui.plot.setLabel('left', 'Intensity', units='a.u.') - self.ui.plot.setLabel('bottom', 'Time (ns)') - - def make_semilog(self): - """ Switch y-log on/off """ - self.ui.plot.setLogMode(False,self.ui.log_checkBox.isChecked()) - - def clear_plot(self): - self.ui.plot.clear() - self.ui.Result_textBrowser.clear() - - def fit_and_plot(self): - """ Fit and plot without IRF """ - try: - if not hasattr(self, "file"): - self.ui.Result_textBrowser.setText("You need to load a data file.") - else: - if self.opened_from_flim: - x, y = self.hist_data_from_flim - else: - x,y = self.acquire_settings() #get data - y_norm = y/np.max(y) #normalized y - - # find the max intensity in the array and start things from there - find_max_int = np.nonzero(y_norm == 1) - y = y[np.asscalar(find_max_int[0]):] - x = x[np.asscalar(find_max_int[0]):] - - t = x - time_fit = t - TRPL_interp = np.interp(time_fit, t, y) - - fit_func = self.ui.FittingFunc_comboBox.currentText() - self.ui.plot.plot(t, y, clear=self.ui.clear_plot_checkBox.isChecked(), pen=pg.mkPen(self.plot_color)) - - if fit_func == "Stretched Exponential": #stretch exponential tab - tc, beta, a, avg_tau, PL_fit = stretch_exp_fit(TRPL_interp, t) - self.out = np.empty((len(t), 3)) - self.out[:,0] = t #time - self.out[:,1] = TRPL_interp #Raw PL - self.out[:,2] = PL_fit # PL fit - self.ui.plot.plot(t, PL_fit, clear=self.ui.clear_plot_checkBox.isChecked(), pen='k') - self.ui.Result_textBrowser.setText("Fit Results:\n\nFit Function: Stretched Exponential" - "\nFit Method: " + "diff_ev" + #TODO : change when diff_ev and fmin_tnc implemented for non-irf - "\nAverage Lifetime = " + str(avg_tau)+ " ns" - "\nCharacteristic Tau = " + str(tc)+" ns" - "\nBeta = "+str(beta)) - self.ui.average_lifetime_spinBox.setValue(avg_tau) - - elif fit_func == "Double Exponential": #double exponential tab - tau1, a1, tau2, a2, avg_tau, PL_fit = double_exp_fit(TRPL_interp, t) - self.out = np.empty((len(t), 3)) - self.out[:,0] = t #time - self.out[:,1] = TRPL_interp #Raw PL - self.out[:,2] = PL_fit # PL fit - self.ui.plot.plot(t, PL_fit, clear=self.ui.clear_plot_checkBox.isChecked(), pen='k') - self.ui.Result_textBrowser.setText("Fit Results:\n\nFit Function: Double Exponential" - "\nFit Method: " + "diff_ev" + - "\nAverage Lifetime = " + str(avg_tau)+ " ns" - "\nTau 1 = " + str(tau1)+" ns" - "\nA 1 = " + str(a1)+ - "\nTau 2 = " + str(tau2)+" ns" - "\nA 2 = " + str(a2)) - #TODO - once tau_avg implemented, set average lifetime spinbox to tau_avg value - - elif fit_func == "Single Exponential": #single exponential tab - tau, a, PL_fit = single_exp_fit(TRPL_interp, t) - self.out = np.empty((len(t), 3)) - self.out[:,0] = t #time - self.out[:,1] = TRPL_interp #Raw PL - self.out[:,2] = PL_fit # PL fit - self.ui.plot.plot(t, PL_fit, clear=self.ui.clear_plot_checkBox.isChecked(), pen='k') - self.ui.Result_textBrowser.setText("Fit Results:\n\nFit Function: Single Exponential" - "\nFit Method: " + "diff_ev" + - "\nLifetime = " + str(tau)+ " ns" - "\nA = " + str(a)) - self.ui.average_lifetime_spinBox.setValue(tau) - - #add fit params to data_list - self.data_list.append("Data Channel: " + str(self.ui.Data_channel_spinBox.value()) + "\n" + self.ui.Result_textBrowser.toPlainText()) - - self.ui.plot.setLabel('left', 'Intensity', units='a.u.') - self.ui.plot.setLabel('bottom', 'Time (ns)') - return self.out - - except Exception as e: - self.ui.Result_textBrowser.append(format(e)) - - def fit_and_plot_with_irf(self): - """ Fit and plot with IRF """ - try: - self.ui.Result_textBrowser.clear() - if not hasattr(self, "file"): - self.ui.Result_textBrowser.append("You need to load a data file.") - if not hasattr(self, "irf_file") and self.ui.separate_irf_checkBox.isChecked(): - self.ui.Result_textBrowser.append("You need to load an IRF file.") - else: - if self.opened_from_flim: - x,y = self.hist_data_from_flim - else: - x,y = self.acquire_settings() #get data - _, irf_counts = self.acquire_settings(mode="irf") #get irf counts - - #make sure Irf and data have the same length - if len(y) != len(irf_counts): - y = y[0:min(len(y), len(irf_counts))] - irf_counts = irf_counts[0:min(len(y), len(irf_counts))] - x = x[0:min(len(y), len(irf_counts))] - - y_norm = y/np.max(y) #normalized y - irf_norm = irf_counts/np.amax(irf_counts) #normalized irf - - t = x - time_fit = t - y = y_norm - irf_counts = irf_norm - - TRPL_interp = np.interp(time_fit, t, y) - - fit_func = self.ui.FittingFunc_comboBox.currentText() - self.ui.plot.plot(t, y, clear=self.ui.clear_plot_checkBox.isChecked(), pen=pg.mkPen(self.plot_color)) - if fit_func == "Stretched Exponential": #stretched exponential tab - tc_bounds = (self.ui.str_tc_min_spinBox.value(), self.ui.str_tc_max_spinBox.value()) #(0, 10000) - a_bounds = (self.ui.str_a_min_spinBox.value(), self.ui.str_a_max_spinBox.value())#(0.9, 1.1) - beta_bounds = (self.ui.str_beta_min_spinBox.value(), self.ui.str_beta_max_spinBox.value())#(0,1) - noise_bounds = (self.ui.str_noise_min_spinBox.value(), self.ui.str_noise_max_spinBox.value())#(0, 1e4) - stretch_exp_bounds = [tc_bounds, beta_bounds, a_bounds, noise_bounds] - stretch_exp_init_params = [self.ui.str_tc_init_spinBox.value(), self.ui.str_a_init_spinBox.value(), self.ui.str_beta_init_spinBox.value(), self.ui.str_noise_init_spinBox.value()] - - #tc, beta, a, avg_tau, PL_fit = stretch_exp_fit(TRPL_interp, t) - # resolution = float(self.ui.Res_comboBox.currentText()) - if self.ui.FittingMethod_comboBox.currentText() == "diff_ev": - bestfit_params, t_avg, bestfit_model, data_array, time_array, irf = fit_exp_stretch_diffev(t, self.resolution, TRPL_interp, irf_counts, stretch_exp_bounds) - else: #if fmin_tnc fitting method selected - bestfit_params, t_avg, bestfit_model, data_array, time_array, irf = fit_exp_stretch_fmin_tnc(t, self.resolution, TRPL_interp, irf_counts, stretch_exp_init_params, stretch_exp_bounds) - self.out = np.empty((len(t), 3)) - self.out[:,0] = t #time - self.out[:,1] = TRPL_interp #Raw PL - self.out[:,2] = bestfit_model # PL fit - self.ui.plot.plot(t, bestfit_model, clear=self.ui.clear_plot_checkBox.isChecked(), pen='k') - self.ui.Result_textBrowser.setText("Fit Results:\n\nFit Function: Stretched Exponential with IRF" - "\nFit Method: "+ self.ui.FittingMethod_comboBox.currentText() + - "\ntau_avg = %.5f ns" - "\nbeta = %.5f" - "\ntau_c = %.5f ns" - "\na = %.5f \nnoise = %.5f counts" %(t_avg, bestfit_params[1], bestfit_params[0], bestfit_params[2], bestfit_params[3])) - #self.effective_lifetime = t_avg - self.ui.average_lifetime_spinBox.setValue(t_avg) - - elif fit_func == "Double Exponential": #double exponential tab - a1_bounds = (self.ui.de_a1_min_spinBox.value(), self.ui.de_a1_max_spinBox.value()) - tau1_bounds = (self.ui.de_tau1_min_spinBox.value(), self.ui.de_tau1_max_spinBox.value()) - a2_bounds = (self.ui.de_a2_min_spinBox.value(), self.ui.de_a2_max_spinBox.value()) - tau2_bounds = (self.ui.de_tau2_min_spinBox.value(), self.ui.de_tau2_max_spinBox.value()) - noise_bounds = (self.ui.de_noise_min_spinBox.value(), self.ui.de_noise_max_spinBox.value()) - double_exp_bounds = [a1_bounds, tau1_bounds, a2_bounds, tau2_bounds, noise_bounds] - double_exp_init_params = [self.ui.de_a1_init_spinBox.value(), self.ui.de_tau1_init_spinBox.value(), self.ui.de_a2_init_spinBox.value(), - self.ui.de_tau2_init_spinBox.value(), self.ui.de_noise_init_spinBox.value()] - - if self.ui.FittingMethod_comboBox.currentText() == "diff_ev": - bestfit_params, bestfit_model, data_array, time_array, irf = fit_multi_exp_diffev(t, self.resolution, TRPL_interp, irf_counts, double_exp_bounds, 2) - #bestfit_params, bestfit_model, data_array, time_array, irf = fit_multi_exp_diffev(t, resolution, TRPL_interp, irf_counts, double_exp_init_bounds, 2) - else: - bestfit_params, bestfit_model, data_array, time_array, irf = fit_multi_exp_fmin_tnc(t, self.resolution, TRPL_interp, irf_counts, double_exp_init_params, double_exp_bounds, 2) - self.out = np.empty((len(t), 3)) - self.out[:,0] = t #time - self.out[:,1] = TRPL_interp #Raw PL - self.out[:,2] = bestfit_model # PL fit - self.ui.plot.plot(t, bestfit_model, clear=self.ui.clear_plot_checkBox.isChecked(), pen='k') - self.ui.Result_textBrowser.setText("Fit Results:\n\nFit Function: Double Exponential with IRF" - "\nFit Method: "+ self.ui.FittingMethod_comboBox.currentText() + - "\na1 = %.5f" - "\ntau1 = %.5f ns" - "\na2 = %.5f" - "\ntau2 = %.5f ns" - "\nnoise = %.5f counts" %(bestfit_params[0], bestfit_params[1], bestfit_params[2], bestfit_params[3], bestfit_params[4])) - #TODO - once tau_avg implemented, set average lifetime spinbox to tau_avg value - - elif fit_func == "Single Exponential": #single exponential tab - a_bounds = (self.ui.se_a_min_spinBox.value(), self.ui.se_a_max_spinBox.value()) - tau_bounds = (self.ui.se_tau_min_spinBox.value(), self.ui.se_tau_max_spinBox.value()) - noise_bounds = (self.ui.se_noise_min_spinBox.value(), self.ui.se_noise_max_spinBox.value()) - single_exp_bounds = [a_bounds, tau_bounds, noise_bounds] - single_exp_init_params = [self.ui.se_a_init_spinBox.value(), self.ui.se_tau_init_spinBox.value(), self.ui.se_noise_init_spinBox.value()] - - if self.ui.FittingMethod_comboBox.currentText() == "diff_ev": - bestfit_params, bestfit_model, data_array, time_array, irf = fit_multi_exp_diffev(t, self.resolution, TRPL_interp, irf_counts, single_exp_bounds, 1) - else: - bestfit_params, bestfit_model, data_array, time_array, irf = fit_multi_exp_fmin_tnc(t, self.resolution, TRPL_interp, irf_counts, single_exp_init_params, single_exp_bounds, 1) - self.out = np.empty((len(t), 3)) - self.out[:,0] = t #time - self.out[:,1] = TRPL_interp #Raw PL - self.out[:,2] = bestfit_model # PL fit - self.ui.plot.plot(t, bestfit_model, clear=self.ui.clear_plot_checkBox.isChecked(), pen='k') - self.ui.Result_textBrowser.setText("Fit Results:\n\nFit Function: Single Exponential with IRF" - "\nFit Method: "+ self.ui.FittingMethod_comboBox.currentText() + - "\na = %.5f" - "\ntau = %.5f ns" - "\nnoise = %.5f counts" %(bestfit_params[0], bestfit_params[1], bestfit_params[2])) - self.ui.average_lifetime_spinBox.setValue(bestfit_params[1]) #set spinbox to tau value - - #add fit params to data_list - self.data_list.append("Data Channel: " + str(self.ui.Data_channel_spinBox.value()) + "\n" + self.ui.Result_textBrowser.toPlainText()) - - except Exception as e: - self.ui.Result_textBrowser.append(format(e)) - - def call_fit_and_plot(self): - if self.ui.fit_with_irf_checkBox.isChecked(): - self.fit_and_plot_with_irf() - else: - self.fit_and_plot() - if self.ui.calculate_srv_groupBox.isChecked(): - self.calculate_srv() #calculate srv on plot - self.data_list.append(self.get_srv_string()) #add srv params to data_list - - def calculate_surface_lifetime(self): - effective_lifetime = self.ui.average_lifetime_spinBox.value() - self.bulk_lifetime = self.ui.bulk_lifetime_spinBox.value() # in ns - self.surface_lifetime = (effective_lifetime * self.bulk_lifetime)/(self.bulk_lifetime - effective_lifetime) - self.ui.surface_lifetime_label.setText(str(self.surface_lifetime)) - - def calculate_srv (self): - self.calculate_surface_lifetime() - self.thickness = self.ui.thickness_spinBox.value()*1e-7 # convert to cm - self.diffusion_coeffecient = self.ui.diffusion_coefficient_spinBox.value() # in cm2/s - - if self.ui.srv1_srv2_checkBox.isChecked(): - self.srv = self.thickness / (2*((1e-9*self.surface_lifetime) - ((1/self.diffusion_coeffecient)*((self.thickness/np.pi)**2)) )) - else: - self.srv = self.thickness / ((1e-9*self.surface_lifetime) - ((4/self.diffusion_coeffecient)*((self.thickness/np.pi)**2)) ) - - self.ui.srv_label.setText(str(self.srv)) - - def get_srv_string(self): - """ Get info from SRV Calculation groupbox as string """ - srv_string = "SRV Calculation:"\ - + "\nAverage Lifetime (ns): " + str(self.ui.average_lifetime_spinBox.value()) \ - + "\nBulk Lifetime (ns): " + str(self.ui.bulk_lifetime_spinBox.value()) \ - + "\nThickness (nm): " + str(self.ui.thickness_spinBox.value()) \ - + "\nDiffusion Coefficient (cm2/s): " + str(self.ui.diffusion_coefficient_spinBox.value()) - if self.ui.srv1_srv2_checkBox.isChecked(): - srv_string += "\nSRV1 = SRV2" - else: - srv_string += "\nSRV1 = 0" - srv_string += "\nSurface Lifetime (ns): " + self.ui.surface_lifetime_label.text() \ - + "\nSRV (cm/s): " + self.ui.srv_label.text() - return srv_string - - def export_data(self): - """ Save fit params and srv calculations stored in data_list as .txt """ - folder = os.path.dirname(self.filename[0]) - filename_ext = os.path.basename(self.filename[0]) - filename = os.path.splitext(filename_ext)[0] #get filename without extension - - path = folder + "/" + filename + "_fit_results.txt" - if not os.path.exists(path): - file = open(path, "w+") - else: - file = open(path, "a+") - - for i in range(len(self.data_list)): - file.write(self.data_list[i] + "\n\n") - - self.data_list = [] - file.close() - - def clear_export_data(self): - self.data_list = [] - - def pub_ready_plot_export(self): - try: - filename = QtWidgets.QFileDialog.getSaveFileName(self,caption="Filename with EXTENSION") - - plt.figure(figsize=(8,6)) - plt.tick_params(direction='out', length=8, width=3.5) - if self.ui.save_w_fit_checkBox.isChecked(): - plt.plot(self.out[:,0],self.out[:,1]/np.max(self.out[:,1])) - plt.plot(self.out[:,0],self.out[:,2]/np.max(self.out[:,1]),'k') - else: - plt.plot(self.acquire_settings()[0],self.acquire_settings()[1]/np.max(self.acquire_settings()[1])) - plt.yscale('log') - plt.xlabel("Time (ns)", fontsize=20, fontweight='bold') - plt.ylabel("Intensity (norm.)", fontsize=20, fontweight='bold') - plt.tight_layout() - - plt.savefig(filename[0],bbox_inches='tight', dpi=300) - plt.close() - - except: - pass - - def close_application(self): - choice = QtGui.QMessageBox.question(self, 'EXIT!', - "Do you want to exit the app?", - QtGui.QMessageBox.Yes | QtGui.QMessageBox.No) - if choice == QtGui.QMessageBox.Yes: - sys.exit() - else: - pass + self.filename = QtWidgets.QFileDialog.getOpenFileName(self) + try: + if ".csv" in self.filename[0] or ".txt" in self.filename[0]: #if txt or csv, prompt user to enter # of rows to skip + self.skip_rows_window = SkipRowsWindow() + self.skip_rows_window.skip_rows_signal.connect(self.open_with_skip_rows_window) + else: + self.file = read_picoharp_phd(self.filename[0]) + self.opened_from_flim = False + except: + pass + + def open_with_skip_rows_window(self): + """ Prompts user to enter how many rows to skip """ + skip_rows = self.skip_rows_window.ui.skip_rows_spinBox.value() + if ".txt" in self.filename[0]: + self.file = np.loadtxt(self.filename[0], skiprows=skip_rows) + elif ".csv" in self.filename[0]: + self.file = np.genfromtxt(self.filename[0], skip_header=skip_rows, delimiter=",") + + def open_irf_file(self): + """ Open file with irf - enabled if 'load separate irf' is checled """ + self.irf_filename = QtWidgets.QFileDialog.getOpenFileName(self) + try: + if ".txt" in self.irf_filename[0] or ".csv" in self.irf_filename[0]: + self.irf_skip_rows_window = SkipRowsWindow() + self.irf_skip_rows_window.skip_rows_signal.connect(self.open_irf_with_skip_rows_window) + else: + self.irf_file = read_picoharp_phd(self.irf_filename[0]) + except: + pass + + def open_irf_with_skip_rows_window(self): + irf_skip_rows = self.irf_skip_rows_window.ui.skip_rows_spinBox.value() + if ".txt" in self.irf_filename[0]: + self.irf_file = np.loadtxt(self.irf_filename[0], skiprows=irf_skip_rows) + elif ".csv" in self.irf_filename[0]: + self.irf_file = np.genfrontxt(self.irf_filename[0], skip_header=irf_skip_rows, delimiter=",") + + def save_file(self): + try: + filename = QtWidgets.QFileDialog.getSaveFileName(self) + np.savetxt(filename[0], self.out, fmt = '%.5f', header = 'Time, Raw_PL, Sim_PL', delimiter = ' ') + except: + pass + + def switch_open_irf(self): + """ Handle 'load separate irf' checkbox """ + self.ui.actionOpen_IRF_File.setEnabled(self.ui.separate_irf_checkBox.isChecked()) + + def switch_fit_settings(self): + """ Enable bounds/initial guess groupboxes only when 'Fit with IRF' is checked """ + checked = self.ui.fit_with_irf_checkBox.isChecked() + for func in "str de se".split(" "): + boundsGb = eval("self.ui."+func+"_bounds_groupBox") + #initGb = eval("self.ui."+func+"_init_groupBox") + boundsGb.setEnabled(checked) + #initGb.setEnabled(checked) + if checked == True: + self.switch_init_params_groupBox() + else: + initGb = eval("self.ui."+func+"_init_groupBox") + initGb.setEnabled(checked) + self.ui.FittingMethod_comboBox.setEnabled(checked) + + def switch_function_tab(self): + """ Switch bounds groupbox contents depending on selected fit function """ + fitting_func = self.ui.FittingFunc_comboBox.currentText() + if fitting_func == "Stretched Exponential": + self.ui.fitting_params_stackedWidget.setCurrentIndex(0) + elif fitting_func == "Double Exponential": + self.ui.fitting_params_stackedWidget.setCurrentIndex(1) + elif fitting_func == "Single Exponential": + self.ui.fitting_params_stackedWidget.setCurrentIndex(2) + + def switch_init_params_groupBox(self): + """ Enable initial guess groupbox only when fmin_tnc fit method selected """ + if self.ui.FittingMethod_comboBox.currentText() == "diff_ev": + for func in "str de se".split(" "): + initGb = eval("self.ui."+func+"_init_groupBox") + initGb.setEnabled(False) + #initGb.setEnabled(checked) + elif self.ui.FittingMethod_comboBox.currentText() == "fmin_tnc": + for func in "str de se".split(" "): + initGb = eval("self.ui."+func+"_init_groupBox") + initGb.setEnabled(True) + + def plot_color_changed(self): + """ Grab new plot_color when color button value is changed """ + self.plot_color = self.plot_color_button.color() + + def acquire_settings(self, mode="data"): + """ + Acquire data or irf from channel specified in spinbox. + + mode -- string specifying whether to use data or irf channel (default "data") + """ + self.resolution = float(self.ui.Res_comboBox.currentText()) + if mode == "data": + channel = int(self.ui.Data_channel_spinBox.value()) + elif mode == "irf": + channel = int(self.ui.irf_channel_spinBox.value()) + try: + try: # + if self.ui.separate_irf_checkBox.isChecked() and mode=="irf": #if separate irf, get from irf file + try: + y = self.irf_file[:,channel] + except: + y = self.irf_file.get_curve(channel)[1] + else: #otherwise, get data/irf from data file + y = self.file[:,channel] + except: + res, y = self.file.get_curve(channel) + # TO DO - check if res read in is the same as selected + time_window = int(np.floor(self.file.get_time_window_in_ns(channel))) + y = y[0:time_window] + + length = np.shape(y)[0] + x = np.arange(0, length, 1) * self.resolution + return x,y + + except Exception as e: + self.ui.Result_textBrowser.setText(str(e)) + + def plot(self): + try: + if self.opened_from_flim: + x, y = self.hist_data_from_flim + else: + x,y = self.acquire_settings() #get data + if self.ui.normalize_checkBox.isChecked(): + y = y / np.amax(y) + + self.ui.plot.plot(x, y, clear=self.ui.clear_plot_checkBox.isChecked(), pen=pg.mkPen(self.plot_color)) + + try: + self.ui.Result_textBrowser.setText("Integral Counts :\n" "{:.2E}".format( + self.file.get_integral_counts(int(self.ui.Channel_spinBox.value())))) + except: + self.ui.Result_textBrowser.setText("Integral Counts :\n" "{:.2E}".format(np.sum(y))) + except: + pass + self.ui.plot.setLabel('left', 'Intensity', units='a.u.') + self.ui.plot.setLabel('bottom', 'Time (ns)') + + def make_semilog(self): + """ Switch y-log on/off """ + self.ui.plot.setLogMode(False,self.ui.log_checkBox.isChecked()) + + def clear_plot(self): + self.ui.plot.clear() + self.ui.Result_textBrowser.clear() + + def fit_and_plot(self): + """ Fit and plot without IRF """ + try: + if not hasattr(self, "file"): + self.ui.Result_textBrowser.setText("You need to load a data file.") + else: + if self.opened_from_flim: + x, y = self.hist_data_from_flim + else: + x,y = self.acquire_settings() #get data + y_norm = y/np.max(y) #normalized y + + # find the max intensity in the array and start things from there + find_max_int = np.nonzero(y_norm == 1) + y = y[np.asscalar(find_max_int[0]):] + x = x[np.asscalar(find_max_int[0]):] + + t = x + time_fit = t + TRPL_interp = np.interp(time_fit, t, y) + + fit_func = self.ui.FittingFunc_comboBox.currentText() + self.ui.plot.plot(t, y, clear=self.ui.clear_plot_checkBox.isChecked(), pen=pg.mkPen(self.plot_color)) + + if fit_func == "Stretched Exponential": #stretch exponential tab + tc, beta, a, avg_tau, PL_fit = stretch_exp_fit(TRPL_interp, t) + self.out = np.empty((len(t), 3)) + self.out[:,0] = t #time + self.out[:,1] = TRPL_interp #Raw PL + self.out[:,2] = PL_fit # PL fit + self.ui.plot.plot(t, PL_fit, clear=self.ui.clear_plot_checkBox.isChecked(), pen='k') + self.ui.Result_textBrowser.setText("Fit Results:\n\nFit Function: Stretched Exponential" + "\nFit Method: " + "diff_ev" + #TODO : change when diff_ev and fmin_tnc implemented for non-irf + "\nAverage Lifetime = " + str(avg_tau)+ " ns" + "\nCharacteristic Tau = " + str(tc)+" ns" + "\nBeta = "+str(beta)) + self.ui.average_lifetime_spinBox.setValue(avg_tau) + + elif fit_func == "Double Exponential": #double exponential tab + tau1, a1, tau2, a2, avg_tau, PL_fit = double_exp_fit(TRPL_interp, t) + self.out = np.empty((len(t), 3)) + self.out[:,0] = t #time + self.out[:,1] = TRPL_interp #Raw PL + self.out[:,2] = PL_fit # PL fit + self.ui.plot.plot(t, PL_fit, clear=self.ui.clear_plot_checkBox.isChecked(), pen='k') + self.ui.Result_textBrowser.setText("Fit Results:\n\nFit Function: Double Exponential" + "\nFit Method: " + "diff_ev" + + "\nAverage Lifetime = " + str(avg_tau)+ " ns" + "\nTau 1 = " + str(tau1)+" ns" + "\nA 1 = " + str(a1)+ + "\nTau 2 = " + str(tau2)+" ns" + "\nA 2 = " + str(a2)) + #TODO - once tau_avg implemented, set average lifetime spinbox to tau_avg value + + elif fit_func == "Single Exponential": #single exponential tab + tau, a, PL_fit = single_exp_fit(TRPL_interp, t) + self.out = np.empty((len(t), 3)) + self.out[:,0] = t #time + self.out[:,1] = TRPL_interp #Raw PL + self.out[:,2] = PL_fit # PL fit + self.ui.plot.plot(t, PL_fit, clear=self.ui.clear_plot_checkBox.isChecked(), pen='k') + self.ui.Result_textBrowser.setText("Fit Results:\n\nFit Function: Single Exponential" + "\nFit Method: " + "diff_ev" + + "\nLifetime = " + str(tau)+ " ns" + "\nA = " + str(a)) + self.ui.average_lifetime_spinBox.setValue(tau) + + #add fit params to data_list + self.data_list.append("Data Channel: " + str(self.ui.Data_channel_spinBox.value()) + "\n" + self.ui.Result_textBrowser.toPlainText()) + + self.ui.plot.setLabel('left', 'Intensity', units='a.u.') + self.ui.plot.setLabel('bottom', 'Time (ns)') + return self.out + + except Exception as e: + self.ui.Result_textBrowser.append(format(e)) + + def fit_and_plot_with_irf(self): + """ Fit and plot with IRF """ + try: + self.ui.Result_textBrowser.clear() + if not hasattr(self, "file"): + self.ui.Result_textBrowser.append("You need to load a data file.") + if not hasattr(self, "irf_file") and self.ui.separate_irf_checkBox.isChecked(): + self.ui.Result_textBrowser.append("You need to load an IRF file.") + else: + if self.opened_from_flim: + x,y = self.hist_data_from_flim + else: + x,y = self.acquire_settings() #get data + _, irf_counts = self.acquire_settings(mode="irf") #get irf counts + + #make sure Irf and data have the same length + if len(y) != len(irf_counts): + y = y[0:min(len(y), len(irf_counts))] + irf_counts = irf_counts[0:min(len(y), len(irf_counts))] + x = x[0:min(len(y), len(irf_counts))] + + y_norm = y/np.max(y) #normalized y + irf_norm = irf_counts/np.amax(irf_counts) #normalized irf + + t = x + time_fit = t + y = y_norm + irf_counts = irf_norm + + TRPL_interp = np.interp(time_fit, t, y) + + fit_func = self.ui.FittingFunc_comboBox.currentText() + self.ui.plot.plot(t, y, clear=self.ui.clear_plot_checkBox.isChecked(), pen=pg.mkPen(self.plot_color)) + if fit_func == "Stretched Exponential": #stretched exponential tab + tc_bounds = (self.ui.str_tc_min_spinBox.value(), self.ui.str_tc_max_spinBox.value()) #(0, 10000) + a_bounds = (self.ui.str_a_min_spinBox.value(), self.ui.str_a_max_spinBox.value())#(0.9, 1.1) + beta_bounds = (self.ui.str_beta_min_spinBox.value(), self.ui.str_beta_max_spinBox.value())#(0,1) + noise_bounds = (self.ui.str_noise_min_spinBox.value(), self.ui.str_noise_max_spinBox.value())#(0, 1e4) + stretch_exp_bounds = [tc_bounds, beta_bounds, a_bounds, noise_bounds] + stretch_exp_init_params = [self.ui.str_tc_init_spinBox.value(), self.ui.str_a_init_spinBox.value(), self.ui.str_beta_init_spinBox.value(), self.ui.str_noise_init_spinBox.value()] + + #tc, beta, a, avg_tau, PL_fit = stretch_exp_fit(TRPL_interp, t) + # resolution = float(self.ui.Res_comboBox.currentText()) + if self.ui.FittingMethod_comboBox.currentText() == "diff_ev": + bestfit_params, t_avg, bestfit_model, data_array, time_array, irf = fit_exp_stretch_diffev(t, self.resolution, TRPL_interp, irf_counts, stretch_exp_bounds) + else: #if fmin_tnc fitting method selected + bestfit_params, t_avg, bestfit_model, data_array, time_array, irf = fit_exp_stretch_fmin_tnc(t, self.resolution, TRPL_interp, irf_counts, stretch_exp_init_params, stretch_exp_bounds) + self.out = np.empty((len(t), 3)) + self.out[:,0] = t #time + self.out[:,1] = TRPL_interp #Raw PL + self.out[:,2] = bestfit_model # PL fit + self.ui.plot.plot(t, bestfit_model, clear=self.ui.clear_plot_checkBox.isChecked(), pen='k') + self.ui.Result_textBrowser.setText("Fit Results:\n\nFit Function: Stretched Exponential with IRF" + "\nFit Method: "+ self.ui.FittingMethod_comboBox.currentText() + + "\ntau_avg = %.5f ns" + "\nbeta = %.5f" + "\ntau_c = %.5f ns" + "\na = %.5f \nnoise = %.5f counts" %(t_avg, bestfit_params[1], bestfit_params[0], bestfit_params[2], bestfit_params[3])) + #self.effective_lifetime = t_avg + self.ui.average_lifetime_spinBox.setValue(t_avg) + + elif fit_func == "Double Exponential": #double exponential tab + a1_bounds = (self.ui.de_a1_min_spinBox.value(), self.ui.de_a1_max_spinBox.value()) + tau1_bounds = (self.ui.de_tau1_min_spinBox.value(), self.ui.de_tau1_max_spinBox.value()) + a2_bounds = (self.ui.de_a2_min_spinBox.value(), self.ui.de_a2_max_spinBox.value()) + tau2_bounds = (self.ui.de_tau2_min_spinBox.value(), self.ui.de_tau2_max_spinBox.value()) + noise_bounds = (self.ui.de_noise_min_spinBox.value(), self.ui.de_noise_max_spinBox.value()) + double_exp_bounds = [a1_bounds, tau1_bounds, a2_bounds, tau2_bounds, noise_bounds] + double_exp_init_params = [self.ui.de_a1_init_spinBox.value(), self.ui.de_tau1_init_spinBox.value(), self.ui.de_a2_init_spinBox.value(), + self.ui.de_tau2_init_spinBox.value(), self.ui.de_noise_init_spinBox.value()] + + if self.ui.FittingMethod_comboBox.currentText() == "diff_ev": + bestfit_params, bestfit_model, data_array, time_array, irf = fit_multi_exp_diffev(t, self.resolution, TRPL_interp, irf_counts, double_exp_bounds, 2) + #bestfit_params, bestfit_model, data_array, time_array, irf = fit_multi_exp_diffev(t, resolution, TRPL_interp, irf_counts, double_exp_init_bounds, 2) + else: + bestfit_params, bestfit_model, data_array, time_array, irf = fit_multi_exp_fmin_tnc(t, self.resolution, TRPL_interp, irf_counts, double_exp_init_params, double_exp_bounds, 2) + self.out = np.empty((len(t), 3)) + self.out[:,0] = t #time + self.out[:,1] = TRPL_interp #Raw PL + self.out[:,2] = bestfit_model # PL fit + self.ui.plot.plot(t, bestfit_model, clear=self.ui.clear_plot_checkBox.isChecked(), pen='k') + self.ui.Result_textBrowser.setText("Fit Results:\n\nFit Function: Double Exponential with IRF" + "\nFit Method: "+ self.ui.FittingMethod_comboBox.currentText() + + "\na1 = %.5f" + "\ntau1 = %.5f ns" + "\na2 = %.5f" + "\ntau2 = %.5f ns" + "\nnoise = %.5f counts" %(bestfit_params[0], bestfit_params[1], bestfit_params[2], bestfit_params[3], bestfit_params[4])) + #TODO - once tau_avg implemented, set average lifetime spinbox to tau_avg value + + elif fit_func == "Single Exponential": #single exponential tab + a_bounds = (self.ui.se_a_min_spinBox.value(), self.ui.se_a_max_spinBox.value()) + tau_bounds = (self.ui.se_tau_min_spinBox.value(), self.ui.se_tau_max_spinBox.value()) + noise_bounds = (self.ui.se_noise_min_spinBox.value(), self.ui.se_noise_max_spinBox.value()) + single_exp_bounds = [a_bounds, tau_bounds, noise_bounds] + single_exp_init_params = [self.ui.se_a_init_spinBox.value(), self.ui.se_tau_init_spinBox.value(), self.ui.se_noise_init_spinBox.value()] + + if self.ui.FittingMethod_comboBox.currentText() == "diff_ev": + bestfit_params, bestfit_model, data_array, time_array, irf = fit_multi_exp_diffev(t, self.resolution, TRPL_interp, irf_counts, single_exp_bounds, 1) + else: + bestfit_params, bestfit_model, data_array, time_array, irf = fit_multi_exp_fmin_tnc(t, self.resolution, TRPL_interp, irf_counts, single_exp_init_params, single_exp_bounds, 1) + self.out = np.empty((len(t), 3)) + self.out[:,0] = t #time + self.out[:,1] = TRPL_interp #Raw PL + self.out[:,2] = bestfit_model # PL fit + self.ui.plot.plot(t, bestfit_model, clear=self.ui.clear_plot_checkBox.isChecked(), pen='k') + self.ui.Result_textBrowser.setText("Fit Results:\n\nFit Function: Single Exponential with IRF" + "\nFit Method: "+ self.ui.FittingMethod_comboBox.currentText() + + "\na = %.5f" + "\ntau = %.5f ns" + "\nnoise = %.5f counts" %(bestfit_params[0], bestfit_params[1], bestfit_params[2])) + self.ui.average_lifetime_spinBox.setValue(bestfit_params[1]) #set spinbox to tau value + + #add fit params to data_list + self.data_list.append("Data Channel: " + str(self.ui.Data_channel_spinBox.value()) + "\n" + self.ui.Result_textBrowser.toPlainText()) + + except Exception as e: + self.ui.Result_textBrowser.append(format(e)) + + def call_fit_and_plot(self): + if self.ui.fit_with_irf_checkBox.isChecked(): + self.fit_and_plot_with_irf() + else: + self.fit_and_plot() + if self.ui.calculate_srv_groupBox.isChecked(): + self.calculate_srv() #calculate srv on plot + self.data_list.append(self.get_srv_string()) #add srv params to data_list + + def calculate_surface_lifetime(self): + effective_lifetime = self.ui.average_lifetime_spinBox.value() + self.bulk_lifetime = self.ui.bulk_lifetime_spinBox.value() # in ns + self.surface_lifetime = (effective_lifetime * self.bulk_lifetime)/(self.bulk_lifetime - effective_lifetime) + self.ui.surface_lifetime_label.setText(str(self.surface_lifetime)) + + def calculate_srv (self): + self.calculate_surface_lifetime() + self.thickness = self.ui.thickness_spinBox.value()*1e-7 # convert to cm + self.diffusion_coeffecient = self.ui.diffusion_coefficient_spinBox.value() # in cm2/s + + if self.ui.srv1_srv2_checkBox.isChecked(): + self.srv = self.thickness / (2*((1e-9*self.surface_lifetime) - ((1/self.diffusion_coeffecient)*((self.thickness/np.pi)**2)) )) + else: + self.srv = self.thickness / ((1e-9*self.surface_lifetime) - ((4/self.diffusion_coeffecient)*((self.thickness/np.pi)**2)) ) + + self.ui.srv_label.setText(str(self.srv)) + + def get_srv_string(self): + """ Get info from SRV Calculation groupbox as string """ + srv_string = "SRV Calculation:"\ + + "\nAverage Lifetime (ns): " + str(self.ui.average_lifetime_spinBox.value()) \ + + "\nBulk Lifetime (ns): " + str(self.ui.bulk_lifetime_spinBox.value()) \ + + "\nThickness (nm): " + str(self.ui.thickness_spinBox.value()) \ + + "\nDiffusion Coefficient (cm2/s): " + str(self.ui.diffusion_coefficient_spinBox.value()) + if self.ui.srv1_srv2_checkBox.isChecked(): + srv_string += "\nSRV1 = SRV2" + else: + srv_string += "\nSRV1 = 0" + srv_string += "\nSurface Lifetime (ns): " + self.ui.surface_lifetime_label.text() \ + + "\nSRV (cm/s): " + self.ui.srv_label.text() + return srv_string + + def export_data(self): + """ Save fit params and srv calculations stored in data_list as .txt """ + folder = os.path.dirname(self.filename[0]) + filename_ext = os.path.basename(self.filename[0]) + filename = os.path.splitext(filename_ext)[0] #get filename without extension + + path = folder + "/" + filename + "_fit_results.txt" + if not os.path.exists(path): + file = open(path, "w+") + else: + file = open(path, "a+") + + for i in range(len(self.data_list)): + file.write(self.data_list[i] + "\n\n") + + self.data_list = [] + file.close() + + def clear_export_data(self): + self.data_list = [] + + def pub_ready_plot_export(self): + try: + filename = QtWidgets.QFileDialog.getSaveFileName(self,caption="Filename with EXTENSION") + + plt.figure(figsize=(8,6)) + plt.tick_params(direction='out', length=8, width=3.5) + if self.ui.save_w_fit_checkBox.isChecked(): + plt.plot(self.out[:,0],self.out[:,1]/np.max(self.out[:,1])) + plt.plot(self.out[:,0],self.out[:,2]/np.max(self.out[:,1]),'k') + else: + plt.plot(self.acquire_settings()[0],self.acquire_settings()[1]/np.max(self.acquire_settings()[1])) + plt.yscale('log') + plt.xlabel("Time (ns)", fontsize=20, fontweight='bold') + plt.ylabel("Intensity (norm.)", fontsize=20, fontweight='bold') + plt.tight_layout() + + plt.savefig(filename[0],bbox_inches='tight', dpi=300) + plt.close() + + except: + pass + + def close_application(self): + choice = QtGui.QMessageBox.question(self, 'EXIT!', + "Do you want to exit the app?", + QtGui.QMessageBox.Yes | QtGui.QMessageBox.No) + if choice == QtGui.QMessageBox.Yes: + sys.exit() + else: + pass """Skip rows GUI""" ui_file_path = (base_path / "skip_rows.ui").resolve() skiprows_WindowTemplate, skiprows_TemplateBaseClass = pg.Qt.loadUiType(ui_file_path) class SkipRowsWindow(skiprows_TemplateBaseClass): - - skip_rows_signal = QtCore.pyqtSignal() #signal to help with pass info back to MainWindow - - def __init__(self): - skiprows_TemplateBaseClass.__init__(self) - - # Create the param window - self.ui = skiprows_WindowTemplate() - self.ui.setupUi(self) - self.ui.done_pushButton.clicked.connect(self.done) - self.setWindowFlag(QtCore.Qt.WindowCloseButtonHint, False) - self.show() - - def done(self): - self.skip_rows_signal.emit() - self.close() + + skip_rows_signal = QtCore.pyqtSignal() #signal to help with pass info back to MainWindow + + def __init__(self): + skiprows_TemplateBaseClass.__init__(self) + + # Create the param window + self.ui = skiprows_WindowTemplate() + self.ui.setupUi(self) + self.ui.done_pushButton.clicked.connect(self.done) + self.setWindowFlag(QtCore.Qt.WindowCloseButtonHint, False) + self.show() + + def done(self): + self.skip_rows_signal.emit() + self.close() def run(): - win = MainWindow() - QtGui.QApplication.instance().exec_() - return win + win = MainWindow() + QtGui.QApplication.instance().exec_() + return win #Uncomment below if you want to run this as standalone #run() \ No newline at end of file diff --git a/PythonGUI_apps/PLQE_analysis/plqe_analysis_gui.ui b/PythonGUI_apps/PLQE_analysis/plqe_analysis_gui.ui index 1caeccf..7720b49 100644 --- a/PythonGUI_apps/PLQE_analysis/plqe_analysis_gui.ui +++ b/PythonGUI_apps/PLQE_analysis/plqe_analysis_gui.ui @@ -11,7 +11,7 @@ - Form + PLQE Analysis diff --git a/PythonGUI_apps/Spectrum_analysis/Spectra_plot_fit_gui.ui b/PythonGUI_apps/Spectrum_analysis/Spectra_plot_fit_gui.ui index 273d006..a176bdd 100644 --- a/PythonGUI_apps/Spectrum_analysis/Spectra_plot_fit_gui.ui +++ b/PythonGUI_apps/Spectrum_analysis/Spectra_plot_fit_gui.ui @@ -17,7 +17,7 @@ - MainWindow + Spectral Analysis @@ -1374,7 +1374,7 @@ Scan 0 0 1728 - 31 + 21 diff --git a/PythonGUI_apps/UV_Vis_analysis/uv_vis_analysis_gui.ui b/PythonGUI_apps/UV_Vis_analysis/uv_vis_analysis_gui.ui index 6cb2989..c3289df 100644 --- a/PythonGUI_apps/UV_Vis_analysis/uv_vis_analysis_gui.ui +++ b/PythonGUI_apps/UV_Vis_analysis/uv_vis_analysis_gui.ui @@ -11,7 +11,7 @@ - MainWindow + UV-Vis Analysis @@ -215,7 +215,7 @@ 0 0 742 - 31 + 21 From 079a67f44d4ae31f786c5e531a9647b76f71956c Mon Sep 17 00:00:00 2001 From: SarthakJariwala Date: Wed, 14 Aug 2019 13:47:07 -0700 Subject: [PATCH 09/25] remove old files that are not required --- .../Spectra_plot_fit_gui_old.ui | 807 ------------------ PythonGUI_apps/version.py | 49 -- 2 files changed, 856 deletions(-) delete mode 100644 PythonGUI_apps/Spectrum_analysis/Spectra_plot_fit_gui_old.ui delete mode 100644 PythonGUI_apps/version.py diff --git a/PythonGUI_apps/Spectrum_analysis/Spectra_plot_fit_gui_old.ui b/PythonGUI_apps/Spectrum_analysis/Spectra_plot_fit_gui_old.ui deleted file mode 100644 index 2ec3fe0..0000000 --- a/PythonGUI_apps/Spectrum_analysis/Spectra_plot_fit_gui_old.ui +++ /dev/null @@ -1,807 +0,0 @@ - - - MainWindow - - - - 0 - 0 - 1430 - 885 - - - - MainWindow - - - - - - 1135 - 30 - 281 - 311 - - - - - 15 - - - - Fitting Settings - - - - - - - 12 - - - - - - - - - 12 - - - - Configure Fit Params - - - - - - - - 12 - - - - Start at (nm): - - - - - - - - 12 - - - - 300 - - - 1100 - - - 600 - - - - - - - - 12 - - - - Stop at (nm): - - - - - - - - 12 - - - - 300 - - - 1100 - - - 900 - - - - - - - - 12 - - - - Adjust Parameters - - - - - - - - 12 - - - - Fit Single Spectrum - - - - - - - - 12 - - - - Fit Entire Scan - - - - - - - - 12 - - - - Export Publication -Ready Figure - - - - - - - - - 1140 - 350 - 281 - 481 - - - - - 10 - - - - - - - 10 - 10 - 1153 - 605 - - - - - 15 - - - - 1 - - - false - - - - Single Spectrum - - - - - 20 - 20 - 204 - 431 - - - - - 15 - - - - Load Settings - - - - - - - 12 - - - - For Single Spectrum - - - - - - - - 12 - - - - Spectrum -File - - - - - - - - 12 - - - - Background -File - - - - - - - - 12 - - - - White Light -Ref File - - - - - - - - 12 - - - - Subtract Background - - - - - - - - 12 - - - - Correct for White Light - - - - - - - - 12 - - - - Normalize - - - - - - - - 12 - 50 - false - - - - Plot - - - - - - - - 12 - - - - Clear Plots Everytime - - - true - - - - - - - - 12 - false - - - - Clear Plot - - - - - - - - - 250 - 50 - 851 - 401 - - - - - - - 250 - 20 - 178 - 24 - - - - - 15 - - - - For Single Spectrum - - - - - - Scan Spectra Data - - - - - 200 - 60 - 521 - 331 - - - - - - - 220 - 20 - 181 - 24 - - - - - 15 - - - - For Raw Scan Data - - - - - - 400 - 20 - 101 - 31 - - - - - 12 - - - - Plot - - - - - - 200 - 460 - 521 - 331 - - - - - - - 560 - 410 - 81 - 31 - - - - - 12 - - - - Plot - - - - - - 210 - 410 - 211 - 31 - - - - - 15 - - - - After Fitting Scan Data - - - - - - 420 - 410 - 131 - 31 - - - - - 15 - - - - - pk_pos - - - - - fwhm - - - - - sigma - - - - - height - - - - - - - 0 - 20 - 181 - 251 - - - - - 15 - - - - Load Settings - - - - - - - 12 - - - - Background -File - - - - - - - - 12 - - - - Spectra Scan -File - - - - - - - - 12 - - - - For Scan Data - - - - - - - - 12 - - - - Load Only - Fit File - - - - - - - - - 800 - 450 - 141 - 41 - - - - # X points - - - - - - 800 - 500 - 141 - 41 - - - - # Y points - - - - - - 950 - 460 - 81 - 31 - - - - 2000 - - - 100 - - - - - - 950 - 510 - 81 - 31 - - - - 2000 - - - 100 - - - - - - 800 - 570 - 231 - 41 - - - - Use Raw Scan Settings - - - true - - - - - - 760 - 20 - 211 - 31 - - - - - 15 - - - - Intensity Sums - - - - - - 970 - 20 - 101 - 31 - - - - - 12 - - - - Plot - - - - - - 580 - 60 - 521 - 331 - - - - - - - pkl to txt - - - - - 10 - 20 - 281 - 201 - - - - Convert - - - - - 10 - 40 - 241 - 31 - - - - - 12 - - - - Import .pkl file - - - - - - 10 - 90 - 241 - 31 - - - - - 12 - - - - Data to .txt - - - - - - 10 - 140 - 241 - 34 - - - - - 12 - - - - Scan params to .txt - - - - - - - - - - 0 - 0 - 1430 - 31 - - - - - - - - PlotWidget - QGraphicsView -
pyqtgraph
-
- - ImageView - QGraphicsView -
pyqtgraph
-
-
- - -
diff --git a/PythonGUI_apps/version.py b/PythonGUI_apps/version.py deleted file mode 100644 index d1302de..0000000 --- a/PythonGUI_apps/version.py +++ /dev/null @@ -1,49 +0,0 @@ -from __future__ import absolute_import, division, print_function -from os.path import join as pjoin - -# Format expected by setup.py and doc/source/conf.py: string of form "X.Y.Z" -_version_major = 0 -_version_minor = 1 -_version_micro = '' # use '' for first of series, number for 1 and above -_version_extra = 'dev0' -# _version_extra = '' # Uncomment this for full releases - -# Construct full version string from these. -_ver = [_version_major, _version_minor] -if _version_micro: - _ver.append(_version_micro) -if _version_extra: - _ver.append(_version_extra) - -__version__ = '.'.join(map(str, _ver)) - -CLASSIFIERS = ["Development Status :: 3 - Alpha", - "Environment :: Console", - "Intended Audience :: Science/Research", - "License :: OSI Approved :: MIT License", - "Operating System :: OS Independent", - "Programming Language :: Python", - "Topic :: Scientific/Engineering"] - -# Description should be a one-liner: -description = "GLabViz: Data Visualization and Analysis Tool" -# Long description will go up on the pypi page -# long_description = """ - -NAME = "glabviz" -MAINTAINER = "Sarthak" -MAINTAINER_EMAIL = "jariwala@uw.edu" -DESCRIPTION = description -# LONG_DESCRIPTION = long_description -URL = "https://github.com/SarthakJariwala/Python_GUI_apps" -DOWNLOAD_URL = "" -LICENSE = "MIT" -AUTHOR = "SARTHAK" -AUTHOR_EMAIL = "jariwala@uw.edu" -PLATFORMS = "OS Independent" -MAJOR = _version_major -MINOR = _version_minor -MICRO = _version_micro -VERSION = __version__ -# PACKAGE_DATA = {'defectfinder': [pjoin('data', '*')]} -REQUIRES = ["pyqtgraph", "numpy", "matplotlib", "ctypes", "lmfit", "seabreeze", "pyusb"] From 95ddb39a89b87b81641233b66d20edca0fce13cb Mon Sep 17 00:00:00 2001 From: "LAKESIDE\\LindaT18" Date: Fri, 16 Aug 2019 15:19:03 -0700 Subject: [PATCH 10/25] initial work on image analysis --- PythonGUI_apps/DataBrowser.py | 7 +- .../Image_analysis/Image_analysis.py | 142 ++++++++++++++++++ .../Image_analysis/image_analysis_gui.ui | 122 +++++++++++++++ 3 files changed, 269 insertions(+), 2 deletions(-) create mode 100644 PythonGUI_apps/Image_analysis/Image_analysis.py create mode 100644 PythonGUI_apps/Image_analysis/image_analysis_gui.ui diff --git a/PythonGUI_apps/DataBrowser.py b/PythonGUI_apps/DataBrowser.py index d77f8c9..250e42a 100644 --- a/PythonGUI_apps/DataBrowser.py +++ b/PythonGUI_apps/DataBrowser.py @@ -18,7 +18,7 @@ from UV_Vis_analysis import uv_vis_analysis from PLQE_analysis import plqe_analysis from H5_Pkl import h5_pkl_view, h5_view_and_plot - +from Image_analysis import Image_analysis pg.mkQApp() #pg.setConfigOption('background', 'w') @@ -38,7 +38,7 @@ def __init__(self): self.ui = WindowTemplate() self.ui.setupUi(self) self.ui.select_comboBox.addItems(["Lifetime Analysis", "Spectrum Analysis", "FLIM Analysis", - "UV-Vis Analysis", "PLQE Analysis", "H5 View/Plot", "H5/PKL Viewer"]) + "UV-Vis Analysis", "PLQE Analysis", "H5 View/Plot", "H5/PKL Viewer", "Image Analysis"]) self.ui.load_pushButton.clicked.connect(self.load_app) self.show() @@ -69,6 +69,9 @@ def load_app(self): elif analysis_software == "H5/PKL Viewer": app = h5_pkl_view.H5PklView(sys.argv) #sys.exit(app.exec_()) + elif analysis_software == "Image Analysis": + self.image_window = Image_analysis.MainWindow() + self.image_window.show() diff --git a/PythonGUI_apps/Image_analysis/Image_analysis.py b/PythonGUI_apps/Image_analysis/Image_analysis.py new file mode 100644 index 0000000..6c24ba7 --- /dev/null +++ b/PythonGUI_apps/Image_analysis/Image_analysis.py @@ -0,0 +1,142 @@ +import sys +from pathlib import Path +import os.path +import pyqtgraph as pg +from pyqtgraph.Qt import QtCore, QtGui, QtWidgets#, QColorDialog +import numpy as np +import matplotlib.pyplot as plt +from PIL import Image + +# local modules + +pg.mkQApp() + +base_path = Path(__file__).parent +file_path = (base_path / "image_analysis_gui.ui").resolve() + +uiFile = file_path + +WindowTemplate, TemplateBaseClass = pg.Qt.loadUiType(uiFile) + +class MainWindow(TemplateBaseClass): + + def __init__(self): + super(TemplateBaseClass, self).__init__() + + # Create the main window + self.ui = WindowTemplate() + self.ui.setupUi(self) + + #setup imageview + self.imv = pg.ImageView() + self.imv.getView().setAspectLocked(lock=False, ratio=1) + self.imv.getView().setMouseEnabled(x=True, y=True) + self.imv.getView().invertY(False) + self.roi = self.imv.roi + self.roi.translateSnap = True + self.roi.scaleSnap = True + self.calc_scaling_factor() #initialize scaling_factor + self.roi.snapSize = self.scaling_factor #roi snaps to multiples of scaling_factor + self.roi.sigRegionChanged.connect(self.line_profile_update_plot) + self.roi_plot = self.imv.getRoiPlot().getPlotItem() + + self.ui.image_groupBox.layout().addWidget(self.imv) + + #set up ui signals + self.ui.load_image_pushButton.clicked.connect(self.load_image) + self.ui.custom_pixel_size_checkBox.stateChanged.connect(self.switch_custom_pixel_size) + + self.show() + + def load_image(self): + """ + Prompts the user to select a text file containing image data. + """ + try: + file = QtWidgets.QFileDialog.getOpenFileName(self, 'Open file', os.getcwd()) + image = Image.open(file[0]) + image = image.rotate(-90, expand=True) + image_array = np.asarray(image) + try: + width = image_array.shape[0] + height = image_array.shape[1] + x_vals = np.arange(width) + self.imv.setImage(img=image_array, xvals= x_vals) + self.calc_scaling_factor() + self.roi.setPos((0,0)) + self.roi.setSize([width, height*self.scaling_factor]) #set line roi + self.line_profile_update_plot() + except: + pass + except Exception as err: + print(format(err)) + + def line_profile_update_plot(self): + """ Handle line profile for intensity sum viewbox """ + #if hasattr(self, "intensity_sums"): + self.roi_plot.clear() + + image = self.imv.getProcessedImage() + + # Extract image data from ROI + axes = (self.imv.axes['x'], self.imv.axes['y']) + data, coords = self.roi.getArrayRegion(image.view(np.ndarray), self.imv.imageItem, axes, returnMappedCoords=True) + if data is None: + return + + self.calc_scaling_factor() + x_values = coords[1][0] * self.scaling_factor #adjust x-axis roi plot + + #calculate sums along columns in region + if len(data.shape) == 2: #if grayscale, average intensities + sums_to_plot = np.mean(data, axis=0) + try: + self.roi_plot.plot(x_values, sums_to_plot) + except: + pass + elif len(data.shape) > 2: #if rgb arrays, plot individual components + r_values = data[:,:,0] + g_values = data[:,:,1] + b_values = data[:,:,2] + r_avg = np.mean(r_values, axis=0) #average red values across columns + g_avg = np.mean(g_values, axis=0) #average green values + b_avg = np.mean(b_values, axis=0) #average blue values + try: + self.roi_plot.plot(x_values, r_avg, pen='r') + self.roi_plot.plot(x_values, g_avg, pen='g') + self.roi_plot.plot(x_values, b_avg, pen='b') + except: + pass + + def calc_scaling_factor(self): + """ + Calculate scaling factor + """ + if self.ui.custom_pixel_size_checkBox.isChecked(): + self.scaling_factor = self.ui.custom_pixel_size_spinBox.value() + else: + pixel_size = 7.4 + self.scaling_factor = pixel_size/int(self.ui.magnification_comboBox.currentText()) + + def switch_custom_pixel_size(self): + checked = self.ui.custom_pixel_size_checkBox.isChecked() + self.ui.custom_pixel_size_spinBox.setEnabled(checked) + self.ui.magnification_comboBox.setEnabled(not checked) + + def close_application(self): + choice = QtGui.QMessageBox.question(self, 'EXIT!', + "Do you want to exit the app?", + QtGui.QMessageBox.Yes | QtGui.QMessageBox.No) + if choice == QtGui.QMessageBox.Yes: + sys.exit() + else: + pass + +"""Run the Main Window""" +def run(): + win = MainWindow() + QtGui.QApplication.instance().exec_() + return win + +#Uncomment below if you want to run this as standalone +#run() \ No newline at end of file diff --git a/PythonGUI_apps/Image_analysis/image_analysis_gui.ui b/PythonGUI_apps/Image_analysis/image_analysis_gui.ui new file mode 100644 index 0000000..e8928b1 --- /dev/null +++ b/PythonGUI_apps/Image_analysis/image_analysis_gui.ui @@ -0,0 +1,122 @@ + + + MainWindow + + + + 0 + 0 + 1050 + 743 + + + + MainWindow + + + QTabWidget::Triangular + + + + + + + + 0 + 0 + + + + + 600 + 0 + + + + Image + + + + + + + + Settings + + + + + + + + + + + + + Load image + + + + + + + + 50 + + + + + 75 + + + + + 100 + + + + + + + + Magnification + + + + + + + Custom pixel size (um) + + + + + + + false + + + + + + + + + + + + + + 0 + 0 + 1050 + 31 + + + + + + + + From 11b21fe623f44ba6ded9700efc30cb919f586391 Mon Sep 17 00:00:00 2001 From: "LAKESIDE\\LindaT18" Date: Mon, 19 Aug 2019 14:24:12 -0700 Subject: [PATCH 11/25] resized image according to scaling_factor --- .../Image_analysis/Image_analysis.py | 50 +++++++++++-------- .../Image_analysis/image_analysis_gui.ui | 31 +++++++----- 2 files changed, 47 insertions(+), 34 deletions(-) diff --git a/PythonGUI_apps/Image_analysis/Image_analysis.py b/PythonGUI_apps/Image_analysis/Image_analysis.py index 6c24ba7..09523ee 100644 --- a/PythonGUI_apps/Image_analysis/Image_analysis.py +++ b/PythonGUI_apps/Image_analysis/Image_analysis.py @@ -35,17 +35,19 @@ def __init__(self): self.roi = self.imv.roi self.roi.translateSnap = True self.roi.scaleSnap = True - self.calc_scaling_factor() #initialize scaling_factor - self.roi.snapSize = self.scaling_factor #roi snaps to multiples of scaling_factor - self.roi.sigRegionChanged.connect(self.line_profile_update_plot) + self.update_scaling_factor() #initialize scaling_factor + self.roi_plot = self.imv.getRoiPlot().getPlotItem() self.ui.image_groupBox.layout().addWidget(self.imv) #set up ui signals + self.roi.sigRegionChanged.connect(self.line_profile_update_plot) self.ui.load_image_pushButton.clicked.connect(self.load_image) self.ui.custom_pixel_size_checkBox.stateChanged.connect(self.switch_custom_pixel_size) + self.ui.update_scaling_factor_pushButton.clicked.connect(self.update_scaling_factor) + self.num_plots = 0 self.show() def load_image(self): @@ -54,28 +56,30 @@ def load_image(self): """ try: file = QtWidgets.QFileDialog.getOpenFileName(self, 'Open file', os.getcwd()) - image = Image.open(file[0]) - image = image.rotate(-90, expand=True) - image_array = np.asarray(image) - try: - width = image_array.shape[0] - height = image_array.shape[1] - x_vals = np.arange(width) - self.imv.setImage(img=image_array, xvals= x_vals) - self.calc_scaling_factor() - self.roi.setPos((0,0)) - self.roi.setSize([width, height*self.scaling_factor]) #set line roi - self.line_profile_update_plot() - except: - pass + self.original_image = Image.open(file[0]) + self.original_image = self.original_image.rotate(-90, expand=True) + self.resize_to_scaling_factor(self.original_image) except Exception as err: print(format(err)) + def resize_to_scaling_factor(self, image): + image = image.resize((round(image.size[0]*self.scaling_factor), round(image.size[1]*self.scaling_factor))) + image_array = np.asarray(image) + width = image_array.shape[0] + height = image_array.shape[1] + try: + x_vals = np.arange(width) + self.imv.setImage(img=image_array, xvals= x_vals) + self.roi.setPos((0,0)) + self.roi.setSize([width, height * self.scaling_factor]) #set line roi + self.line_profile_update_plot() + except: + pass + + def line_profile_update_plot(self): """ Handle line profile for intensity sum viewbox """ - #if hasattr(self, "intensity_sums"): self.roi_plot.clear() - image = self.imv.getProcessedImage() # Extract image data from ROI @@ -84,8 +88,7 @@ def line_profile_update_plot(self): if data is None: return - self.calc_scaling_factor() - x_values = coords[1][0] * self.scaling_factor #adjust x-axis roi plot + x_values = coords[1][0] #calculate sums along columns in region if len(data.shape) == 2: #if grayscale, average intensities @@ -108,7 +111,7 @@ def line_profile_update_plot(self): except: pass - def calc_scaling_factor(self): + def update_scaling_factor(self): """ Calculate scaling factor """ @@ -117,6 +120,9 @@ def calc_scaling_factor(self): else: pixel_size = 7.4 self.scaling_factor = pixel_size/int(self.ui.magnification_comboBox.currentText()) + self.roi.snapSize = self.scaling_factor + if hasattr(self, "original_image"): + self.resize_to_scaling_factor(self.original_image) def switch_custom_pixel_size(self): checked = self.ui.custom_pixel_size_checkBox.isChecked() diff --git a/PythonGUI_apps/Image_analysis/image_analysis_gui.ui b/PythonGUI_apps/Image_analysis/image_analysis_gui.ui index e8928b1..d2a471e 100644 --- a/PythonGUI_apps/Image_analysis/image_analysis_gui.ui +++ b/PythonGUI_apps/Image_analysis/image_analysis_gui.ui @@ -6,7 +6,7 @@ 0 0 - 1050 + 1059 743 @@ -51,10 +51,10 @@
- - + + - Load image + Custom pixel size (um) @@ -77,6 +77,13 @@
+ + + + false + + + @@ -84,17 +91,17 @@ - - + + - Custom pixel size (um) + Load image - - - - false + + + + Update scaling factor @@ -110,7 +117,7 @@ 0 0 - 1050 + 1059 31 From 73bb638777e8a91b83c679ea6e8c9d62722e2f01 Mon Sep 17 00:00:00 2001 From: "LAKESIDE\\LindaT18" Date: Mon, 19 Aug 2019 16:15:09 -0700 Subject: [PATCH 12/25] image_analysis: add grayscale option, flim: average instead of sum for line profile --- PythonGUI_apps/FLIM_analysis/FLIM_plot.py | 2 +- .../Image_analysis/Image_analysis.py | 30 +++++--- .../Image_analysis/image_analysis_gui.ui | 74 ++++++++++++++----- 3 files changed, 77 insertions(+), 29 deletions(-) diff --git a/PythonGUI_apps/FLIM_analysis/FLIM_plot.py b/PythonGUI_apps/FLIM_analysis/FLIM_plot.py index 79a8032..f7dafde 100644 --- a/PythonGUI_apps/FLIM_analysis/FLIM_plot.py +++ b/PythonGUI_apps/FLIM_analysis/FLIM_plot.py @@ -129,7 +129,7 @@ def line_profile_update_plot(self): data, coords = roi.getArrayRegion(image.view(np.ndarray), self.ui.intensity_sums_viewBox.imageItem, axes, returnMappedCoords=True) #calculate sums along columns in region - sums_to_plot = np.sum(data, axis=0) + sums_to_plot = np.mean(data, axis=0) #get scan x-coordinates in region x_values = coords[1][0] diff --git a/PythonGUI_apps/Image_analysis/Image_analysis.py b/PythonGUI_apps/Image_analysis/Image_analysis.py index 09523ee..c700865 100644 --- a/PythonGUI_apps/Image_analysis/Image_analysis.py +++ b/PythonGUI_apps/Image_analysis/Image_analysis.py @@ -35,10 +35,10 @@ def __init__(self): self.roi = self.imv.roi self.roi.translateSnap = True self.roi.scaleSnap = True + self.update_camera() #initialize camera pixel size self.update_scaling_factor() #initialize scaling_factor - self.roi_plot = self.imv.getRoiPlot().getPlotItem() - + self.roi_plot = self.imv.getRoiPlot().getPlotItem() #get roi plot self.ui.image_groupBox.layout().addWidget(self.imv) #set up ui signals @@ -46,6 +46,7 @@ def __init__(self): self.ui.load_image_pushButton.clicked.connect(self.load_image) self.ui.custom_pixel_size_checkBox.stateChanged.connect(self.switch_custom_pixel_size) self.ui.update_scaling_factor_pushButton.clicked.connect(self.update_scaling_factor) + self.ui.spot_radioButton.toggled.connect(self.update_camera) self.num_plots = 0 self.show() @@ -57,18 +58,23 @@ def load_image(self): try: file = QtWidgets.QFileDialog.getOpenFileName(self, 'Open file', os.getcwd()) self.original_image = Image.open(file[0]) - self.original_image = self.original_image.rotate(-90, expand=True) + #self.original_image = self.original_image.rotate(-90, expand=True) self.resize_to_scaling_factor(self.original_image) except Exception as err: print(format(err)) def resize_to_scaling_factor(self, image): + """ + Handles loading of image according to scaling_factor + """ image = image.resize((round(image.size[0]*self.scaling_factor), round(image.size[1]*self.scaling_factor))) - image_array = np.asarray(image) + if self.ui.greyscale_checkBox.isChecked(): + image = image.convert("L") #convert to greyscale + image_array = np.asarray(image).T #correct numpy array auto-flip width = image_array.shape[0] height = image_array.shape[1] try: - x_vals = np.arange(width) + x_vals = np.arange(width) #imv x-axis self.imv.setImage(img=image_array, xvals= x_vals) self.roi.setPos((0,0)) self.roi.setSize([width, height * self.scaling_factor]) #set line roi @@ -76,7 +82,6 @@ def resize_to_scaling_factor(self, image): except: pass - def line_profile_update_plot(self): """ Handle line profile for intensity sum viewbox """ self.roi_plot.clear() @@ -118,17 +123,22 @@ def update_scaling_factor(self): if self.ui.custom_pixel_size_checkBox.isChecked(): self.scaling_factor = self.ui.custom_pixel_size_spinBox.value() else: - pixel_size = 7.4 - self.scaling_factor = pixel_size/int(self.ui.magnification_comboBox.currentText()) - self.roi.snapSize = self.scaling_factor + self.scaling_factor = self.camera_pixel_size/int(self.ui.magnification_comboBox.currentText()) + self.roi.snapSize = self.scaling_factor #roi snaps to multiples of scaling_factor if hasattr(self, "original_image"): - self.resize_to_scaling_factor(self.original_image) + self.resize_to_scaling_factor(self.original_image) #resize image, sets up roi def switch_custom_pixel_size(self): checked = self.ui.custom_pixel_size_checkBox.isChecked() self.ui.custom_pixel_size_spinBox.setEnabled(checked) self.ui.magnification_comboBox.setEnabled(not checked) + def update_camera(self): + if self.ui.spot_radioButton.isChecked(): + self.camera_pixel_size = 7.4 + elif self.ui.pixera_radioButton.isChecked(): + self.camera_pixel_size = 0 + def close_application(self): choice = QtGui.QMessageBox.question(self, 'EXIT!', "Do you want to exit the app?", diff --git a/PythonGUI_apps/Image_analysis/image_analysis_gui.ui b/PythonGUI_apps/Image_analysis/image_analysis_gui.ui index d2a471e..21e111c 100644 --- a/PythonGUI_apps/Image_analysis/image_analysis_gui.ui +++ b/PythonGUI_apps/Image_analysis/image_analysis_gui.ui @@ -6,7 +6,7 @@ 0 0 - 1059 + 1029 743 @@ -51,14 +51,21 @@ - - + + - Custom pixel size (um) + Load image + + + + + + + Greyscale image - + @@ -75,30 +82,61 @@ 100 + + + 150 + + - - - - false - - - - + Magnification - - + + - Load image + Custom pixel size (um) + + + + + + + false + + + + + + + Camera + + + + + SPOT + + + true + + + + + + + Pixera + + + + - + Update scaling factor @@ -117,7 +155,7 @@ 0 0 - 1059 + 1029 31 From 52be7a405891e0946ff257b473a51397a6e9ede2 Mon Sep 17 00:00:00 2001 From: "LAKESIDE\\LindaT18" Date: Mon, 19 Aug 2019 16:19:20 -0700 Subject: [PATCH 13/25] added pixera pixel size --- PythonGUI_apps/Image_analysis/Image_analysis.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/PythonGUI_apps/Image_analysis/Image_analysis.py b/PythonGUI_apps/Image_analysis/Image_analysis.py index c700865..485b097 100644 --- a/PythonGUI_apps/Image_analysis/Image_analysis.py +++ b/PythonGUI_apps/Image_analysis/Image_analysis.py @@ -137,7 +137,7 @@ def update_camera(self): if self.ui.spot_radioButton.isChecked(): self.camera_pixel_size = 7.4 elif self.ui.pixera_radioButton.isChecked(): - self.camera_pixel_size = 0 + self.camera_pixel_size = 3 def close_application(self): choice = QtGui.QMessageBox.question(self, 'EXIT!', From 0c6944e75da8702e2c8a49d071dc261e0ae5a2d2 Mon Sep 17 00:00:00 2001 From: SarthakJariwala Date: Mon, 19 Aug 2019 17:38:19 -0700 Subject: [PATCH 14/25] fix scalebar -- include delay in update solved it --- PythonGUI_apps/FLIM_analysis/FLIM_plot.py | 521 +++++++++++----------- 1 file changed, 263 insertions(+), 258 deletions(-) diff --git a/PythonGUI_apps/FLIM_analysis/FLIM_plot.py b/PythonGUI_apps/FLIM_analysis/FLIM_plot.py index f7dafde..51b2eef 100644 --- a/PythonGUI_apps/FLIM_analysis/FLIM_plot.py +++ b/PythonGUI_apps/FLIM_analysis/FLIM_plot.py @@ -7,7 +7,7 @@ import numpy as np import matplotlib.pyplot as plt import pickle -import time +#import time from lmfit.models import GaussianModel import customplotting.mscope as cpm @@ -28,268 +28,273 @@ WindowTemplate, TemplateBaseClass = pg.Qt.loadUiType(uiFile) +def updateDelay(scale, time): + QtCore.QTimer.singleShot(time, scale.updateBar) + class MainWindow(TemplateBaseClass): - hist_data_signal = QtCore.pyqtSignal() - - def __init__(self): - super(TemplateBaseClass, self).__init__() - - # Create the main window - self.ui = WindowTemplate() - self.ui.setupUi(self) - - #set up ui signals - self.ui.load_scan_pushButton.clicked.connect(self.open_file) - self.ui.plot_intensity_sums_pushButton.clicked.connect(self.plot_intensity_sums) - self.ui.plot_raw_hist_data_pushButton.clicked.connect(self.plot_raw_scan) - self.ui.save_intensities_image_pushButton.clicked.connect(self.save_intensities_image) - self.ui.save_intensities_array_pushButton.clicked.connect(self.save_intensities_array) - self.ui.compare_checkBox.stateChanged.connect(self.switch_compare) - self.ui.intensity_sums_viewBox.roi.sigRegionChanged.connect(self.line_profile_update_plot) - self.ui.import_pkl_pushButton.clicked.connect(self.import_pkl_to_convert) - self.ui.pkl_to_h5_pushButton.clicked.connect(self.pkl_to_h5) - self.ui.analyze_lifetime_pushButton.clicked.connect(self.on_analyze_lifetime) - self.ui.analyze_psf_pushButton.clicked.connect(self.on_analyze_psf) - - self.show() - - def open_file(self): - """ Open FLIM scan file """ - try: - self.filename = QtWidgets.QFileDialog.getOpenFileName(self, filter="Scan files (*.pkl *.h5)") - if ".pkl" in self.filename[0]: - self.flim_scan_file = pickle.load(open(self.filename[0], 'rb')) - self.scan_file_type = "pkl" - elif ".h5" in self.filename[0]: - self.flim_scan_file = h5py.File(self.filename[0], 'r') - self.scan_file_type = "h5" - self.get_data_params() - # self.pkl_file = pickle.load(open(self.filename[0], 'rb')) - except Exception as err: - print(format(err)) - - def import_pkl_to_convert(self): - """ Open pkl file to convert to h5 """ - try: - self.pkl_to_convert = QtWidgets.QFileDialog.getOpenFileName(self) - self.ui.result_textBrowser.append("Done Loading - .pkl to convert") - except: - pass - - def get_data_params(self): - - data = self.flim_scan_file - if self.scan_file_type == "pkl": - self.x_scan_size = data['Scan Parameters']['X scan size (um)'] - self.y_scan_size = data['Scan Parameters']['Y scan size (um)'] - self.x_step_size = data['Scan Parameters']['X step size (um)'] - self.y_step_size = data['Scan Parameters']['Y step size (um)'] - self.hist_data = data['Histogram data'] - self.time_data = data['Time data'] - else: #run this if scan file is h5 - self.x_scan_size = data['Scan Parameters'].attrs['X scan size (um)'] - self.y_scan_size = data['Scan Parameters'].attrs['Y scan size (um)'] - self.x_step_size = data['Scan Parameters'].attrs['X step size (um)'] - self.y_step_size = data['Scan Parameters'].attrs['Y step size (um)'] - self.hist_data = data['Histogram data'][()] #get dataset values - self.time_data = data['Time data'][()] - - self.numb_x_pixels = int(self.x_scan_size/self.x_step_size) - self.numb_y_pixels = int(self.y_scan_size/self.y_step_size) - - - def plot_intensity_sums(self): - try: - self.hist_data = np.reshape(self.hist_data, newshape=(self.hist_data.shape[0], self.numb_x_pixels*self.numb_y_pixels)) - self.intensity_sums = np.sum(self.hist_data, axis=0) #sum intensities for each pixel - self.intensity_sums = np.reshape(self.intensity_sums, newshape=(self.numb_x_pixels, self.numb_y_pixels)) - self.ui.intensity_sums_viewBox.view.invertY(False) # stop y axis invert - self.ui.intensity_sums_viewBox.setImage(self.intensity_sums, scale= - (self.x_step_size, - self.y_step_size)) - self.ui.intensity_sums_viewBox.roi.setSize([self.x_scan_size, self.y_step_size]) #line roi - scale = pg.ScaleBar(size=1,suffix='um') - scale.setParentItem(self.ui.intensity_sums_viewBox.view) - scale.anchor((1, 1), (1, 1), offset=(-30, -30)) - except Exception as err: - print(format(err)) - - def line_profile_update_plot(self): - """ Handle line profile for intensity sum viewbox """ - if hasattr(self, "intensity_sums"): - roiPlot = self.ui.intensity_sums_viewBox.getRoiPlot() - roiPlot.clear() - roi = self.ui.intensity_sums_viewBox.roi - - image = self.ui.intensity_sums_viewBox.getProcessedImage() - - # Extract image data from ROI - axes = (self.ui.intensity_sums_viewBox.axes['x'], self.ui.intensity_sums_viewBox.axes['y']) - data, coords = roi.getArrayRegion(image.view(np.ndarray), self.ui.intensity_sums_viewBox.imageItem, axes, returnMappedCoords=True) - - #calculate sums along columns in region - sums_to_plot = np.mean(data, axis=0) - - #get scan x-coordinates in region - x_values = coords[1][0] - - try: - roiPlot.plot(x_values, sums_to_plot) - except: - pass - - def on_analyze_psf(self): - self.spectrum_window = Spectra_plot_fit.MainWindow() - self.spectrum_window.show() - self.spectrum_window.opened_from_flim = True - sum_data = self.ui.intensity_sums_viewBox.getRoiPlot().getPlotItem().curves[0].getData() - self.spectrum_window.sum_data_from_flim = np.asarray(sum_data) - self.spectrum_window.ui.plot_without_bck_radioButton.setChecked(True) - self.spectrum_window.ui.result_textBrowser.setText("Data successfully loaded from FLIM analysis.") - - def plot_raw_scan(self): - try: - self.hist_image = np.reshape(self.hist_data, newshape=(self.hist_data.shape[0],self.numb_x_pixels,self.numb_y_pixels)) - self.times = self.time_data[:, 0, 0]*1e-3 - self.ui.raw_hist_data_viewBox.view.invertY(False) # stops y-axis invert - self.ui.raw_hist_data_viewBox.setImage(self.hist_image, scale= - (self.x_step_size, - self.y_step_size), xvals=self.times) - self.ui.raw_hist_data_viewBox.roi.setSize([self.x_scan_size, self.y_scan_size]) - # if self.ui.compare_checkBox.isChecked(): - # self.ui.imv2.setImage(self.hist_image, scale= (data['Scan Parameters']['X step size (um)'], - # data['Scan Parameters']['Y step size (um)']), xvals=self.times) - self.switch_compare() - self.ui.raw_hist_data_viewBox.ui.roiBtn.clicked.connect(self.switch_compare) - scale = pg.ScaleBar(size=1,suffix='um') - scale.setParentItem(self.ui.raw_hist_data_viewBox.view) - scale.anchor((1, 1), (1, 1), offset=(-30, -30)) - - except Exception as err: - print(format(err)) - - def switch_compare(self): - """ - Handles compare checkbox. If checked, show second ROI on raw histogram data that user can use for comparison to first ROI. - """ - if self.ui.compare_checkBox.isChecked() and hasattr(self, "hist_image"): - if not hasattr(self, "roi2"): #create roi if doesn't exist yet - self.roi2 = pg.ROI(pos=[0,0], size=[int(self.x_scan_size/2), int(self.y_scan_size/2)], movable=True, pen='r') - self.roi2.addScaleHandle([1, 1], [0, 0]) - self.roi2.addRotateHandle([0, 0], [1, 1]) - self.roi2.sigRegionChanged.connect(self.update_roi2_plot) - self.ui.raw_hist_data_viewBox.addItem(self.roi2) - self.update_roi2_plot() - self.roi2.hide() - self.roi2_plot.hide() - if self.ui.raw_hist_data_viewBox.ui.roiBtn.isChecked(): - self.roi2.show() - self.roi2_plot.show() - else: - self.roi2.hide() - self.roi2_plot.hide() - else: #if not checked, hide roi - if hasattr(self, "roi2"): - self.roi2.hide() - self.roi2_plot.hide() - - def update_roi2_plot(self): - """ Update plot corresponding to second roi """ - #Adapted from pyqtgraph imageview sourcecode - - image = self.ui.raw_hist_data_viewBox.getProcessedImage() - - # Extract image data from ROI - axes = (self.ui.raw_hist_data_viewBox.axes['x'], self.ui.raw_hist_data_viewBox.axes['y']) - data, coords = self.roi2.getArrayRegion(image.view(np.ndarray), self.ui.raw_hist_data_viewBox.imageItem, axes, returnMappedCoords=True) - if data is None: - return - - # Average data within entire ROI for each frame - data = data.mean(axis=max(axes)).mean(axis=min(axes)) - xvals = self.ui.raw_hist_data_viewBox.tVals - if hasattr(self, "roi2_plot"): #make sure second plot is properly cleared everytime - self.roi2_plot.clear() - c = self.ui.raw_hist_data_viewBox.getRoiPlot().getPlotItem().curves.pop() - c.scene().removeItem(c) - self.roi2_plot = self.ui.raw_hist_data_viewBox.getRoiPlot().plot(xvals, data, pen='r') - - def get_raw_hist_curve(self, curve_index): - #curve_index = 0 for original roi - #curve_index = 1 for second comparison roi - curves = self.ui.raw_hist_data_viewBox.getRoiPlot().getPlotItem().curves - return curves[curve_index].getData() - - def on_analyze_lifetime(self): - self.lifetime_window = Lifetime_plot_fit.MainWindow() - self.lifetime_window.show() - self.lifetime_window.opened_from_flim = True - self.lifetime_window.hist_data_from_flim = np.asarray(self.get_raw_hist_curve(0)) - self.lifetime_window.ui.Result_textBrowser.setText("Data successfully loaded from FLIM analysis.") - - def save_intensities_image(self): - try: - folder = os.path.dirname(self.filename[0]) - filename_ext = os.path.basename(self.filename[0]) - filename = os.path.splitext(filename_ext)[0] #get filename without extension - save_to = folder + "\\" + filename + "_intensity_sums.png" - cpm.plot_confocal(self.intensity_sums, FLIM_adjust=False, stepsize=np.abs(self.x_step_size)) - plt.savefig(save_to, bbox_inches='tight', dpi=300) - except Exception as e: - print(format(e)) - - def save_intensities_array(self): - try: - folder = os.path.dirname(self.filename[0]) - filename_ext = os.path.basename(self.filename[0]) - filename = os.path.splitext(filename_ext)[0] #get filename without extension - save_to = folder + "\\" + filename + "_intensity_sums.txt" - np.savetxt(save_to, self.intensity_sums.T, fmt='%f') #save transposed intensity sums, as original array handles x in cols and y in rows - except: - pass - - def pkl_to_h5(self): - #Convert scan .pkl file into h5 - try: - folder = os.path.dirname(self.pkl_to_convert[0]) - filename_ext = os.path.basename(self.pkl_to_convert[0]) - filename = os.path.splitext(filename_ext)[0] #get filename without extension - pkl_file = pickle.load(open(self.pkl_to_convert[0], 'rb')) - - h5_filename = folder + "/" + filename + ".h5" - h5_file = h5py.File(h5_filename, "w") - self.traverse_dict_into_h5(pkl_file, h5_file) - except Exception as err: - print(format(err)) - - def traverse_dict_into_h5(self, dictionary, h5_output): - #Create an h5 file using .pkl with scan data and params - for key in dictionary: - if type(dictionary[key]) == dict: #if subdictionary, create a group - group = h5_output.create_group(key) - previous_dict = dictionary[key] - self.traverse_dict_into_h5(dictionary[key], group) #traverse subdictionary - else: - if key == "Histogram data" or key == "Time data": - h5_output.create_dataset(key, data=dictionary[key]) - else: - h5_output.attrs[key] = dictionary[key] #if not dataset, create attribute - - def close_application(self): - choice = QtGui.QMessageBox.question(self, 'EXIT!', - "Do you want to exit the app?", - QtGui.QMessageBox.Yes | QtGui.QMessageBox.No) - if choice == QtGui.QMessageBox.Yes: - sys.exit() - else: - pass + hist_data_signal = QtCore.pyqtSignal() + + def __init__(self): + super(TemplateBaseClass, self).__init__() + + # Create the main window + self.ui = WindowTemplate() + self.ui.setupUi(self) + + #set up ui signals + self.ui.load_scan_pushButton.clicked.connect(self.open_file) + self.ui.plot_intensity_sums_pushButton.clicked.connect(self.plot_intensity_sums) + self.ui.plot_raw_hist_data_pushButton.clicked.connect(self.plot_raw_scan) + self.ui.save_intensities_image_pushButton.clicked.connect(self.save_intensities_image) + self.ui.save_intensities_array_pushButton.clicked.connect(self.save_intensities_array) + self.ui.compare_checkBox.stateChanged.connect(self.switch_compare) + self.ui.intensity_sums_viewBox.roi.sigRegionChanged.connect(self.line_profile_update_plot) + self.ui.import_pkl_pushButton.clicked.connect(self.import_pkl_to_convert) + self.ui.pkl_to_h5_pushButton.clicked.connect(self.pkl_to_h5) + self.ui.analyze_lifetime_pushButton.clicked.connect(self.on_analyze_lifetime) + self.ui.analyze_psf_pushButton.clicked.connect(self.on_analyze_psf) + + self.show() + + def open_file(self): + """ Open FLIM scan file """ + try: + self.filename = QtWidgets.QFileDialog.getOpenFileName(self, filter="Scan files (*.pkl *.h5)") + if ".pkl" in self.filename[0]: + self.flim_scan_file = pickle.load(open(self.filename[0], 'rb')) + self.scan_file_type = "pkl" + elif ".h5" in self.filename[0]: + self.flim_scan_file = h5py.File(self.filename[0], 'r') + self.scan_file_type = "h5" + self.get_data_params() + # self.pkl_file = pickle.load(open(self.filename[0], 'rb')) + except Exception as err: + print(format(err)) + + def import_pkl_to_convert(self): + """ Open pkl file to convert to h5 """ + try: + self.pkl_to_convert = QtWidgets.QFileDialog.getOpenFileName(self) + self.ui.result_textBrowser.append("Done Loading - .pkl to convert") + except: + pass + + def get_data_params(self): + + data = self.flim_scan_file + if self.scan_file_type == "pkl": + self.x_scan_size = data['Scan Parameters']['X scan size (um)'] + self.y_scan_size = data['Scan Parameters']['Y scan size (um)'] + self.x_step_size = data['Scan Parameters']['X step size (um)'] + self.y_step_size = data['Scan Parameters']['Y step size (um)'] + self.hist_data = data['Histogram data'] + self.time_data = data['Time data'] + else: #run this if scan file is h5 + self.x_scan_size = data['Scan Parameters'].attrs['X scan size (um)'] + self.y_scan_size = data['Scan Parameters'].attrs['Y scan size (um)'] + self.x_step_size = data['Scan Parameters'].attrs['X step size (um)'] + self.y_step_size = data['Scan Parameters'].attrs['Y step size (um)'] + self.hist_data = data['Histogram data'][()] #get dataset values + self.time_data = data['Time data'][()] + + self.numb_x_pixels = int(self.x_scan_size/self.x_step_size) + self.numb_y_pixels = int(self.y_scan_size/self.y_step_size) + + + def plot_intensity_sums(self): + try: + self.hist_data = np.reshape(self.hist_data, newshape=(self.hist_data.shape[0], self.numb_x_pixels*self.numb_y_pixels)) + self.intensity_sums = np.sum(self.hist_data, axis=0) #sum intensities for each pixel + self.intensity_sums = np.reshape(self.intensity_sums, newshape=(self.numb_x_pixels, self.numb_y_pixels)) + self.ui.intensity_sums_viewBox.view.invertY(False) # stop y axis invert + self.ui.intensity_sums_viewBox.setImage(self.intensity_sums, scale= + (self.x_step_size, + self.y_step_size)) + self.ui.intensity_sums_viewBox.roi.setSize([self.x_scan_size, self.y_step_size]) #line roi + scale = pg.ScaleBar(size=3,suffix='um') + scale.setParentItem(self.ui.intensity_sums_viewBox.view) + scale.anchor((1, 1), (1, 1), offset=(-30, -30)) + self.ui.intensity_sums_viewBox.view.sigRangeChanged.connect(lambda: updateDelay(scale, 10)) + except Exception as err: + print(format(err)) + + def line_profile_update_plot(self): + """ Handle line profile for intensity sum viewbox """ + if hasattr(self, "intensity_sums"): + roiPlot = self.ui.intensity_sums_viewBox.getRoiPlot() + roiPlot.clear() + roi = self.ui.intensity_sums_viewBox.roi + + image = self.ui.intensity_sums_viewBox.getProcessedImage() + + # Extract image data from ROI + axes = (self.ui.intensity_sums_viewBox.axes['x'], self.ui.intensity_sums_viewBox.axes['y']) + data, coords = roi.getArrayRegion(image.view(np.ndarray), self.ui.intensity_sums_viewBox.imageItem, axes, returnMappedCoords=True) + + #calculate sums along columns in region + sums_to_plot = np.mean(data, axis=0) + + #get scan x-coordinates in region + x_values = coords[1][0] + + try: + roiPlot.plot(x_values, sums_to_plot) + except: + pass + + def on_analyze_psf(self): + self.spectrum_window = Spectra_plot_fit.MainWindow() + self.spectrum_window.show() + self.spectrum_window.opened_from_flim = True + sum_data = self.ui.intensity_sums_viewBox.getRoiPlot().getPlotItem().curves[0].getData() + self.spectrum_window.sum_data_from_flim = np.asarray(sum_data) + self.spectrum_window.ui.plot_without_bck_radioButton.setChecked(True) + self.spectrum_window.ui.result_textBrowser.setText("Data successfully loaded from FLIM analysis.") + + def plot_raw_scan(self): + try: + self.hist_image = np.reshape(self.hist_data, newshape=(self.hist_data.shape[0],self.numb_x_pixels,self.numb_y_pixels)) + self.times = self.time_data[:, 0, 0]*1e-3 + self.ui.raw_hist_data_viewBox.view.invertY(False) # stops y-axis invert + self.ui.raw_hist_data_viewBox.setImage(self.hist_image, scale= + (self.x_step_size, + self.y_step_size), xvals=self.times) + self.ui.raw_hist_data_viewBox.roi.setSize([self.x_scan_size, self.y_scan_size]) + # if self.ui.compare_checkBox.isChecked(): + # self.ui.imv2.setImage(self.hist_image, scale= (data['Scan Parameters']['X step size (um)'], + # data['Scan Parameters']['Y step size (um)']), xvals=self.times) + self.switch_compare() + self.ui.raw_hist_data_viewBox.ui.roiBtn.clicked.connect(self.switch_compare) + scale = pg.ScaleBar(size=1,suffix='um') + scale.setParentItem(self.ui.raw_hist_data_viewBox.view) + scale.anchor((1, 1), (1, 1), offset=(-30, -30)) + self.ui.raw_hist_data_viewBox.view.sigRangeChanged.connect(lambda: updateDelay(scale, 10)) + + except Exception as err: + print(format(err)) + + def switch_compare(self): + """ + Handles compare checkbox. If checked, show second ROI on raw histogram data that user can use for comparison to first ROI. + """ + if self.ui.compare_checkBox.isChecked() and hasattr(self, "hist_image"): + if not hasattr(self, "roi2"): #create roi if doesn't exist yet + self.roi2 = pg.ROI(pos=[0,0], size=[int(self.x_scan_size/2), int(self.y_scan_size/2)], movable=True, pen='r') + self.roi2.addScaleHandle([1, 1], [0, 0]) + self.roi2.addRotateHandle([0, 0], [1, 1]) + self.roi2.sigRegionChanged.connect(self.update_roi2_plot) + self.ui.raw_hist_data_viewBox.addItem(self.roi2) + self.update_roi2_plot() + self.roi2.hide() + self.roi2_plot.hide() + if self.ui.raw_hist_data_viewBox.ui.roiBtn.isChecked(): + self.roi2.show() + self.roi2_plot.show() + else: + self.roi2.hide() + self.roi2_plot.hide() + else: #if not checked, hide roi + if hasattr(self, "roi2"): + self.roi2.hide() + self.roi2_plot.hide() + + def update_roi2_plot(self): + """ Update plot corresponding to second roi """ + #Adapted from pyqtgraph imageview sourcecode + + image = self.ui.raw_hist_data_viewBox.getProcessedImage() + + # Extract image data from ROI + axes = (self.ui.raw_hist_data_viewBox.axes['x'], self.ui.raw_hist_data_viewBox.axes['y']) + data, coords = self.roi2.getArrayRegion(image.view(np.ndarray), self.ui.raw_hist_data_viewBox.imageItem, axes, returnMappedCoords=True) + if data is None: + return + + # Average data within entire ROI for each frame + data = data.mean(axis=max(axes)).mean(axis=min(axes)) + xvals = self.ui.raw_hist_data_viewBox.tVals + if hasattr(self, "roi2_plot"): #make sure second plot is properly cleared everytime + self.roi2_plot.clear() + c = self.ui.raw_hist_data_viewBox.getRoiPlot().getPlotItem().curves.pop() + c.scene().removeItem(c) + self.roi2_plot = self.ui.raw_hist_data_viewBox.getRoiPlot().plot(xvals, data, pen='r') + + def get_raw_hist_curve(self, curve_index): + #curve_index = 0 for original roi + #curve_index = 1 for second comparison roi + curves = self.ui.raw_hist_data_viewBox.getRoiPlot().getPlotItem().curves + return curves[curve_index].getData() + + def on_analyze_lifetime(self): + self.lifetime_window = Lifetime_plot_fit.MainWindow() + self.lifetime_window.show() + self.lifetime_window.opened_from_flim = True + self.lifetime_window.hist_data_from_flim = np.asarray(self.get_raw_hist_curve(0)) + self.lifetime_window.ui.Result_textBrowser.setText("Data successfully loaded from FLIM analysis.") + + def save_intensities_image(self): + try: + folder = os.path.dirname(self.filename[0]) + filename_ext = os.path.basename(self.filename[0]) + filename = os.path.splitext(filename_ext)[0] #get filename without extension + save_to = folder + "\\" + filename + "_intensity_sums.png" + cpm.plot_confocal(self.intensity_sums, FLIM_adjust=False, stepsize=np.abs(self.x_step_size)) + plt.savefig(save_to, bbox_inches='tight', dpi=300) + except Exception as e: + print(format(e)) + + def save_intensities_array(self): + try: + folder = os.path.dirname(self.filename[0]) + filename_ext = os.path.basename(self.filename[0]) + filename = os.path.splitext(filename_ext)[0] #get filename without extension + save_to = folder + "\\" + filename + "_intensity_sums.txt" + np.savetxt(save_to, self.intensity_sums.T, fmt='%f') #save transposed intensity sums, as original array handles x in cols and y in rows + except: + pass + + def pkl_to_h5(self): + #Convert scan .pkl file into h5 + try: + folder = os.path.dirname(self.pkl_to_convert[0]) + filename_ext = os.path.basename(self.pkl_to_convert[0]) + filename = os.path.splitext(filename_ext)[0] #get filename without extension + pkl_file = pickle.load(open(self.pkl_to_convert[0], 'rb')) + + h5_filename = folder + "/" + filename + ".h5" + h5_file = h5py.File(h5_filename, "w") + self.traverse_dict_into_h5(pkl_file, h5_file) + except Exception as err: + print(format(err)) + + def traverse_dict_into_h5(self, dictionary, h5_output): + #Create an h5 file using .pkl with scan data and params + for key in dictionary: + if type(dictionary[key]) == dict: #if subdictionary, create a group + group = h5_output.create_group(key) + previous_dict = dictionary[key] + self.traverse_dict_into_h5(dictionary[key], group) #traverse subdictionary + else: + if key == "Histogram data" or key == "Time data": + h5_output.create_dataset(key, data=dictionary[key]) + else: + h5_output.attrs[key] = dictionary[key] #if not dataset, create attribute + + def close_application(self): + choice = QtGui.QMessageBox.question(self, 'EXIT!', + "Do you want to exit the app?", + QtGui.QMessageBox.Yes | QtGui.QMessageBox.No) + if choice == QtGui.QMessageBox.Yes: + sys.exit() + else: + pass """Run the Main Window""" def run(): - win = MainWindow() - QtGui.QApplication.instance().exec_() - return win + win = MainWindow() + QtGui.QApplication.instance().exec_() + return win #Uncomment below if you want to run this as standalone #run() \ No newline at end of file From 8fce78384b1be5efda542eba2ce78cfb93381fa3 Mon Sep 17 00:00:00 2001 From: "LAKESIDE\\LindaT18" Date: Tue, 20 Aug 2019 11:26:07 -0700 Subject: [PATCH 15/25] image analysis: fix image orientation, roi height, add scalebar; spectra analysis: fix scalebar --- PythonGUI_apps/FLIM_analysis/FLIM_plot.py | 2 +- .../Image_analysis/Image_analysis.py | 29 ++++++++++++++----- .../Image_analysis/image_analysis_gui.ui | 2 +- .../Spectrum_analysis/Spectra_plot_fit.py | 16 ++++++---- 4 files changed, 34 insertions(+), 15 deletions(-) diff --git a/PythonGUI_apps/FLIM_analysis/FLIM_plot.py b/PythonGUI_apps/FLIM_analysis/FLIM_plot.py index 51b2eef..25e0605 100644 --- a/PythonGUI_apps/FLIM_analysis/FLIM_plot.py +++ b/PythonGUI_apps/FLIM_analysis/FLIM_plot.py @@ -112,7 +112,7 @@ def plot_intensity_sums(self): (self.x_step_size, self.y_step_size)) self.ui.intensity_sums_viewBox.roi.setSize([self.x_scan_size, self.y_step_size]) #line roi - scale = pg.ScaleBar(size=3,suffix='um') + scale = pg.ScaleBar(size=1,suffix='um') scale.setParentItem(self.ui.intensity_sums_viewBox.view) scale.anchor((1, 1), (1, 1), offset=(-30, -30)) self.ui.intensity_sums_viewBox.view.sigRangeChanged.connect(lambda: updateDelay(scale, 10)) diff --git a/PythonGUI_apps/Image_analysis/Image_analysis.py b/PythonGUI_apps/Image_analysis/Image_analysis.py index 485b097..0d5f64d 100644 --- a/PythonGUI_apps/Image_analysis/Image_analysis.py +++ b/PythonGUI_apps/Image_analysis/Image_analysis.py @@ -10,6 +10,7 @@ # local modules pg.mkQApp() +pg.setConfigOption('imageAxisOrder', 'col-major') base_path = Path(__file__).parent file_path = (base_path / "image_analysis_gui.ui").resolve() @@ -18,6 +19,10 @@ WindowTemplate, TemplateBaseClass = pg.Qt.loadUiType(uiFile) +def updateDelay(scale, time): + """ Hack fix for scalebar inaccuracy""" + QtCore.QTimer.singleShot(time, scale.updateBar) + class MainWindow(TemplateBaseClass): def __init__(self): @@ -45,10 +50,9 @@ def __init__(self): self.roi.sigRegionChanged.connect(self.line_profile_update_plot) self.ui.load_image_pushButton.clicked.connect(self.load_image) self.ui.custom_pixel_size_checkBox.stateChanged.connect(self.switch_custom_pixel_size) - self.ui.update_scaling_factor_pushButton.clicked.connect(self.update_scaling_factor) + self.ui.update_scaling_factor_pushButton.clicked.connect(self.reload_image) self.ui.spot_radioButton.toggled.connect(self.update_camera) - self.num_plots = 0 self.show() def load_image(self): @@ -58,7 +62,7 @@ def load_image(self): try: file = QtWidgets.QFileDialog.getOpenFileName(self, 'Open file', os.getcwd()) self.original_image = Image.open(file[0]) - #self.original_image = self.original_image.rotate(-90, expand=True) + self.original_image = self.original_image.rotate(-90, expand=True) self.resize_to_scaling_factor(self.original_image) except Exception as err: print(format(err)) @@ -67,17 +71,25 @@ def resize_to_scaling_factor(self, image): """ Handles loading of image according to scaling_factor """ + self.update_camera() #initialize camera pixel size + self.update_scaling_factor() #initialize scaling_factor image = image.resize((round(image.size[0]*self.scaling_factor), round(image.size[1]*self.scaling_factor))) if self.ui.greyscale_checkBox.isChecked(): image = image.convert("L") #convert to greyscale - image_array = np.asarray(image).T #correct numpy array auto-flip + image_array = np.array(image) #correct numpy array auto-flip + width = image_array.shape[0] height = image_array.shape[1] try: x_vals = np.arange(width) #imv x-axis - self.imv.setImage(img=image_array, xvals= x_vals) + self.imv.setImage(image_array, xvals= x_vals) self.roi.setPos((0,0)) - self.roi.setSize([width, height * self.scaling_factor]) #set line roi + self.roi.setSize([width, self.camera_pixel_size]) + + scale = pg.ScaleBar(size=1,suffix='um') + scale.setParentItem(self.imv.view) + scale.anchor((1, 1), (1, 1), offset=(-30, -30)) + self.imv.view.sigRangeChanged.connect(lambda: updateDelay(scale, 10)) self.line_profile_update_plot() except: pass @@ -121,10 +133,13 @@ def update_scaling_factor(self): Calculate scaling factor """ if self.ui.custom_pixel_size_checkBox.isChecked(): - self.scaling_factor = self.ui.custom_pixel_size_spinBox.value() + self.camera_pixel_size = self.ui.custom_pixel_size_spinBox.value() + self.scaling_factor = self.camera_pixel_size else: self.scaling_factor = self.camera_pixel_size/int(self.ui.magnification_comboBox.currentText()) self.roi.snapSize = self.scaling_factor #roi snaps to multiples of scaling_factor + + def reload_image(self): if hasattr(self, "original_image"): self.resize_to_scaling_factor(self.original_image) #resize image, sets up roi diff --git a/PythonGUI_apps/Image_analysis/image_analysis_gui.ui b/PythonGUI_apps/Image_analysis/image_analysis_gui.ui index 21e111c..06e5055 100644 --- a/PythonGUI_apps/Image_analysis/image_analysis_gui.ui +++ b/PythonGUI_apps/Image_analysis/image_analysis_gui.ui @@ -11,7 +11,7 @@ - MainWindow + Image Analysis QTabWidget::Triangular diff --git a/PythonGUI_apps/Spectrum_analysis/Spectra_plot_fit.py b/PythonGUI_apps/Spectrum_analysis/Spectra_plot_fit.py index ace143a..3cf79bd 100644 --- a/PythonGUI_apps/Spectrum_analysis/Spectra_plot_fit.py +++ b/PythonGUI_apps/Spectrum_analysis/Spectra_plot_fit.py @@ -44,6 +44,10 @@ WindowTemplate, TemplateBaseClass = pg.Qt.loadUiType(uiFile) +def updateDelay(scale, time): + """ Hack fix for scalebar inaccuracy""" + QtCore.QTimer.singleShot(time, scale.updateBar) + class MainWindow(TemplateBaseClass): def __init__(self): @@ -539,11 +543,12 @@ def plot_fit_scan(self): scale = pg.ScaleBar(size=2,suffix='um') scale.setParentItem(self.ui.fit_scan_viewbox.view) scale.anchor((1, 1), (1, 1), offset=(-30, -30)) + self.ui.fit_scan_viewbox.view.sigRangeChanged.connect(lambda: updateDelay(scale, 10)) else: self.ui.fit_scan_viewbox.setImage(self.img) self.ui.fit_scan_viewbox.view.invertY(False) - + except Exception as e: self.ui.result_textBrowser2.append(str(e)) pass @@ -553,20 +558,18 @@ def plot_raw_scan(self): # TODO test line scan plots intensities = self.intensities.T #this is only there because of how we are saving the data in the app - - intensities = np.reshape(intensities, newshape=(2048,self.numb_x_pixels, self.numb_y_pixels)) - - self.ui.raw_scan_viewbox.view.invertY(False) + intensities = np.reshape(intensities, newshape=(2048,self.numb_x_pixels, self.numb_y_pixels)) self.ui.raw_scan_viewbox.setImage(intensities, scale= (self.x_step_size, self.y_step_size), xvals=self.wavelengths) - #roi_plot = self.ui.raw_scan_viewBox.getRoiPlot() #roi_plot.plot(data['Wavelengths'], intensities) + self.ui.raw_scan_viewbox.view.invertY(False) scale = pg.ScaleBar(size=2,suffix='um') scale.setParentItem(self.ui.raw_scan_viewbox.view) scale.anchor((1, 1), (1, 1), offset=(-30, -30)) + self.ui.raw_scan_viewbox.view.sigRangeChanged.connect(lambda: updateDelay(scale, 10)) except Exception as e: self.ui.result_textBrowser2.append(str(e)) @@ -588,6 +591,7 @@ def plot_intensity_sums(self): scale = pg.ScaleBar(size=2,suffix='um') scale.setParentItem(self.ui.intensity_sums_viewBox.view) scale.anchor((1, 1), (1, 1), offset=(-30, -30)) + self.ui.intensity_sums_viewbox.view.sigRangeChanged.connect(lambda: updateDelay(scale, 10)) except Exception as e: self.ui.result_textBrowser2.append(str(e)) From 1fa99d0810900b7a840824b24b4a4a6d6d6957fd Mon Sep 17 00:00:00 2001 From: "LAKESIDE\\LindaT18" Date: Tue, 20 Aug 2019 11:33:34 -0700 Subject: [PATCH 16/25] add comments --- PythonGUI_apps/FLIM_analysis/FLIM_plot.py | 1 + PythonGUI_apps/Image_analysis/Image_analysis.py | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/PythonGUI_apps/FLIM_analysis/FLIM_plot.py b/PythonGUI_apps/FLIM_analysis/FLIM_plot.py index 25e0605..457b3dd 100644 --- a/PythonGUI_apps/FLIM_analysis/FLIM_plot.py +++ b/PythonGUI_apps/FLIM_analysis/FLIM_plot.py @@ -29,6 +29,7 @@ WindowTemplate, TemplateBaseClass = pg.Qt.loadUiType(uiFile) def updateDelay(scale, time): + """ Hack fix for scalebar inaccuracy """ QtCore.QTimer.singleShot(time, scale.updateBar) class MainWindow(TemplateBaseClass): diff --git a/PythonGUI_apps/Image_analysis/Image_analysis.py b/PythonGUI_apps/Image_analysis/Image_analysis.py index 0d5f64d..0550026 100644 --- a/PythonGUI_apps/Image_analysis/Image_analysis.py +++ b/PythonGUI_apps/Image_analysis/Image_analysis.py @@ -62,7 +62,7 @@ def load_image(self): try: file = QtWidgets.QFileDialog.getOpenFileName(self, 'Open file', os.getcwd()) self.original_image = Image.open(file[0]) - self.original_image = self.original_image.rotate(-90, expand=True) + self.original_image = self.original_image.rotate(-90, expand=True) #correct image orientation self.resize_to_scaling_factor(self.original_image) except Exception as err: print(format(err)) @@ -76,7 +76,7 @@ def resize_to_scaling_factor(self, image): image = image.resize((round(image.size[0]*self.scaling_factor), round(image.size[1]*self.scaling_factor))) if self.ui.greyscale_checkBox.isChecked(): image = image.convert("L") #convert to greyscale - image_array = np.array(image) #correct numpy array auto-flip + image_array = np.array(image) width = image_array.shape[0] height = image_array.shape[1] From 0c29d95b574dbee537cdf3e933fff536ff0001ec Mon Sep 17 00:00:00 2001 From: "LAKESIDE\\LindaT18" Date: Tue, 20 Aug 2019 17:25:00 -0700 Subject: [PATCH 17/25] fix roi direction, keep pixera image size --- .../Image_analysis/Image_analysis.py | 30 ++++++++++++++----- 1 file changed, 22 insertions(+), 8 deletions(-) diff --git a/PythonGUI_apps/Image_analysis/Image_analysis.py b/PythonGUI_apps/Image_analysis/Image_analysis.py index 0550026..a98da93 100644 --- a/PythonGUI_apps/Image_analysis/Image_analysis.py +++ b/PythonGUI_apps/Image_analysis/Image_analysis.py @@ -10,7 +10,7 @@ # local modules pg.mkQApp() -pg.setConfigOption('imageAxisOrder', 'col-major') +pg.setConfigOption('imageAxisOrder', 'row-major') base_path = Path(__file__).parent file_path = (base_path / "image_analysis_gui.ui").resolve() @@ -36,8 +36,9 @@ def __init__(self): self.imv = pg.ImageView() self.imv.getView().setAspectLocked(lock=False, ratio=1) self.imv.getView().setMouseEnabled(x=True, y=True) - self.imv.getView().invertY(False) + #self.imv.getView().invertY(False) self.roi = self.imv.roi + self.roi.translateSnap = True self.roi.scaleSnap = True self.update_camera() #initialize camera pixel size @@ -62,7 +63,7 @@ def load_image(self): try: file = QtWidgets.QFileDialog.getOpenFileName(self, 'Open file', os.getcwd()) self.original_image = Image.open(file[0]) - self.original_image = self.original_image.rotate(-90, expand=True) #correct image orientation + #self.original_image = self.original_image.rotate(-90, expand=True) #correct image orientation self.resize_to_scaling_factor(self.original_image) except Exception as err: print(format(err)) @@ -73,18 +74,29 @@ def resize_to_scaling_factor(self, image): """ self.update_camera() #initialize camera pixel size self.update_scaling_factor() #initialize scaling_factor - image = image.resize((round(image.size[0]*self.scaling_factor), round(image.size[1]*self.scaling_factor))) + + if self.ui.pixera_radioButton.isChecked(): + image = self.original_image + elif self.ui.spot_radioButton.isChecked(): + image = self.original_image.resize((round(image.size[0]*self.scaling_factor), round(image.size[1]*self.scaling_factor))) + if self.ui.greyscale_checkBox.isChecked(): image = image.convert("L") #convert to greyscale - image_array = np.array(image) + image_array = np.array(image) width = image_array.shape[0] height = image_array.shape[1] + if self.ui.pixera_radioButton.isChecked(): + width = width * self.scaling_factor + height = height * self.scaling_factor + try: - x_vals = np.arange(width) #imv x-axis + x_vals = np.arange(width) self.imv.setImage(image_array, xvals= x_vals) - self.roi.setPos((0,0)) - self.roi.setSize([width, self.camera_pixel_size]) + + roi_height = self.scaling_factor * height + self.roi.setPos((0,height - roi_height)) + self.roi.setSize([width, roi_height]) scale = pg.ScaleBar(size=1,suffix='um') scale.setParentItem(self.imv.view) @@ -151,8 +163,10 @@ def switch_custom_pixel_size(self): def update_camera(self): if self.ui.spot_radioButton.isChecked(): self.camera_pixel_size = 7.4 + self.ui.greyscale_checkBox.setChecked(False) elif self.ui.pixera_radioButton.isChecked(): self.camera_pixel_size = 3 + self.ui.greyscale_checkBox.setChecked(True) def close_application(self): choice = QtGui.QMessageBox.question(self, 'EXIT!', From 5f21a07af2ac20586f556d79c28a6b897c45dfd7 Mon Sep 17 00:00:00 2001 From: "LAKESIDE\\LindaT18" Date: Wed, 21 Aug 2019 14:16:35 -0700 Subject: [PATCH 18/25] fix roi plot orientationm spot greyscale --- .../Image_analysis/Image_analysis.py | 44 +++++++------- .../Image_analysis/image_analysis_gui.ui | 58 ++++++++++++++----- PythonGUI_apps/test_im.py | 19 ++++++ 3 files changed, 84 insertions(+), 37 deletions(-) create mode 100644 PythonGUI_apps/test_im.py diff --git a/PythonGUI_apps/Image_analysis/Image_analysis.py b/PythonGUI_apps/Image_analysis/Image_analysis.py index a98da93..60c9e5d 100644 --- a/PythonGUI_apps/Image_analysis/Image_analysis.py +++ b/PythonGUI_apps/Image_analysis/Image_analysis.py @@ -10,7 +10,7 @@ # local modules pg.mkQApp() -pg.setConfigOption('imageAxisOrder', 'row-major') +pg.setConfigOption('imageAxisOrder', 'col-major') base_path = Path(__file__).parent file_path = (base_path / "image_analysis_gui.ui").resolve() @@ -36,11 +36,13 @@ def __init__(self): self.imv = pg.ImageView() self.imv.getView().setAspectLocked(lock=False, ratio=1) self.imv.getView().setMouseEnabled(x=True, y=True) - #self.imv.getView().invertY(False) + self.imv.getView().invertY(False) self.roi = self.imv.roi self.roi.translateSnap = True self.roi.scaleSnap = True + self.roi.removeHandle(1) + self.roi.addScaleHandle([0, 0], [1, 1]) self.update_camera() #initialize camera pixel size self.update_scaling_factor() #initialize scaling_factor @@ -53,9 +55,11 @@ def __init__(self): self.ui.custom_pixel_size_checkBox.stateChanged.connect(self.switch_custom_pixel_size) self.ui.update_scaling_factor_pushButton.clicked.connect(self.reload_image) self.ui.spot_radioButton.toggled.connect(self.update_camera) + self.ui.custom_pixel_size_spinBox.valueChanged.connect(self.update_scaling_factor) self.show() + #row major. invert y false, rotate false def load_image(self): """ Prompts the user to select a text file containing image data. @@ -63,7 +67,7 @@ def load_image(self): try: file = QtWidgets.QFileDialog.getOpenFileName(self, 'Open file', os.getcwd()) self.original_image = Image.open(file[0]) - #self.original_image = self.original_image.rotate(-90, expand=True) #correct image orientation + self.original_image = self.original_image.rotate(-90, expand=True) #correct image orientation self.resize_to_scaling_factor(self.original_image) except Exception as err: print(format(err)) @@ -72,8 +76,6 @@ def resize_to_scaling_factor(self, image): """ Handles loading of image according to scaling_factor """ - self.update_camera() #initialize camera pixel size - self.update_scaling_factor() #initialize scaling_factor if self.ui.pixera_radioButton.isChecked(): image = self.original_image @@ -86,18 +88,15 @@ def resize_to_scaling_factor(self, image): image_array = np.array(image) width = image_array.shape[0] height = image_array.shape[1] - if self.ui.pixera_radioButton.isChecked(): - width = width * self.scaling_factor - height = height * self.scaling_factor try: x_vals = np.arange(width) + if self.ui.pixera_radioButton.isChecked(): + x_vals = x_vals * self.scaling_factor self.imv.setImage(image_array, xvals= x_vals) - roi_height = self.scaling_factor * height - self.roi.setPos((0,height - roi_height)) + self.roi.setPos((0, 0)) self.roi.setSize([width, roi_height]) - scale = pg.ScaleBar(size=1,suffix='um') scale.setParentItem(self.imv.view) scale.anchor((1, 1), (1, 1), offset=(-30, -30)) @@ -117,27 +116,29 @@ def line_profile_update_plot(self): if data is None: return - x_values = coords[1][0] - - #calculate sums along columns in region + x_values = coords[0,:,0] + if self.ui.pixera_radioButton.isChecked(): + x_values = x_values * self.scaling_factor + + #calculate average along columns in region if len(data.shape) == 2: #if grayscale, average intensities - sums_to_plot = np.mean(data, axis=0) + avg_to_plot = np.mean(data, axis=-1) try: - self.roi_plot.plot(x_values, sums_to_plot) + self.roi_plot.plot(x_values, avg_to_plot) except: pass elif len(data.shape) > 2: #if rgb arrays, plot individual components r_values = data[:,:,0] g_values = data[:,:,1] b_values = data[:,:,2] - r_avg = np.mean(r_values, axis=0) #average red values across columns - g_avg = np.mean(g_values, axis=0) #average green values - b_avg = np.mean(b_values, axis=0) #average blue values + r_avg = np.mean(r_values, axis=-1) #average red values across columns + g_avg = np.mean(g_values, axis=-1) #average green values + b_avg = np.mean(b_values, axis=-1) #average blue values try: self.roi_plot.plot(x_values, r_avg, pen='r') self.roi_plot.plot(x_values, g_avg, pen='g') self.roi_plot.plot(x_values, b_avg, pen='b') - except: + except Exception as e: pass def update_scaling_factor(self): @@ -164,10 +165,11 @@ def update_camera(self): if self.ui.spot_radioButton.isChecked(): self.camera_pixel_size = 7.4 self.ui.greyscale_checkBox.setChecked(False) + self.update_scaling_factor() elif self.ui.pixera_radioButton.isChecked(): self.camera_pixel_size = 3 self.ui.greyscale_checkBox.setChecked(True) - + self.update_scaling_factor() def close_application(self): choice = QtGui.QMessageBox.question(self, 'EXIT!', "Do you want to exit the app?", diff --git a/PythonGUI_apps/Image_analysis/image_analysis_gui.ui b/PythonGUI_apps/Image_analysis/image_analysis_gui.ui index 06e5055..edb9aa6 100644 --- a/PythonGUI_apps/Image_analysis/image_analysis_gui.ui +++ b/PythonGUI_apps/Image_analysis/image_analysis_gui.ui @@ -51,21 +51,21 @@ - - + + - Load image + Greyscale image - - + + - Greyscale image + Load image - + @@ -89,27 +89,34 @@ - + Magnification - - + + - Custom pixel size (um) + Update settings - + false + + + + Custom pixel size (um) + + + @@ -136,11 +143,30 @@ - - - - Update scaling factor + + + + Direction to average pixels + + + + + Vertical + + + true + + + + + + + Horizontal + + + + diff --git a/PythonGUI_apps/test_im.py b/PythonGUI_apps/test_im.py new file mode 100644 index 0000000..a74056f --- /dev/null +++ b/PythonGUI_apps/test_im.py @@ -0,0 +1,19 @@ +import sys +from pathlib import Path +import os.path +import pyqtgraph as pg +from pyqtgraph.Qt import QtCore, QtGui, QtWidgets#, QColorDialog +import numpy as np +import matplotlib.pyplot as plt +from PIL import Image + +scale = 7.4/50 +image = Image.open(r"C:\Users\lindat18\Desktop\BREAD.png") +image = image.rotate(-90, expand=True) +image = image.resize((round(image.size[0]*scale), round(image.size[1]*scale))) +image_array = np.array(image) +width = image_array.shape[0] +height = image_array.shape[1] +print(image_array.shape) +arr = image_array[:,0,0] +print(arr.shape) From c196dda20dd0bdcc0bb78906f7ef764f1acad2f5 Mon Sep 17 00:00:00 2001 From: "LAKESIDE\\LindaT18" Date: Wed, 21 Aug 2019 15:23:03 -0700 Subject: [PATCH 19/25] initial work on separate rgb plot and horizontal rgb avg --- .../Image_analysis/Image_analysis.py | 63 ++++++++++++++----- .../Image_analysis/image_analysis_gui.ui | 48 ++++++++------ PythonGUI_apps/test_im.py | 19 ------ 3 files changed, 75 insertions(+), 55 deletions(-) delete mode 100644 PythonGUI_apps/test_im.py diff --git a/PythonGUI_apps/Image_analysis/Image_analysis.py b/PythonGUI_apps/Image_analysis/Image_analysis.py index 60c9e5d..7f82b97 100644 --- a/PythonGUI_apps/Image_analysis/Image_analysis.py +++ b/PythonGUI_apps/Image_analysis/Image_analysis.py @@ -37,18 +37,23 @@ def __init__(self): self.imv.getView().setAspectLocked(lock=False, ratio=1) self.imv.getView().setMouseEnabled(x=True, y=True) self.imv.getView().invertY(False) + self.imv.ui.roiBtn.setEnabled(False) self.roi = self.imv.roi - self.roi.translateSnap = True self.roi.scaleSnap = True - self.roi.removeHandle(1) - self.roi.addScaleHandle([0, 0], [1, 1]) + #self.roi.removeHandle(1) + #self.roi.addScaleHandle([0, 0], [1, 1]) self.update_camera() #initialize camera pixel size self.update_scaling_factor() #initialize scaling_factor self.roi_plot = self.imv.getRoiPlot().getPlotItem() #get roi plot self.ui.image_groupBox.layout().addWidget(self.imv) + #setup plot + self.rgb_plot_layout=pg.GraphicsLayoutWidget() + self.ui.rgb_plot_groupBox.layout().addWidget(self.rgb_plot_layout) + self.rgb_plot = self.rgb_plot_layout.addPlot() + #set up ui signals self.roi.sigRegionChanged.connect(self.line_profile_update_plot) self.ui.load_image_pushButton.clicked.connect(self.load_image) @@ -90,24 +95,37 @@ def resize_to_scaling_factor(self, image): height = image_array.shape[1] try: - x_vals = np.arange(width) + if self.ui.vertical_radioButton.isChecked(): + x_vals = np.arange(width) + elif self.ui.horizontal_radioButton.isChecked(): + x_vals = np.arange(height) + if self.ui.pixera_radioButton.isChecked(): x_vals = x_vals * self.scaling_factor + self.imv.setImage(image_array, xvals= x_vals) - roi_height = self.scaling_factor * height + + if self.ui.vertical_radioButton.isChecked(): + roi_height = self.scaling_factor * height + self.roi.setSize([width, roi_height]) + elif self.ui.horizontal_radioButton.isChecked(): + roi_height = self.scaling_factor * width + self.roi.setSize([roi_height, height]) + self.roi.setPos((0, 0)) - self.roi.setSize([width, roi_height]) + scale = pg.ScaleBar(size=1,suffix='um') scale.setParentItem(self.imv.view) scale.anchor((1, 1), (1, 1), offset=(-30, -30)) self.imv.view.sigRangeChanged.connect(lambda: updateDelay(scale, 10)) + self.roi.show() self.line_profile_update_plot() except: pass def line_profile_update_plot(self): """ Handle line profile for intensity sum viewbox """ - self.roi_plot.clear() + self.rgb_plot.clear() image = self.imv.getProcessedImage() # Extract image data from ROI @@ -116,28 +134,40 @@ def line_profile_update_plot(self): if data is None: return - x_values = coords[0,:,0] + if self.ui.vertical_radioButton.isChecked(): + x_values = coords[0,:,0] + elif self.ui.horizontal_radioButton.isChecked(): + x_values = coords[1,0,:] + if self.ui.pixera_radioButton.isChecked(): x_values = x_values * self.scaling_factor #calculate average along columns in region if len(data.shape) == 2: #if grayscale, average intensities - avg_to_plot = np.mean(data, axis=-1) + if self.ui.vertical_radioButton.isChecked(): + avg_to_plot = np.mean(data, axis=-1) + elif self.ui.horizontal_radioButton.isChecked(): + avg_to_plot = np.mean(data, axis=0) try: - self.roi_plot.plot(x_values, avg_to_plot) + self.rgb_plot.plot(x_values, avg_to_plot) except: pass elif len(data.shape) > 2: #if rgb arrays, plot individual components r_values = data[:,:,0] g_values = data[:,:,1] b_values = data[:,:,2] - r_avg = np.mean(r_values, axis=-1) #average red values across columns - g_avg = np.mean(g_values, axis=-1) #average green values - b_avg = np.mean(b_values, axis=-1) #average blue values + if self.ui.vertical_radioButton.isChecked(): + r_avg = np.mean(r_values, axis=-1) #average red values across columns + g_avg = np.mean(g_values, axis=-1) #average green values + b_avg = np.mean(b_values, axis=-1) #average blue values + elif self.ui.horizontal_radioButton.isChecked(): + r_avg = np.mean(r_values, axis=0) + g_avg = np.mean(g_values, axis=0) + b_avg = np.mean(b_values, axis=0) try: - self.roi_plot.plot(x_values, r_avg, pen='r') - self.roi_plot.plot(x_values, g_avg, pen='g') - self.roi_plot.plot(x_values, b_avg, pen='b') + self.rgb_plot.plot(x_values, r_avg, pen='r') + self.rgb_plot.plot(x_values, g_avg, pen='g') + self.rgb_plot.plot(x_values, b_avg, pen='b') except Exception as e: pass @@ -170,6 +200,7 @@ def update_camera(self): self.camera_pixel_size = 3 self.ui.greyscale_checkBox.setChecked(True) self.update_scaling_factor() + def close_application(self): choice = QtGui.QMessageBox.question(self, 'EXIT!', "Do you want to exit the app?", diff --git a/PythonGUI_apps/Image_analysis/image_analysis_gui.ui b/PythonGUI_apps/Image_analysis/image_analysis_gui.ui index edb9aa6..233fcf6 100644 --- a/PythonGUI_apps/Image_analysis/image_analysis_gui.ui +++ b/PythonGUI_apps/Image_analysis/image_analysis_gui.ui @@ -18,26 +18,6 @@ - - - - - 0 - 0 - - - - - 600 - 0 - - - - Image - - - - @@ -174,6 +154,34 @@ + + + + + 0 + 0 + + + + + 600 + 0 + + + + Image + + + + + + + + RGB Plot + + + +
diff --git a/PythonGUI_apps/test_im.py b/PythonGUI_apps/test_im.py deleted file mode 100644 index a74056f..0000000 --- a/PythonGUI_apps/test_im.py +++ /dev/null @@ -1,19 +0,0 @@ -import sys -from pathlib import Path -import os.path -import pyqtgraph as pg -from pyqtgraph.Qt import QtCore, QtGui, QtWidgets#, QColorDialog -import numpy as np -import matplotlib.pyplot as plt -from PIL import Image - -scale = 7.4/50 -image = Image.open(r"C:\Users\lindat18\Desktop\BREAD.png") -image = image.rotate(-90, expand=True) -image = image.resize((round(image.size[0]*scale), round(image.size[1]*scale))) -image_array = np.array(image) -width = image_array.shape[0] -height = image_array.shape[1] -print(image_array.shape) -arr = image_array[:,0,0] -print(arr.shape) From d9844ada05c514f442f86d282a7de615a77fa535 Mon Sep 17 00:00:00 2001 From: "LAKESIDE\\LindaT18" Date: Wed, 21 Aug 2019 16:13:04 -0700 Subject: [PATCH 20/25] moved pg.setConfigOption to init functions --- PythonGUI_apps/FLIM_analysis/FLIM_plot.py | 3 ++- PythonGUI_apps/H5_Pkl/h5_view_and_plot.py | 3 ++- PythonGUI_apps/Image_analysis/Image_analysis.py | 3 ++- PythonGUI_apps/Spectrum_analysis/Spectra_plot_fit.py | 3 ++- 4 files changed, 8 insertions(+), 4 deletions(-) diff --git a/PythonGUI_apps/FLIM_analysis/FLIM_plot.py b/PythonGUI_apps/FLIM_analysis/FLIM_plot.py index 457b3dd..8a0124f 100644 --- a/PythonGUI_apps/FLIM_analysis/FLIM_plot.py +++ b/PythonGUI_apps/FLIM_analysis/FLIM_plot.py @@ -19,7 +19,7 @@ pg.mkQApp() pg.setConfigOption('background', 'w') -pg.setConfigOption('imageAxisOrder', 'row-major') + base_path = Path(__file__).parent file_path = (base_path / "flim_plot_gui.ui").resolve() @@ -37,6 +37,7 @@ class MainWindow(TemplateBaseClass): hist_data_signal = QtCore.pyqtSignal() def __init__(self): + pg.setConfigOption('imageAxisOrder', 'row-major') super(TemplateBaseClass, self).__init__() # Create the main window diff --git a/PythonGUI_apps/H5_Pkl/h5_view_and_plot.py b/PythonGUI_apps/H5_Pkl/h5_view_and_plot.py index 4b162f6..760cd46 100644 --- a/PythonGUI_apps/H5_Pkl/h5_view_and_plot.py +++ b/PythonGUI_apps/H5_Pkl/h5_view_and_plot.py @@ -13,13 +13,14 @@ from .h5_tree import H5TreeSearchView from .pkl_tree import PklTreeSearchView -pg.setConfigOption('imageAxisOrder', 'row-major') + class H5ViewPlot(BaseApp): name = "h5_view_plot" def __init__(self, argv): + pg.setConfigOption('imageAxisOrder', 'row-major') BaseApp.__init__(self, argv) self.setup() parser = argparse.ArgumentParser() diff --git a/PythonGUI_apps/Image_analysis/Image_analysis.py b/PythonGUI_apps/Image_analysis/Image_analysis.py index 7f82b97..2ad8e65 100644 --- a/PythonGUI_apps/Image_analysis/Image_analysis.py +++ b/PythonGUI_apps/Image_analysis/Image_analysis.py @@ -10,7 +10,7 @@ # local modules pg.mkQApp() -pg.setConfigOption('imageAxisOrder', 'col-major') + base_path = Path(__file__).parent file_path = (base_path / "image_analysis_gui.ui").resolve() @@ -26,6 +26,7 @@ def updateDelay(scale, time): class MainWindow(TemplateBaseClass): def __init__(self): + pg.setConfigOption('imageAxisOrder', 'col-major') super(TemplateBaseClass, self).__init__() # Create the main window diff --git a/PythonGUI_apps/Spectrum_analysis/Spectra_plot_fit.py b/PythonGUI_apps/Spectrum_analysis/Spectra_plot_fit.py index 3cf79bd..76e23d2 100644 --- a/PythonGUI_apps/Spectrum_analysis/Spectra_plot_fit.py +++ b/PythonGUI_apps/Spectrum_analysis/Spectra_plot_fit.py @@ -35,7 +35,7 @@ pg.mkQApp() pg.setConfigOption('background', 'w') -pg.setConfigOption('imageAxisOrder', 'row-major') + base_path = Path(__file__).parent file_path = (base_path / "Spectra_plot_fit_gui.ui").resolve() @@ -51,6 +51,7 @@ def updateDelay(scale, time): class MainWindow(TemplateBaseClass): def __init__(self): + pg.setConfigOption('imageAxisOrder', 'row-major') super(TemplateBaseClass, self).__init__() # Create the main window From 45d4ac4ba67de4febe6f5f847e6b22043f5f7d66 Mon Sep 17 00:00:00 2001 From: "LAKESIDE\\LindaT18" Date: Thu, 22 Aug 2019 10:18:18 -0700 Subject: [PATCH 21/25] use separate image plot instead of imageview --- .../Image_analysis/Image_analysis.py | 68 +++++++++---------- 1 file changed, 31 insertions(+), 37 deletions(-) diff --git a/PythonGUI_apps/Image_analysis/Image_analysis.py b/PythonGUI_apps/Image_analysis/Image_analysis.py index 2ad8e65..8ad4ab0 100644 --- a/PythonGUI_apps/Image_analysis/Image_analysis.py +++ b/PythonGUI_apps/Image_analysis/Image_analysis.py @@ -33,36 +33,41 @@ def __init__(self): self.ui = WindowTemplate() self.ui.setupUi(self) - #setup imageview - self.imv = pg.ImageView() - self.imv.getView().setAspectLocked(lock=False, ratio=1) - self.imv.getView().setMouseEnabled(x=True, y=True) - self.imv.getView().invertY(False) - self.imv.ui.roiBtn.setEnabled(False) - self.roi = self.imv.roi + #setup image plot + self.image_plot_layout=pg.GraphicsLayoutWidget() + self.ui.image_groupBox.layout().addWidget(self.image_plot_layout) + self.image_plot = self.image_plot_layout.addPlot() + self.img_item = pg.ImageItem() + self.image_plot.addItem(self.img_item) + self.image_plot_view = self.image_plot.getViewBox() + + #setup lookup table + self.hist_lut = pg.HistogramLUTItem() + self.image_plot_layout.addItem(self.hist_lut) + + #region of interest - allows user to select scan area + self.roi = pg.ROI([0,0],[10, 10], movable=True) + self.roi.addScaleHandle([1, 1], [0, 0]) + self.roi.addRotateHandle([0, 0], [1, 1]) self.roi.translateSnap = True self.roi.scaleSnap = True - #self.roi.removeHandle(1) - #self.roi.addScaleHandle([0, 0], [1, 1]) - self.update_camera() #initialize camera pixel size - self.update_scaling_factor() #initialize scaling_factor - - self.roi_plot = self.imv.getRoiPlot().getPlotItem() #get roi plot - self.ui.image_groupBox.layout().addWidget(self.imv) + self.roi.sigRegionChanged.connect(self.line_profile_update_plot) + self.image_plot.addItem(self.roi) - #setup plot + #setup rgb plot self.rgb_plot_layout=pg.GraphicsLayoutWidget() self.ui.rgb_plot_groupBox.layout().addWidget(self.rgb_plot_layout) self.rgb_plot = self.rgb_plot_layout.addPlot() #set up ui signals - self.roi.sigRegionChanged.connect(self.line_profile_update_plot) self.ui.load_image_pushButton.clicked.connect(self.load_image) self.ui.custom_pixel_size_checkBox.stateChanged.connect(self.switch_custom_pixel_size) self.ui.update_scaling_factor_pushButton.clicked.connect(self.reload_image) self.ui.spot_radioButton.toggled.connect(self.update_camera) self.ui.custom_pixel_size_spinBox.valueChanged.connect(self.update_scaling_factor) + self.update_camera() #initialize camera pixel size + self.update_scaling_factor() #initialize scaling_factor self.show() #row major. invert y false, rotate false @@ -91,20 +96,18 @@ def resize_to_scaling_factor(self, image): if self.ui.greyscale_checkBox.isChecked(): image = image.convert("L") #convert to greyscale - image_array = np.array(image) - width = image_array.shape[0] - height = image_array.shape[1] + self.image_array = np.array(image) + width = self.image_array.shape[0] + height = self.image_array.shape[1] try: - if self.ui.vertical_radioButton.isChecked(): - x_vals = np.arange(width) - elif self.ui.horizontal_radioButton.isChecked(): - x_vals = np.arange(height) + #set image bounds with qrect + self.img_item_rect = QtCore.QRectF(0, 0, width, height) + self.img_item.setImage(image=self.image_array) + self.img_item.setRect(self.img_item_rect) - if self.ui.pixera_radioButton.isChecked(): - x_vals = x_vals * self.scaling_factor - - self.imv.setImage(image_array, xvals= x_vals) + if self.ui.greyscale_checkBox.isChecked(): + self.hist_lut.setImageItem(self.img_item) if self.ui.vertical_radioButton.isChecked(): roi_height = self.scaling_factor * height @@ -113,13 +116,6 @@ def resize_to_scaling_factor(self, image): roi_height = self.scaling_factor * width self.roi.setSize([roi_height, height]) - self.roi.setPos((0, 0)) - - scale = pg.ScaleBar(size=1,suffix='um') - scale.setParentItem(self.imv.view) - scale.anchor((1, 1), (1, 1), offset=(-30, -30)) - self.imv.view.sigRangeChanged.connect(lambda: updateDelay(scale, 10)) - self.roi.show() self.line_profile_update_plot() except: pass @@ -127,11 +123,9 @@ def resize_to_scaling_factor(self, image): def line_profile_update_plot(self): """ Handle line profile for intensity sum viewbox """ self.rgb_plot.clear() - image = self.imv.getProcessedImage() # Extract image data from ROI - axes = (self.imv.axes['x'], self.imv.axes['y']) - data, coords = self.roi.getArrayRegion(image.view(np.ndarray), self.imv.imageItem, axes, returnMappedCoords=True) + data, coords = self.roi.getArrayRegion(self.image_array, self.img_item, returnMappedCoords=True) if data is None: return From 9afb6b9e5f5dab991bf9670951f1a962cffccb25 Mon Sep 17 00:00:00 2001 From: "LAKESIDE\\LindaT18" Date: Thu, 22 Aug 2019 10:42:00 -0700 Subject: [PATCH 22/25] add default roi position and angle --- PythonGUI_apps/Image_analysis/Image_analysis.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/PythonGUI_apps/Image_analysis/Image_analysis.py b/PythonGUI_apps/Image_analysis/Image_analysis.py index 8ad4ab0..5525564 100644 --- a/PythonGUI_apps/Image_analysis/Image_analysis.py +++ b/PythonGUI_apps/Image_analysis/Image_analysis.py @@ -115,7 +115,8 @@ def resize_to_scaling_factor(self, image): elif self.ui.horizontal_radioButton.isChecked(): roi_height = self.scaling_factor * width self.roi.setSize([roi_height, height]) - + self.roi.setAngle(0) + self.roi.setPos(0, 0) self.line_profile_update_plot() except: pass From f0505dd62b9003d40c79f3af6d286ec2e5146943 Mon Sep 17 00:00:00 2001 From: "LAKESIDE\\LindaT18" Date: Thu, 22 Aug 2019 10:47:05 -0700 Subject: [PATCH 23/25] update scaling factor before loading image --- PythonGUI_apps/Image_analysis/Image_analysis.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/PythonGUI_apps/Image_analysis/Image_analysis.py b/PythonGUI_apps/Image_analysis/Image_analysis.py index 5525564..99134a7 100644 --- a/PythonGUI_apps/Image_analysis/Image_analysis.py +++ b/PythonGUI_apps/Image_analysis/Image_analysis.py @@ -64,7 +64,6 @@ def __init__(self): self.ui.custom_pixel_size_checkBox.stateChanged.connect(self.switch_custom_pixel_size) self.ui.update_scaling_factor_pushButton.clicked.connect(self.reload_image) self.ui.spot_radioButton.toggled.connect(self.update_camera) - self.ui.custom_pixel_size_spinBox.valueChanged.connect(self.update_scaling_factor) self.update_camera() #initialize camera pixel size self.update_scaling_factor() #initialize scaling_factor @@ -87,6 +86,7 @@ def resize_to_scaling_factor(self, image): """ Handles loading of image according to scaling_factor """ + self.update_scaling_factor() if self.ui.pixera_radioButton.isChecked(): image = self.original_image From e41bf1e772947db0c48d8618e43c0b0c741f16c9 Mon Sep 17 00:00:00 2001 From: "LAKESIDE\\LindaT18" Date: Thu, 22 Aug 2019 11:52:50 -0700 Subject: [PATCH 24/25] add resize option for spot, fixed image plot axes --- .../Image_analysis/Image_analysis.py | 22 ++++++++++++------- .../Image_analysis/image_analysis_gui.ui | 15 +++++++++---- 2 files changed, 25 insertions(+), 12 deletions(-) diff --git a/PythonGUI_apps/Image_analysis/Image_analysis.py b/PythonGUI_apps/Image_analysis/Image_analysis.py index 99134a7..50b2d1c 100644 --- a/PythonGUI_apps/Image_analysis/Image_analysis.py +++ b/PythonGUI_apps/Image_analysis/Image_analysis.py @@ -62,7 +62,7 @@ def __init__(self): #set up ui signals self.ui.load_image_pushButton.clicked.connect(self.load_image) self.ui.custom_pixel_size_checkBox.stateChanged.connect(self.switch_custom_pixel_size) - self.ui.update_scaling_factor_pushButton.clicked.connect(self.reload_image) + self.ui.update_settings_pushButton.clicked.connect(self.reload_image) self.ui.spot_radioButton.toggled.connect(self.update_camera) self.update_camera() #initialize camera pixel size @@ -88,10 +88,14 @@ def resize_to_scaling_factor(self, image): """ self.update_scaling_factor() - if self.ui.pixera_radioButton.isChecked(): - image = self.original_image - elif self.ui.spot_radioButton.isChecked(): + if self.ui.spot_radioButton.isChecked() and self.ui.resize_image_checkBox.isChecked(): image = self.original_image.resize((round(image.size[0]*self.scaling_factor), round(image.size[1]*self.scaling_factor))) + self.image_plot.getAxis("bottom").setScale(scale = 1) + self.image_plot.getAxis("left").setScale(scale = 1) + else: + image = self.original_image + self.image_plot.getAxis("bottom").setScale(scale = self.scaling_factor) + self.image_plot.getAxis("left").setScale(scale = self.scaling_factor) if self.ui.greyscale_checkBox.isChecked(): image = image.convert("L") #convert to greyscale @@ -106,8 +110,8 @@ def resize_to_scaling_factor(self, image): self.img_item.setImage(image=self.image_array) self.img_item.setRect(self.img_item_rect) - if self.ui.greyscale_checkBox.isChecked(): - self.hist_lut.setImageItem(self.img_item) + # if self.ui.greyscale_checkBox.isChecked(): + # self.hist_lut.setImageItem(self.img_item) if self.ui.vertical_radioButton.isChecked(): roi_height = self.scaling_factor * height @@ -135,11 +139,11 @@ def line_profile_update_plot(self): elif self.ui.horizontal_radioButton.isChecked(): x_values = coords[1,0,:] - if self.ui.pixera_radioButton.isChecked(): + if self.ui.pixera_radioButton.isChecked() or (self.ui.spot_radioButton.isChecked() and not self.ui.resize_image_checkBox.isChecked()): x_values = x_values * self.scaling_factor #calculate average along columns in region - if len(data.shape) == 2: #if grayscale, average intensities + if len(data.shape) <= 2: #if grayscale, average intensities if self.ui.vertical_radioButton.isChecked(): avg_to_plot = np.mean(data, axis=-1) elif self.ui.horizontal_radioButton.isChecked(): @@ -191,10 +195,12 @@ def update_camera(self): if self.ui.spot_radioButton.isChecked(): self.camera_pixel_size = 7.4 self.ui.greyscale_checkBox.setChecked(False) + self.ui.resize_image_checkBox.setEnabled(True) self.update_scaling_factor() elif self.ui.pixera_radioButton.isChecked(): self.camera_pixel_size = 3 self.ui.greyscale_checkBox.setChecked(True) + self.ui.resize_image_checkBox.setEnabled(False) self.update_scaling_factor() def close_application(self): diff --git a/PythonGUI_apps/Image_analysis/image_analysis_gui.ui b/PythonGUI_apps/Image_analysis/image_analysis_gui.ui index 233fcf6..9fcffd9 100644 --- a/PythonGUI_apps/Image_analysis/image_analysis_gui.ui +++ b/PythonGUI_apps/Image_analysis/image_analysis_gui.ui @@ -77,7 +77,7 @@
- + Update settings @@ -102,8 +102,8 @@ Camera - - + + SPOT @@ -113,13 +113,20 @@ - + Pixera + + + + Resize image + + + From e2f3e9a668c638a8025341054c546421281bef1a Mon Sep 17 00:00:00 2001 From: "LAKESIDE\\LindaT18" Date: Thu, 22 Aug 2019 13:21:23 -0700 Subject: [PATCH 25/25] add interpolation to psf data --- .../Spectrum_analysis/Spectra_plot_fit.py | 20 ++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/PythonGUI_apps/Spectrum_analysis/Spectra_plot_fit.py b/PythonGUI_apps/Spectrum_analysis/Spectra_plot_fit.py index 76e23d2..a5196c8 100644 --- a/PythonGUI_apps/Spectrum_analysis/Spectra_plot_fit.py +++ b/PythonGUI_apps/Spectrum_analysis/Spectra_plot_fit.py @@ -17,6 +17,7 @@ import pickle import time from lmfit.models import GaussianModel +from scipy import interpolate import customplotting.mscope as cpm # local modules try: @@ -260,8 +261,18 @@ def check_loaded_files(self): def plot(self): try: if self.opened_from_flim: - self.x, self.y = self.sum_data_from_flim - elif self.file is None: + flim_data = self.sum_data_from_flim.T + interp = interpolate.interp1d(flim_data[:,0], flim_data[:,1]) + x_range = [flim_data[:,0][0], flim_data[:,0][-1]] + xnew = np.linspace(x_range[0], x_range[1], 100 ) + ynew = interp(xnew) + self.file = np.zeros((xnew.shape[0], 2)) + self.file[:,0] = xnew + self.file[:,1] = ynew + self.x = xnew + self.y = ynew + + elif self.file is None: #elif self.ui.result_textBrowser.setText("You need to load a data file.") else: self.x = self.file[:,0] @@ -310,7 +321,10 @@ def fit_and_plot(self): try: self.plot() if self.opened_from_flim: - self.file = self.sum_data_from_flim.T + self.file = np.zeros((self.x.shape[0], 2)) + self.file[:,0] = self.x + self.file[:,1] = self.y + if self.ui.plot_without_bck_radioButton.isChecked(): #if plot w/o bck, create dummy bck_file self.bck_file = np.zeros(shape=(self.file.shape[0], 2)) self.bck_file[:,0] = self.file[:,0]