microeye 2.3.2__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (190) hide show
  1. microEye/__init__.py +47 -0
  2. microEye/_version.py +2 -0
  3. microEye/analysis/__init__.py +1 -0
  4. microEye/analysis/checklist_dialog.py +143 -0
  5. microEye/analysis/cmosMaps.py +228 -0
  6. microEye/analysis/filters/__init__.py +9 -0
  7. microEye/analysis/filters/base.py +21 -0
  8. microEye/analysis/filters/spatial.py +338 -0
  9. microEye/analysis/filters/temporal.py +76 -0
  10. microEye/analysis/fitting/__init__.py +0 -0
  11. microEye/analysis/fitting/fit.py +680 -0
  12. microEye/analysis/fitting/nena.py +375 -0
  13. microEye/analysis/fitting/phasor_fit.py +90 -0
  14. microEye/analysis/fitting/processing.py +317 -0
  15. microEye/analysis/fitting/psf/__init__.py +6 -0
  16. microEye/analysis/fitting/psf/extract.py +1129 -0
  17. microEye/analysis/fitting/psf/rubost_mean.py +150 -0
  18. microEye/analysis/fitting/psf/spline.py +167 -0
  19. microEye/analysis/fitting/psf/stats/__init__.py +12 -0
  20. microEye/analysis/fitting/psf/stats/core.py +295 -0
  21. microEye/analysis/fitting/psf/stats/curve_fit.py +708 -0
  22. microEye/analysis/fitting/psf/stats/io.py +104 -0
  23. microEye/analysis/fitting/psf/stats/slope_fit.py +171 -0
  24. microEye/analysis/fitting/psf/temp.py +147 -0
  25. microEye/analysis/fitting/psf/test.py +47 -0
  26. microEye/analysis/fitting/pyfit3Dcspline/CPU/CPUfunctions.py +657 -0
  27. microEye/analysis/fitting/pyfit3Dcspline/CPU/CPUmleFit_LM.py +1336 -0
  28. microEye/analysis/fitting/pyfit3Dcspline/CPU/CPUsplineLib.py +270 -0
  29. microEye/analysis/fitting/pyfit3Dcspline/CPU/__init__.py +1 -0
  30. microEye/analysis/fitting/pyfit3Dcspline/GPU/GPUfunctions.py +609 -0
  31. microEye/analysis/fitting/pyfit3Dcspline/GPU/GPUmleFit_LM_EMCCD.py +1396 -0
  32. microEye/analysis/fitting/pyfit3Dcspline/GPU/GPUmleFit_LM_sCMOS.py +1426 -0
  33. microEye/analysis/fitting/pyfit3Dcspline/GPU/GPUsplineLib.py +231 -0
  34. microEye/analysis/fitting/pyfit3Dcspline/GPU/__init__.py +2 -0
  35. microEye/analysis/fitting/pyfit3Dcspline/__init__.py +10 -0
  36. microEye/analysis/fitting/pyfit3Dcspline/constants.py +27 -0
  37. microEye/analysis/fitting/pyfit3Dcspline/mainfunctions.py +903 -0
  38. microEye/analysis/fitting/results.py +917 -0
  39. microEye/analysis/fitting/results_stats.py +251 -0
  40. microEye/analysis/fitting/tardis.py +209 -0
  41. microEye/analysis/multi_viewer.py +568 -0
  42. microEye/analysis/processing/__init__.py +1 -0
  43. microEye/analysis/processing/frc.py +120 -0
  44. microEye/analysis/rendering/__init__.py +3 -0
  45. microEye/analysis/rendering/base.py +452 -0
  46. microEye/analysis/rendering/cloud.py +215 -0
  47. microEye/analysis/rendering/core.py +47 -0
  48. microEye/analysis/rendering/volumetric.py +198 -0
  49. microEye/analysis/tools/__init__.py +0 -0
  50. microEye/analysis/tools/kymograms.py +1079 -0
  51. microEye/analysis/tools/roi_selectors.py +556 -0
  52. microEye/analysis/utils/__init__.py +3 -0
  53. microEye/analysis/utils/coordinates.py +18 -0
  54. microEye/analysis/utils/images.py +68 -0
  55. microEye/analysis/utils/windows.py +19 -0
  56. microEye/analysis/viewer/__init__.py +3 -0
  57. microEye/analysis/viewer/image_options_widget.py +615 -0
  58. microEye/analysis/viewer/images.py +1225 -0
  59. microEye/analysis/viewer/layers_widget.py +415 -0
  60. microEye/analysis/viewer/localizations.py +1304 -0
  61. microEye/analysis/viewer/psf.py +1003 -0
  62. microEye/analysis/viewer/volume.py +456 -0
  63. microEye/hardware/__init__.py +3 -0
  64. microEye/hardware/cams/__init__.py +29 -0
  65. microEye/hardware/cams/camera_calibration.py +99 -0
  66. microEye/hardware/cams/camera_list.py +528 -0
  67. microEye/hardware/cams/camera_options.py +694 -0
  68. microEye/hardware/cams/camera_panel.py +941 -0
  69. microEye/hardware/cams/dummy/__init__.py +1 -0
  70. microEye/hardware/cams/dummy/dummy_panel.py +759 -0
  71. microEye/hardware/cams/jobs.py +497 -0
  72. microEye/hardware/cams/line_profiler.py +99 -0
  73. microEye/hardware/cams/linescan/IR_Cam.py +474 -0
  74. microEye/hardware/cams/linescan/__init__.py +1 -0
  75. microEye/hardware/cams/micam.py +524 -0
  76. microEye/hardware/cams/pco/__init__.py +58 -0
  77. microEye/hardware/cams/pco/enums.py +382 -0
  78. microEye/hardware/cams/pco/pco_cam.py +761 -0
  79. microEye/hardware/cams/pco/pco_panel.py +477 -0
  80. microEye/hardware/cams/shortcuts.py +312 -0
  81. microEye/hardware/cams/thorlabs/__init__.py +1 -0
  82. microEye/hardware/cams/thorlabs/thorlabs.py +1508 -0
  83. microEye/hardware/cams/thorlabs/thorlabs_panel.py +850 -0
  84. microEye/hardware/cams/ueye/__init__.py +1 -0
  85. microEye/hardware/cams/ueye/ueye_camera.py +1023 -0
  86. microEye/hardware/cams/ueye/ueye_panel.py +861 -0
  87. microEye/hardware/cams/vimba/__init__.py +1 -0
  88. microEye/hardware/cams/vimba/vimba_cam.py +1000 -0
  89. microEye/hardware/cams/vimba/vimba_panel.py +813 -0
  90. microEye/hardware/device.py +60 -0
  91. microEye/hardware/lasers/__init__.py +13 -0
  92. microEye/hardware/lasers/io_matchbox.py +791 -0
  93. microEye/hardware/lasers/io_params.py +85 -0
  94. microEye/hardware/lasers/io_single_laser.py +742 -0
  95. microEye/hardware/lasers/laser_relay.py +594 -0
  96. microEye/hardware/mieye/__init__.py +1 -0
  97. microEye/hardware/mieye/acquisition_manager.py +467 -0
  98. microEye/hardware/mieye/devices_manager.py +533 -0
  99. microEye/hardware/mieye/miEye.py +659 -0
  100. microEye/hardware/misc/__init__.py +0 -0
  101. microEye/hardware/misc/acquisition_view.py +71 -0
  102. microEye/hardware/misc/reglo.py +761 -0
  103. microEye/hardware/misc/temp.py +188 -0
  104. microEye/hardware/port_config.py +59 -0
  105. microEye/hardware/protocols/__init__.py +2 -0
  106. microEye/hardware/protocols/actions.py +402 -0
  107. microEye/hardware/protocols/actions_items.py +703 -0
  108. microEye/hardware/protocols/designer.py +244 -0
  109. microEye/hardware/protocols/scene_manager.py +191 -0
  110. microEye/hardware/protocols/serialization.py +97 -0
  111. microEye/hardware/pycromanager/__init__.py +16 -0
  112. microEye/hardware/pycromanager/core.py +1433 -0
  113. microEye/hardware/pycromanager/devices.py +461 -0
  114. microEye/hardware/pycromanager/enums.py +107 -0
  115. microEye/hardware/pycromanager/headless.py +153 -0
  116. microEye/hardware/pycromanager/utils.py +34 -0
  117. microEye/hardware/pycromanager/widgets/__init__.py +5 -0
  118. microEye/hardware/pycromanager/widgets/bridges.py +407 -0
  119. microEye/hardware/pycromanager/widgets/headless_manager.py +258 -0
  120. microEye/hardware/pycromanager/widgets/headless_options.py +224 -0
  121. microEye/hardware/pycromanager/widgets/pycro_panel.py +455 -0
  122. microEye/hardware/stages/__init__.py +18 -0
  123. microEye/hardware/stages/elliptec/__init__.py +5 -0
  124. microEye/hardware/stages/elliptec/baseDevice.py +314 -0
  125. microEye/hardware/stages/elliptec/device.py +384 -0
  126. microEye/hardware/stages/elliptec/deviceID.py +212 -0
  127. microEye/hardware/stages/elliptec/devicePort.py +379 -0
  128. microEye/hardware/stages/elliptec/deviceStatus.py +65 -0
  129. microEye/hardware/stages/elliptec/devicesView.py +706 -0
  130. microEye/hardware/stages/elliptec/ellDevices.py +134 -0
  131. microEye/hardware/stages/elliptec/messageUpdater.py +34 -0
  132. microEye/hardware/stages/elliptec/motorInfo.py +153 -0
  133. microEye/hardware/stages/elliptec/stage.py +62 -0
  134. microEye/hardware/stages/elliptec/test.py +139 -0
  135. microEye/hardware/stages/kinesis/__init__.py +1 -0
  136. microEye/hardware/stages/kinesis/kdc101/__init__.py +1 -0
  137. microEye/hardware/stages/kinesis/kdc101/enums.py +1002 -0
  138. microEye/hardware/stages/kinesis/kdc101/factory.py +171 -0
  139. microEye/hardware/stages/kinesis/kdc101/kdc101.py +718 -0
  140. microEye/hardware/stages/kinesis/kinesis.py +776 -0
  141. microEye/hardware/stages/piezo_concept.py +607 -0
  142. microEye/hardware/stages/stabilizer.py +785 -0
  143. microEye/hardware/stages/stage.py +89 -0
  144. microEye/hardware/widgets/__init__.py +10 -0
  145. microEye/hardware/widgets/controller.py +246 -0
  146. microEye/hardware/widgets/devices.py +133 -0
  147. microEye/hardware/widgets/focusWidget.py +264 -0
  148. microEye/hardware/widgets/qlist_slider.py +113 -0
  149. microEye/hardware/widgets/scan_acquisition.py +424 -0
  150. microEye/icons/1024.png +0 -0
  151. microEye/icons/128.png +0 -0
  152. microEye/icons/16.png +0 -0
  153. microEye/icons/24.png +0 -0
  154. microEye/icons/256.png +0 -0
  155. microEye/icons/32.png +0 -0
  156. microEye/icons/48.png +0 -0
  157. microEye/icons/512.png +0 -0
  158. microEye/icons/64.png +0 -0
  159. microEye/icons/__init__.py +0 -0
  160. microEye/icons/close.svg +88 -0
  161. microEye/icons/mieye.png +0 -0
  162. microEye/icons/min.svg +83 -0
  163. microEye/icons/viewer.png +0 -0
  164. microEye/launcher.py +42 -0
  165. microEye/qt.py +181 -0
  166. microEye/utils/__init__.py +2 -0
  167. microEye/utils/enum_encoder.py +10 -0
  168. microEye/utils/expandable_groupbox.py +93 -0
  169. microEye/utils/gui_helper.py +457 -0
  170. microEye/utils/hid/__init__.py +8 -0
  171. microEye/utils/hid/controller.py +153 -0
  172. microEye/utils/hid/device.py +63 -0
  173. microEye/utils/hid/enums.py +140 -0
  174. microEye/utils/hid/utils.py +58 -0
  175. microEye/utils/labelled_slider.py +134 -0
  176. microEye/utils/metadata.py +599 -0
  177. microEye/utils/metadata_tree.py +718 -0
  178. microEye/utils/micro_launcher.py +245 -0
  179. microEye/utils/parameter_tree.py +325 -0
  180. microEye/utils/pyscripting.py +444 -0
  181. microEye/utils/retry_exec.py +35 -0
  182. microEye/utils/start_gui.py +112 -0
  183. microEye/utils/thread_worker.py +115 -0
  184. microEye/utils/uImage.py +1512 -0
  185. microeye-2.3.2.dist-info/METADATA +401 -0
  186. microeye-2.3.2.dist-info/RECORD +190 -0
  187. microeye-2.3.2.dist-info/WHEEL +5 -0
  188. microeye-2.3.2.dist-info/entry_points.txt +2 -0
  189. microeye-2.3.2.dist-info/licenses/LICENSE +674 -0
  190. microeye-2.3.2.dist-info/top_level.txt +1 -0
