├── .gitignore
├── LICENSE
├── PythonGUI_apps
├── DataBrowser.py
├── DataBrowser.spec
├── DataBrowser_GUI.ui
├── Export_Windows
│ ├── Export_window.py
│ ├── Multi_Trace_Exporter.py
│ ├── Multi_Trace_Exporter.ui
│ ├── __init__.py
│ ├── export_fig_gui.ui
│ └── export_plot.ui
├── FLIM_analysis
│ ├── FLIM_plot.py
│ ├── flim_plot_gui.ui
│ └── step_size_labview_files.ui
├── H5_Pkl
│ ├── h5_pkl_view.py
│ ├── h5_pkl_view_gui.ui
│ ├── h5_tree.py
│ ├── h5_view_and_plot.py
│ ├── h5_view_and_plot_gui.ui
│ └── pkl_tree.py
├── Image_analysis
│ ├── Image_analysis.py
│ └── image_analysis_gui.ui
├── Lifetime_analysis
│ ├── Fit_functions.py
│ ├── Fit_functions_with_irf.py
│ ├── Lifetime_analysis_gui_layout.ui
│ ├── Lifetime_plot_fit.py
│ ├── __init__.py
│ ├── picoharp_phd.py
│ ├── read_ph_phd.py
│ └── skip_rows.ui
├── OceanOptics_acquire
│ ├── OO_PZstageScan_acquire_gui.ui
│ ├── OO_acquire_gui.ui
│ └── OceanOptics_acquire_plot.py
├── PLQE_analysis
│ ├── column_selection_gui.ui
│ ├── plqe_analysis.py
│ └── plqe_analysis_gui.ui
├── Spectrum_analysis
│ ├── Spectra_fit_funcs.py
│ ├── Spectra_plot_fit.py
│ ├── Spectra_plot_fit_gui.ui
│ ├── __init__.py
│ ├── analyze_fit_results.ui
│ ├── pyqtgraph_MATPLOTLIBWIDGET.py
│ └── scan_params_input.ui
├── Table
│ ├── Table_widget.py
│ ├── Table_widget_gui.ui
│ └── __init__.py
├── UV_Vis_analysis
│ ├── uv_vis_analysis.py
│ └── uv_vis_analysis_gui.ui
└── __init__.py
├── README.md
├── Screenshots
├── GLabViz_FLIM_analysis_1.PNG
├── GLabViz_FLIM_analysis_2.png
├── GLabViz_Image_analysis_1.png
├── GLabViz_Lifetime_analysis_2.png
├── GLabViz_Spectrum_analysis_1.PNG
├── GLabViz_Spectrum_analysis_1.png
├── GLabViz_Spectrum_analysis_2.png
├── GLabViz_UVvis_analysis_1.PNG
├── GLabViz_h5_ViewPlot_analysis_1.PNG
├── GLabViz_h5_ViewPlot_analysis_2.PNG
└── GLabViz_interface_1.png
└── requirements.txt
/.gitignore:
--------------------------------------------------------------------------------
1 | *.pyc
2 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2019 SarthakJariwala
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/PythonGUI_apps/DataBrowser.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | """
3 | Created on Wed Apr 10 14:41:08 2019
4 |
5 | @author: Sarthak
6 | """
7 |
8 | # system imports
9 | import sys
10 | from pathlib import Path
11 |
12 | import pyqtgraph as pg
13 | from pyqtgraph.Qt import QtGui, QtCore
14 |
15 | from Lifetime_analysis import Lifetime_plot_fit
16 | from Spectrum_analysis import Spectra_plot_fit
17 | from FLIM_analysis import FLIM_plot
18 | from UV_Vis_analysis import uv_vis_analysis
19 | from PLQE_analysis import plqe_analysis
20 | from H5_Pkl import h5_pkl_view, h5_view_and_plot
21 | from Image_analysis import Image_analysis
22 | from Table import Table_widget
23 | from Export_Windows import Multi_Trace_Exporter
24 |
25 | pg.mkQApp()
26 | #pg.setConfigOption('background', 'w')
27 |
28 | base_path = Path(__file__).parent
29 | file_path = (base_path / "DataBrowser_GUI.ui").resolve()
30 |
31 | uiFile = file_path
32 |
33 | WindowTemplate, TemplateBaseClass = pg.Qt.loadUiType(uiFile)
34 |
35 | class MainWindow(TemplateBaseClass):
36 |
37 | def __init__(self):
38 | TemplateBaseClass.__init__(self)
39 |
40 | # Create the main window
41 | self.ui = WindowTemplate()
42 | self.ui.setupUi(self)
43 | self.ui.select_comboBox.addItems(["Lifetime Analysis", "Spectrum Analysis", "FLIM Analysis",
44 | "UV-Vis Analysis", "PLQE Analysis", "H5 View/Plot", "H5/PKL Viewer", "Image Analysis", "Table View",
45 | "Mulit-Trace Exporter"])
46 | self.ui.load_pushButton.clicked.connect(self.load_app)
47 |
48 | self.show()
49 |
50 |
51 | def load_app(self):
52 |
53 | analysis_software = self.ui.select_comboBox.currentText()
54 |
55 | if analysis_software == "Lifetime Analysis":
56 | self.lifetime_window = Lifetime_plot_fit.MainWindow()
57 | self.lifetime_window.show()
58 | elif analysis_software == "Spectrum Analysis":
59 | self.spectrum_window = Spectra_plot_fit.MainWindow()
60 | self.spectrum_window.show()
61 | elif analysis_software == "FLIM Analysis":
62 | self.flim_window = FLIM_plot.MainWindow()
63 | self.flim_window.show()
64 | elif analysis_software == "UV-Vis Analysis":
65 | self.uv_vis_window = uv_vis_analysis.MainWindow()
66 | self.uv_vis_window.show()
67 | elif analysis_software == "PLQE Analysis":
68 | self.plqe_window = plqe_analysis.MainWindow()
69 | self.plqe_window.show()
70 | elif analysis_software == "H5 View/Plot":
71 | app = h5_view_and_plot.H5ViewPlot(sys.argv)
72 | #sys.exit(app.exec_())
73 | elif analysis_software == "H5/PKL Viewer":
74 | app = h5_pkl_view.H5PklView(sys.argv)
75 | #sys.exit(app.exec_())
76 | elif analysis_software == "Image Analysis":
77 | self.image_window = Image_analysis.MainWindow()
78 | self.image_window.show()
79 | elif analysis_software == "Table View":
80 | self.table_widget = Table_widget.MainWindow()
81 | self.table_widget.show()
82 | elif analysis_software == "Mulit-Trace Exporter":
83 | self.trace_exporter = Multi_Trace_Exporter.MainWindow()
84 | self.trace_exporter.show()
85 |
86 |
87 | def run():
88 | app = QtGui.QApplication(sys.argv)#.instance()
89 | app.setStyle("Fusion")
90 | win = MainWindow()
91 | sys.exit(app.exec_())
92 | return
93 |
94 | run()
--------------------------------------------------------------------------------
/PythonGUI_apps/DataBrowser.spec:
--------------------------------------------------------------------------------
1 | # -*- mode: python ; coding: utf-8 -*-
2 |
3 | block_cipher = None
4 |
5 |
6 | a = Analysis(['DataBrowser.py'],
7 | pathex=['E:\\QT_projects\\Python_GUI_apps\\PythonGUI_apps'],
8 | binaries=[],
9 | datas=[],
10 | hiddenimports=['ipykernel.datapub'],
11 | hookspath=[],
12 | runtime_hooks=[],
13 | excludes=[],
14 | win_no_prefer_redirects=False,
15 | win_private_assemblies=False,
16 | cipher=block_cipher,
17 | noarchive=False)
18 | pyz = PYZ(a.pure, a.zipped_data,
19 | cipher=block_cipher)
20 | exe = EXE(pyz,
21 | a.scripts,
22 | [],
23 | exclude_binaries=True,
24 | name='DataBrowser',
25 | debug=False,
26 | bootloader_ignore_signals=False,
27 | strip=False,
28 | upx=True,
29 | console=True )
30 | coll = COLLECT(exe,
31 | a.binaries,
32 | a.zipfiles,
33 | a.datas,
34 | strip=False,
35 | upx=True,
36 | upx_exclude=[],
37 | name='DataBrowser')
38 |
--------------------------------------------------------------------------------
/PythonGUI_apps/DataBrowser_GUI.ui:
--------------------------------------------------------------------------------
1 |
2 |
3 | MainWindow
4 |
5 |
6 |
7 | 0
8 | 0
9 | 435
10 | 221
11 |
12 |
13 |
14 | GLabViz - DataBrowser
15 |
16 |
17 |
18 | -
19 |
20 |
21 |
22 | 30
23 | 75
24 | true
25 |
26 |
27 |
28 | GLabViz
29 |
30 |
31 | Qt::AlignCenter
32 |
33 |
34 |
35 | -
36 |
37 |
38 | Qt::Vertical
39 |
40 |
41 |
42 | 20
43 | 40
44 |
45 |
46 |
47 |
48 | -
49 |
50 |
51 |
52 | 15
53 |
54 |
55 |
56 | Analysis Tool :
57 |
58 |
59 |
60 | -
61 |
62 |
63 |
64 | 15
65 |
66 |
67 |
68 |
69 | -
70 |
71 |
72 |
73 | 15
74 |
75 |
76 |
77 | Load
78 |
79 |
80 |
81 |
82 |
83 |
93 |
94 |
95 |
96 |
97 |
98 |
--------------------------------------------------------------------------------
/PythonGUI_apps/Export_Windows/Export_window.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | """
3 | Created on Sun Nov 3 20:43:12 2019
4 |
5 | @author: sarth
6 | """
7 | from pathlib import Path
8 | import pyqtgraph as pg
9 | from pyqtgraph.Qt import QtCore, QtGui
10 |
11 | """Export Images GUI"""
12 | base_path = Path(__file__).parent
13 | ui_file_path = (base_path / "export_fig_gui.ui").resolve()
14 | exportFig_WindowTemplate, exportFig_TemplateBaseClass = pg.Qt.loadUiType(ui_file_path)
15 |
16 | class ExportFigureWindow(exportFig_TemplateBaseClass):
17 |
18 | export_fig_signal = QtCore.pyqtSignal()
19 |
20 | def __init__(self):
21 | exportFig_TemplateBaseClass.__init__(self)
22 |
23 | self.ui = exportFig_WindowTemplate()
24 | self.ui.setupUi(self)
25 | self.ui.cmap_comboBox.addItems(['viridis', 'plasma', 'inferno', 'magma',
26 | 'cividis','Greys', 'Purples', 'Blues',
27 | 'Greens', 'Oranges', 'Reds', 'YlOrBr',
28 | 'YlOrRd', 'OrRd', 'PuRd', 'RdPu', 'BuPu',
29 | 'GnBu', 'PuBu', 'YlGnBu', 'PuBuGn', 'BuGn',
30 | 'YlGn', 'binary', 'gist_yarg', 'gist_gray',
31 | 'gray', 'bone', 'pink', 'spring', 'summer',
32 | 'autumn', 'winter', 'cool', 'Wistia', 'hot',
33 | 'afmhot', 'gist_heat', 'copper', 'rainbow', 'jet'])
34 | self.ui.cbar_checkBox.stateChanged.connect(self.cbar_title_state)
35 | self.ui.exportFig_pushButton.clicked.connect(self.export)
36 | self.show()
37 |
38 | def cbar_title_state(self):
39 | if self.ui.cbar_checkBox.isChecked():
40 | self.ui.cbar_label.setEnabled(True)
41 | else:
42 | self.ui.cbar_label.setEnabled(False)
43 |
44 | def export(self):
45 | self.export_fig_signal.emit()
46 | self.close()
47 |
48 | """Export plot GUI"""
49 | ui_file_path = (base_path / "export_plot.ui").resolve()
50 | export_WindowTemplate, export_TemplateBaseClass = pg.Qt.loadUiType(ui_file_path)
51 |
52 | class ExportPlotWindow(export_TemplateBaseClass):
53 |
54 | export_fig_signal = QtCore.pyqtSignal()
55 |
56 | def __init__(self):
57 | export_TemplateBaseClass.__init__(self)
58 |
59 | self.ui = export_WindowTemplate()
60 | self.ui.setupUi(self)
61 | #self.ui.traceColor_comboBox.addItems(["C0","C1","C2","C3","C4","C5","C6","C7", "r", "g", "b", "y", "k"])
62 | #self.ui.fitColor_comboBox.addItems(["k", "r", "b", "y", "g","C0","C1","C2","C3","C4","C5","C6","C7"])
63 | self.ui.export_pushButton.clicked.connect(self.export)
64 | #self.ui.legend_checkBox.stateChanged.connect(self.legend_title)
65 | self.show()
66 |
67 | #def legend_title(self):
68 | # if self.ui.legend_checkBox.isChecked():
69 | # self.ui.legend1_lineEdit.setEnabled(True)
70 | # self.ui.legend2_lineEdit.setEnabled(True)
71 | # else:
72 | # self.ui.legend1_lineEdit.setEnabled(False)
73 | # self.ui.legend2_lineEdit.setEnabled(False)
74 |
75 | def export(self):
76 | self.export_fig_signal.emit()
77 | self.close()
--------------------------------------------------------------------------------
/PythonGUI_apps/Export_Windows/Multi_Trace_Exporter.py:
--------------------------------------------------------------------------------
1 | import pyqtgraph as pg
2 | from pathlib import Path
3 | from pyqtgraph.Qt import QtCore, QtGui, QtWidgets
4 | try:
5 | from Lifetime_analysis.read_ph_phd import read_picoharp_phd, get_x_y
6 | except Exception as e:
7 | print(e)
8 | import matplotlib.pyplot as plt
9 |
10 | """Recylce params for plotting"""
11 | plt.rc('xtick', labelsize = 20)
12 | plt.rc('xtick.major', pad = 3)
13 | plt.rc('ytick', labelsize = 20)
14 | plt.rc('lines', lw = 2.5, markersize = 7.5)
15 | plt.rc('legend', fontsize = 20)
16 | plt.rc('axes', linewidth=3.5)
17 |
18 | pg.mkQApp()
19 |
20 | base_path = Path(__file__).parent
21 | file_path = (base_path / "Multi_Trace_Exporter.ui").resolve()
22 |
23 | uiFile = file_path
24 |
25 | WindowTemplate, TemplateBaseClass = pg.Qt.loadUiType(uiFile)
26 |
27 | class MainWindow(TemplateBaseClass):
28 |
29 | def __init__(self):
30 | super(TemplateBaseClass, self).__init__()
31 |
32 | # Create the main window
33 | self.ui = WindowTemplate()
34 | self.ui.setupUi(self)
35 |
36 | self.temp_layout = pg.GraphicsLayoutWidget()
37 |
38 | # file system tree
39 | self.fs_model = QtWidgets.QFileSystemModel()
40 | self.fs_model.setRootPath(QtCore.QDir.currentPath())
41 | self.ui.treeView.setModel(self.fs_model)
42 | self.ui.treeView.setIconSize(QtCore.QSize(25,25))
43 | self.ui.treeView.setSortingEnabled(True)
44 |
45 | self.tree_selectionModel = self.ui.treeView.selectionModel()
46 | self.tree_selectionModel.selectionChanged.connect(self.on_treeview_selection_change)
47 |
48 | self.ui.comboBox.currentIndexChanged.connect(self.add_trace_to_temp_plot)
49 | self.ui.add_pushButton.clicked.connect(self.add_trace_to_mem)
50 | self.ui.export_pushButton.clicked.connect(self.pub_ready_plot_export)
51 |
52 | self.x_i = []
53 | self.y_i = []
54 | self.x_mem = []
55 | self.y_mem = []
56 | self.legend = []
57 |
58 | self.show()
59 |
60 | def on_treeview_selection_change(self):
61 | try:
62 | fname = self.fs_model.filePath(self.tree_selectionModel.currentIndex())
63 | _ , ext = fname.rsplit('.',1)
64 |
65 | self.ui.comboBox.clear()
66 | self.ui.textBrowser.clear()
67 | self.x_i = []
68 | self.y_i = []
69 |
70 | if ext in ['phd']:
71 | self.parser = read_picoharp_phd(fname)
72 | curve_list = []
73 |
74 | for i in range(self.parser.no_of_curves()):
75 | curve_list.append("Curve "+str(i))
76 | x, y = get_x_y(i, self.parser, smooth_trace=self.ui.smooth_checkBox.isChecked(), boxwidth=self.ui.smooth_spinBox.value())
77 | self.x_i.append(x)
78 | self.y_i.append(y)
79 |
80 | self.ui.comboBox.addItems(curve_list)
81 | self.ui.textBrowser.setText(str(self.parser.info()))
82 |
83 | else:
84 | self.ui.textBrowser.setText(str("Select a PicoHarp File"))
85 | except Exception as e:
86 | print(e)
87 |
88 | def add_trace_to_temp_plot(self):
89 | try:
90 | #self.temp_layout = pg.GraphicsLayoutWidget()
91 | self.temp_layout.clear()
92 | self.temp_plot = self.temp_layout.addPlot(title = "Current Selection")
93 | self.temp_plot.plot(self.x_i[self.ui.comboBox.currentIndex()], self.y_i[self.ui.comboBox.currentIndex()], pen='r')
94 | self.temp_plot.setLogMode(False, True)
95 | self.temp_layout.show()
96 | except Exception as e:
97 | print(e)
98 |
99 | def add_trace_to_mem(self):
100 | try:
101 | self.x_mem.append(self.x_i[self.ui.comboBox.currentIndex()])
102 | self.y_mem.append(self.y_i[self.ui.comboBox.currentIndex()])
103 | self.legend.append(self.ui.lineEdit.text())
104 | except Exception as e:
105 | print(e)
106 |
107 | def pub_ready_plot_export(self):
108 | try:
109 | filename = QtWidgets.QFileDialog.getSaveFileName(self,caption="Filename with EXTENSION")
110 |
111 | plt.figure(figsize=(8,6))
112 | plt.tick_params(direction='out', length=8, width=3.5)
113 | for i in range(len(self.x_mem)):
114 | if self.ui.Normalize_checkBox.isChecked():
115 | plt.plot(self.x_mem[i], self.y_mem[i]/max(self.y_mem[i]), label=str(self.legend[i]))
116 | else:
117 | plt.plot(self.x_mem[i], self.y_mem[i], label=str(self.legend[i]))
118 |
119 | plt.yscale('log')
120 | plt.xlabel("Time (ns)", fontsize=20, fontweight='bold')
121 | plt.ylabel("Intensity (norm.)", fontsize=20, fontweight='bold')
122 | plt.legend()
123 | plt.tight_layout()
124 |
125 | plt.savefig(filename[0],bbox_inches='tight', dpi=300)
126 | plt.close()
127 |
128 | self.clear_memory()
129 |
130 | except Exception as e:
131 | print(e)
132 | pass
133 |
134 | def clear_memory(self):
135 | self.x_mem = []
136 | self.y_mem = []
137 | self.legend = []
138 |
139 |
140 |
141 |
142 | def run():
143 | win = MainWindow()
144 | QtGui.QApplication.instance().exec_()
145 | return win
146 |
147 | #run()
--------------------------------------------------------------------------------
/PythonGUI_apps/Export_Windows/Multi_Trace_Exporter.ui:
--------------------------------------------------------------------------------
1 |
2 |
3 | MainWindow
4 |
5 |
6 |
7 | 0
8 | 0
9 | 1108
10 | 1063
11 |
12 |
13 |
14 | MainWindow
15 |
16 |
17 |
18 | -
19 |
20 |
21 | -
22 |
23 |
24 | Smoothen Trace
25 |
26 |
27 |
28 | -
29 |
30 |
31 | Enter Trace Legend Here
32 |
33 |
34 |
35 | -
36 |
37 |
38 | Add
39 |
40 |
41 |
42 | -
43 |
44 |
45 | Normalize (for export)
46 |
47 |
48 |
49 | -
50 |
51 |
52 | 1
53 |
54 |
55 |
56 | -
57 |
58 |
59 | Export
60 |
61 |
62 |
63 | -
64 |
65 |
66 | -
67 |
68 |
69 |
70 |
71 |
81 |
82 |
83 |
84 |
85 |
86 |
--------------------------------------------------------------------------------
/PythonGUI_apps/Export_Windows/__init__.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
--------------------------------------------------------------------------------
/PythonGUI_apps/Export_Windows/export_fig_gui.ui:
--------------------------------------------------------------------------------
1 |
2 |
3 | ExportFigure
4 |
5 |
6 |
7 | 0
8 | 0
9 | 420
10 | 369
11 |
12 |
13 |
14 | Form
15 |
16 |
17 | -
18 |
19 |
20 |
21 | 15
22 |
23 |
24 |
25 | 1000000000
26 |
27 |
28 |
29 | -
30 |
31 |
32 |
33 | 15
34 |
35 |
36 |
37 | Color Bar Label
38 |
39 |
40 |
41 | -
42 |
43 |
44 |
45 | 15
46 |
47 |
48 |
49 | Data Channel to Save
50 |
51 |
52 |
53 | -
54 |
55 |
56 |
57 | 15
58 |
59 |
60 |
61 |
62 | -
63 |
64 |
65 |
66 | 15
67 |
68 |
69 |
70 |
71 | -
72 |
73 |
74 |
75 | 15
76 |
77 |
78 |
79 | ColorMap
80 |
81 |
82 |
83 | -
84 |
85 |
86 |
87 | 15
88 |
89 |
90 |
91 | 1000000000
92 |
93 |
94 |
95 | -
96 |
97 |
98 |
99 | 15
100 |
101 |
102 |
103 | ColorBar Min
104 |
105 |
106 |
107 | -
108 |
109 |
110 |
111 | 15
112 |
113 |
114 |
115 | ColorBar Max
116 |
117 |
118 |
119 | -
120 |
121 |
122 | false
123 |
124 |
125 |
126 | 15
127 |
128 |
129 |
130 |
131 | -
132 |
133 |
134 |
135 | 15
136 |
137 |
138 |
139 | Export Figure
140 |
141 |
142 |
143 | -
144 |
145 |
146 |
147 | 15
148 |
149 |
150 |
151 | Reversed
152 |
153 |
154 |
155 | -
156 |
157 |
158 |
159 | 15
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 |
172 |
--------------------------------------------------------------------------------
/PythonGUI_apps/Export_Windows/export_plot.ui:
--------------------------------------------------------------------------------
1 |
2 |
3 | Form
4 |
5 |
6 |
7 | 0
8 | 0
9 | 930
10 | 435
11 |
12 |
13 |
14 | Form
15 |
16 |
17 | -
18 |
19 |
20 |
21 | 10
22 |
23 |
24 |
25 | 4
26 |
27 |
28 | -100.000000000000000
29 |
30 |
31 | 10000000000000000000000.000000000000000
32 |
33 |
34 | 1.500000000000000
35 |
36 |
37 |
38 | -
39 |
40 |
41 |
42 | 10
43 |
44 |
45 |
46 | Lower
47 |
48 |
49 |
50 | -
51 |
52 |
53 |
54 | 10
55 |
56 |
57 |
58 | Lower
59 |
60 |
61 |
62 | -
63 |
64 |
65 |
66 | 10
67 |
68 |
69 |
70 | Upper
71 |
72 |
73 |
74 | -
75 |
76 |
77 |
78 | 15
79 |
80 |
81 |
82 | Export Graph
83 |
84 |
85 |
86 | -
87 |
88 |
89 |
90 | 12
91 |
92 |
93 |
94 | Y limits
95 |
96 |
97 |
98 | -
99 |
100 |
101 |
102 | 10
103 |
104 |
105 |
106 | Upper
107 |
108 |
109 |
110 | -
111 |
112 |
113 |
114 | 12
115 |
116 |
117 |
118 | X limits
119 |
120 |
121 |
122 | -
123 |
124 |
125 |
126 | 10
127 |
128 |
129 |
130 | 4
131 |
132 |
133 | -10000.000000000000000
134 |
135 |
136 | 1000000000000000000.000000000000000
137 |
138 |
139 | 0.010000000000000
140 |
141 |
142 |
143 | -
144 |
145 |
146 |
147 | 10
148 |
149 |
150 |
151 | 4
152 |
153 |
154 | -10000000.000000000000000
155 |
156 |
157 | 100000000000.000000000000000
158 |
159 |
160 |
161 | -
162 |
163 |
164 |
165 | 10
166 |
167 |
168 |
169 | 4
170 |
171 |
172 | -1000000000.000000000000000
173 |
174 |
175 | 10000000000000.000000000000000
176 |
177 |
178 | 10000.000000000000000
179 |
180 |
181 |
182 |
183 |
184 |
185 |
186 |
187 |
--------------------------------------------------------------------------------
/PythonGUI_apps/FLIM_analysis/flim_plot_gui.ui:
--------------------------------------------------------------------------------
1 |
2 |
3 | Form
4 |
5 |
6 |
7 | 0
8 | 0
9 | 738
10 | 876
11 |
12 |
13 |
14 | FLIM Analysis
15 |
16 |
17 | -
18 |
19 |
20 | 0
21 |
22 |
23 |
24 | Analysis
25 |
26 |
27 |
-
28 |
29 |
-
30 |
31 |
32 | Load Scan
33 |
34 |
35 |
36 | -
37 |
38 |
-
39 |
40 |
41 | Plot
42 |
43 |
44 |
45 | -
46 |
47 |
48 | Save intensities array
49 |
50 |
51 |
52 | -
53 |
54 |
55 | Save intensities image
56 |
57 |
58 |
59 | -
60 |
61 |
62 | Analyze PSF
63 |
64 |
65 |
66 |
67 |
68 | -
69 |
70 |
71 |
72 | 500
73 | 300
74 |
75 |
76 |
77 |
78 | -
79 |
80 |
81 |
82 | 12
83 |
84 |
85 |
86 | Histogram Intensity Sums
87 |
88 |
89 |
90 | -
91 |
92 |
93 |
94 | 12
95 |
96 |
97 |
98 | Raw Histogram Data
99 |
100 |
101 |
102 | -
103 |
104 |
105 |
106 | 500
107 | 300
108 |
109 |
110 |
111 |
112 | -
113 |
114 |
-
115 |
116 |
117 | Plot
118 |
119 |
120 |
121 | -
122 |
123 |
124 | Analyze lifetime
125 |
126 |
127 |
128 | -
129 |
130 |
131 | Compare ROIs
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 | .pkl to .h5
144 |
145 |
146 |
147 |
148 | 20
149 | 20
150 | 171
151 | 34
152 |
153 |
154 |
155 | Import .pkl file
156 |
157 |
158 |
159 |
160 |
161 | 20
162 | 80
163 | 171
164 | 34
165 |
166 |
167 |
168 | .pkl to .h5
169 |
170 |
171 |
172 |
173 |
174 |
175 |
176 |
177 |
178 | ImageView
179 | QGraphicsView
180 |
181 |
182 |
183 |
184 |
185 |
186 |
--------------------------------------------------------------------------------
/PythonGUI_apps/FLIM_analysis/step_size_labview_files.ui:
--------------------------------------------------------------------------------
1 |
2 |
3 | Form
4 |
5 |
6 |
7 | 0
8 | 0
9 | 255
10 | 75
11 |
12 |
13 |
14 | Form
15 |
16 |
17 | -
18 |
19 |
20 |
21 | 12
22 |
23 |
24 |
25 | Step Size (um)
26 |
27 |
28 |
29 | -
30 |
31 |
32 | Done!
33 |
34 |
35 |
36 | -
37 |
38 |
39 |
40 | 12
41 |
42 |
43 |
44 | 4
45 |
46 |
47 | 100.000000000000000
48 |
49 |
50 | 0.100000000000000
51 |
52 |
53 | 0.100000000000000
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
--------------------------------------------------------------------------------
/PythonGUI_apps/H5_Pkl/h5_pkl_view.py:
--------------------------------------------------------------------------------
1 | from __future__ import division, print_function, absolute_import
2 | from ScopeFoundry import BaseApp
3 | from ScopeFoundry.helper_funcs import load_qt_ui_file, sibling_path
4 | from collections import OrderedDict
5 | import os
6 | from qtpy import QtCore, QtWidgets, QtGui
7 | import pyqtgraph as pg
8 | import pyqtgraph.dockarea as dockarea
9 | import numpy as np
10 | from ScopeFoundry.logged_quantity import LQCollection
11 | from scipy.stats import spearmanr
12 | import argparse
13 | from .h5_tree import H5TreeSearchView
14 | from .pkl_tree import PklTreeSearchView
15 |
16 | pg.setConfigOption('imageAxisOrder', 'row-major')
17 |
18 | class H5PklView(BaseApp):
19 |
20 | name = "h5_pkl_view"
21 |
22 | def __init__(self, argv):
23 | BaseApp.__init__(self, argv)
24 | self.setup()
25 | parser = argparse.ArgumentParser()
26 | for lq in self.settings.as_list():
27 | parser.add_argument("--" + lq.name)
28 | args = parser.parse_args()
29 | for lq in self.settings.as_list():
30 | if lq.name in args:
31 | val = getattr(args,lq.name)
32 | if val is not None:
33 | lq.update_value(val)
34 |
35 | def setup(self):
36 | self.ui_filename = sibling_path(__file__, "h5_pkl_view_gui.ui")
37 | self.ui = load_qt_ui_file(self.ui_filename)
38 | self.ui.show()
39 | self.ui.raise_()
40 |
41 | self.views = OrderedDict()
42 |
43 | self.settings.New('data_filename', dtype='file')
44 | self.settings.New('auto_select_view',dtype=bool, initial=True)
45 | self.settings.New('view_name', dtype=str, initial='0', choices=('0',))
46 |
47 | self.settings.data_filename.add_listener(self.on_change_data_filename)
48 |
49 | # UI Connections/
50 | self.settings.data_filename.connect_to_browse_widgets(self.ui.data_filename_lineEdit,
51 | self.ui.data_filename_browse_pushButton)
52 |
53 | # set views
54 | self.h5treeview = H5TreeSearchView(self)
55 | self.load_view(self.h5treeview)
56 | self.pkltreeview = PklTreeSearchView(self)
57 | self.load_view(self.pkltreeview)
58 |
59 | self.settings.view_name.add_listener(self.on_change_view_name)
60 |
61 | self.current_view = None
62 |
63 | self.ui.show()
64 |
65 | def load_view(self, new_view):
66 | # add to views dict
67 | self.views[new_view.name] = new_view
68 |
69 | self.ui.dataview_page.layout().addWidget(new_view.ui)
70 | new_view.ui.hide()
71 |
72 | # update choices for view_name
73 | self.settings.view_name.change_choice_list(list(self.views.keys()))
74 | return new_view
75 |
76 | def on_change_data_filename(self):
77 | #Handle file change
78 | try:
79 | fname = self.settings.data_filename.val
80 | if not self.settings['auto_select_view']:
81 | self.current_view.on_change_data_filename(fname)
82 | else:
83 | view_name = self.auto_select_view(fname)
84 | if self.current_view is None or view_name != self.current_view.name:
85 | # update view (automatically calls on_change_data_filename)
86 | self.settings['view_name'] = view_name
87 | else:
88 | # force update
89 | if os.path.isfile(fname):
90 | self.current_view.on_change_data_filename(fname)
91 | except:
92 | pass
93 |
94 | def on_change_view_name(self):
95 | #Handle view change - happens when filetype changes
96 | self.ui.dataview_placeholder.hide()
97 | previous_view = self.current_view
98 |
99 | self.current_view = self.views[self.settings['view_name']]
100 | # hide current view
101 | # (handle the initial case where previous_view is None )
102 | if previous_view:
103 | previous_view.ui.hide()
104 |
105 | # show new view
106 | self.current_view.ui.show()
107 |
108 | # set datafile for new (current) view
109 | fname = self.settings['data_filename']
110 | if os.path.isfile(fname):
111 | self.current_view.on_change_data_filename(self.settings['data_filename'])
112 |
113 | def auto_select_view(self, fname):
114 | #return the name of the last supported view for the given fname
115 | for view_name, view in list(self.views.items())[::-1]:
116 | if view.is_file_supported(fname):
117 | return view_name
118 | # return default file_info view if no others work
119 | return "h5_tree_search"
120 |
121 | # if __name__ == '__main__':
122 | # import sys
123 | # app = H5PklView(sys.argv)
124 | # sys.exit(app.exec_())
125 |
--------------------------------------------------------------------------------
/PythonGUI_apps/H5_Pkl/h5_pkl_view_gui.ui:
--------------------------------------------------------------------------------
1 |
2 |
3 | MainWindow
4 |
5 |
6 |
7 | 0
8 | 0
9 | 856
10 | 925
11 |
12 |
13 |
14 | H5/pkl View
15 |
16 |
17 |
18 | -
19 |
20 |
21 | Qt::Horizontal
22 |
23 |
24 |
25 | File
26 |
27 |
28 |
-
29 |
30 |
31 | -
32 |
33 |
34 | File:
35 |
36 |
37 |
38 | -
39 |
40 |
41 | Browse...
42 |
43 |
44 |
45 | -
46 |
47 |
48 | true
49 |
50 |
51 | 0
52 |
53 |
54 |
55 | Data View
56 |
57 |
58 |
-
59 |
60 |
61 | Once a file is loaded, data will show up here.
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
85 |
86 |
87 |
88 |
89 |
90 |
--------------------------------------------------------------------------------
/PythonGUI_apps/H5_Pkl/h5_tree.py:
--------------------------------------------------------------------------------
1 | from ScopeFoundry.data_browser import DataBrowserView
2 | from qtpy import QtWidgets
3 | import h5py
4 |
5 | class H5TreeSearchView(DataBrowserView):
6 |
7 | name = 'h5_tree_search'
8 |
9 | def is_file_supported(self, fname):
10 | return ('.h5' in fname)
11 |
12 | def setup(self):
13 | #self.settings.New('search_text', dtype=str, initial="")
14 |
15 | self.ui = QtWidgets.QWidget()
16 | self.ui.setLayout(QtWidgets.QVBoxLayout())
17 | self.search_lineEdit = QtWidgets.QLineEdit()
18 | self.search_lineEdit.setPlaceholderText("Search")
19 | self.tree_textEdit = QtWidgets.QTextEdit("")
20 |
21 | self.ui.layout().addWidget(self.search_lineEdit)
22 | self.ui.layout().addWidget(self.tree_textEdit)
23 |
24 | #self.settings.search_text.connect_to_widget(self.search_lineEdit)
25 | #self.settings.search_text.add_listener(self.on_new_search_text)
26 | self.search_text = ""
27 |
28 | self.search_lineEdit.textChanged.connect(self.on_new_search_text)
29 |
30 | def on_change_data_filename(self, fname=None):
31 | """ Handle file change """
32 | self.tree_textEdit.setText("loading {}".format(fname))
33 | try:
34 | #if using h5_plot_and_view
35 | if hasattr(self.databrowser.ui, "dataset_listWidget"):
36 | self.dataset_dict = {}
37 | self.databrowser.ui.dataset_listWidget.clear()
38 |
39 | self.fname = fname
40 | self.f = h5py.File(fname, 'r')
41 | self.on_new_search_text()
42 | self.databrowser.ui.statusbar.showMessage("")
43 | return self.f
44 |
45 | except Exception as err:
46 | msg = "Failed to load %s:\n%s" %(fname, err)
47 | self.databrowser.ui.statusbar.showMessage(msg)
48 | self.tree_textEdit.setText(msg)
49 | raise(err)
50 |
51 | def on_new_search_text(self, x=None):
52 | if x is not None:
53 | self.search_text = x.lower()
54 | old_scroll_pos = self.tree_textEdit.verticalScrollBar().value()
55 | self.tree_str = ""
56 | self.f.visititems(self._visitfunc)
57 |
58 | self.tree_text_html = \
59 | """{}
60 |
61 | {}
62 |
63 | """.format(self.fname, self.tree_str)
64 |
65 | self.tree_textEdit.setText(self.tree_text_html)
66 | self.tree_textEdit.verticalScrollBar().setValue(old_scroll_pos)
67 |
68 | def _visitfunc(self, name, node):
69 | level = len(name.split('/'))
70 | indent = ' '*4*(level-1)
71 |
72 | #indent = ''.format(level*4)
73 | localname = name.split('/')[-1]
74 |
75 | #search_text = self.settings['search_text'].lower()
76 | search_text = self.search_text
77 | if search_text and (search_text in localname.lower()): #highlight terms that contain search text
78 | localname = """{}""".format(localname)
79 |
80 | if isinstance(node, h5py.Group):
81 | self.tree_str += indent +"|> {}/
".format(localname)
82 | elif isinstance(node, h5py.Dataset):
83 | self.tree_str += indent +"|D {}: {} {}
".format(localname, node.shape, node.dtype)
84 |
85 | #if using h5_plot_and_view
86 | if hasattr(self.databrowser.ui, "dataset_listWidget"):
87 | item_name = "{}: {} {}".format(localname, node.shape, node.dtype)
88 | self.databrowser.ui.dataset_listWidget.addItem(item_name)
89 | if not hasattr(self, "dataset_dict"):
90 | self.dataset_dict = {}
91 | self.dataset_dict[item_name] = node
92 |
93 |
94 | for key, val in node.attrs.items(): #highlight terms that contain search text
95 | if search_text:
96 | if search_text in str(key).lower():
97 | key = """{}""".format(key)
98 | if search_text in str(val).lower():
99 | val = """{}""".format(val)
100 | self.tree_str += indent+" |- {} = {}
".format(key, val)
--------------------------------------------------------------------------------
/PythonGUI_apps/H5_Pkl/h5_view_and_plot.py:
--------------------------------------------------------------------------------
1 | from __future__ import division, print_function, absolute_import
2 | from ScopeFoundry import BaseApp
3 | from ScopeFoundry.helper_funcs import load_qt_ui_file, sibling_path
4 | from collections import OrderedDict
5 | import os
6 | from qtpy import QtCore, QtWidgets, QtGui
7 | import pyqtgraph as pg
8 | import pyqtgraph.dockarea as dockarea
9 | import numpy as np
10 | from ScopeFoundry.logged_quantity import LQCollection
11 | from scipy.stats import spearmanr
12 | import argparse
13 | from .h5_tree import H5TreeSearchView
14 | from .pkl_tree import PklTreeSearchView
15 |
16 |
17 |
18 | class H5ViewPlot(BaseApp):
19 |
20 | name = "h5_view_plot"
21 |
22 | def __init__(self, argv):
23 | pg.setConfigOption('imageAxisOrder', 'row-major')
24 | BaseApp.__init__(self, argv)
25 | self.setup()
26 | parser = argparse.ArgumentParser()
27 | for lq in self.settings.as_list():
28 | parser.add_argument("--" + lq.name)
29 | args = parser.parse_args()
30 | for lq in self.settings.as_list():
31 | if lq.name in args:
32 | val = getattr(args,lq.name)
33 | if val is not None:
34 | lq.update_value(val)
35 |
36 | def setup(self):
37 | self.ui_filename = sibling_path(__file__, "h5_view_and_plot_gui.ui")
38 | self.ui = load_qt_ui_file(self.ui_filename)
39 | self.ui.show()
40 | self.ui.raise_()
41 |
42 | self.settings.New('data_filename', dtype='file')
43 |
44 | self.settings.data_filename.add_listener(self.on_change_data_filename)
45 |
46 | self.settings.New('view_name', dtype=str, initial='0', choices=('0',))
47 |
48 | # UI Connections
49 | self.settings.data_filename.connect_to_browse_widgets(self.ui.data_filename_lineEdit,
50 | self.ui.data_filename_browse_pushButton)
51 | self.ui.plot_pushButton.clicked.connect(self.plot_dataset)
52 | self.ui.dataset_listWidget.currentItemChanged.connect(self.on_data_selection)
53 | self.ui.plot_radioButton.toggled.connect(self.update_data_widget)
54 | self.ui.image_radioButton.toggled.connect(self.update_data_widget)
55 |
56 | #set up image item for 2d array
57 | self.data_img_layout = pg.GraphicsLayoutWidget()
58 | self.ui.imageItem_page.layout().addWidget(self.data_img_layout)
59 | self.data_img_layout = self.data_img_layout.addViewBox()
60 | self.data_img = pg.ImageItem()
61 | self.data_img_layout.addItem(self.data_img)
62 |
63 | #set up image view for 3d array
64 | self.ui.data_imageView.getView().invertY(False)
65 |
66 | self.h5treeview = H5TreeSearchView(self)
67 | self.ui.dataview_page.layout().addWidget(self.h5treeview.ui)
68 | self.h5treeview.ui.hide()
69 | self.ui.show()
70 |
71 | def on_change_data_filename(self):
72 | """ Handle file change """
73 | try:
74 | fname = self.settings.data_filename.val
75 | if os.path.isfile(fname):
76 | self.f = self.h5treeview.on_change_data_filename(fname)
77 | self.ui.dataview_placeholder.hide()
78 | self.h5treeview.ui.show()
79 | except:
80 | pass
81 |
82 | def plot_dataset(self):
83 | """ Plot data set depending on dataset shape and plot type option. """
84 | self.plot = self.ui.data_plotWidget.getPlotItem()
85 | self.plot.clear()
86 |
87 | data = self.dataset[()]
88 | if self.dataset_shape == 1:
89 | x_start = self.ui.plotWidget_x_start_spinBox.value()
90 | x_end = self.ui.plotWidget_x_end_spinBox.value()
91 | num_points = self.dataset.shape[0]
92 | x_values = np.linspace(x_start, x_end, num_points)
93 | self.plot.plot(x_values, data)
94 | elif self.dataset_shape == 2 and self.ui.plot_radioButton.isChecked():
95 | self.plot.plot(data[0], data[1]) # TODO check and test this
96 | elif self.dataset_shape == 2 and self.ui.image_radioButton.isChecked():
97 | self.data_img.setImage(data)
98 | elif self.dataset_shape == 3:
99 | if self.f['Cube/Info/Cube'].attrs['AcqMode'] == b'Hyperspectral Acquisition': # This works for our PhotonEtc. Hyperspectral Camera output
100 | x_start = int(self.f['Cube/Info/Cube'].attrs['LowerWavelength'])
101 | x_end = int(self.f['Cube/Info/Cube'].attrs['UpperWavelength'])
102 | else:
103 | x_start = self.ui.imageView_x_start_spinBox.value()
104 | x_end = self.ui.imageView_x_end_spinBox.value()
105 | num_points = self.dataset.shape[0]
106 | x_values = np.linspace(x_start, x_end, num_points) #scale x axis
107 | self.ui.data_imageView.setImage(data, xvals=x_values)
108 |
109 | def on_data_selection(self):
110 | """ Handle dataset selection """
111 | try:
112 | dataset_name = self.ui.dataset_listWidget.currentItem().text()
113 | self.dataset = self.h5treeview.dataset_dict[dataset_name]
114 | self.dataset_shape = len(self.dataset[()].shape)
115 | self.update_data_widget()
116 | if self.dataset_shape == 1:
117 | self.ui.plot_type_groupBox.setEnabled(False)
118 | self.ui.plot_radioButton.setChecked(True)
119 | elif self.dataset_shape == 2:
120 | self.ui.plot_type_groupBox.setEnabled(True)
121 | elif self.dataset_shape == 3:
122 | self.ui.plot_type_groupBox.setEnabled(False)
123 | self.ui.image_radioButton.setChecked(True)
124 | except:
125 | pass
126 |
127 | def update_data_widget(self):
128 | """ Decide which widget to display based on dataset shape and plot type option. """
129 | if self.dataset_shape == 1:
130 | self.ui.data_stackedWidget.setCurrentIndex(0)
131 | elif self.dataset_shape == 2 and self.ui.plot_radioButton.isChecked():
132 | self.ui.data_stackedWidget.setCurrentIndex(0)
133 | elif self.dataset_shape == 2 and self.ui.image_radioButton.isChecked():
134 | self.ui.data_stackedWidget.setCurrentIndex(1)
135 | elif self.dataset_shape == 3:
136 | self.ui.data_stackedWidget.setCurrentIndex(2)
137 |
138 | # if __name__ == '__main__':
139 | # import sys
140 | # app = H5ViewPlot(sys.argv)
141 | # sys.exit(app.exec_())
--------------------------------------------------------------------------------
/PythonGUI_apps/H5_Pkl/h5_view_and_plot_gui.ui:
--------------------------------------------------------------------------------
1 |
2 |
3 | MainWindow
4 |
5 |
6 |
7 | 0
8 | 0
9 | 856
10 | 925
11 |
12 |
13 |
14 | H5 View and Plot
15 |
16 |
17 |
18 | -
19 |
20 |
21 | Qt::Horizontal
22 |
23 |
24 |
25 | File
26 |
27 |
28 |
-
29 |
30 |
31 | -
32 |
33 |
34 | File:
35 |
36 |
37 |
38 | -
39 |
40 |
41 | Browse...
42 |
43 |
44 |
45 | -
46 |
47 |
48 | true
49 |
50 |
51 | 0
52 |
53 |
54 |
55 | Data View
56 |
57 |
58 |
-
59 |
60 |
61 | Once a file is loaded, data will show up here.
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 | true
70 |
71 |
72 | Plot
73 |
74 |
75 | -
76 |
77 |
78 | Datasets
79 |
80 |
81 |
-
82 |
83 |
84 |
85 |
86 |
87 | -
88 |
89 |
90 | Plot data
91 |
92 |
93 |
-
94 |
95 |
96 | 0
97 |
98 |
99 |
100 |
-
101 |
102 |
103 | -
104 |
105 |
-
106 |
107 |
108 |
109 | 203
110 | 16777215
111 |
112 |
113 |
114 | 9999999.000000000000000
115 |
116 |
117 | 0.000000000000000
118 |
119 |
120 |
121 | -
122 |
123 |
124 | X start
125 |
126 |
127 |
128 | -
129 |
130 |
131 | 9999999.000000000000000
132 |
133 |
134 |
135 | -
136 |
137 |
138 | X end
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 | -
152 |
153 |
154 | -
155 |
156 |
-
157 |
158 |
159 | 9999999.000000000000000
160 |
161 |
162 |
163 | -
164 |
165 |
166 |
167 | 203
168 | 16777215
169 |
170 |
171 |
172 | 9999999.000000000000000
173 |
174 |
175 | 0.000000000000000
176 |
177 |
178 |
179 | -
180 |
181 |
182 | X start
183 |
184 |
185 |
186 | -
187 |
188 |
189 | X end
190 |
191 |
192 |
193 |
194 |
195 |
196 |
197 |
198 |
199 | -
200 |
201 |
202 | Plot
203 |
204 |
205 |
206 | -
207 |
208 |
209 | true
210 |
211 |
212 | Type
213 |
214 |
215 |
-
216 |
217 |
218 | true
219 |
220 |
221 | Plot
222 |
223 |
224 | true
225 |
226 |
227 |
228 | -
229 |
230 |
231 | true
232 |
233 |
234 | Image
235 |
236 |
237 |
238 |
239 |
240 |
241 |
242 |
243 |
244 |
245 |
246 |
247 |
248 |
249 |
250 |
251 |
252 |
253 |
254 |
264 |
265 |
266 |
267 |
268 | PlotWidget
269 | QGraphicsView
270 |
271 |
272 |
273 | ImageView
274 | QGraphicsView
275 |
276 |
277 |
278 |
279 |
280 |
281 |
--------------------------------------------------------------------------------
/PythonGUI_apps/H5_Pkl/pkl_tree.py:
--------------------------------------------------------------------------------
1 | from ScopeFoundry.data_browser import DataBrowserView
2 | from qtpy import QtWidgets
3 | import h5py
4 | import pickle
5 | import numpy as np
6 | import lmfit
7 |
8 | class PklTreeSearchView(DataBrowserView):
9 |
10 | name = 'pkl_tree_search'
11 |
12 | def is_file_supported(self, fname):
13 | return ('.pkl' in fname)
14 |
15 | def setup(self):
16 | #self.settings.New('search_text', dtype=str, initial="")
17 |
18 | self.ui = QtWidgets.QWidget()
19 | self.ui.setLayout(QtWidgets.QVBoxLayout())
20 | self.search_lineEdit = QtWidgets.QLineEdit()
21 | self.search_lineEdit.setPlaceholderText("Search")
22 | self.tree_textEdit = QtWidgets.QTextEdit("")
23 |
24 | self.ui.layout().addWidget(self.search_lineEdit)
25 | self.ui.layout().addWidget(self.tree_textEdit)
26 |
27 | #self.settings.search_text.connect_to_widget(self.search_lineEdit)
28 | #self.settings.search_text.add_listener(self.on_new_search_text)
29 | self.search_text = ""
30 |
31 | self.search_lineEdit.textChanged.connect(self.on_new_search_text)
32 |
33 | def on_change_data_filename(self, fname=None):
34 | """ Handle file change """
35 | self.tree_textEdit.setText("loading {}".format(fname))
36 | try:
37 | self.fname = fname
38 | #self.f = h5py.File(fname, 'r')
39 | self.dictionary = pickle.load(open(self.fname, 'rb'))
40 | self.on_new_search_text()
41 | self.databrowser.ui.statusbar.showMessage("")
42 |
43 | except Exception as err:
44 | msg = "Failed to load %s:\n%s" %(fname, err)
45 | self.databrowser.ui.statusbar.showMessage(msg)
46 | self.tree_textEdit.setText(msg)
47 | raise(err)
48 |
49 | def on_new_search_text(self, x=None):
50 | if x is not None:
51 | self.search_text = x.lower()
52 | old_scroll_pos = self.tree_textEdit.verticalScrollBar().value()
53 | self.tree_str = ""
54 | #self.f.visititems(self._visitfunc)
55 | self.traverse_dict(self.dictionary, self.dictionary, 0)
56 |
57 |
58 | self.tree_text_html = \
59 | """{}
60 |
61 | {}
62 |
63 | """.format(self.fname, self.tree_str)
64 |
65 | self.tree_textEdit.setText(self.tree_text_html)
66 | self.tree_textEdit.verticalScrollBar().setValue(old_scroll_pos)
67 |
68 | def traverse_dict(self, dictionary, previous_dict, level):
69 | """
70 | Visit all values in the dictionary and its subdictionaries.
71 |
72 | dictionary -- dictionary to traverse
73 | previous_dict -- dictionary one level up
74 | level -- track how far to indent
75 | """
76 | for key in dictionary:
77 | if key not in previous_dict:
78 | level -=1
79 | indent = " "*4*(level)
80 |
81 | if type(dictionary[key]) == dict:
82 | print_string = key
83 | if self.search_text and self.search_text in print_string:
84 | self.tree_str += indent + """{}""".format(print_string)
85 | else:
86 | self.tree_str += indent + "|> {}/
".format(print_string)
87 | level += 1
88 | previous_dict = dictionary[key]
89 | self.traverse_dict(dictionary[key], previous_dict, level)
90 | else:
91 | value = dictionary[key]
92 | if type(value) == np.ndarray or type(value)==np.memmap:
93 | value = str(value.shape) + " " + str(value.dtype)
94 | elif type(value) == lmfit.model.ModelResult:
95 | value = "lmfit.model.ModelResult"
96 | # if type(value) == list and len(value) > 5: ##account for data stored in lists
97 | # value = str(np.asarray(value).shape) + " " + str(type(value[0]))
98 |
99 | print_string = key + " = " + str(value)
100 | if self.search_text and self.search_text in print_string:
101 | self.tree_str += indent + """{}""".format(print_string)
102 | else:
103 | self.tree_str += indent + "|- {}
".format(print_string)
--------------------------------------------------------------------------------
/PythonGUI_apps/Image_analysis/Image_analysis.py:
--------------------------------------------------------------------------------
1 | import sys
2 | from pathlib import Path
3 | import os.path
4 | import pyqtgraph as pg
5 | from pyqtgraph.Qt import QtCore, QtGui, QtWidgets#, QColorDialog
6 | import numpy as np
7 | import matplotlib.pyplot as plt
8 | from PIL import Image
9 |
10 | # local modules
11 |
12 | pg.mkQApp()
13 |
14 |
15 | base_path = Path(__file__).parent
16 | file_path = (base_path / "image_analysis_gui.ui").resolve()
17 |
18 | uiFile = file_path
19 |
20 | WindowTemplate, TemplateBaseClass = pg.Qt.loadUiType(uiFile)
21 |
22 | def updateDelay(scale, time):
23 | """ Hack fix for scalebar inaccuracy"""
24 | QtCore.QTimer.singleShot(time, scale.updateBar)
25 |
26 | class MainWindow(TemplateBaseClass):
27 |
28 | def __init__(self):
29 | pg.setConfigOption('imageAxisOrder', 'col-major')
30 | super(TemplateBaseClass, self).__init__()
31 |
32 | # Create the main window
33 | self.ui = WindowTemplate()
34 | self.ui.setupUi(self)
35 |
36 | #setup image plot
37 | self.image_plot_layout=pg.GraphicsLayoutWidget()
38 | self.ui.image_groupBox.layout().addWidget(self.image_plot_layout)
39 | self.image_plot = self.image_plot_layout.addPlot()
40 | self.img_item = pg.ImageItem()
41 | self.image_plot.addItem(self.img_item)
42 | self.image_plot_view = self.image_plot.getViewBox()
43 |
44 | #setup lookup table
45 | self.hist_lut = pg.HistogramLUTItem()
46 | self.image_plot_layout.addItem(self.hist_lut)
47 |
48 | #region of interest - allows user to select scan area
49 | self.roi = pg.ROI([0,0],[10, 10], movable=True)
50 | self.roi.addScaleHandle([1, 1], [0, 0])
51 | self.roi.addRotateHandle([0, 0], [1, 1])
52 | self.roi.translateSnap = True
53 | self.roi.scaleSnap = True
54 | self.roi.sigRegionChanged.connect(self.line_profile_update_plot)
55 | self.image_plot.addItem(self.roi)
56 |
57 | #setup rgb plot
58 | self.rgb_plot_layout=pg.GraphicsLayoutWidget()
59 | self.ui.rgb_plot_groupBox.layout().addWidget(self.rgb_plot_layout)
60 | self.rgb_plot = self.rgb_plot_layout.addPlot()
61 |
62 | #set up ui signals
63 | self.ui.load_image_pushButton.clicked.connect(self.load_image)
64 | self.ui.custom_pixel_size_checkBox.stateChanged.connect(self.switch_custom_pixel_size)
65 | self.ui.update_settings_pushButton.clicked.connect(self.reload_image)
66 | self.ui.spot_radioButton.toggled.connect(self.update_camera)
67 |
68 | self.update_camera() #initialize camera pixel size
69 | self.update_scaling_factor() #initialize scaling_factor
70 | self.show()
71 |
72 | #row major. invert y false, rotate false
73 | def load_image(self):
74 | """
75 | Prompts the user to select a text file containing image data.
76 | """
77 | try:
78 | file = QtWidgets.QFileDialog.getOpenFileName(self, 'Open file', os.getcwd())
79 | self.original_image = Image.open(file[0])
80 | self.original_image = self.original_image.rotate(-90, expand=True) #correct image orientation
81 | self.resize_to_scaling_factor(self.original_image)
82 | except Exception as err:
83 | print(format(err))
84 |
85 | def resize_to_scaling_factor(self, image):
86 | """
87 | Handles loading of image according to scaling_factor
88 | """
89 | self.update_scaling_factor()
90 |
91 | if self.ui.spot_radioButton.isChecked() and self.ui.resize_image_checkBox.isChecked():
92 | image = self.original_image.resize((round(image.size[0]*self.scaling_factor), round(image.size[1]*self.scaling_factor)))
93 | self.image_plot.getAxis("bottom").setScale(scale = 1)
94 | self.image_plot.getAxis("left").setScale(scale = 1)
95 | else:
96 | image = self.original_image
97 | self.image_plot.getAxis("bottom").setScale(scale = self.scaling_factor)
98 | self.image_plot.getAxis("left").setScale(scale = self.scaling_factor)
99 |
100 | if self.ui.greyscale_checkBox.isChecked():
101 | image = image.convert("L") #convert to greyscale
102 |
103 | self.image_array = np.array(image)
104 | width = self.image_array.shape[0]
105 | height = self.image_array.shape[1]
106 |
107 | try:
108 | #set image bounds with qrect
109 | self.img_item_rect = QtCore.QRectF(0, 0, width, height)
110 | self.img_item.setImage(image=self.image_array)
111 | self.img_item.setRect(self.img_item_rect)
112 |
113 | # if self.ui.greyscale_checkBox.isChecked():
114 | # self.hist_lut.setImageItem(self.img_item)
115 |
116 | if self.ui.vertical_radioButton.isChecked():
117 | roi_height = self.scaling_factor * height
118 | self.roi.setSize([width, roi_height])
119 | elif self.ui.horizontal_radioButton.isChecked():
120 | roi_height = self.scaling_factor * width
121 | self.roi.setSize([roi_height, height])
122 | self.roi.setAngle(0)
123 | self.roi.setPos(0, 0)
124 | self.line_profile_update_plot()
125 | except:
126 | pass
127 |
128 | def line_profile_update_plot(self):
129 | """ Handle line profile for intensity sum viewbox """
130 | self.rgb_plot.clear()
131 |
132 | # Extract image data from ROI
133 | data, coords = self.roi.getArrayRegion(self.image_array, self.img_item, returnMappedCoords=True)
134 | if data is None:
135 | return
136 |
137 | if self.ui.vertical_radioButton.isChecked():
138 | x_values = coords[0,:,0]
139 | elif self.ui.horizontal_radioButton.isChecked():
140 | x_values = coords[1,0,:]
141 |
142 | if self.ui.pixera_radioButton.isChecked() or (self.ui.spot_radioButton.isChecked() and not self.ui.resize_image_checkBox.isChecked()):
143 | x_values = x_values * self.scaling_factor
144 |
145 | #calculate average along columns in region
146 | if len(data.shape) <= 2: #if grayscale, average intensities
147 | if self.ui.vertical_radioButton.isChecked():
148 | avg_to_plot = np.mean(data, axis=-1)
149 | elif self.ui.horizontal_radioButton.isChecked():
150 | avg_to_plot = np.mean(data, axis=0)
151 | try:
152 | self.rgb_plot.plot(x_values, avg_to_plot)
153 | except:
154 | pass
155 | elif len(data.shape) > 2: #if rgb arrays, plot individual components
156 | r_values = data[:,:,0]
157 | g_values = data[:,:,1]
158 | b_values = data[:,:,2]
159 | if self.ui.vertical_radioButton.isChecked():
160 | r_avg = np.mean(r_values, axis=-1) #average red values across columns
161 | g_avg = np.mean(g_values, axis=-1) #average green values
162 | b_avg = np.mean(b_values, axis=-1) #average blue values
163 | elif self.ui.horizontal_radioButton.isChecked():
164 | r_avg = np.mean(r_values, axis=0)
165 | g_avg = np.mean(g_values, axis=0)
166 | b_avg = np.mean(b_values, axis=0)
167 | try:
168 | self.rgb_plot.plot(x_values, r_avg, pen='r')
169 | self.rgb_plot.plot(x_values, g_avg, pen='g')
170 | self.rgb_plot.plot(x_values, b_avg, pen='b')
171 | except Exception as e:
172 | pass
173 |
174 | def update_scaling_factor(self):
175 | """
176 | Calculate scaling factor
177 | """
178 | if self.ui.custom_pixel_size_checkBox.isChecked():
179 | self.camera_pixel_size = self.ui.custom_pixel_size_spinBox.value()
180 | self.scaling_factor = self.camera_pixel_size
181 | else:
182 | self.scaling_factor = self.camera_pixel_size/int(self.ui.magnification_comboBox.currentText())
183 | self.roi.snapSize = self.scaling_factor #roi snaps to multiples of scaling_factor
184 |
185 | def reload_image(self):
186 | if hasattr(self, "original_image"):
187 | self.resize_to_scaling_factor(self.original_image) #resize image, sets up roi
188 |
189 | def switch_custom_pixel_size(self):
190 | checked = self.ui.custom_pixel_size_checkBox.isChecked()
191 | self.ui.custom_pixel_size_spinBox.setEnabled(checked)
192 | self.ui.magnification_comboBox.setEnabled(not checked)
193 |
194 | def update_camera(self):
195 | if self.ui.spot_radioButton.isChecked():
196 | self.camera_pixel_size = 7.4
197 | self.ui.greyscale_checkBox.setChecked(False)
198 | self.ui.resize_image_checkBox.setEnabled(True)
199 | self.update_scaling_factor()
200 | elif self.ui.pixera_radioButton.isChecked():
201 | self.camera_pixel_size = 3
202 | self.ui.greyscale_checkBox.setChecked(True)
203 | self.ui.resize_image_checkBox.setEnabled(False)
204 | self.update_scaling_factor()
205 |
206 | def close_application(self):
207 | choice = QtGui.QMessageBox.question(self, 'EXIT!',
208 | "Do you want to exit the app?",
209 | QtGui.QMessageBox.Yes | QtGui.QMessageBox.No)
210 | if choice == QtGui.QMessageBox.Yes:
211 | sys.exit()
212 | else:
213 | pass
214 |
215 | """Run the Main Window"""
216 | def run():
217 | win = MainWindow()
218 | QtGui.QApplication.instance().exec_()
219 | return win
220 |
221 | #Uncomment below if you want to run this as standalone
222 | #run()
--------------------------------------------------------------------------------
/PythonGUI_apps/Image_analysis/image_analysis_gui.ui:
--------------------------------------------------------------------------------
1 |
2 |
3 | MainWindow
4 |
5 |
6 |
7 | 0
8 | 0
9 | 1029
10 | 743
11 |
12 |
13 |
14 | Image Analysis
15 |
16 |
17 | QTabWidget::Triangular
18 |
19 |
20 |
21 | -
22 |
23 |
24 | Settings
25 |
26 |
27 |
-
28 |
29 |
30 |
31 |
32 | -
33 |
34 |
-
35 |
36 |
37 | Greyscale image
38 |
39 |
40 |
41 | -
42 |
43 |
44 | Load image
45 |
46 |
47 |
48 | -
49 |
50 |
-
51 |
52 | 50
53 |
54 |
55 | -
56 |
57 | 75
58 |
59 |
60 | -
61 |
62 | 100
63 |
64 |
65 | -
66 |
67 | 150
68 |
69 |
70 |
71 |
72 | -
73 |
74 |
75 | Magnification
76 |
77 |
78 |
79 | -
80 |
81 |
82 | Update settings
83 |
84 |
85 |
86 | -
87 |
88 |
89 | false
90 |
91 |
92 |
93 | -
94 |
95 |
96 | Custom pixel size (um)
97 |
98 |
99 |
100 | -
101 |
102 |
103 | Camera
104 |
105 |
106 |
-
107 |
108 |
109 | SPOT
110 |
111 |
112 | true
113 |
114 |
115 |
116 | -
117 |
118 |
119 | Pixera
120 |
121 |
122 |
123 | -
124 |
125 |
126 | Resize image
127 |
128 |
129 |
130 |
131 |
132 |
133 | -
134 |
135 |
136 | Direction to average pixels
137 |
138 |
139 |
-
140 |
141 |
142 | Vertical
143 |
144 |
145 | true
146 |
147 |
148 |
149 | -
150 |
151 |
152 | Horizontal
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 | -
165 |
166 |
167 |
168 | 0
169 | 0
170 |
171 |
172 |
173 |
174 | 600
175 | 0
176 |
177 |
178 |
179 | Image
180 |
181 |
182 |
183 |
184 | -
185 |
186 |
187 | RGB Plot
188 |
189 |
190 |
191 |
192 |
193 |
194 |
204 |
205 |
206 |
207 |
208 |
209 |
--------------------------------------------------------------------------------
/PythonGUI_apps/Lifetime_analysis/Fit_functions.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | """
3 | Created on Fri Mar 29 11:21:59 2019
4 |
5 | @author: Sarthak
6 | """
7 |
8 | import numpy as np
9 | from scipy.optimize import differential_evolution
10 | from scipy.special import gamma
11 |
12 | def stretch_exp_fit(TRPL, t, Tc = (0,1e5), Beta = (0,1), A = (0,1e6), noise=(0,1e6)):
13 |
14 | def exp_stretch(t, tc, beta, a, noise):
15 | return ((a * np.exp(-((1.0 / tc) * t) ** beta)) + noise)
16 |
17 | def avg_tau_from_exp_stretch(tc, beta):
18 | return (tc / beta) * gamma(1.0 / beta)
19 |
20 | def Diff_Ev_Fit_SE(TRPL):
21 | TRPL = TRPL
22 |
23 | def residuals(params):#params are the parameters to be adjusted by differential evolution or leastsq, interp is the data to compare to the model.
24 | #Variable Rates
25 | tc = params[0]
26 | beta = params[1]
27 | a = params[2]
28 | noise = params[3]
29 |
30 | PL_sim = exp_stretch(t,tc,beta,a, noise)
31 |
32 | Resid= np.sum(((PL_sim-TRPL)**2)/(np.sqrt(TRPL)**2))
33 | return Resid #returns the difference between the PL data and simulated data
34 |
35 | bounds = [Tc, Beta, A, noise]
36 |
37 | result = differential_evolution(residuals, bounds)
38 | return result.x
39 |
40 | p = Diff_Ev_Fit_SE(TRPL)
41 |
42 | tc = p[0]
43 | beta = p[1]
44 | a = p[2]
45 | noise = p[3]
46 |
47 | PL_fit = exp_stretch(t,tc,beta,a, noise)
48 |
49 | avg_tau = avg_tau_from_exp_stretch(tc,beta)
50 |
51 | return tc, beta, a, avg_tau, PL_fit, noise
52 |
53 | def double_exp_fit(TRPL, t, tau1_bounds=(0,1000), a1_bounds=(0,1e6), tau2_bounds=(0,10000), a2_bounds=(0,1e5), noise=(0,1e6)):
54 |
55 | def single_exp(t, tau, a):
56 | return (a * np.exp(-((1.0 / tau)*t)))
57 |
58 | def double_exp(t, tau1, a1, tau2, a2, noise):
59 | return ((single_exp(t, tau1, a1)) + (single_exp(t, tau2, a2)) + noise)
60 |
61 | def avg_tau_from_double_exp(tau1, a1, tau2, a2):
62 | return (((tau1*a1) + (tau2*a2))/(a1+a2))
63 |
64 | def Diff_Ev_Fit_DE(TRPL):
65 | TRPL = TRPL
66 |
67 | def residuals(params):#params are the parameters to be adjusted by differential evolution or leastsq, interp is the data to compare to the model.
68 | #Variable Rates
69 | tau1 = params[0]
70 | a1 = params[1]
71 | tau2 = params[2]
72 | a2 = params[3]
73 | noise = params[4]
74 |
75 | PL_sim = double_exp(t,tau1, a1, tau2, a2, noise)
76 |
77 | Resid= np.sum(((PL_sim-TRPL)**2)/(np.sqrt(TRPL)**2))
78 | return Resid #returns the difference between the PL data and simulated data
79 |
80 | bounds = [tau1_bounds, a1_bounds, tau2_bounds, a2_bounds, noise]
81 |
82 | result = differential_evolution(residuals, bounds)
83 | return result.x
84 |
85 | p = Diff_Ev_Fit_DE(TRPL)
86 |
87 | tau1 = p[0]
88 | a1 = p[1]
89 | tau2 = p[2]
90 | a2 = p[3]
91 | noise = p[4]
92 |
93 | PL_fit = double_exp(t, tau1, a1, tau2, a2, noise)
94 |
95 | avg_tau = avg_tau_from_double_exp(tau1, a1, tau2, a2)
96 |
97 | return tau1, a1, tau2, a2, avg_tau, PL_fit, noise
98 |
99 | def single_exp_fit(TRPL, t, tau_bounds=(0,10000), a_bounds=(0,1e6), noise=(0,1e6)):
100 |
101 | def single_exp(t, tau, a, noise):
102 | return (a * np.exp(-((1.0 / tau)*t) ) + noise)
103 |
104 | def Diff_Ev_Fit_singleExp(TRPL):
105 | TRPL = TRPL
106 |
107 | def residuals(params):#params are the parameters to be adjusted by differential evolution or leastsq, interp is the data to compare to the model.
108 | #Variable Rates
109 | tau = params[0]
110 | a = params[1]
111 | noise = params[2]
112 |
113 | PL_sim = single_exp(t, tau, a, noise)
114 |
115 | Resid= np.sum(((PL_sim-TRPL)**2)/(np.sqrt(TRPL)**2))
116 | return Resid #returns the difference between the PL data and simulated data
117 |
118 | bounds = [tau_bounds, a_bounds, noise]
119 |
120 | result = differential_evolution(residuals, bounds)
121 | return result.x
122 |
123 | p = Diff_Ev_Fit_singleExp(TRPL)
124 |
125 | tau = p[0]
126 | a = p[1]
127 | noise = p[2]
128 |
129 | PL_fit = single_exp(t, tau, a, noise)
130 |
131 | return tau, a, PL_fit, noise
132 |
--------------------------------------------------------------------------------
/PythonGUI_apps/Lifetime_analysis/Fit_functions_with_irf.py:
--------------------------------------------------------------------------------
1 | import numpy as np
2 | import matplotlib.pyplot as plt
3 | from scipy.optimize import fmin_tnc, differential_evolution
4 | from scipy.special import gamma
5 | from scipy.signal import fftconvolve
6 | from scipy.integrate import odeint
7 |
8 |
9 | """Fit TCSPC data to a model by reconvolution with the IRF
10 | Convolution is done in time domain with np.convolve()
11 | Convolution can be done in the frequency domain of np.convolve() is replaced by scipy.signal.fftconvolve()
12 |
13 | For a good tutorial on numerical convolution, see section 13.1 of Numerical Recipes:
14 |
15 | Press, W. H.; Teukolsky, S. A.; Vetterling, W. T.; Flannery, B. P.,
16 | Numerical Recipes 3rd Edition: The Art of Scientific Computing. 3 ed.;
17 | Cambridge University Press: New York, 2007
18 |
19 | ***Note that algorithm given in Numerical Recipes does convolution in the frequency
20 | domain using the FFT. However the discussion of convolution in 13.1 applies to the time
21 | domain and can be used to understand this Python code.***
22 |
23 | -MZ, 2/2017
24 | """
25 |
26 | def convolve_sig_resp(signal_array, response_array, t_array, tstep):
27 |
28 | def normalize_response(response_array, t_array):
29 | area = np.trapz(response_array, x = t_array)
30 | return response_array / area
31 |
32 | def array_zeropad_neg(array, pad_length):
33 |
34 | return np.pad(array, (pad_length, 0), 'constant', constant_values = (0,0))
35 |
36 | def array_zeropad_pos(array, pad_length):
37 | return np.pad(array, (0, pad_length), 'constant', constant_values = (0,0))
38 |
39 | # def array_symmetricpad_neg(array, pad_length):
40 | #
41 | # return np.pad(array, (pad_length, 0), 'symmetric')
42 |
43 | def signal_and_resp_forconv(signal_array, response_array):
44 | resp_pad_negtime = array_zeropad_neg(normalize_response(response_array, t_array), len(response_array) - 1)
45 | sig_pad_negtime = array_zeropad_neg(signal_array, len(signal_array) - 1)
46 | sig_pad_postime = array_zeropad_pos(sig_pad_negtime, len(response_array))
47 | return [resp_pad_negtime, sig_pad_postime]
48 |
49 | resp, sig = signal_and_resp_forconv(signal_array, response_array)
50 | convolution = tstep * fftconvolve(sig, resp, mode = 'same')#np.convolve(resp, sig, mode = 'same')
51 |
52 | return convolution[len(signal_array) - 1 : (2*len(signal_array)) - 1]
53 |
54 | def convolution_plusnoise(signal_array, response_array, t_array, tstep, noiselevel):
55 | return convolve_sig_resp(signal_array, response_array, t_array, tstep) + noiselevel
56 |
57 | def herz_ode(t, n0, params):
58 | a = params[0]
59 | k1 = params[1]
60 | k2 = params[2]
61 | k3 = params[3]
62 | def odefun(n, t, k1, k2, k3):
63 | dndt = -(k1 * n) - (k2 * (n ** 2.0)) - (k3 * (n ** 3.0))
64 | return dndt
65 | ode_sol = odeint(odefun, n0, t, args = (k1, k2, k3))[:,0]
66 | pl = k2 * (ode_sol ** 2.0)
67 | return a*pl
68 |
69 | def fit_herz_ode_global_3traces_fmin_tnc(t1, t2, t3, tstep, d1, d2, d3, irf, init_params, bounds, n0array):
70 | time_array1 = t1
71 | time_array2 = t2
72 | time_array3 = t3
73 | data_array1 = d1
74 | data_array2 = d2
75 | data_array3 = d3
76 | n0 = n0array[0]
77 | n1 = n0array[1]
78 | n2 = n0array[2]
79 | def min_fit_decay(params):
80 | #Minimize chi-squre for data set with Poisson distribution ()
81 |
82 | a0 = params[0]
83 | a1 = params[1]
84 | a2 = params[2]
85 | k1 = params[3]
86 | k2 = params[4]
87 | k3 = params[5]
88 | noise1 = params[6]
89 | noise2 = params[7]
90 | noise3 = params[8]
91 | decaymodel1 = herz_ode(time_array1, n0, np.array([a0,k1,k2,k3]))
92 | decaymodel2 = herz_ode(time_array2, n1, np.array([a1,k1,k2,k3]))
93 | decaymodel3 = herz_ode(time_array3, n2, np.array([a2,k1,k2,k3]))
94 | model1 = convolution_plusnoise(decaymodel1, irf, time_array1, tstep, noise1)
95 | model2 = convolution_plusnoise(decaymodel2, irf, time_array2, tstep, noise2)
96 |
97 | model3 = convolution_plusnoise(decaymodel3, irf, time_array3, tstep, noise3)
98 |
99 | data_fit_idx1 = np.nonzero(data_array1)
100 | data_fit_idx2 = np.nonzero(data_array2)
101 | data_fit_idx3 = np.nonzero(data_array3)
102 | data_array_fit1 = data_array1[data_fit_idx1]
103 | data_array_fit2 = data_array2[data_fit_idx2]
104 | data_array_fit3 = data_array3[data_fit_idx3]
105 |
106 | model_fit1 = model1[data_fit_idx1]
107 | model_fit2 = model2[data_fit_idx2]
108 | model_fit3 = model3[data_fit_idx3]
109 |
110 | min1 = np.sum(((data_array_fit1 - model_fit1)** 2.0) / (np.sqrt(data_array_fit1) ** 2.0))
111 | min2 = np.sum(((data_array_fit2 - model_fit2)** 2.0) / (np.sqrt(data_array_fit2) ** 2.0))
112 | min3 = np.sum(((data_array_fit3 - model_fit3)** 2.0) / (np.sqrt(data_array_fit3) ** 2.0))
113 | return np.sqrt((min1 ** 2.0) + (min2 ** 2.0) + (min3 ** 2.0))
114 | bestfit_params = fmin_tnc(min_fit_decay, init_params, approx_grad = True, bounds = bounds)[0]
115 | def bestfit_decay(params):
116 | a0 = params[0]
117 | a1 = params[1]
118 | a2 = params[2]
119 | k1 = params[3]
120 | k2 = params[4]
121 | k3 = params[5]
122 | noise1 = params[6]
123 | # noise2 = params[7]
124 | # noise3 = params[8]
125 | decaymodel1 = herz_ode(time_array, n0, np.array([a0,k1,k2,k3]))
126 | decaymodel2 = herz_ode(time_array, n1, np.array([a1,k1,k2,k3]))
127 | decaymodel3 = herz_ode(time_array, n2, np.array([a2,k1,k2,k3]))
128 |
129 | model1 = convolution_plusnoise(decaymodel1, irf, time_array, tstep, noise1)
130 | model2 = convolution_plusnoise(decaymodel2, irf, time_array, tstep, noise2)
131 | model3 = convolution_plusnoise(decaymodel3, irf, time_array, tstep, noise3)
132 | return [model1, model2, model3]
133 |
134 | bestfit_model = bestfit_decay(bestfit_params)
135 | # plt.figure()
136 | # plt.ylabel('PL Counts')
137 | # plt.xlabel('Time (ns)')
138 | # plt.semilogy(time_array1, data_array1,'b', label = 'Data')
139 | # plt.semilogy(time_array1, bestfit_model[0], 'r', label = 'Fit')
140 | # plt.semilogy(time_array2, data_array2,'b', label = 'Data')
141 | # plt.semilogy(time_array2, bestfit_model[1], 'r', label = 'Fit')
142 | # plt.semilogy(time_array3, data_array3,'b', label = 'Data')
143 | # plt.semilogy(time_array3, bestfit_model[2], 'r', label = 'Fit')
144 | # plt.legend(loc = 'best')
145 | return bestfit_params, bestfit_model, data_array, time_array, irf
146 |
147 | def multi_exp(t, params, num_exp):
148 | exp_array = np.empty((len(t), num_exp))
149 |
150 | i = 0
151 | while (i" % (self.res, len(self.data))
199 |
200 |
201 | def timefmt(t):
202 | d = datetime.datetime.fromtimestamp(t)
203 | return d.strftime("%a %b %d %H:%M:%S %Y")
204 |
205 |
206 | class PicoharpParser(object):
207 | _ready = False
208 |
209 | def __init__(self, filename):
210 | if isinstance(filename, (str)): # , unicode)):
211 | filename = open(filename, mode="rb")
212 | self.f = filename
213 | self._prepare()
214 |
215 | def _prepare(self):
216 | self.f.seek(0)
217 |
218 | header = self._header = _read(self.f, TxtHdr)
219 | """SJ commented this --- it was giving ParseError"""
220 | # _validate_header(header)
221 |
222 | bin_header = self._bin_header = _read(self.f, BinHdr)
223 |
224 | self._boards = []
225 | for i in range(bin_header.NumberOfBoards):
226 | self._boards.append(_read(self.f, BoardHdr))
227 |
228 | self._curves = []
229 | for i in range(bin_header.Curves):
230 | self._curves.append(_read(self.f, CurveHdr))
231 |
232 | def header(self):
233 | return [(k, getattr(self._header, k)) for k, t in self._header._fields_]
234 |
235 | def no_of_curves(self):
236 | return self._bin_header.Curves
237 |
238 | def get_curve(self, n):
239 | header = self._curves[n]
240 | res = header.Resolution
241 |
242 | self.f.seek(header.DataOffset)
243 | array = np.fromfile(self.f, c_uint, header.Channels)
244 |
245 | return res, array
246 |
247 | def get_all_curves(self):
248 | all_curves = []
249 | for i in range(len(self._curves)):
250 | all_curves.append(self.get_curve(i))
251 |
252 | return all_curves
253 |
254 | def get_time_window_in_ns(self, curve_no):
255 | curve = self._curves[curve_no]
256 | rep_rate = curve.InpRate0
257 | res, _ = self.get_curve(curve_no)
258 | time_window_s = (1 / rep_rate) / res # in seconds
259 |
260 | return time_window_s * 1e9 # in nannoseconds
261 |
262 | def get_integral_counts(self, curve_no):
263 | curve = self._curves[curve_no]
264 | integral_counts = curve.IntegralCount
265 |
266 | return integral_counts
267 |
268 | def info(self):
269 | txthdr = self._header
270 | binhdr = self._bin_header
271 | boards = self._boards
272 | curves = self._curves
273 | r = []
274 | w = r.append
275 | yesno = lambda x: "true" if x else "false"
276 |
277 | w("Ident : %s" % txthdr.Ident)
278 | w("Format Version : %s" % txthdr.FormatVersion)
279 | w("Creator Name : %s" % txthdr.CreatorName)
280 | w("Creator Version : %s" % txthdr.CreatorVersion)
281 | w("Time of Creation : %s" % txthdr.FileTime)
282 | w("File Comment : %s" % txthdr.CommentField)
283 |
284 | w("No of Curves : %s" % binhdr.Curves)
285 | w("Bits per HistoBin: %s" % binhdr.BitsPerHistoBin)
286 | w("RoutingChannels : %s" % binhdr.RoutingChannels)
287 | w("No of Boards : %s" % binhdr.NumberOfBoards)
288 | w("Active Curve : %s" % binhdr.ActiveCurve)
289 | w("Measurement Mode : %s" % binhdr.MeasMode)
290 | w("Sub-Mode : %s" % binhdr.SubMode)
291 | w("Range No : %s" % binhdr.RangeNo)
292 | w("Offset : %s" % binhdr.Offset)
293 | w("AcquisitionTime : %s" % binhdr.Tacq)
294 | w("Stop at : %s" % binhdr.StopAt)
295 | w("Stop on Ovfl. : %s" % binhdr.StopOnOvfl)
296 | w("Restart : %s" % binhdr.Restart)
297 | w("DispLinLog : %s" % binhdr.DispLinLog)
298 | w("DispTimeAxisFrom : %s" % binhdr.DispTimeFrom)
299 | w("DispTimeAxisTo : %s" % binhdr.DispTimeTo)
300 | w("DispCountAxisFrom: %s" % binhdr.DispCountsFrom)
301 | w("DispCountAxisTo : %s" % binhdr.DispCountsTo)
302 |
303 | for i in range(DISPCURVES):
304 | w("---------------------")
305 | w("Curve No %s" % i)
306 | w(" MapTo : %s" % binhdr.DispCurves[i].MapTo)
307 | w(" Show : %s" % yesno(binhdr.DispCurves[i].Show))
308 | w("---------------------")
309 |
310 | for i in range(3):
311 | w("---------------------")
312 | w("Parameter No %s" % i)
313 | w(" Start : %f" % binhdr.Params[i].Start)
314 | w(" Step : %f" % binhdr.Params[i].Step)
315 | w(" End : %f" % binhdr.Params[i].End)
316 | w("---------------------")
317 |
318 | w("Repeat Mode : %d" % binhdr.RepeatMode)
319 | w("Repeats per Curve: %d" % binhdr.RepeatsPerCurve)
320 | w("Repeat Time : %d" % binhdr.RepeatTime)
321 | w("Repeat wait Time : %d" % binhdr.RepeatWaitTime)
322 | w("Script Name : %s" % binhdr.ScriptName)
323 |
324 | for i, board in enumerate(boards):
325 | w("---------------------")
326 | w("Board No %d" % i)
327 | w(" HardwareIdent : %s" % board.HardwareIdent)
328 | w(" HardwareVersion : %s" % board.HardwareVersion)
329 | w(" HardwareSerial : %d" % board.HardwareSerial)
330 | w(" SyncDivider : %d" % board.SyncDivider)
331 | w(" CFDZeroCross0 : %d" % board.CFDZeroCross0)
332 | w(" CFDLevel0 : %d" % board.CFDLevel0)
333 | w(" CFDZeroCross1 : %d" % board.CFDZeroCross1)
334 | w(" CFDLevel1 : %d" % board.CFDLevel1)
335 | w(" Resolution : %.6f" % board.Resolution)
336 |
337 | if board.RouterModelCode:
338 | w(" RouterModelCode : %d" % board.RouterModelCode)
339 | w(" RouterEnabled : %d" % board.RouterEnabled)
340 |
341 | w(" RtChan1_InputType : %d" % board.RtChan1_InputType)
342 | w(" RtChan1_InputLevel : %d" % board.RtChan1_InputLevel)
343 | w(" RtChan1_InputEdge : %d" % board.RtChan1_InputEdge)
344 | w(" RtChan1_CFDPresent : %d" % board.RtChan1_CFDPresent)
345 | w(" RtChan1_CFDLevel : %d" % board.RtChan1_CFDLevel)
346 | w(" RtChan1_CFDZeroCross : %d" % board.RtChan1_CFDZeroCross)
347 |
348 | w(" RtChan2_InputType : %d" % board.RtChan2_InputType)
349 | w(" RtChan2_InputLevel : %d" % board.RtChan2_InputLevel)
350 | w(" RtChan2_InputEdge : %d" % board.RtChan2_InputEdge)
351 | w(" RtChan2_CFDPresent : %d" % board.RtChan2_CFDPresent)
352 | w(" RtChan2_CFDLevel : %d" % board.RtChan2_CFDLevel)
353 | w(" RtChan2_CFDZeroCross : %d" % board.RtChan2_CFDZeroCross)
354 |
355 | w(" RtChan3_InputType : %d" % board.RtChan3_InputType)
356 | w(" RtChan3_InputLevel : %d" % board.RtChan3_InputLevel)
357 | w(" RtChan3_InputEdge : %d" % board.RtChan3_InputEdge)
358 | w(" RtChan3_CFDPresent : %d" % board.RtChan3_CFDPresent)
359 | w(" RtChan3_CFDLevel : %d" % board.RtChan3_CFDLevel)
360 | w(" RtChan3_CFDZeroCross : %d" % board.RtChan3_CFDZeroCross)
361 |
362 | w(" RtChan4_InputType : %d" % board.RtChan4_InputType)
363 | w(" RtChan4_InputLevel : %d" % board.RtChan4_InputLevel)
364 | w(" RtChan4_InputEdge : %d" % board.RtChan4_InputEdge)
365 | w(" RtChan4_CFDPresent : %d" % board.RtChan4_CFDPresent)
366 | w(" RtChan4_CFDLevel : %d" % board.RtChan4_CFDLevel)
367 | w(" RtChan4_CFDZeroCross : %d" % board.RtChan4_CFDZeroCross)
368 |
369 | w("---------------------")
370 |
371 | for i, curve in enumerate(curves):
372 | w("---------------------")
373 | w("Curve Index : %d" % curve.CurveIndex)
374 | w("Time of Recording : %s" % timefmt(curve.TimeOfRecording))
375 | w("HardwareIdent : %s" % curve.HardwareIdent)
376 | w("HardwareVersion : %s" % curve.HardwareVersion)
377 | w("HardwareSerial : %d" % curve.HardwareSerial)
378 | w("SyncDivider : %d" % curve.SyncDivider)
379 | w("CFDZeroCross0 : %d" % curve.CFDZeroCross0)
380 | w("CFDLevel0 : %d" % curve.CFDLevel0)
381 | w("CFDZeroCross1 : %d" % curve.CFDZeroCross1)
382 | w("CFDLevel1 : %d" % curve.CFDLevel1)
383 | w("Offset : %d" % curve.Offset)
384 | w("RoutingChannel : %d" % curve.RoutingChannel)
385 | w("ExtDevices : %d" % curve.ExtDevices)
386 | w("Meas. Mode : %d" % curve.MeasMode)
387 | w("Sub-Mode : %d" % curve.SubMode)
388 | w("Par. 1 : %f" % curve.P1)
389 | w("Par. 2 : %.6f" % curve.P2)
390 | w("Par. 3 : %.6f" % curve.P3)
391 | w("Range No : %d" % curve.RangeNo)
392 | w("Resolution : %f" % curve.Resolution)
393 | w("Channels : %d" % curve.Channels)
394 | w("Acq. Time : %d" % curve.Tacq)
395 | w("Stop after : %d" % curve.StopAfter)
396 | w("Stop Reason : %d" % curve.StopReason)
397 | w("InpRate0 : %d" % curve.InpRate0)
398 | w("InpRate1 : %d" % curve.InpRate1)
399 | w("HistCountRate : %d" % curve.HistCountRate)
400 | w("IntegralCount : %d" % curve.IntegralCount)
401 | w("reserved : %d" % curve.reserved)
402 | w("dataoffset : %d" % curve.DataOffset)
403 |
404 | if curve.RouterModelCode:
405 | w("RouterModelCode : %d" % curve.RouterModelCode)
406 | w("RouterEnabled : %d" % curve.RouterEnabled)
407 | w("RtChan_InputType : %d" % curve.RtChan_InputType)
408 | w("RtChan_InputLevel : %d" % curve.RtChan_InputLevel)
409 | w("RtChan_InputEdge : %d" % curve.RtChan_InputEdge)
410 | w("RtChan_CFDPresent : %d" % curve.RtChan_CFDPresent)
411 | w("RtChan_CFDLevel : %d" % curve.RtChan_CFDLevel)
412 | w("RtChan_CFDZeroCross : %d" % curve.RtChan_CFDZeroCross)
413 |
414 | return "\n".join(r)
415 |
--------------------------------------------------------------------------------
/PythonGUI_apps/Lifetime_analysis/read_ph_phd.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | """
3 | Created on Fri Apr 5 15:52:05 2019
4 |
5 | @author: Sarthak
6 | """
7 |
8 | try:
9 | from Lifetime_analysis import picoharp_phd
10 | except:
11 | import picoharp_phd
12 | import numpy as np
13 | import matplotlib.pyplot as plt
14 | #import sys
15 |
16 | #datafile = "E:/Python code/APTES_APTMS.phd"
17 |
18 |
19 | def read_picoharp_phd(datafile):
20 | parser = picoharp_phd.PicoharpParser(datafile)
21 | return parser
22 |
23 | #def phd_to_csv(datafile, return_df = False):
24 | # parser = read_picoharp_phd(datafile)
25 | # name, ext = datafile.rsplit('.', 1)
26 | #
27 | # total_curves = parser.no_of_curves()
28 | # y = []
29 | # for i in range(total_curves):
30 | # res, curve = parser.get_curve(i)
31 | # time_window = int(np.floor(parser.get_time_window_in_ns(curve_no)))
32 | # curve = curve[0:time_window]
33 | # y.append(curve)
34 | #
35 | # df = pd.DataFrame(y)
36 | # df.T.to_csv(name+".csv", index=False, header=False)
37 | # if return_df == True:
38 | # return df.T
39 |
40 | def smooth(curve, boxwidth):
41 | sm_curve = np.convolve(curve, np.ones(boxwidth)/boxwidth, mode="same")
42 | return sm_curve
43 |
44 | def get_x_y(curve_no, parser, smooth_trace = False, boxwidth = 3):
45 |
46 | assert type(parser) == picoharp_phd.PicoharpParser, 'must be picoharp parser'
47 | res, curve = parser.get_curve(curve_no)
48 | time_window = int(np.floor(parser.get_time_window_in_ns(curve_no)))
49 | curve = curve[0:time_window]
50 | size = len(curve)
51 | x = np.arange(0, size*res, res, np.float)
52 | if smooth_trace == True:
53 | curve = smooth(curve, boxwidth=boxwidth)
54 | return x,curve
55 |
--------------------------------------------------------------------------------
/PythonGUI_apps/Lifetime_analysis/skip_rows.ui:
--------------------------------------------------------------------------------
1 |
2 |
3 | Form
4 |
5 |
6 |
7 | 0
8 | 0
9 | 413
10 | 94
11 |
12 |
13 |
14 | Enter rows to skip
15 |
16 |
17 | -
18 |
19 |
20 | Rows to skip
21 |
22 |
23 |
24 | -
25 |
26 |
27 | 10
28 |
29 |
30 |
31 | -
32 |
33 |
34 | Done
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
--------------------------------------------------------------------------------
/PythonGUI_apps/OceanOptics_acquire/OO_acquire_gui.ui:
--------------------------------------------------------------------------------
1 |
2 |
3 | MainWindow
4 |
5 |
6 |
7 | 0
8 | 0
9 | 1206
10 | 668
11 |
12 |
13 |
14 | MainWindow
15 |
16 |
17 |
18 | -
19 |
20 |
-
21 |
22 |
23 |
24 | 15
25 |
26 |
27 |
28 | Acquire Settings
29 |
30 |
31 |
-
32 |
33 |
34 |
35 | 15
36 |
37 |
38 |
39 | Save Settings
40 |
41 |
42 |
-
43 |
44 |
45 |
46 | 12
47 |
48 |
49 |
50 | Configure Folder to Save
51 |
52 |
53 |
54 | -
55 |
56 |
57 |
58 | 12
59 |
60 |
61 |
62 | Save Every Spectrum
63 |
64 |
65 |
66 | -
67 |
68 |
69 |
70 | 12
71 |
72 |
73 |
74 | Save Single Spectrum
75 |
76 |
77 |
78 |
79 |
80 |
81 | -
82 |
83 |
84 |
85 | 12
86 |
87 |
88 |
89 | Correct Dark Counts
90 |
91 |
92 | true
93 |
94 |
95 |
96 | -
97 |
98 |
99 |
100 | 15
101 |
102 |
103 |
104 | Close Connection
105 |
106 |
107 |
108 | -
109 |
110 |
111 |
112 | 12
113 |
114 |
115 |
116 |
117 | -
118 |
119 |
120 |
121 | 15
122 |
123 |
124 |
125 | ALWAYS CLOSE CONNECTION!!!
126 | BEFORE EXITING APP
127 |
128 |
129 |
130 | -
131 |
132 |
133 |
134 | 12
135 |
136 |
137 |
138 | Intg. Time (ms)
139 |
140 |
141 |
142 | -
143 |
144 |
145 |
146 | 12
147 |
148 |
149 |
150 | Scans to Average
151 |
152 |
153 |
154 | -
155 |
156 |
157 |
158 | 10
159 |
160 |
161 |
162 | 3
163 |
164 |
165 | 3000
166 |
167 |
168 |
169 | -
170 |
171 |
172 |
173 | 10
174 |
175 |
176 |
177 | 1
178 |
179 |
180 |
181 | -
182 |
183 |
184 |
185 | 15
186 |
187 |
188 |
189 | Live
190 |
191 |
192 |
193 | -
194 |
195 |
196 |
197 | 12
198 |
199 |
200 |
201 | Connect to Spectrometer
202 |
203 |
204 |
205 |
206 |
207 |
208 |
209 |
210 | -
211 |
212 |
-
213 |
214 |
215 |
216 |
217 |
218 |
219 |
229 |
230 |
231 |
232 |
233 | PlotWidget
234 | QGraphicsView
235 |
236 |
237 |
238 |
239 |
240 |
241 |
--------------------------------------------------------------------------------
/PythonGUI_apps/OceanOptics_acquire/OceanOptics_acquire_plot.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | """
3 | Created on Wed Mar 27 16:50:26 2019
4 |
5 | @author: Sarthak
6 | """
7 |
8 | import pyqtgraph as pg
9 | from pyqtgraph.Qt import QtCore, QtGui, QtWidgets#, QColorDialog
10 | import numpy as np
11 | import pickle
12 | import sys
13 | import seabreeze.spectrometers as sb
14 | from pipython import GCSDevice
15 | import time
16 |
17 | pg.mkQApp()
18 | pg.setConfigOption('background', 'w')
19 |
20 | #uiFile = "OO_acquire_gui.ui" "OO_PZstageScan_acquire_gui"
21 | uiFile = "OO_PZstageScan_acquire_gui.ui"
22 |
23 | WindowTemplate, TemplateBaseClass = pg.Qt.loadUiType(uiFile)
24 |
25 | class MainWindow(TemplateBaseClass):
26 |
27 | def __init__(self):
28 | TemplateBaseClass.__init__(self)
29 |
30 | # Create the main window
31 | self.ui = WindowTemplate()
32 | self.ui.setupUi(self)
33 |
34 | self.ui.connect_checkBox.stateChanged.connect(self._handle_spectrometer_connection)
35 | self.ui.live_pushButton.clicked.connect(self.live)
36 |
37 | self.ui.path_to_folder_pushButton.clicked.connect(self.save_file_location)
38 | self.ui.save_single_spec_pushButton.clicked.connect(self.save_single_spec)
39 |
40 | self.ui.init_stage_pushButton.clicked.connect(self.init_piezo_stage)
41 | self.ui.show_curr_pos_pushButton.clicked.connect(self.current_piezo_stage_pos)
42 | self.ui.center_stage_pushButton.clicked.connect(self.center_piezo)
43 | self.ui.abs_mov_pushButton.clicked.connect(self.abs_mov)
44 | self.ui.rel_mov_pushButton.clicked.connect(self.rel_mov)
45 | self.ui.estimate_scan_time_pushButton.clicked.connect(self.estimate_scan_time)
46 | self.ui.start_x_y_sacan_pushButton.clicked.connect(self.x_y_scan)
47 |
48 | # self.ui.clear_pushButton.clicked.connect(self.clear_plot)
49 | self.pi_device = None
50 | self.spec = None
51 |
52 | self.ui.status_textBrowser.setText("Welcome!\nGUI Initiated!")
53 |
54 | self.show()
55 |
56 | def _handle_spectrometer_connection(self):
57 | if self.ui.connect_checkBox.isChecked():
58 | self.connect_spectrometer()
59 | else:
60 | self.close_connection()
61 |
62 | def connect_spectrometer(self):
63 | if self.spec is None:
64 | devices = sb.list_devices()
65 | self.spec = sb.Spectrometer(devices[0])
66 | self.ui.status_textBrowser.append("Ocean Optics Device Connected!\n\n Device:\n\n"+str(sb.list_devices()[0]))
67 | else:
68 | self.ui.status_textBrowser.append("Already Connected")
69 |
70 | def init_piezo_stage(self):
71 | if self.pi_device is None:
72 | self.pi_device = GCSDevice("E-710") # Creates a Controller instant
73 | self.pi_device.ConnectNIgpib(board=0,device=4) # Connect to GPIB board
74 | self.ui.status_textBrowser.append('Connected: {}'.format(self.pi_device.qIDN().strip()))
75 | # print('connected: {}'.format(self.pi_device.qIDN().strip()))
76 |
77 | self.axes = self.pi_device.axes[0:2] # selecting x and y axis of the stage
78 |
79 | self.pi_device.INI()
80 | self.pi_device.REF(axes=self.axes)
81 |
82 | self.pi_device.SVO(axes=self.axes, values=[True,True]) # Turn on servo control for both axes
83 | self.ui.status_textBrowser.append("Current Stage Position:\n{}".format(self.pi_device.qPOS(axes=self.axes)))
84 | # print(self.pi_device.qPOS(axes=self.axes))
85 | else:
86 | self.ui.status_textBrowser.append("Piezo Stage Is Already Initialized!")
87 |
88 | def center_piezo(self):
89 | if self.pi_device is None:
90 | self.init_piezo_stage()
91 | self.pi_device.MOV(axes=self.axes, values=[50,50])
92 | self.ui.status_textBrowser.append("Piezo Stage Centered: [50x,50y]")
93 |
94 | def current_piezo_stage_pos(self):
95 | if self.pi_device is None:
96 | self.init_piezo_stage()
97 | self.ui.status_textBrowser.append("Current Stage Position:\n{}".format(self.pi_device.qPOS(axes=self.axes)))
98 |
99 | def abs_mov(self):
100 | if self.pi_device is None:
101 | self.init_piezo_stage()
102 | x_abs_pos = self.ui.x_abs_doubleSpinBox.value()
103 | y_abs_pos = self.ui.y_abs_doubleSpinBox.value()
104 | self.pi_device.MOV(axes=self.axes, values=[x_abs_pos,y_abs_pos])
105 |
106 | def rel_mov(self):
107 | if self.pi_device is None:
108 | self.init_piezo_stage()
109 | x_rel_pos = self.ui.x_rel_doubleSpinBox.value()
110 | y_rel_pos = self.ui.y_rel_doubleSpinBox.value()
111 | self.pi_device.MVR(axes=self.axes, values=[x_rel_pos,y_rel_pos])
112 |
113 | def estimate_scan_time(self):
114 | x_scan_size = self.ui.x_size_doubleSpinBox.value()
115 | y_scan_size = self.ui.y_size_doubleSpinBox.value()
116 |
117 | x_step = self.ui.x_step_doubleSpinBox.value()
118 | y_step = self.ui.y_step_doubleSpinBox.value()
119 |
120 | if y_scan_size == 0:
121 | y_scan_size = 1
122 |
123 | if x_scan_size == 0:
124 | x_scan_size = 1
125 |
126 | if y_step == 0:
127 | y_step = 1
128 |
129 | if x_step == 0:
130 | x_step = 1
131 |
132 | y_range = int(np.ceil(y_scan_size/y_step))
133 | x_range = int(np.ceil(x_scan_size/x_step))
134 |
135 | total_points = x_range*y_range
136 |
137 | intg_time_ms = self.ui.intg_time_spinBox.value()
138 | scans_to_avg = self.ui.scan_to_avg_spinBox.value()
139 |
140 | total_time = total_points*(intg_time_ms*1e-3)*(scans_to_avg) # in seconds
141 |
142 | self.ui.status_textBrowser.append("Estimated scan time: "+str(np.float16(total_time/60))+" mins")
143 |
144 | def x_y_scan(self):
145 | if self.pi_device is None:
146 | self.init_piezo_stage()
147 |
148 | if self.spec is None:
149 | self.ui.status_textBrowser.append("Spectrometer not connected!\nForce connecting the spectrometer...")
150 | self.connect_spectrometer()
151 |
152 | start_time = time.time()
153 | x_start = self.ui.x_start_doubleSpinBox.value()
154 | y_start = self.ui.y_start_doubleSpinBox.value()
155 |
156 | x_scan_size = self.ui.x_size_doubleSpinBox.value()
157 | y_scan_size = self.ui.y_size_doubleSpinBox.value()
158 |
159 | x_step = self.ui.x_step_doubleSpinBox.value()
160 | y_step = self.ui.y_step_doubleSpinBox.value()
161 |
162 | if y_scan_size == 0:
163 | y_scan_size = 1
164 |
165 | if x_scan_size == 0:
166 | x_scan_size = 1
167 |
168 | if y_step == 0:
169 | y_step = 1
170 |
171 | if x_step == 0:
172 | x_step = 1
173 |
174 | y_range = int(np.ceil(y_scan_size/y_step))
175 | x_range = int(np.ceil(x_scan_size/x_step))
176 |
177 | # Define empty array for saving intensities
178 | data_array = np.zeros(shape=(x_range*y_range,2048))
179 |
180 | self.ui.status_textBrowser.append("Starting Scan...")
181 | # Move to the starting position
182 | self.pi_device.MOV(axes=self.axes, values=[x_start,y_start])
183 |
184 | self.ui.status_textBrowser.append("Scan in Progress...")
185 |
186 | k = 0
187 | for i in range(y_range):
188 | for j in range(x_range):
189 | # print(self.pi_device.qPOS(axes=self.axes))
190 |
191 | self._read_spectrometer()
192 | data_array[k,:] = self.y
193 | self.ui.plot.plot(self.spec.wavelengths(), self.y, pen='r', clear=True)
194 | pg.QtGui.QApplication.processEvents()
195 |
196 | self.pi_device.MVR(axes=self.axes[0], values=[x_step])
197 |
198 | self.ui.progressBar.setValue(100*((k+1)/(x_range*y_range)))
199 | k+=1
200 | # TODO
201 | # if statement needs to be modified to keep the stage at the finish y-pos for line scans in x, and same for y
202 | if i == y_range-1: # this if statement is there to keep the stage at the finish position (in x) and not bring it back like we were doing during the scan
203 | self.pi_device.MVR(axes=self.axes[1], values=[y_step])
204 | else:
205 | self.pi_device.MVR(axes=self.axes, values=[-x_scan_size, y_step])
206 |
207 | self.ui.status_textBrowser.append("Scan Complete!\nSaving Data...")
208 |
209 | save_dict = {"Wavelengths": self.spec.wavelengths(), "Intensities": data_array,
210 | "Scan Parameters":{"X scan start (um)": x_start, "Y scan start (um)": y_start,
211 | "X scan size (um)": x_scan_size, "Y scan size (um)": y_scan_size,
212 | "X step size (um)": x_step, "Y step size (um)": y_step},
213 | "OceanOptics Parameters":{"Integration Time (ms)": self.ui.intg_time_spinBox.value(),
214 | "Scans Averages": self.ui.scan_to_avg_spinBox.value(),
215 | "Correct Dark Counts": self.ui.correct_dark_counts_checkBox.isChecked()}
216 | }
217 |
218 | pickle.dump(save_dict, open(self.save_folder+"/"+self.ui.lineEdit.text()+"_raw_PL_spectra_data.pkl", "wb"))
219 |
220 | self.ui.status_textBrowser.append("Data saved!\nTotal time taken:"+str(np.float16((time.time()-start_time)/60))+" mins")
221 |
222 | def save_file_location(self):
223 | self.save_folder = QtWidgets.QFileDialog.getExistingDirectory(self, caption="Select Folder")
224 |
225 | def save_single_spec(self):
226 | save_array = np.zeros(shape=(2048,2))
227 | self._read_spectrometer()
228 | save_array[:,1] = self.y
229 | save_array[:,0] = self.spec.wavelengths()
230 |
231 | np.savetxt(self.save_folder+"/"+self.ui.lineEdit.text()+".txt", save_array, fmt = '%.5f',
232 | header = 'Wavelength (nm), Intensity (counts)', delimiter = ' ')
233 |
234 | def live(self):
235 | save_array = np.zeros(shape=(2048,2))
236 |
237 | self.ui.plot.setLabel('left', 'Intensity', units='a.u.')
238 | self.ui.plot.setLabel('bottom', 'Wavelength', units='nm')
239 | j = 0
240 | while self.spec is not None:#self.ui.connect_checkBox.isChecked(): # this while loop works!
241 | self._read_spectrometer()
242 | save_array[:,1] = self.y
243 |
244 | self.ui.plot.plot(self.spec.wavelengths(), self.y, pen='r', clear=True)
245 |
246 | if self.ui.save_every_spec_checkBox.isChecked():
247 | save_array[:,0] = self.spec.wavelengths()
248 | np.savetxt(self.save_folder+"/"+self.ui.lineEdit.text()+str(j)+".txt", save_array, fmt = '%.5f',
249 | header = 'Wavelength (nm), Intensity (counts)', delimiter = ' ')
250 |
251 | pg.QtGui.QApplication.processEvents()
252 | j += 1
253 |
254 | def _read_spectrometer(self):
255 | if self.spec is not None:
256 |
257 | intg_time_ms = self.ui.intg_time_spinBox.value()
258 | self.spec.integration_time_micros(intg_time_ms*1e3)
259 |
260 | scans_to_avg = self.ui.scan_to_avg_spinBox.value()
261 | Int_array = np.zeros(shape=(2048,scans_to_avg))
262 |
263 | for i in range(scans_to_avg): #software average
264 | data = self.spec.spectrum(correct_dark_counts=self.ui.correct_dark_counts_checkBox.isChecked())
265 | Int_array[:,i] = data[1]
266 | self.y = np.mean(Int_array, axis=-1)
267 |
268 | else:
269 | self.ui.status_textBrowser.append("Connect to Spectrometer!")
270 | raise Exception("Must connect to spectrometer first!")
271 |
272 |
273 | def close_connection(self):
274 | if self.spec is not None:
275 | self.spec.close()
276 | self.ui.status_textBrowser.append("Ocean Optics Device Disconnected")
277 | del self.spec
278 | self.spec = None
279 |
280 | def close_application(self):
281 | choice = QtGui.QMessageBox.question(self, 'EXIT!',
282 | "Do you want to exit the app?",
283 | QtGui.QMessageBox.Yes | QtGui.QMessageBox.No)
284 | if choice == QtGui.QMessageBox.Yes:
285 | sys.exit()
286 | else:
287 | pass
288 |
289 |
290 | win = MainWindow()
291 |
292 |
293 | ## Start Qt event loop unless running in interactive mode or using pyside.
294 | if __name__ == '__main__':
295 | import sys
296 | if (sys.flags.interactive != 1) or not hasattr(QtCore, 'PYQT_VERSION'):
297 | QtGui.QApplication.instance().exec_()
298 |
--------------------------------------------------------------------------------
/PythonGUI_apps/PLQE_analysis/column_selection_gui.ui:
--------------------------------------------------------------------------------
1 |
2 |
3 | MainWindow
4 |
5 |
6 |
7 | 0
8 | 0
9 | 800
10 | 600
11 |
12 |
13 |
14 | Select number of columns
15 |
16 |
17 |
18 | -
19 |
20 |
21 | Data preview
22 |
23 |
24 |
25 |
26 | -
27 |
28 |
29 | Select data columns
30 |
31 |
32 |
-
33 |
34 |
-
35 |
36 |
37 | Ref
38 |
39 |
40 |
41 | -
42 |
43 |
44 | Inpath
45 |
46 |
47 |
48 | -
49 |
50 |
51 | Outpath
52 |
53 |
54 |
55 | -
56 |
57 |
58 | 2
59 |
60 |
61 |
62 | -
63 |
64 |
65 | 3
66 |
67 |
68 |
69 | -
70 |
71 |
72 | 4
73 |
74 |
75 |
76 | -
77 |
78 |
79 | Done
80 |
81 |
82 |
83 | -
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
103 |
104 |
105 |
106 |
107 |
108 |
--------------------------------------------------------------------------------
/PythonGUI_apps/PLQE_analysis/plqe_analysis.py:
--------------------------------------------------------------------------------
1 | # system imports
2 | from pathlib import Path
3 | import os.path
4 | import pyqtgraph as pg
5 | from pyqtgraph import exporters
6 | from pyqtgraph.Qt import QtCore, QtGui, QtWidgets
7 | import matplotlib.pyplot as plt
8 | import numpy as np
9 |
10 | # local modules
11 |
12 | pg.mkQApp()
13 | pg.setConfigOption('background', 'w')
14 |
15 | base_path = Path(__file__).parent
16 | file_path = (base_path / "plqe_analysis_gui.ui").resolve()
17 |
18 | uiFile = file_path
19 |
20 | WindowTemplate, TemplateBaseClass = pg.Qt.loadUiType(uiFile)
21 |
22 | """params for plotting"""
23 | plt.rc('xtick', labelsize = 20)
24 | plt.rc('xtick.major', pad = 3)
25 | plt.rc('ytick', labelsize = 20)
26 | plt.rc('lines', lw = 1.5, markersize = 7.5)
27 | plt.rc('legend', fontsize = 20)
28 | plt.rc('axes', linewidth = 3.5)
29 |
30 | class MainWindow(TemplateBaseClass):
31 |
32 | def __init__(self):
33 | super(TemplateBaseClass, self).__init__()
34 |
35 | # Create the main window
36 | self.ui = WindowTemplate()
37 | self.ui.setupUi(self)
38 |
39 | #setup uv vis plot
40 | self.plot = self.ui.plotWidget.getPlotItem()
41 | self.plot.setTitle(title="Wavelength vs. Intensity")
42 | self.plot.setLabel('bottom', 'Wavelength', unit='nm')
43 | self.plot.setLabel('left', 'Intensity', unit='a.u.')
44 | self.plot.setLogMode(x=None, y=1)
45 |
46 | #setup line rois for laser and emission
47 | self.laser_region = pg.LinearRegionItem(brush=QtGui.QBrush(QtGui.QColor(255, 0, 0, 50)))
48 | self.laser_region.sigRegionChanged.connect(self.update_laser_spinBoxes)
49 | self.emission_region = pg.LinearRegionItem()
50 | self.emission_region.sigRegionChanged.connect(self.update_emission_spinBoxes)
51 | self.laser_region.setRegion((200, 400))
52 | self.emission_region.setRegion((700, 800))
53 |
54 | #setup ui signals
55 | self.ui.load_data_pushButton.clicked.connect(self.open_data_file)
56 | self.ui.plot_pushButton.clicked.connect(self.plot_intensity)
57 | self.ui.clear_pushButton.clicked.connect(self.clear)
58 | self.ui.calculate_plqe_pushButton.clicked.connect(self.calculate_plqe)
59 | self.ui.laser_start_spinBox.valueChanged.connect(self.update_laser_region)
60 | self.ui.laser_stop_spinBox.valueChanged.connect(self.update_laser_region)
61 | self.ui.emission_start_spinBox.valueChanged.connect(self.update_emission_region)
62 | self.ui.emission_stop_spinBox.valueChanged.connect(self.update_emission_region)
63 |
64 | self.show()
65 |
66 | def open_data_file(self):
67 | """ Open data file """
68 | try:
69 | self.filename = QtWidgets.QFileDialog.getOpenFileName(self)
70 | #self.data = np.loadtxt(self.filename[0], delimiter = '\t', skiprows = 1)
71 | if ".txt" in self.filename[0]:
72 | self.data = np.loadtxt(self.filename[0], delimiter = '\t', skiprows = 1)
73 | elif ".csv" in self.filename[0]:
74 | self.data = np.loadtxt(self.filename[0], delimiter = ',', skiprows = 1)
75 | elif ".qua" in self.filename[0]:#TODO: Include a Pop-up window for input for skipping header
76 | self.data = np.genfromtxt(self.filename[0], delimiter = '\t', skip_header = 28)
77 | self.cs_window = ColSelectionWindow(self.data)
78 | self.cs_window.col_selection_signal.connect(self.open_with_col_selection)
79 | self.nm = np.copy(self.data[:,0])
80 | #self.ref_data = np.copy(self.data[:,1])
81 | #self.inpath_data = np.copy(self.data[:,2])
82 | #self.outpath_data = np.copy(self.data[:,3])
83 | except Exception as err:
84 | print(format(err))
85 |
86 | def open_with_col_selection(self):
87 | ref_data_col = self.cs_window.ui.ref_spinBox.value() - 1 #subtract since spinboxes refer to column num and not index
88 | inpath_data_col = self.cs_window.ui.inpath_spinBox.value() - 1
89 | outpath_data_col = self.cs_window.ui.outpath_spinBox.value() - 1
90 | self.ref_data = np.copy(self.data[:,ref_data_col])
91 | self.inpath_data = np.copy(self.data[:,inpath_data_col])
92 | self.outpath_data = np.copy(self.data[:,outpath_data_col])
93 |
94 | def update_laser_spinBoxes(self):
95 | """ Update laser spinboxes based on line rois """
96 | self.laser_start, self.laser_stop = self.laser_region.getRegion()
97 | self.ui.laser_start_spinBox.setValue(self.laser_start)
98 | self.ui.laser_stop_spinBox.setValue(self.laser_stop)
99 |
100 |
101 | def update_emission_spinBoxes(self):
102 | """ Update emission spinboxes based on line rois """
103 | self.emission_start, self.emission_stop = self.emission_region.getRegion()
104 | self.ui.emission_start_spinBox.setValue(self.emission_start)
105 | self.ui.emission_stop_spinBox.setValue(self.emission_stop)
106 |
107 | def update_laser_region(self):
108 | """ Update laser line rois based on spinboxes """
109 | laser_start = self.ui.laser_start_spinBox.value()
110 | laser_stop = self.ui.laser_stop_spinBox.value()
111 | self.laser_region.setRegion((laser_start, laser_stop))
112 |
113 | def update_emission_region(self):
114 | """ Update emission line rois based on spinboxes """
115 | emission_start = self.ui.emission_start_spinBox.value()
116 | emission_stop = self.ui.emission_stop_spinBox.value()
117 | self.emission_region.setRegion((emission_start, emission_stop))
118 |
119 | def plot_intensity(self):
120 | try:
121 | self.plot.plot(self.nm, self.inpath_data, pen='r')
122 | self.plot.addItem(self.laser_region, ignoreBounds=True)
123 | self.plot.addItem(self.emission_region, ignoreBounds=True)
124 | except Exception as err:
125 | print(format(err))
126 |
127 | def find_nearest(self,array,value):
128 | idx = (np.abs(array-value)).argmin()
129 | return idx
130 |
131 | def calculate_plqe(self):
132 |
133 | nm_interp_step = 1
134 | nm_interp_start = np.ceil(self.nm[0] / nm_interp_step) * nm_interp_step
135 | nm_interp_stop = np.floor(self.nm[len(self.nm) - 1] / nm_interp_step) * nm_interp_step
136 | nm_interp = np.arange(nm_interp_start, nm_interp_stop + nm_interp_step, nm_interp_step)
137 |
138 | ref_interp = np.interp(nm_interp, self.nm, self.ref_data)
139 |
140 |
141 | inpath_interp = np.interp(nm_interp, self.nm, self.inpath_data)
142 | outpath_interp = np.interp(nm_interp, self.nm, self.outpath_data)
143 |
144 |
145 | """L_x is area under laser profile for experiment x"""
146 | """P_x_ is area under emission profile for experiment x"""
147 |
148 |
149 | #plt.semilogy(nm, a1_outpath_data[:,1])
150 |
151 | emission_start_idx = self.find_nearest(nm_interp, self.emission_start)
152 | emission_stop_idx = self.find_nearest(nm_interp, self.emission_stop)
153 |
154 | laser_start_idx = self.find_nearest(nm_interp, self.laser_start)
155 | laser_stop_idx = self.find_nearest(nm_interp, self.laser_stop)
156 |
157 | la = np.trapz(ref_interp[laser_start_idx: laser_stop_idx], x = nm_interp[laser_start_idx:laser_stop_idx])
158 | lb = np.trapz(outpath_interp[laser_start_idx: laser_stop_idx], x = nm_interp[laser_start_idx:laser_stop_idx])
159 | lc = np.trapz(inpath_interp[laser_start_idx: laser_stop_idx], x = nm_interp[laser_start_idx:laser_stop_idx])
160 |
161 | pa = np.trapz(ref_interp[emission_start_idx:emission_stop_idx], x = nm_interp[emission_start_idx:emission_stop_idx])
162 | pb = np.trapz(outpath_interp[emission_start_idx:emission_stop_idx], x = nm_interp[emission_start_idx:emission_stop_idx])
163 | pc = np.trapz(inpath_interp[emission_start_idx:emission_stop_idx], x = nm_interp[emission_start_idx:emission_stop_idx])
164 |
165 | absorb = 1.0 - (lc / lb)
166 |
167 | plqe = 100 * (pc - ((1.0 - absorb) * pb)) / (la * absorb)
168 | #print('PLQE Percent = %.3f' %(plqe))
169 | #return plqe
170 | self.ui.plqe_label.setText("%.3f" %(plqe))
171 |
172 | def clear(self):
173 | self.plot.clear()
174 |
175 | """Table view GUI"""
176 | ui_file_path = (base_path / "column_selection_gui.ui").resolve()
177 | col_selection_WindowTemplate, col_selection_TemplateBaseClass = pg.Qt.loadUiType(ui_file_path)
178 |
179 | class ColSelectionWindow(col_selection_TemplateBaseClass):
180 |
181 | col_selection_signal = QtCore.pyqtSignal() #signal to help with pass info back to MainWindow
182 |
183 | def __init__(self, data):
184 | col_selection_TemplateBaseClass.__init__(self)
185 | # Create the param window
186 | self.ui = col_selection_WindowTemplate()
187 | self.ui.setupUi(self)
188 | self.ui.done_pushButton.clicked.connect(self.done)
189 |
190 | self.table_widget = pg.TableWidget()
191 | self.ui.data_preview_groupBox.layout().addWidget(self.table_widget)
192 |
193 | self.table_widget.setData(data)
194 |
195 | #self.setWindowFlag(QtCore.Qt.WindowCloseButtonHint, False)
196 | self.show()
197 |
198 | def done(self):
199 | self.col_selection_signal.emit()
200 | self.ui.textBrowser.setText("Data successfully loaded.")
201 | #self.close()
202 |
203 | def closeEvent(self, event):
204 | self.col_selection_signal.emit()
205 |
206 | """Run the Main Window"""
207 | def run():
208 | win = MainWindow()
209 | QtGui.QApplication.instance().exec_()
210 | return win
211 |
212 | #run()
213 |
--------------------------------------------------------------------------------
/PythonGUI_apps/PLQE_analysis/plqe_analysis_gui.ui:
--------------------------------------------------------------------------------
1 |
2 |
3 | Form
4 |
5 |
6 |
7 | 0
8 | 0
9 | 575
10 | 524
11 |
12 |
13 |
14 | PLQE Analysis
15 |
16 |
17 | -
18 |
19 |
20 | PLQE
21 |
22 |
23 |
-
24 |
25 |
26 | Laser start
27 |
28 |
29 |
30 | -
31 |
32 |
33 | 9999.000000000000000
34 |
35 |
36 | 200.000000000000000
37 |
38 |
39 |
40 | -
41 |
42 |
43 | Laser stop
44 |
45 |
46 |
47 | -
48 |
49 |
50 | 9999.000000000000000
51 |
52 |
53 | 400.000000000000000
54 |
55 |
56 |
57 | -
58 |
59 |
60 | Emission start
61 |
62 |
63 |
64 | -
65 |
66 |
67 | 9999.000000000000000
68 |
69 |
70 | 700.000000000000000
71 |
72 |
73 |
74 | -
75 |
76 |
77 | Emission stop
78 |
79 |
80 |
81 | -
82 |
83 |
84 | 9999.000000000000000
85 |
86 |
87 | 800.000000000000000
88 |
89 |
90 |
91 | -
92 |
93 |
94 | PLQE Percent
95 |
96 |
97 |
98 | -
99 |
100 |
101 | 0
102 |
103 |
104 |
105 | -
106 |
107 |
108 | Calculate PLQE
109 |
110 |
111 |
112 |
113 |
114 |
115 | -
116 |
117 |
118 | Clear
119 |
120 |
121 |
122 | -
123 |
124 |
125 | Plot
126 |
127 |
128 |
129 | -
130 |
131 |
132 | Load data
133 |
134 |
135 |
136 | -
137 |
138 |
139 |
140 |
141 |
142 |
143 | PlotWidget
144 | QGraphicsView
145 |
146 |
147 |
148 |
149 |
150 |
151 |
--------------------------------------------------------------------------------
/PythonGUI_apps/Spectrum_analysis/Spectra_fit_funcs.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | """
3 | Created on Sun Mar 31 15:46:54 2019
4 |
5 | @author: Sarthak
6 | """
7 |
8 | # -*- coding: utf-8 -*-
9 | """
10 | Created on Thu Jan 31 20:48:03 2019
11 |
12 | @author: Sarthak
13 | """
14 | import numpy as np
15 | from lmfit.models import GaussianModel, LorentzianModel
16 |
17 | class Spectra_Fit(object):
18 | """
19 | Fit a spectrum.
20 |
21 | Attributes:
22 | data: spectrum data (x-axis and y-axis)
23 | ref: reference spectrum (both x and y-axis) for background correction
24 | """
25 |
26 | def __init__(self, data, ref, wlref = None, fit_in_eV = True):
27 | self.data = data
28 | self.ref = ref
29 | self.wlref = wlref
30 | self.fit_in_eV = fit_in_eV
31 |
32 | def background_correction(self):
33 | """Return the background corrected spectrum"""
34 | x = self.data[:, 0] # wavelengths
35 | y = self.data[:, 1] # intensity
36 | yref = self.ref[:, 1]
37 | y = y - yref # background correction
38 | if self.wlref is not None:
39 | wlref = self.wlref[:,1]
40 | y = y/wlref
41 |
42 | if self.fit_in_eV is True:
43 | x = np.sort(1240/self.data[:, 0]) # converting to eV and sorting in ascending order
44 | y = [y[i] for i in np.argsort(1240/x)] # sorting argument of y acc to x sorting index
45 | # need to do this because data is collected in wavelength
46 |
47 | return [x,y]
48 |
49 | class Single_Gaussian(Spectra_Fit):
50 | """Fit a single gaussian to the spectrum
51 |
52 | Attributes:
53 | data: spectrum data (x-axis and y-axis)
54 | ref: reference spectrum (both x and y-axis) for background correction
55 | """
56 |
57 | def gaussian_model(self):
58 | x,y = self.background_correction()
59 | gmodel = GaussianModel(prefix = 'g1_') # calling gaussian model
60 | pars = gmodel.guess(y, x=x) # parameters - center, width, height
61 | result = gmodel.fit(y, pars, x=x, nan_policy='propagate')
62 | return result
63 |
64 | # def gaussian_model_w_lims(self, center_initial_guess=None, sigma_initial_guess=None, center_min=None, center_max=None):
65 | # x,y = self.background_correction()
66 | # gmodel = GaussianModel(prefix = 'g1_') # calling gaussian model
67 | # pars = gmodel.guess(y, x=x) # parameters - center, width, height
68 | # pars['g1_center'].set(center_initial_guess, min=center_min, max=center_max)
69 | # pars['g1_sigma'].set(sigma_initial_guess)
70 | # result = gmodel.fit(y, pars, x=x, nan_policy='propagate')
71 | # return result #770 760 780 sigma 15
72 | def gaussian_model_w_lims(self, peak_pos, sigma, min_max_range):
73 | x,y = self.background_correction()
74 | if self.fit_in_eV is True:
75 | peak_pos = 1240/peak_pos
76 | sigma = 1240/sigma
77 | min_max_range = np.sort(1240/np.asarray(min_max_range))
78 | gmodel = GaussianModel(prefix = 'g1_') # calling gaussian model
79 | pars = gmodel.guess(y, x=x) # parameters - center, width, height
80 | pars['g1_center'].set(peak_pos, min=min_max_range[0], max=min_max_range[1])
81 | pars['g1_sigma'].set(sigma)
82 | result = gmodel.fit(y, pars, x=x, nan_policy='propagate')
83 | return result
84 |
85 | class Single_Lorentzian(Spectra_Fit):
86 | """Fit a single Lorentzian to the spectrum
87 |
88 | Attributes:
89 | data: spectrum data (x-axis and y-axis)
90 | ref: reference spectrum (both x and y-axis) for background correction
91 | """
92 |
93 | def lorentzian_model(self):
94 | x,y = self.background_correction()
95 | lmodel = LorentzianModel(prefix = 'l1_') # calling lorentzian model
96 | pars = lmodel.guess(y, x=x) # parameters - center, width, height
97 | result = lmodel.fit(y, pars, x=x, nan_policy='propagate')
98 | return result
99 |
100 | def lorentzian_model_w_lims(self, peak_pos, sigma, min_max_range):
101 | x,y = self.background_correction()
102 | if self.fit_in_eV is True:
103 | peak_pos = 1240/peak_pos
104 | sigma = 1240/sigma
105 | min_max_range = np.sort(1240/np.asarray(min_max_range))
106 | lmodel = LorentzianModel(prefix = 'l1_') # calling lorentzian model
107 | pars = lmodel.guess(y, x=x) # parameters - center, width, height
108 | pars['l1_center'].set(peak_pos, min = min_max_range[0], max = min_max_range[1])
109 | pars['l1_sigma'].set(sigma)
110 | result = lmodel.fit(y, pars, x=x, nan_policy='propagate')
111 | return result
112 |
113 | class Double_Gaussian(Spectra_Fit):
114 | """Fit two gaussians to the spectrum
115 |
116 | Attributes:
117 | data: spectrum data (x-axis and y-axis)
118 | ref: reference spectrum (both x and y-axis) for background correction
119 | """
120 |
121 | def gaussian_model(self):
122 |
123 | x,y = self.background_correction()
124 | gmodel_1 = GaussianModel(prefix='g1_') # calling gaussian model
125 | pars = gmodel_1.guess(y, x=x) # parameters - center, width, height
126 |
127 | gmodel_2 = GaussianModel(prefix='g2_')
128 | pars.update(gmodel_2.make_params()) # update parameters - center, width, height
129 |
130 | gmodel = gmodel_1 + gmodel_2
131 | result = gmodel.fit(y, pars, x=x, nan_policy='propagate')
132 | return result
133 |
134 | def gaussian_model_w_lims(self, peak_pos, sigma, min_max_range):
135 | #center_initial_guesses - list containing initial guesses for peak centers. [center_guess1, center_guess2]
136 | #sigma_initial_guesses - list containing initial guesses for sigma. [sigma1, sigma2]
137 | #min_max_range - list containing lists of min and max for peak center. [ [min1, max1], [min2, max2] ]
138 |
139 | x,y = self.background_correction()
140 | if self.fit_in_eV is True:
141 | peak_pos = 1240/np.asarray(peak_pos)
142 | sigma = 1240/np.asarray(sigma)
143 | min_max_range = np.sort(1240/np.asarray(min_max_range))
144 | gmodel_1 = GaussianModel(prefix='g1_') # calling gaussian model
145 | pars = gmodel_1.guess(y, x=x) # parameters - center, width, height
146 | pars['g1_center'].set(peak_pos[0], min = min_max_range[0][0], max = min_max_range[0][1])
147 | pars['g1_sigma'].set(sigma[0])
148 | pars['g1_amplitude'].set(min=0)
149 |
150 | gmodel_2 = GaussianModel(prefix='g2_')
151 | pars.update(gmodel_2.make_params()) # update parameters - center, width, height
152 | pars['g2_center'].set(peak_pos[1], min = min_max_range[1][0], max = min_max_range[1][1])
153 | pars['g2_sigma'].set(sigma[1], min = pars['g1_sigma'].value)
154 | pars['g2_amplitude'].set(min = 0)
155 |
156 | gmodel = gmodel_1 + gmodel_2
157 | result = gmodel.fit(y, pars, x=x, nan_policy='propagate')
158 | return result
159 |
160 | class Multi_Gaussian(Spectra_Fit):
161 |
162 | # def __init__(self, data, ref, num_of_gaussians, peak_pos, sigma, min_max_range):
163 | # Spectra_Fit.__init__(self, data, ref)
164 | # self.num_of_gaussians = num_of_gaussians
165 | # self.peak_pos = peak_pos
166 | # self.min_max_range = min_max_range
167 | def __init__(self, data, ref, num_of_gaussians, wlref=None, fit_in_eV = True):
168 | Spectra_Fit.__init__(self, data, ref, wlref, fit_in_eV=True)
169 | self.num_of_gaussians = num_of_gaussians
170 |
171 | def gaussian_model(self):
172 | composite_model = None
173 | composite_pars = None
174 |
175 | x,y = self.background_correction()
176 |
177 | for i in range(self.num_of_gaussians):
178 |
179 | model = GaussianModel(prefix='g'+str(i+1)+'_')
180 |
181 | if composite_pars is None:
182 | composite_pars = model.guess(y, x=x)
183 | # composite_pars = model.make_params()
184 |
185 | else:
186 | composite_pars.update(model.make_params())
187 |
188 | if composite_model is None:
189 | composite_model = model
190 | else:
191 | composite_model += model
192 |
193 | result = composite_model.fit(y, composite_pars, x=x, nan_policy='propagate')
194 | return result
195 |
196 | def gaussian_model_w_lims(self, peak_pos, sigma, min_max_range):
197 | self.peak_pos = peak_pos
198 | self.sigma = sigma
199 | self.min_max_range = min_max_range
200 |
201 | composite_model = None
202 | composite_pars = None
203 |
204 | x,y = self.background_correction()
205 |
206 | assert self.num_of_gaussians == len(self.peak_pos), ("Number of gaussians must be equal to the number of peak positions")
207 | assert len(self.min_max_range) == len(self.peak_pos), ("Number of bounds on the range must be equal to the number of peak positions")
208 |
209 | if self.fit_in_eV is True:
210 | peak_pos = 1240/np.asarray(peak_pos)
211 | sigma = 1240/np.asarray(sigma)
212 | min_max_range = np.sort(1240/np.asarray(min_max_range))
213 |
214 |
215 | for i in range(self.num_of_gaussians):
216 |
217 | model = GaussianModel(prefix='g'+str(i+1)+'_')
218 |
219 | if composite_pars is None:
220 | composite_pars = model.guess(y, x=x)
221 | # composite_pars = model.make_params()
222 | composite_pars['g'+str(i+1)+'_center'].set(self.peak_pos[i],
223 | min = self.min_max_range[0][0], max = self.min_max_range[0][1])
224 | composite_pars['g'+str(i+1)+'_sigma'].set(self.sigma[i])
225 | composite_pars['g'+str(i+1)+'_amplitude'].set(min = 0)
226 |
227 | else:
228 | composite_pars.update(model.make_params())
229 | composite_pars['g'+str(i+1)+'_center'].set(self.peak_pos[i],
230 | min = self.min_max_range[i][0], max = self.min_max_range[i][1])
231 | composite_pars['g'+str(i+1)+'_sigma'].set(self.sigma[i], min = composite_pars['g1_sigma'].value)
232 | composite_pars['g'+str(i+1)+'_amplitude'].set(min = 0)
233 |
234 |
235 | if composite_model is None:
236 | composite_model = model
237 | else:
238 | composite_model += model
239 |
240 | result = composite_model.fit(y, composite_pars, x=x, nan_policy='propagate')
241 | return result
--------------------------------------------------------------------------------
/PythonGUI_apps/Spectrum_analysis/__init__.py:
--------------------------------------------------------------------------------
1 | from __future__ import absolute_import, division, print_function
--------------------------------------------------------------------------------
/PythonGUI_apps/Spectrum_analysis/analyze_fit_results.ui:
--------------------------------------------------------------------------------
1 |
2 |
3 | Form
4 |
5 |
6 |
7 | 0
8 | 0
9 | 664
10 | 136
11 |
12 |
13 |
14 | Analze Fit Results
15 |
16 |
17 | -
18 |
19 |
-
20 |
21 |
22 | QFrame::StyledPanel
23 |
24 |
25 | QFrame::Raised
26 |
27 |
28 |
-
29 |
30 |
31 |
32 | 12
33 |
34 |
35 |
36 | Check!
37 |
38 |
39 |
40 | -
41 |
42 |
43 |
44 | 12
45 |
46 |
47 |
48 | 1000000000
49 |
50 |
51 |
52 | -
53 |
54 |
55 |
56 | 12
57 |
58 |
59 |
60 | Result number:
61 |
62 |
63 | Qt::AlignCenter
64 |
65 |
66 |
67 | -
68 |
69 |
70 |
71 | 15
72 |
73 |
74 |
75 | Analyze Fit Results
76 |
77 |
78 | Qt::AlignCenter
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
--------------------------------------------------------------------------------
/PythonGUI_apps/Spectrum_analysis/pyqtgraph_MATPLOTLIBWIDGET.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | """
3 | Created on Mon Sep 2 13:02:50 2019
4 |
5 | @author: Sarthak
6 | """
7 |
8 | from pyqtgraph.Qt import QtGui, QtCore, USE_PYSIDE, USE_PYQT5
9 | import matplotlib
10 |
11 | #if not USE_PYQT5:
12 | # if USE_PYSIDE:
13 | # matplotlib.rcParams['backend.qt4']='PySide'
14 | #
15 | # from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg as FigureCanvas
16 | # from matplotlib.backends.backend_qt4agg import NavigationToolbar2QTAgg as NavigationToolbar
17 | #else:
18 | from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
19 | from matplotlib.backends.backend_qt5agg import NavigationToolbar2QT as NavigationToolbar
20 |
21 | from matplotlib.figure import Figure
22 |
23 | if matplotlib.get_backend() is not 'Qt5Agg':
24 | matplotlib.use('Qt5Agg')
25 |
26 | class MatplotlibWidget(QtGui.QWidget):
27 | """
28 | Implements a Matplotlib figure inside a QWidget.
29 | Use getFigure() and redraw() to interact with matplotlib.
30 |
31 | Example::
32 |
33 | mw = MatplotlibWidget()
34 | subplot = mw.getFigure().add_subplot(111)
35 | subplot.plot(x,y)
36 | mw.draw()
37 | """
38 |
39 | def __init__(self, size=(5.0, 4.0), dpi=100):
40 | QtGui.QWidget.__init__(self)
41 | self.fig = Figure(size, dpi=dpi)
42 | self.canvas = FigureCanvas(self.fig)
43 | self.canvas.setParent(self)
44 | self.toolbar = NavigationToolbar(self.canvas, self)
45 |
46 | self.vbox = QtGui.QVBoxLayout()
47 | self.vbox.addWidget(self.toolbar)
48 | self.vbox.addWidget(self.canvas)
49 |
50 | self.setLayout(self.vbox)
51 |
52 | def getFigure(self):
53 | return self.fig
54 |
55 | def draw(self):
56 | self.canvas.draw()
--------------------------------------------------------------------------------
/PythonGUI_apps/Spectrum_analysis/scan_params_input.ui:
--------------------------------------------------------------------------------
1 |
2 |
3 | Form
4 |
5 |
6 |
7 | 0
8 | 0
9 | 542
10 | 211
11 |
12 |
13 |
14 | Form
15 |
16 |
17 | -
18 |
19 |
20 | X scan size
21 |
22 |
23 |
24 | -
25 |
26 |
27 | -
28 |
29 |
30 | Y scan size
31 |
32 |
33 |
34 | -
35 |
36 |
37 | -
38 |
39 |
40 | X step size
41 |
42 |
43 |
44 | -
45 |
46 |
47 | -
48 |
49 |
50 | Y step size
51 |
52 |
53 |
54 | -
55 |
56 |
57 | -
58 |
59 |
60 | Done
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
--------------------------------------------------------------------------------
/PythonGUI_apps/Table/Table_widget.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | """
3 | Created on Mon Sep 2 17:04:49 2019
4 |
5 | @author: Sarthak
6 | """
7 |
8 | from pathlib import Path
9 | import pyqtgraph as pg
10 | from pyqtgraph.python2_3 import asUnicode
11 | from pyqtgraph.Qt import QtCore, QtGui
12 |
13 |
14 | pg.mkQApp()
15 | pg.setConfigOption('background', 'w')
16 |
17 |
18 | base_path = Path(__file__).parent
19 | file_path = (base_path / "Table_widget_gui.ui").resolve()
20 |
21 | uiFile = file_path
22 |
23 | WindowTemplate, TemplateBaseClass = pg.Qt.loadUiType(uiFile)
24 |
25 | class MainWindow(TemplateBaseClass):
26 |
27 | def __init__(self):
28 | super(TemplateBaseClass, self).__init__()
29 |
30 | # Create the main window
31 | self.ui = WindowTemplate()
32 | self.ui.setupUi(self)
33 |
34 | self.clear()
35 |
36 | self.ui.clear_pushButton.clicked.connect(self.clear)
37 | self.ui.add_row_pushButton.clicked.connect(self.add_row)
38 | self.ui.add_column_pushButton.clicked.connect(self.add_column)
39 |
40 | """Saving and Copying --- implemented from pyqtgraph TableWidget"""
41 | self.contextMenu = QtGui.QMenu()
42 | self.contextMenu.addAction('Copy Selection').triggered.connect(self.copySel)
43 | self.contextMenu.addAction('Copy All').triggered.connect(self.copyAll)
44 | self.contextMenu.addAction('Save Selection').triggered.connect(self.saveSel)
45 | self.contextMenu.addAction('Save All').triggered.connect(self.saveAll)
46 |
47 | self.show()
48 |
49 | def clear(self):
50 | self.ui.tableWidget.clear()
51 | self.verticalHeadersSet = False
52 | self.horizontalHeadersSet = False
53 |
54 | def add_row(self):
55 | row_position = self.ui.tableWidget.rowCount()
56 | self.ui.tableWidget.insertRow(row_position)
57 |
58 | def add_column(self):
59 | column_position = self.ui.tableWidget.columnCount()
60 | self.ui.tableWidget.insertColumn(column_position)
61 |
62 | def save_table(self):# Needs to be implemented
63 | print(self.ui.tableWidget.currentItem().text())
64 |
65 | def serialize(self, useSelection=False):
66 | """Convert entire table (or just selected area) into tab-separated text values"""
67 | if useSelection:
68 | selection = self.ui.tableWidget.selectedRanges()[0]
69 | rows = list(range(selection.topRow(),
70 | selection.bottomRow() + 1))
71 | columns = list(range(selection.leftColumn(),
72 | selection.rightColumn() + 1))
73 | else:
74 | rows = list(range(self.ui.tableWidget.rowCount()))
75 | columns = list(range(self.ui.tableWidget.columnCount()))
76 |
77 | data = []
78 | if self.horizontalHeadersSet:
79 | row = []
80 | if self.verticalHeadersSet:
81 | row.append(asUnicode(''))
82 |
83 | for c in columns:
84 | row.append(asUnicode(self.ui.tableWidget.horizontalHeaderItem(c).text()))
85 | data.append(row)
86 |
87 | for r in rows:
88 | row = []
89 | if self.verticalHeadersSet:
90 | row.append(asUnicode(self.ui.tableWidget.verticalHeaderItem(r).text()))
91 | for c in columns:
92 | item = self.ui.tableWidget.item(r, c)
93 | if item is not None:
94 | row.append(asUnicode(item.text()))
95 | else:
96 | row.append(asUnicode(''))
97 | data.append(row)
98 |
99 | s = ''
100 | for row in data:
101 | s += ('\t'.join(row) + '\n')
102 | return s
103 |
104 |
105 | def copySel(self):
106 | """Copy selected data to clipboard."""
107 | QtGui.QApplication.clipboard().setText(self.serialize(useSelection=True))
108 |
109 | def copyAll(self):
110 | """Copy all data to clipboard."""
111 | QtGui.QApplication.clipboard().setText(self.serialize(useSelection=False))
112 |
113 |
114 | def saveSel(self):
115 | """Save selected data to file."""
116 | self.save(self.serialize(useSelection=True))
117 |
118 |
119 | def saveAll(self):
120 | """Save all data to file."""
121 | self.save(self.serialize(useSelection=False))
122 |
123 |
124 | def save(self, data):
125 | fileName = QtGui.QFileDialog.getSaveFileName(self, "Save As..", "", "Tab-separated values (*.tsv)")
126 | if fileName == '':
127 | return
128 | open(fileName[0], 'w').write(data)
129 |
130 | def contextMenuEvent(self, ev):
131 | self.contextMenu.popup(ev.globalPos())
132 |
133 | def keyPressEvent(self, ev):
134 | if ev.key() == QtCore.Qt.Key_C and ev.modifiers() == QtCore.Qt.ControlModifier:
135 | ev.accept()
136 | self.copySel()
137 | # else:
138 | # QtGui.QTableWidget.keyPressEvent(self, ev)
139 | """Run the Main Window"""
140 | def run():
141 | win = MainWindow()
142 | QtGui.QApplication.instance().exec_()
143 | return win
144 |
145 | #run()
--------------------------------------------------------------------------------
/PythonGUI_apps/Table/Table_widget_gui.ui:
--------------------------------------------------------------------------------
1 |
2 |
3 | Form
4 |
5 |
6 |
7 | 0
8 | 0
9 | 658
10 | 438
11 |
12 |
13 |
14 | TableWidget
15 |
16 |
17 | -
18 |
19 |
20 | Add Row
21 |
22 |
23 |
24 | -
25 |
26 |
27 | Add Column
28 |
29 |
30 |
31 | -
32 |
33 |
34 | Clear
35 |
36 |
37 |
38 | -
39 |
40 |
41 | 12
42 |
43 |
44 | 6
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
--------------------------------------------------------------------------------
/PythonGUI_apps/Table/__init__.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | """
3 | Created on Mon Sep 2 17:52:35 2019
4 |
5 | @author: Sarthak
6 | """
7 |
8 |
--------------------------------------------------------------------------------
/PythonGUI_apps/UV_Vis_analysis/uv_vis_analysis.py:
--------------------------------------------------------------------------------
1 | # system imports
2 | from pathlib import Path
3 | import os.path
4 | import pyqtgraph as pg
5 | from pyqtgraph import exporters
6 | from pyqtgraph.Qt import QtCore, QtGui, QtWidgets
7 | import matplotlib.pyplot as plt
8 |
9 | import numpy as np
10 | import time
11 |
12 | # local modules
13 |
14 | pg.mkQApp()
15 | pg.setConfigOption('background', 'w')
16 |
17 | base_path = Path(__file__).parent
18 | file_path = (base_path / "uv_vis_analysis_gui.ui").resolve()
19 |
20 | uiFile = file_path
21 |
22 | WindowTemplate, TemplateBaseClass = pg.Qt.loadUiType(uiFile)
23 |
24 | """params for plotting"""
25 | plt.rc('xtick', labelsize = 20)
26 | plt.rc('xtick.major', pad = 3)
27 | plt.rc('ytick', labelsize = 20)
28 | plt.rc('lines', lw = 1.5, markersize = 7.5)
29 | plt.rc('legend', fontsize = 20)
30 | plt.rc('axes', linewidth = 3.5)
31 |
32 | class MainWindow(TemplateBaseClass):
33 |
34 | def __init__(self):
35 | super(TemplateBaseClass, self).__init__()
36 |
37 | # Create the main window
38 | self.ui = WindowTemplate()
39 | self.ui.setupUi(self)
40 |
41 | #setup uv vis plot
42 | self.absorbance_plot_layout = pg.GraphicsLayoutWidget()
43 | self.ui.absorbance_plot_container.layout().addWidget(self.absorbance_plot_layout)
44 | self.absorbance_plot = self.absorbance_plot_layout.addPlot(title="Wavelengths vs. Absorbance")
45 | self.absorbance_plot.setLabel('bottom', 'Wavelength', unit='nm')
46 | self.absorbance_plot.setLabel('left', 'Absorbance', unit='a.u.')
47 |
48 | #setup correction region for uv vis
49 | self.correction_region = pg.LinearRegionItem()
50 | self.correction_region_min = 600
51 | self.correction_region_max = 900
52 | self.correction_region.setRegion((self.correction_region_min, self.correction_region_max))
53 |
54 | #setup uv vis ui signals
55 | self.ui.correct_for_scattering_checkBox.stateChanged.connect(self.scattering_checkBox_state)
56 | self.scatter_corrected = False
57 | self.ui.actionLoad_data.triggered.connect(self.open_data_file)
58 | self.ui.plot_absorbance_pushButton.clicked.connect(self.plot_absorbance)
59 | self.ui.clear_uvvis_pushButton.clicked.connect(self.clear_uvvis)
60 | self.ui.export_uv_vis_pushButton.clicked.connect(self.export_uv_vis)
61 | self.correction_region.sigRegionChanged.connect(self.update_correction_region)
62 |
63 | #setup tauc plot
64 | self.tauc_plot_layout = pg.GraphicsLayoutWidget()
65 | self.ui.tauc_plot_container.layout().addWidget(self.tauc_plot_layout)
66 | self.tauc_plot = self.tauc_plot_layout.addPlot(title="Tauc plot fit")
67 | self.tauc_plot.setLabel('bottom', 'hv', unit='ev')
68 | y_label = '(ahv)' + chr(0x00B2) #char is superscripted 2
69 | self.tauc_plot.setLabel('left', y_label)
70 |
71 | #setup tauc ui signals
72 | self.ui.plot_tauc_pushButton.clicked.connect(self.plot_tauc)
73 | self.ui.clear_tauc_pushButton.clicked.connect(self.clear_tauc)
74 | self.ui.export_tauc_pushButton.clicked.connect(self.export_tauc)
75 |
76 | self.show()
77 |
78 | def open_data_file(self):
79 | try:
80 | self.filename = QtWidgets.QFileDialog.getOpenFileName(self)
81 | self.data = np.loadtxt(self.filename[0], delimiter = ',', skiprows = 2)
82 | self.Wavelength = self.data[:,0] # in nm
83 | self.Absorbance = self.data[:,1]
84 | except Exception as err:
85 | print(format(err))
86 |
87 | def update_correction_region(self):
88 | """ Update correction region variables from region """
89 | self.correction_region_min, self.correction_region_max = self.correction_region.getRegion()
90 |
91 | def scattering_checkBox_state(self):
92 | if self.ui.correct_for_scattering_checkBox.isChecked():
93 | self.scatter_corrected = True
94 | self.ui.mean_radioButton.setEnabled(True)
95 | self.ui.fourth_orderpoly_radioButton.setEnabled(True)
96 | else:
97 | self.scatter_corrected = False
98 | self.ui.mean_radioButton.setEnabled(False)
99 | self.ui.fourth_orderpoly_radioButton.setEnabled(False)
100 |
101 | def plot_absorbance(self):
102 | try:
103 | self.plotted_absorbance = self.Absorbance #by default set to original absorbance data
104 | if self.scatter_corrected == True:
105 | if self.ui.fourth_orderpoly_radioButton.isChecked():
106 | p = (np.polyfit(self.Wavelength[(self.Wavelength>self.correction_region_min) & (self.Wavelengthself.correction_region_min) & (self.Wavelengthself.correction_region_min) & (self.Wavelengthself.correction_region_min) & (self.Wavelengthself.correction_region_min) & (self.Wavelengthself.correction_region_min) & (self.Wavelength self.hv_min) & (self.hv < self.hv_max)
128 | model = np.polyfit(self.hv[self.index], self.Alpha_hv[self.index], 1)
129 | self.Alpha_hv_fit = self.hv * model[0] + model[1] #This is the linear fit
130 | self.tauc_plot.plot(self.hv, self.Alpha_hv, pen='r')
131 | self.tauc_plot.plot(self.hv, self.Alpha_hv_fit, pen='k')
132 | self.tauc_plot.setXRange(1,2)
133 | self.tauc_plot.setYRange(0, np.max(self.Alpha_hv[self.index]) + 1)
134 |
135 | self.Eg = - model[1]/model[0]
136 | self.ui.bandgap_label.setText(str(self.Eg))
137 | except:
138 | pass
139 |
140 | def clear_tauc(self):
141 | self.tauc_plot.clear()
142 |
143 | def export_uv_vis(self):
144 | """ Export publication ready uv vis figure """
145 | try:
146 | filename = QtWidgets.QFileDialog.getSaveFileName(self,caption="Filename with EXTENSION")
147 | plt.figure(figsize=(8,6))
148 | plt.tick_params(direction='out', length=8, width=3.5)
149 | plt.plot(self.Wavelength, self.plotted_absorbance, linewidth = 3, color = 'r')
150 | if self.scatter_corrected:
151 | plt.xlim(self.correction_region_min, self.correction_region_max)
152 | plt.ylim(0, np.max(self.plotted_absorbance[(self.Wavelength>self.correction_region_min)]) +0.5)
153 | else:
154 | plt.xlim(self.correction_region_min, self.correction_region_max)
155 | plt.ylim(0, np.max(self.plotted_absorbance[(self.Wavelength>self.correction_region_min)] +0.5))
156 | plt.xlabel('Wavelength (nm)', fontsize = 20)
157 | plt.ylabel('Absorbance (a.u.)', fontsize = 20)
158 | plt.savefig(filename[0],bbox_inches='tight', dpi=300)
159 | plt.close()
160 | except:
161 | pass
162 |
163 | def export_tauc(self):
164 | """ Export publication ready tauc figure"""
165 | try:
166 | filename = QtWidgets.QFileDialog.getSaveFileName(self,caption="Filename with EXTENSION")
167 | plt.figure(figsize=(8,6))
168 | plt.tick_params(direction='out', length=8, width=3.5)
169 | plt.plot(self.hv, self.Alpha_hv, linewidth = 3, color = 'r')
170 | plt.plot(self.hv, self.Alpha_hv_fit, linewidth = 2, color = 'black')
171 | plt.xlim(1,2)
172 | plt.ylim(0, np.max(self.Alpha_hv[self.index]) + 1)
173 | plt.xlabel('h$\\nu$ (eV)', fontsize = 20)
174 | plt.ylabel('($\\alpha$h$\\nu$)$^2$', fontsize = 20)
175 | #plt.title(Plot_title, fontsize = 20)
176 |
177 | plt.text(1.2, 1.2, r'E$_{g}$ = %.2f eV'%self.Eg, fontsize = 15)
178 | plt.tight_layout()
179 | plt.savefig(filename[0],bbox_inches='tight', dpi=300)
180 | plt.close()
181 | except:
182 | pass
183 |
184 | """Run the Main Window"""
185 | def run():
186 | win = MainWindow()
187 | QtGui.QApplication.instance().exec_()
188 | return win
--------------------------------------------------------------------------------
/PythonGUI_apps/UV_Vis_analysis/uv_vis_analysis_gui.ui:
--------------------------------------------------------------------------------
1 |
2 |
3 | MainWindow
4 |
5 |
6 |
7 | 0
8 | 0
9 | 742
10 | 924
11 |
12 |
13 |
14 | UV-Vis Analysis
15 |
16 |
17 |
18 | -
19 |
20 |
21 | UV-Vis plot
22 |
23 |
24 |
-
25 |
26 |
-
27 |
28 |
29 | Scattering Correction
30 |
31 |
32 |
33 | -
34 |
35 |
36 | Plot
37 |
38 |
39 |
40 | -
41 |
42 |
43 | false
44 |
45 |
46 | 4th Order Polynomial
47 |
48 |
49 | true
50 |
51 |
52 |
53 | -
54 |
55 |
56 | Clear
57 |
58 |
59 |
60 | -
61 |
62 |
63 | Correct for scattering
64 |
65 |
66 |
67 | -
68 |
69 |
70 | false
71 |
72 |
73 | Simple Mean
74 |
75 |
76 |
77 |
78 |
79 | -
80 |
81 |
82 |
83 | 0
84 | 0
85 |
86 |
87 |
88 |
89 |
90 | -
91 |
92 |
93 | Export UV-Vis plot
94 |
95 |
96 |
97 |
98 |
99 |
100 | -
101 |
102 |
103 | Tauc plot
104 |
105 |
106 | true
107 |
108 |
109 | false
110 |
111 |
112 |
-
113 |
114 |
-
115 |
116 |
117 | hv min (ev)
118 |
119 |
120 |
121 | -
122 |
123 |
124 |
125 | 180
126 | 0
127 |
128 |
129 |
130 | -9999999.000000000000000
131 |
132 |
133 | 9999999.000000000000000
134 |
135 |
136 | 0.010000000000000
137 |
138 |
139 | 1.500000000000000
140 |
141 |
142 |
143 | -
144 |
145 |
146 |
147 | 180
148 | 0
149 |
150 |
151 |
152 | -9999999.000000000000000
153 |
154 |
155 | 9999999.000000000000000
156 |
157 |
158 | 0.010000000000000
159 |
160 |
161 | 1.800000000000000
162 |
163 |
164 |
165 | -
166 |
167 |
168 | hv max (ev)
169 |
170 |
171 |
172 | -
173 |
174 |
175 | Plot
176 |
177 |
178 |
179 | -
180 |
181 |
182 | Clear
183 |
184 |
185 |
186 |
187 |
188 | -
189 |
190 |
191 |
192 | 0
193 | 0
194 |
195 |
196 |
197 |
198 |
199 | -
200 |
201 |
-
202 |
203 |
204 | Bandgap (ev):
205 |
206 |
207 |
208 | -
209 |
210 |
211 | 0
212 |
213 |
214 |
215 | -
216 |
217 |
218 |
219 | 16777215
220 | 16777215
221 |
222 |
223 |
224 | Export tauc plot
225 |
226 |
227 |
228 | -
229 |
230 |
231 |
232 |
233 |
234 |
235 |
236 |
237 |
238 |
239 |
240 |
241 |
242 |
259 |
260 |
261 |
262 | Load data
263 |
264 |
265 |
266 |
267 |
268 |
269 |
--------------------------------------------------------------------------------
/PythonGUI_apps/__init__.py:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # GLabViz
2 | Graphical User Interface (GUI) Python apps written in python using qt and [pyqtgrpah](http://www.pyqtgraph.org/) for quick analysis of scientific data. It also includes the ability to convert data to *H5* if needed.
3 |
4 | _**Python is not required to use GLabViz**_ (see **How to use?**)
5 |
6 | [**DOWNLOAD HERE**](https://github.com/SarthakJariwala/Python_GUI_apps/releases)
7 |
8 | The primary users for this Python package application are Ginger Lab members at the University of Washington, Seattle but is licensed under MIT License and open for everyone to use.
9 |
10 | ## Includes
11 |
12 | * **Fluorescence Lifetime Analysis**
13 | * Analyze lifetime
14 | * Fit data with or without IRF
15 | * Fit with stretched, single, or double exponential functions by diff_ev or fmin_tnc
16 | * Calculate surface recombination velocity
17 | * Export graph and fit results
18 |
19 | * **Spectra Analysis**
20 | * Analyze single spectrum
21 | * Fit with or without background and white light
22 | * Fit with single Lorentzian, single Gaussian, double Gaussian, triple Gaussian models
23 | * Export graph and fit results
24 | * Analyze spectra scan
25 | * Load spectra scan data in .h5 or .pkl files
26 | * Plot raw scan data
27 | * Plot scan intensity sums
28 | * Plot fitted scan by pk_pos, fwhm, sigma, or height
29 | * Export fitted scan
30 | * .pkl to .txt, .pkl to .h5 converters
31 |
32 | * **Fluorescence Lifetime Imaging Microscopy (FLIM) Data Analysis**
33 | * Load lifetime scans in .h5 or .pkl files
34 | * Plot histogram intensity sums and analyze PSF
35 | * Export intensities array and intensities image
36 | * Plot raw histogram data and analyze lifetime
37 | * Compare lifetime in two different regions
38 |
39 | * **Photluminescence Quantum Efficiency (PLQE) Analysis**
40 | * Plot PLQE data
41 | * Calculate PLQE
42 |
43 | * **UV-Vis Data Analysis**
44 | * Plot UV-Vis data
45 | * Correct UV-Vis data for scattering
46 | * Plot Tauc data
47 | * Calculate bandgap
48 | * Export UV-Vis and Tauc plots
49 |
50 | * **General *H5* View and Plot**
51 | * Load .h5 file to view file structure
52 | * Plot datasets as a graph or an image
53 |
54 | * **H5 and PKL File Viewer**
55 | * Load .h5 or .pkl file to view file structure
56 |
57 | * **Image Analysis**
58 | * Load image on SPOT or Pixera settings, or specify pixel size
59 | * Handle RGB and greyscale images
60 | * Select magnification
61 | * Color profile horizontally or vertically
62 |
63 | ## Screenshots
64 | ### Welcome Screen
65 | 
66 | ### Lifetime Analysis
67 | 
68 | ### Spectra Analysis
69 | 
70 | 
71 | ### FLIM Analysis
72 | 
73 | ### UV-Vis Analysis
74 | 
75 | ### H5 & Pkl View
76 | 
77 | ### H5 Quick Plot
78 | 
79 | ### Image Analysis
80 | 
81 |
82 | ## How to use?
83 | ### Standalone App - without Python or any dependencies (_only for Windows users, comming soon for Mac users_)
84 | * Under the [releases](https://github.com/SarthakJariwala/Python_GUI_apps/releases) page, download the latest release of the _**DataBrowser**_ zip file
85 | * Extract the zip file and run _**DataBrowser.exe**_
86 | ### With Python and its dependencies
87 | ```
88 | git clone https://github.com/SarthakJariwala/Python_GUI_apps.git
89 | ```
90 | * Install all dependencies
91 | * Run the application by double-clicking DataBrowser.py.
92 | * OR Run it from command-line while in the PythonGUI_apps folder:
93 | ```
94 | python DataBrowser.py
95 | ```
96 |
97 | #### Dependencies
98 | * [ScopeFoundry](https://github.com/ScopeFoundry/ScopeFoundry)
99 | * [pyqtgraph](http://www.pyqtgraph.org/)
100 | * numpy
101 | * pyqt
102 | * qtpy
103 | * h5py
104 | * matplotlib
105 | * scipy
106 | * [lmfit](https://lmfit.github.io/lmfit-py/)
107 | * [customplotting](https://github.com/SarthakJariwala/Custom-Plotting)
108 |
109 | #### Installing dependencies from command-line
110 | ```
111 | conda install numpy pyqt qtpy h5py pyqtgraph
112 | pip install ScopeFoundry
113 | pip install matplotlib scipy lmfit customplotting==0.1.4.dev0
114 | ```
115 |
--------------------------------------------------------------------------------
/Screenshots/GLabViz_FLIM_analysis_1.PNG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SarthakJariwala/Python_GUI_apps/be78d92568e430c551ccf2a081521a0a81def20d/Screenshots/GLabViz_FLIM_analysis_1.PNG
--------------------------------------------------------------------------------
/Screenshots/GLabViz_FLIM_analysis_2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SarthakJariwala/Python_GUI_apps/be78d92568e430c551ccf2a081521a0a81def20d/Screenshots/GLabViz_FLIM_analysis_2.png
--------------------------------------------------------------------------------
/Screenshots/GLabViz_Image_analysis_1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SarthakJariwala/Python_GUI_apps/be78d92568e430c551ccf2a081521a0a81def20d/Screenshots/GLabViz_Image_analysis_1.png
--------------------------------------------------------------------------------
/Screenshots/GLabViz_Lifetime_analysis_2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SarthakJariwala/Python_GUI_apps/be78d92568e430c551ccf2a081521a0a81def20d/Screenshots/GLabViz_Lifetime_analysis_2.png
--------------------------------------------------------------------------------
/Screenshots/GLabViz_Spectrum_analysis_1.PNG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SarthakJariwala/Python_GUI_apps/be78d92568e430c551ccf2a081521a0a81def20d/Screenshots/GLabViz_Spectrum_analysis_1.PNG
--------------------------------------------------------------------------------
/Screenshots/GLabViz_Spectrum_analysis_1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SarthakJariwala/Python_GUI_apps/be78d92568e430c551ccf2a081521a0a81def20d/Screenshots/GLabViz_Spectrum_analysis_1.png
--------------------------------------------------------------------------------
/Screenshots/GLabViz_Spectrum_analysis_2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SarthakJariwala/Python_GUI_apps/be78d92568e430c551ccf2a081521a0a81def20d/Screenshots/GLabViz_Spectrum_analysis_2.png
--------------------------------------------------------------------------------
/Screenshots/GLabViz_UVvis_analysis_1.PNG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SarthakJariwala/Python_GUI_apps/be78d92568e430c551ccf2a081521a0a81def20d/Screenshots/GLabViz_UVvis_analysis_1.PNG
--------------------------------------------------------------------------------
/Screenshots/GLabViz_h5_ViewPlot_analysis_1.PNG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SarthakJariwala/Python_GUI_apps/be78d92568e430c551ccf2a081521a0a81def20d/Screenshots/GLabViz_h5_ViewPlot_analysis_1.PNG
--------------------------------------------------------------------------------
/Screenshots/GLabViz_h5_ViewPlot_analysis_2.PNG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SarthakJariwala/Python_GUI_apps/be78d92568e430c551ccf2a081521a0a81def20d/Screenshots/GLabViz_h5_ViewPlot_analysis_2.PNG
--------------------------------------------------------------------------------
/Screenshots/GLabViz_interface_1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SarthakJariwala/Python_GUI_apps/be78d92568e430c551ccf2a081521a0a81def20d/Screenshots/GLabViz_interface_1.png
--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------
1 | altgraph==0.16.1
2 | asteval==0.9.14
3 | attrs==19.1.0
4 | backcall==0.1.0
5 | bleach==3.3.0
6 | bokeh==1.3.2
7 | certifi==2019.6.16
8 | Click==7.0
9 | cloudpickle==1.2.1
10 | cmarkgfm==0.4.2
11 | colorama==0.4.1
12 | customplotting==0.1.4.dev0
13 | cycler==0.10.0
14 | cytoolz==0.10.0
15 | dask==2.2.0
16 | decorator==4.4.0
17 | defusedxml==0.6.0
18 | distributed==2.2.0
19 | entrypoints==0.3
20 | fsspec==0.4.0
21 | gwyfile==0.2.0
22 | h5py==2.9.0
23 | heapdict==1.0.0
24 | igor==0.3
25 | imageio==2.5.0
26 | ipykernel==5.1.1
27 | ipython==7.7.0
28 | ipython-genutils==0.2.0
29 | ipywidgets==7.5.0
30 | jedi==0.14.1
31 | Jinja2==2.10.1
32 | joblib==0.13.2
33 | jsonschema==3.0.1
34 | jupyter-client==5.3.1
35 | jupyter-core==4.5.0
36 | kiwisolver==1.1.0
37 | llvmlite==0.29.0
38 | lmfit==0.9.13
39 | locket==0.2.0
40 | MarkupSafe==1.1.1
41 | matplotlib==3.1.1
42 | matplotlib-scalebar==0.6.0
43 | mistune==0.8.4
44 | mkl-fft==1.0.12
45 | mkl-random==1.0.2
46 | mkl-service==2.0.2
47 | msgpack==0.6.1
48 | nbconvert==5.5.0
49 | nbformat==4.4.0
50 | networkx==2.3
51 | notebook==6.1.5
52 | numba==0.45.1
53 | numpy==1.16.4
54 | numpy-groupies==0.9.7
55 | olefile==0.46
56 | opencv-python==4.1.0.25
57 | packaging==19.0
58 | pandas==0.25.0
59 | pandocfilters==1.4.2
60 | parso==0.5.1
61 | partd==1.0.0
62 | pefile==2019.4.18
63 | pickleshare==0.7.5
64 | Pillow==8.1.1
65 | pkginfo==1.4.2
66 | prometheus-client==0.7.1
67 | prompt-toolkit==2.0.9
68 | psutil==5.6.6
69 | pycroscopy==0.59.8
70 | Pygments==2.4.2
71 | PyInstaller==3.5
72 | pyparsing==2.4.0
73 | PyQt5==5.9
74 | PyQt5-sip==4.19.18
75 | pyqtgraph==0.10.0
76 | pyreadline==2.1
77 | pyrsistent==0.14.11
78 | python-dateutil==2.8.0
79 | pytz==2019.1
80 | pyUSID==0.0.6.1
81 | PyWavelets==1.0.3
82 | pywin32-ctypes==0.2.0
83 | pywinpty==0.5.5
84 | PyYAML==5.1.1
85 | pyzmq==18.0.2
86 | qtconsole==4.5.1
87 | QtPy==1.8.0
88 | readme-renderer==22.0
89 | requests-toolbelt==0.8.0
90 | scikit-image==0.15.0
91 | scikit-learn==0.21.2
92 | scipy==1.3.0
93 | ScopeFoundry==1.1.1
94 | Send2Trash==1.5.0
95 | sip==4.19.8
96 | six==1.12.0
97 | sortedcontainers==2.1.0
98 | tblib==1.4.0
99 | terminado==0.8.2
100 | testpath==0.4.2
101 | toolz==0.10.0
102 | tornado==6.0.3
103 | traitlets==4.3.2
104 | twine==1.12.1
105 | uncertainties==3.1.1
106 | wcwidth==0.1.7
107 | webencodings==0.5.1
108 | widgetsnbextension==3.5.0
109 | wincertstore==0.2
110 | xlrd==1.2.0
111 | zict==1.0.0
112 |
--------------------------------------------------------------------------------