diff --git a/PythonGUI_apps/DataBrowser.py b/PythonGUI_apps/DataBrowser.py index 2ab2b25..250e42a 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 @@ -18,9 +18,9 @@ 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') +#pg.setConfigOption('background', 'w') base_path = Path(__file__).parent file_path = (base_path / "DataBrowser_GUI.ui").resolve() @@ -29,50 +29,55 @@ 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", "Image Analysis"]) + 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_()) + elif analysis_software == "Image Analysis": + self.image_window = Image_analysis.MainWindow() + self.image_window.show() + + 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.py b/PythonGUI_apps/FLIM_analysis/FLIM_plot.py index a17c7c5..8a0124f 100644 --- a/PythonGUI_apps/FLIM_analysis/FLIM_plot.py +++ b/PythonGUI_apps/FLIM_analysis/FLIM_plot.py @@ -7,14 +7,19 @@ 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 + +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() pg.setConfigOption('background', 'w') -pg.setConfigOption('imageAxisOrder', 'row-major') + base_path = Path(__file__).parent file_path = (base_path / "flim_plot_gui.ui").resolve() @@ -23,231 +28,275 @@ 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): - 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_pkl_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.show() - - def open_pkl_file(self): - """ Open FLIM scan file """ - try: - self.filename = QtWidgets.QFileDialog.getOpenFileName(self) - 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 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.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.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.sum(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 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.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.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"): - self.roi2_plot.clear() - self.roi2_plot = self.ui.raw_hist_data_viewBox.getRoiPlot().plot(xvals, data, pen='r') - - 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, stepsize=np.abs(self.pkl_file['Scan Parameters']['X step size (um)'])) - plt.savefig(save_to, bbox_inches='tight', dpi=300) - except: - pass - - 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): + pg.setConfigOption('imageAxisOrder', 'row-major') + 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)) + 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 diff --git a/PythonGUI_apps/FLIM_analysis/flim_plot_gui.ui b/PythonGUI_apps/FLIM_analysis/flim_plot_gui.ui index 5daa01e..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 @@ -56,6 +56,13 @@ + + + + Analyze PSF + + + @@ -111,6 +118,13 @@ + + + + Analyze lifetime + + + 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.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/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/Image_analysis/Image_analysis.py b/PythonGUI_apps/Image_analysis/Image_analysis.py new file mode 100644 index 0000000..50b2d1c --- /dev/null +++ b/PythonGUI_apps/Image_analysis/Image_analysis.py @@ -0,0 +1,222 @@ +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) + +def updateDelay(scale, time): + """ Hack fix for scalebar inaccuracy""" + QtCore.QTimer.singleShot(time, scale.updateBar) + +class MainWindow(TemplateBaseClass): + + def __init__(self): + pg.setConfigOption('imageAxisOrder', 'col-major') + super(TemplateBaseClass, self).__init__() + + # Create the main window + self.ui = WindowTemplate() + self.ui.setupUi(self) + + #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.sigRegionChanged.connect(self.line_profile_update_plot) + self.image_plot.addItem(self.roi) + + #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.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_settings_pushButton.clicked.connect(self.reload_image) + self.ui.spot_radioButton.toggled.connect(self.update_camera) + + self.update_camera() #initialize camera pixel size + self.update_scaling_factor() #initialize 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. + """ + 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.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 + """ + self.update_scaling_factor() + + 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 + + self.image_array = np.array(image) + width = self.image_array.shape[0] + height = self.image_array.shape[1] + + try: + #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.greyscale_checkBox.isChecked(): + # self.hist_lut.setImageItem(self.img_item) + + 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.setAngle(0) + self.roi.setPos(0, 0) + self.line_profile_update_plot() + except: + pass + + def line_profile_update_plot(self): + """ Handle line profile for intensity sum viewbox """ + self.rgb_plot.clear() + + # Extract image data from ROI + data, coords = self.roi.getArrayRegion(self.image_array, self.img_item, returnMappedCoords=True) + if data is None: + return + + 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() 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 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.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] + 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.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 + + def update_scaling_factor(self): + """ + Calculate scaling factor + """ + if self.ui.custom_pixel_size_checkBox.isChecked(): + 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 + + 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 + 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): + 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..9fcffd9 --- /dev/null +++ b/PythonGUI_apps/Image_analysis/image_analysis_gui.ui @@ -0,0 +1,208 @@ + + + MainWindow + + + + 0 + 0 + 1029 + 743 + + + + Image Analysis + + + QTabWidget::Triangular + + + + + + + Settings + + + + + + + + + + + + + Greyscale image + + + + + + + Load image + + + + + + + + 50 + + + + + 75 + + + + + 100 + + + + + 150 + + + + + + + + Magnification + + + + + + + Update settings + + + + + + + false + + + + + + + Custom pixel size (um) + + + + + + + Camera + + + + + + SPOT + + + true + + + + + + + Pixera + + + + + + + Resize image + + + + + + + + + + Direction to average pixels + + + + + + Vertical + + + true + + + + + + + Horizontal + + + + + + + + + + + + + + + + 0 + 0 + + + + + 600 + 0 + + + + Image + + + + + + + + RGB Plot + + + + + + + + + + 0 + 0 + 1029 + 31 + + + + + + + + diff --git a/PythonGUI_apps/Lifetime_analysis/Lifetime_analysis_gui_layout.ui b/PythonGUI_apps/Lifetime_analysis/Lifetime_analysis_gui_layout.ui index b4fc950..e80df57 100644 --- a/PythonGUI_apps/Lifetime_analysis/Lifetime_analysis_gui_layout.ui +++ b/PythonGUI_apps/Lifetime_analysis/Lifetime_analysis_gui_layout.ui @@ -6,12 +6,12 @@ 0 0 - 1985 - 1470 + 1490 + 1201 - MainWindow + Lifetime Analysis @@ -1038,6 +1038,13 @@ Export Settings + + + + Export data + + + @@ -1053,7 +1060,14 @@ - + + + + Clear export data + + + + @@ -1067,13 +1081,6 @@ - - - - Export data - - -
@@ -1254,8 +1261,8 @@ 0 0 - 1985 - 31 + 1490 + 21 diff --git a/PythonGUI_apps/Lifetime_analysis/Lifetime_plot_fit.py b/PythonGUI_apps/Lifetime_analysis/Lifetime_plot_fit.py index ec792f2..fb9bca5 100644 --- a/PythonGUI_apps/Lifetime_analysis/Lifetime_plot_fit.py +++ b/PythonGUI_apps/Lifetime_analysis/Lifetime_plot_fit.py @@ -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,7 +45,7 @@ WindowTemplate, TemplateBaseClass = pg.Qt.loadUiType(uiFile) -class MainWindow(TemplateBaseClass): +class MainWindow(TemplateBaseClass): def __init__(self): TemplateBaseClass.__init__(self) @@ -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): @@ -93,24 +99,42 @@ def open_file(self): # 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) - except UnicodeDecodeError: - self.file = read_picoharp_phd(self.filename[0]) + 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 """ - filename = QtWidgets.QFileDialog.getOpenFileName(self) + self.irf_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]) + 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) @@ -198,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) @@ -225,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(): @@ -465,6 +505,8 @@ def export_data(self): self.data_list = [] file.close() + def clear_export_data(self): + self.data_list = [] def pub_ready_plot_export(self): try: @@ -497,6 +539,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 + + + + + + + + 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.py b/PythonGUI_apps/Spectrum_analysis/Spectra_plot_fit.py index 005746a..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: @@ -35,7 +36,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() @@ -44,9 +45,14 @@ 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): + pg.setConfigOption('imageAxisOrder', 'row-major') super(TemplateBaseClass, self).__init__() # Create the main window @@ -60,6 +66,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) @@ -73,7 +80,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) @@ -85,6 +93,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")) @@ -99,17 +110,25 @@ 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 = [] + + #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 @@ -137,8 +156,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)) @@ -219,23 +244,52 @@ 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: + 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] + 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(): @@ -260,30 +314,28 @@ 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_fit_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 = 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] + + # 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() @@ -298,7 +350,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(): @@ -314,7 +366,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() @@ -343,7 +395,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(): @@ -377,9 +429,10 @@ 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.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") @@ -407,14 +460,73 @@ 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): + 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) + + """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(): - 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,70 +553,60 @@ 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)) + 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 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 = np.reshape(intensities, newshape=(2048,numb_pixels_X,numb_pixels_Y)) - - wavelengths = data['Wavelengths'] - - self.ui.raw_scan_viewbox.view.invertY(False) + 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.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() #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)) 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') 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)) @@ -522,10 +624,10 @@ def fit_and_plot_scan(self): ref = self.bck_file index = (ref[:,0]>start_nm) & (ref[:,0] - MainWindow + Spectral Analysis @@ -758,46 +758,72 @@ Load Settings - - - + + + 10 - For Single Spectrum + Background +File - - + + 10 - Spectrum -File + Normalize - - + + 10 - Background -File + Clear Plots Everytime + + + true - + + + + + 10 + + + + Correct for White Light + + + + + + + + 10 + + + + For Single Spectrum + + + + @@ -810,8 +836,8 @@ Ref File - - + + 10 @@ -820,33 +846,46 @@ Ref File Subtract Background + + true + - - + + 10 - Correct for White Light + Spectrum +File - - + + 10 - Normalize + Export data - + + + + + 10 + + + + + @@ -860,54 +899,54 @@ Ref File - - + + 10 - Clear Plots Everytime - - - true + Export Publication +Ready Figure - - + + 10 - false - Clear Plot + Plot without Background - - + + 10 + false - Export Publication -Ready Figure + Clear Plot - - + + 10 + + Clear export data + @@ -1211,6 +1250,19 @@ File + + + + + 12 + + + + Export Fitted +Scan + + + @@ -1322,7 +1374,7 @@ File 0 0 1728 - 31 + 21 @@ -1330,12 +1382,12 @@ File - PlotWidget + ImageView QGraphicsView
pyqtgraph
- ImageView + PlotWidget QGraphicsView
pyqtgraph
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/Spectrum_analysis/scan_params_input.ui b/PythonGUI_apps/Spectrum_analysis/scan_params_input.ui new file mode 100644 index 0000000..4df8d40 --- /dev/null +++ b/PythonGUI_apps/Spectrum_analysis/scan_params_input.ui @@ -0,0 +1,68 @@ + + + Form + + + + 0 + 0 + 542 + 211 + + + + Form + + + + + + X scan size + + + + + + + + + + Y scan size + + + + + + + + + + X step size + + + + + + + + + + Y step size + + + + + + + + + + Done + + + + + + + + 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 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"]