@@ -0,0 +1,245 @@
1
+ import importlib
2
+ import os
3
+ import subprocess
4
+ from collections.abc import Iterable
5
+
6
+ import pkg_resources
7
+
8
+ from microEye.qt import QApplication, Qt, QtCore, QtGui, QtSvg, QtWidgets
9
+ from microEye.utils.start_gui import StartGUI
10
+
11
+
12
+ def check_modules(modules):
13
+ availability = {}
14
+ for module in modules:
15
+ try:
16
+ imported_module = importlib.import_module(module)
17
+ try:
18
+ version = pkg_resources.get_distribution(module).version
19
+ except pkg_resources.DistributionNotFound:
20
+ version = 'Version not found'
21
+ availability[module] = version
22
+ except ImportError:
23
+ availability[module] = None
24
+ return availability
25
+
26
+
27
+ class microLauncher(QtWidgets.QMainWindow):
28
+ def __init__(self):
29
+ super().__init__()
30
+
31
+ # Remove the title bar
32
+ self.setWindowFlags(Qt.WindowType.FramelessWindowHint)
33
+
34
+ # Set round corners, white border, and dark gray background
35
+ self.setStyleSheet('''
36
+ microLauncher {
37
+ border: 1px solid white !important;
38
+ padding: 0;
39
+ }
40
+ QPushButton#closeButton {
41
+ border: none;
42
+ }
43
+ QPushButton#minButton {
44
+ border: none;
45
+ }
46
+ ''')
47
+
48
+ self.dirname = os.path.dirname(os.path.abspath(__file__))
49
+
50
+ width = 160
51
+ height = 130
52
+
53
+ # Create a close button with SVG icon
54
+ self.close_button = QtWidgets.QPushButton()
55
+ self.close_button.setObjectName('closeButton')
56
+ self.close_button.setFixedSize(30, 30)
57
+ self.close_button.clicked.connect(self.close)
58
+
59
+ self.minimize_button = QtWidgets.QPushButton()
60
+ self.minimize_button.setObjectName('minButton')
61
+ self.minimize_button.setFixedSize(30, 30)
62
+ self.minimize_button.clicked.connect(lambda: self.showMinimized())
63
+
64
+ # Load SVG and set as icon
65
+ svg_renderer = QtSvg.QSvgRenderer(
66
+ os.path.join(self.dirname, '../icons/close.svg')
67
+ )
68
+ svg_renderer.setAspectRatioMode(Qt.AspectRatioMode.KeepAspectRatio)
69
+ svg_pixmap = QtGui.QPixmap(24, 24)
70
+ svg_pixmap.fill(QtCore.Qt.GlobalColor.transparent)
71
+ painter = QtGui.QPainter(svg_pixmap)
72
+ svg_renderer.render(painter)
73
+ painter.end()
74
+ self.close_button.setIcon(QtGui.QIcon(svg_pixmap))
75
+ self.close_button.setIconSize(QtCore.QSize(24, 24))
76
+
77
+ svg_renderer = QtSvg.QSvgRenderer(
78
+ os.path.join(self.dirname, '../icons/min.svg')
79
+ )
80
+ svg_renderer.setAspectRatioMode(Qt.AspectRatioMode.KeepAspectRatio)
81
+ svg_pixmap = QtGui.QPixmap(24, 24)
82
+ svg_pixmap.fill(QtCore.Qt.GlobalColor.transparent)
83
+ painter = QtGui.QPainter(svg_pixmap)
84
+ svg_renderer.render(painter)
85
+ painter.end()
86
+ self.minimize_button.setIcon(QtGui.QIcon(svg_pixmap))
87
+ self.minimize_button.setIconSize(QtCore.QSize(24, 24))
88
+
89
+ # Layout for close button
90
+ self.close_button_layout = QtWidgets.QHBoxLayout()
91
+ self.close_button_layout.addStretch()
92
+ self.close_button_layout.addWidget(self.minimize_button)
93
+ self.close_button_layout.addWidget(self.close_button)
94
+
95
+ # Set the main layout
96
+ self.main_layout = QtWidgets.QVBoxLayout()
97
+ self.main_layout.addLayout(self.close_button_layout)
98
+
99
+ # Create buttons with images
100
+ self.button1 = QtWidgets.QPushButton()
101
+ pixmap1 = QtGui.QPixmap(
102
+ os.path.join(self.dirname, '../icons/mieye.png')
103
+ ).scaled(
104
+ width,
105
+ height,
106
+ Qt.AspectRatioMode.KeepAspectRatio,
107
+ Qt.TransformationMode.SmoothTransformation,
108
+ )
109
+ self.button1.setIcon(QtGui.QIcon(pixmap1))
110
+ self.button1.setIconSize(QtCore.QSize(width, height))
111
+ self.button1.clicked.connect(lambda: self.launch_module())
112
+
113
+ self.button2 = QtWidgets.QPushButton()
114
+ pixmap2 = QtGui.QPixmap(
115
+ os.path.join(self.dirname, '../icons/viewer.png')
116
+ ).scaled(
117
+ width,
118
+ height,
119
+ Qt.AspectRatioMode.KeepAspectRatio,
120
+ Qt.TransformationMode.SmoothTransformation,
121
+ )
122
+ self.button2.setIcon(QtGui.QIcon(pixmap2))
123
+ self.button2.setIconSize(QtCore.QSize(width, height))
124
+ self.button2.clicked.connect(lambda: self.launch_module('viewer'))
125
+
126
+ # Create comboboxes
127
+ self.qt_api_combobox = QtWidgets.QComboBox()
128
+ self.populate_combobox(self.qt_api_combobox, ['PySide6', 'PyQt5', 'PyQt6'])
129
+
130
+ self.theme_combobox = QtWidgets.QComboBox()
131
+ self.populate_combobox(
132
+ self.theme_combobox, ['qdarktheme', 'qdarkstyle', 'None'], True
133
+ )
134
+
135
+ # Layout for buttons
136
+ self.buttons_layout = QtWidgets.QHBoxLayout()
137
+ self.buttons_layout.addWidget(self.button1)
138
+ self.buttons_layout.addWidget(self.button2)
139
+
140
+ # Add widgets to the main layout
141
+ self.main_layout.addLayout(self.buttons_layout)
142
+ self.main_layout.addWidget(self.qt_api_combobox)
143
+ self.main_layout.addWidget(self.theme_combobox)
144
+
145
+ # Set central widget
146
+ central_widget = QtWidgets.QWidget()
147
+ central_widget.setLayout(self.main_layout)
148
+ self.setCentralWidget(central_widget)
149
+
150
+ # Window size and title
151
+ self.setWindowTitle('microEye Launcher')
152
+ # self.resize(400, 300)
153
+ self.setContentsMargins(0, 0, 0, 0)
154
+
155
+ self.show()
156
+ self.center()
157
+
158
+ def launch_module(self, module='mieye'):
159
+ '''Launch the selected module'''
160
+ qt_api = self.qt_api_combobox.currentText()
161
+ miTheme = self.theme_combobox.currentText()
162
+
163
+ env = dict(os.environ, QT_API=qt_api, PYQTGRAPH_QT_LIB=qt_api, MITHEME=miTheme)
164
+
165
+ # Define the command and arguments
166
+ cmd = ['python', '-m', 'microEye.launcher', '--module', module]
167
+
168
+ # Get the current working directory
169
+ cwd = os.getcwd()
170
+
171
+ # Open a new terminal and run the command
172
+ if os.name == 'nt': # Windows
173
+ flags = 0
174
+ flags |= subprocess.DETACHED_PROCESS
175
+ flags |= subprocess.CREATE_NEW_PROCESS_GROUP
176
+ flags |= subprocess.CREATE_BREAKAWAY_FROM_JOB
177
+ flags |= subprocess.CREATE_NO_WINDOW
178
+
179
+ pkwargs = {
180
+ 'close_fds': True, # close stdin/stdout/stderr on child
181
+ 'creationflags': flags,
182
+ }
183
+ subprocess.Popen(
184
+ ['start', 'cmd', '/k'] + cmd, cwd=cwd, shell=True, env=env, **pkwargs
185
+ )
186
+ # self.close()
187
+ else: # Unix-based systems (Linux, macOS, etc.)
188
+ subprocess.Popen(
189
+ ['setsid', 'gnome-terminal', '--working-directory=' + cwd, '--'] + cmd,
190
+ env=env,
191
+ )
192
+ self.close()
193
+
194
+ def center(self):
195
+ '''Centers the window within the screen.'''
196
+ qtRectangle = self.frameGeometry()
197
+ centerPoint = QApplication.primaryScreen().availableGeometry().center()
198
+ qtRectangle.moveCenter(centerPoint)
199
+ self.move(qtRectangle.topLeft())
200
+
201
+ def populate_combobox(self, combobox, items: Iterable[str], theme=False):
202
+ model = QtGui.QStandardItemModel()
203
+ availability = check_modules(items)
204
+ for item in items:
205
+ standard_item = QtGui.QStandardItem(item)
206
+ if availability[item] is None and item.lower() != 'none':
207
+ disabledColor = QtGui.QBrush(QtGui.QColor(Qt.GlobalColor.red))
208
+ standard_item.setData(
209
+ disabledColor, QtCore.Qt.ItemDataRole.ForegroundRole
210
+ )
211
+ standard_item.setEnabled(False)
212
+ standard_item.setToolTip(f'{standard_item.text()} is not installed')
213
+ elif item.lower() != 'none':
214
+ prefix = (
215
+ '' if availability[item] == 'Version not found' else 'Version: '
216
+ )
217
+ standard_item.setToolTip(f'{prefix}{availability[item]}')
218
+ model.appendRow(standard_item)
219
+
220
+ if theme:
221
+ for item in QtWidgets.QStyleFactory.keys(): # noqa: SIM118
222
+ standard_item = QtGui.QStandardItem(item)
223
+ model.appendRow(standard_item)
224
+ combobox.setModel(model)
225
+
226
+ def StartGUI():
227
+ '''
228
+ Initializes a new QApplication and microLauncher.
229
+
230
+ Parameters
231
+ ----------
232
+ path : str, optional
233
+ The path to a file to be loaded initially.
234
+
235
+ Returns
236
+ -------
237
+ tuple of QApplication and microLauncher
238
+ Returns a tuple with QApplication and microLauncher window.
239
+ '''
240
+ return StartGUI(microLauncher, theme=None)
241
+
242
+
243
+ if __name__ == '__main__':
244
+ app, window = microLauncher.StartGUI()
245
+ app.exec()
@@ -0,0 +1,325 @@
1
+ import json
2
+ from enum import Enum
3
+ from typing import Any, Optional, Union
4
+
5
+ from pyqtgraph.parametertree import Parameter, ParameterTree
6
+ from pyqtgraph.parametertree.parameterTypes import ActionParameter, GroupParameter
7
+
8
+ from microEye.qt import QtWidgets, Signal, Slot, getOpenFileName, getSaveFileName
9
+
10
+
11
+ class Tree(ParameterTree):
12
+ '''
13
+ Tree widget for editing parameters.
14
+
15
+ Attributes
16
+ ----------
17
+ paramsChanged : Signal
18
+ Signal for parameter changed event.
19
+ '''
20
+
21
+ PARAMS: type[Enum] = None
22
+
23
+ paramsChanged = Signal(Parameter, object)
24
+ '''Signal emitted when parameters are changed.
25
+
26
+ Parameters
27
+ ----------
28
+ GroupParameter
29
+ The group parameter that was changed.
30
+ list
31
+ A list of changes made to the parameter.
32
+ '''
33
+
34
+ def __init__(self, parent: Optional['QtWidgets.QWidget'] = None):
35
+ '''
36
+ Initialize the Tree.
37
+
38
+ Parameters
39
+ ----------
40
+ parent : QWidget, optional
41
+ The parent widget, by default None.
42
+ '''
43
+ super().__init__(parent=parent)
44
+
45
+ self.setMinimumWidth(50)
46
+ self.create_parameters()
47
+ self.setParameters(self.param_tree, showTop=False)
48
+
49
+ def create_parameters(self):
50
+ '''
51
+ Create the parameter tree structure.
52
+
53
+ Reimplement in child class.
54
+ '''
55
+ params = []
56
+
57
+ self.param_tree = Parameter.create(name='', type='group', children=params)
58
+ self.param_tree.sigTreeStateChanged.connect(self.change)
59
+ self.header().setSectionResizeMode(QtWidgets.QHeaderView.ResizeMode.Stretch)
60
+
61
+ def get_param(self, param: Union[Enum, str]) -> Union[Parameter, ActionParameter]:
62
+ '''Get a parameter by name.
63
+
64
+ Parameters
65
+ ----------
66
+ param : Enum
67
+ parameter.
68
+
69
+ Returns
70
+ -------
71
+ Union[Parameter, ActionParameter]
72
+ Retrieved parameter.
73
+ '''
74
+ try:
75
+ if isinstance(param, Enum):
76
+ return self.param_tree.param(*param.value.split('.'))
77
+ else:
78
+ return self.param_tree.param(*param.split('.'))
79
+ except KeyError:
80
+ return None
81
+
82
+ def get_param_value(self, param: Union[Enum, str]):
83
+ '''Get a parameter value by name.
84
+
85
+ Parameters
86
+ ----------
87
+ param : Enum
88
+ parameter.
89
+
90
+ Returns
91
+ -------
92
+ Any
93
+ The value of the parameter.
94
+ '''
95
+ try:
96
+ if isinstance(param, Enum):
97
+ return self.param_tree.param(*param.value.split('.')).value()
98
+ else:
99
+ return self.param_tree.param(*param.split('.')).value()
100
+ except KeyError:
101
+ return None
102
+
103
+ def set_param_value(
104
+ self, param: Enum, value, blockSignals: Union[Any, None] = None
105
+ ):
106
+ '''
107
+ Set a parameter value by name.
108
+
109
+ Parameters
110
+ ----------
111
+ param : Enum
112
+ parameter.
113
+ value : Any
114
+ The value to set.
115
+ blockSignals : Union[Any, None], optional
116
+ If provided, signals for parameter changes are blocked during the update.
117
+ The interpretation of the value is left to the implementation.
118
+
119
+ Returns
120
+ -------
121
+ bool
122
+ True if the value is set successfully, False otherwise.
123
+ '''
124
+ try:
125
+ parameter: Parameter = self.param_tree.param(*param.value.split('.'))
126
+ parameter.setValue(value, blockSignals)
127
+ except Exception:
128
+ import traceback
129
+
130
+ traceback.print_exc()
131
+ return False
132
+ else:
133
+ return True
134
+
135
+ def get_param_path(self, param: Parameter):
136
+ '''
137
+ Get the child path of a parameter in the parameter tree.
138
+
139
+ Parameters
140
+ ----------
141
+ param : Parameter
142
+ The parameter for which to retrieve the child path.
143
+
144
+ Returns
145
+ -------
146
+ list
147
+ The child path of the parameter.
148
+ '''
149
+ return self.param_tree.childPath(param)
150
+
151
+ def add_param_child(self, parent: Enum, value: dict):
152
+ """
153
+ Add a child parameter to the specified parent parameter.
154
+
155
+ Parameters
156
+ ----------
157
+ parent : Enum
158
+ The parent parameter to which the child will be added.
159
+ value : dict
160
+ A dictionary representing the child parameter. It should contain at
161
+ least the following key-value pairs:
162
+ - 'name': str, the name of the parameter.
163
+ - 'type': str, the type of the parameter (e.g., 'int', 'float', 'str').
164
+ - 'value': Any, the initial value of the parameter.
165
+ Additional optional keys can be included based on the desired configuration.
166
+
167
+ Returns
168
+ -------
169
+ None
170
+ """
171
+ parent = self.get_param(parent)
172
+ parent.addChild(value, autoIncrementName=True)
173
+
174
+ def get_children(self, param: Enum):
175
+ """
176
+ Get the values of all children of a specified parameter.
177
+
178
+ Parameters
179
+ ----------
180
+ param : Enum
181
+ The parameter whose children's values will be retrieved.
182
+
183
+ Returns
184
+ -------
185
+ list
186
+ List of values of all children of the specified parameter.
187
+ """
188
+ res = []
189
+ param = self.get_param(param)
190
+ if isinstance(param, GroupParameter):
191
+ for child in param.children():
192
+ res.append(child.value())
193
+ return res
194
+
195
+ def change(self, param: Parameter, changes: list):
196
+ '''
197
+ Handle parameter changes as needed.
198
+
199
+ Parameters
200
+ ----------
201
+ param : Parameter
202
+ The parameter that triggered the change.
203
+ changes : list
204
+ List of changes.
205
+
206
+ Returns
207
+ -------
208
+ None
209
+ '''
210
+ # Handle parameter changes as needed
211
+ pass
212
+
213
+ @Slot(object)
214
+ def export_json(self, action=None):
215
+ '''
216
+ Export parameters to a JSON file.
217
+
218
+ Returns
219
+ -------
220
+ None
221
+ '''
222
+ filename, _ = getSaveFileName(
223
+ None, 'Save Parameters', '', 'JSON Files (*.json);;All Files (*)'
224
+ )
225
+ if not filename:
226
+ return # User canceled the operation
227
+
228
+ state = self.param_tree.saveState()
229
+ with open(filename, 'w', encoding='utf8') as file:
230
+ json.dump(state, file, indent=2)
231
+
232
+ def get_json(self):
233
+ '''
234
+ Export parameters to a JSON text.
235
+
236
+ Returns
237
+ -------
238
+ str
239
+ A string containing all parameters in JSON format.
240
+ '''
241
+ return self.param_tree.saveState()
242
+
243
+ # Load parameters from JSON
244
+ @Slot(object)
245
+ def load_json(self, action=None):
246
+ '''
247
+ Load parameters from a JSON file.
248
+
249
+ Returns
250
+ -------
251
+ None
252
+ '''
253
+ filename, _ = getOpenFileName(
254
+ None, 'Load Parameters', '', 'JSON Files (*.json);;All Files (*)'
255
+ )
256
+ if not filename:
257
+ return # User canceled the operation
258
+
259
+ with open(filename, encoding='utf8') as file:
260
+ state = json.load(file)
261
+ self.param_tree.restoreState(
262
+ state, addChildren=False, removeChildren=False, blockSignals=False)
263
+
264
+ def get_param_paths(self) -> list[str]:
265
+ '''
266
+ Get a list of all parameter paths in the tree, excluding group parameters.
267
+
268
+ Returns
269
+ -------
270
+ list
271
+ A list of all parameter paths, excluding groups.
272
+ '''
273
+
274
+ def collect_paths(param, current_path=None):
275
+ paths = []
276
+ if current_path is None:
277
+ current_path = []
278
+ for child in param.children():
279
+ child_path = current_path + [child.name()]
280
+ if not child.hasChildren(): # This checks if parameter is not a group
281
+ paths.append('.'.join(child_path))
282
+ else:
283
+ paths.extend(collect_paths(child, child_path))
284
+ return paths
285
+
286
+ return collect_paths(self.param_tree)
287
+
288
+ def search_param(self, contains: str) -> Union[None, Parameter, ActionParameter]:
289
+ '''
290
+ Find parameter that contains the supplied string
291
+ in the tree and return it if found.
292
+
293
+ Parameters
294
+ ----------
295
+ contains : str
296
+ The string to search for in the parameter paths.
297
+
298
+ Returns
299
+ -------
300
+ object or None
301
+ The value of the first parameter that contains the supplied string,
302
+ or None if no match is found.
303
+ '''
304
+ path = [
305
+ path
306
+ for path in self.get_param_paths()
307
+ if contains.lower().strip() in path.lower().split('.')[-1]
308
+ ]
309
+ if path:
310
+ self.get_param(path[0])
311
+ else:
312
+ return None
313
+
314
+ def set_expanded(self, param: Union[Parameter, Enum, str], value: bool = False):
315
+ if isinstance(param, (Enum, str)):
316
+ param = self.get_param(param)
317
+
318
+ if not isinstance(param, Parameter):
319
+ return
320
+
321
+ if param:
322
+ for item in self.listAllItems():
323
+ if item.param == param:
324
+ item.setExpanded(value)
325
+ break