pymodaq 5.1.6__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 (154) hide show
  1. pymodaq/__init__.py +98 -0
  2. pymodaq/control_modules/__init__.py +1 -0
  3. pymodaq/control_modules/daq_move.py +1238 -0
  4. pymodaq/control_modules/daq_move_ui/__init__.py +0 -0
  5. pymodaq/control_modules/daq_move_ui/factory.py +48 -0
  6. pymodaq/control_modules/daq_move_ui/ui_base.py +359 -0
  7. pymodaq/control_modules/daq_move_ui/uis/__init__.py +0 -0
  8. pymodaq/control_modules/daq_move_ui/uis/binary.py +139 -0
  9. pymodaq/control_modules/daq_move_ui/uis/original.py +120 -0
  10. pymodaq/control_modules/daq_move_ui/uis/relative.py +124 -0
  11. pymodaq/control_modules/daq_move_ui/uis/simple.py +126 -0
  12. pymodaq/control_modules/daq_viewer.py +1517 -0
  13. pymodaq/control_modules/daq_viewer_ui.py +407 -0
  14. pymodaq/control_modules/mocks.py +57 -0
  15. pymodaq/control_modules/move_utility_classes.py +1141 -0
  16. pymodaq/control_modules/thread_commands.py +137 -0
  17. pymodaq/control_modules/ui_utils.py +72 -0
  18. pymodaq/control_modules/utils.py +591 -0
  19. pymodaq/control_modules/viewer_utility_classes.py +670 -0
  20. pymodaq/daq_utils/__init__.py +0 -0
  21. pymodaq/daq_utils/daq_utils.py +6 -0
  22. pymodaq/dashboard.py +2396 -0
  23. pymodaq/examples/Labview_TCP_Client/DAQ_TCP_Client.aliases +3 -0
  24. pymodaq/examples/Labview_TCP_Client/DAQ_TCP_Client.lvlps +3 -0
  25. pymodaq/examples/Labview_TCP_Client/DAQ_TCP_Client.lvproj +32 -0
  26. pymodaq/examples/Labview_TCP_Client/DAQ_TCP_Client.vi +0 -0
  27. pymodaq/examples/Labview_TCP_Client/DAQ_TCP_Server_1Dgaussian.vi +0 -0
  28. pymodaq/examples/Labview_TCP_Client/DAQ_TCP_Server_2Dgaussian.vi +0 -0
  29. pymodaq/examples/Labview_TCP_Client/DAQ_TCP_read_cmd.vi +0 -0
  30. pymodaq/examples/Labview_TCP_Client/DAQ_TCP_read_float.vi +0 -0
  31. pymodaq/examples/Labview_TCP_Client/DAQ_TCP_read_int.vi +0 -0
  32. pymodaq/examples/Labview_TCP_Client/DAQ_TCP_send_data.vi +0 -0
  33. pymodaq/examples/Labview_TCP_Client/DAQ_TCP_send_int.vi +0 -0
  34. pymodaq/examples/Labview_TCP_Client/DAQ_TCP_send_scalar.vi +0 -0
  35. pymodaq/examples/Labview_TCP_Client/DAQ_TCP_send_string.vi +0 -0
  36. pymodaq/examples/Labview_TCP_Client/client_state.ctl +0 -0
  37. pymodaq/examples/Labview_TCP_Client/cmd_types.ctl +0 -0
  38. pymodaq/examples/__init__.py +0 -0
  39. pymodaq/examples/function_plotter.py +160 -0
  40. pymodaq/examples/nonlinearscanner.py +126 -0
  41. pymodaq/examples/qt_less_standalone_module.py +165 -0
  42. pymodaq/examples/tcp_client.py +97 -0
  43. pymodaq/extensions/__init__.py +25 -0
  44. pymodaq/extensions/adaptive/__init__.py +2 -0
  45. pymodaq/extensions/adaptive/adaptive_optimization.py +179 -0
  46. pymodaq/extensions/adaptive/loss_function/_1d_loss_functions.py +73 -0
  47. pymodaq/extensions/adaptive/loss_function/_2d_loss_functions.py +73 -0
  48. pymodaq/extensions/adaptive/loss_function/__init__.py +3 -0
  49. pymodaq/extensions/adaptive/loss_function/loss_factory.py +110 -0
  50. pymodaq/extensions/adaptive/utils.py +123 -0
  51. pymodaq/extensions/bayesian/__init__.py +2 -0
  52. pymodaq/extensions/bayesian/acquisition/__init__.py +2 -0
  53. pymodaq/extensions/bayesian/acquisition/acquisition_function_factory.py +80 -0
  54. pymodaq/extensions/bayesian/acquisition/base_acquisition_function.py +105 -0
  55. pymodaq/extensions/bayesian/bayesian_optimization.py +143 -0
  56. pymodaq/extensions/bayesian/utils.py +180 -0
  57. pymodaq/extensions/console.py +73 -0
  58. pymodaq/extensions/daq_logger/__init__.py +1 -0
  59. pymodaq/extensions/daq_logger/abstract.py +52 -0
  60. pymodaq/extensions/daq_logger/daq_logger.py +519 -0
  61. pymodaq/extensions/daq_logger/db/__init__.py +0 -0
  62. pymodaq/extensions/daq_logger/db/db_logger.py +300 -0
  63. pymodaq/extensions/daq_logger/db/db_logger_models.py +100 -0
  64. pymodaq/extensions/daq_logger/h5logging.py +84 -0
  65. pymodaq/extensions/daq_scan.py +1218 -0
  66. pymodaq/extensions/daq_scan_ui.py +241 -0
  67. pymodaq/extensions/data_mixer/__init__.py +0 -0
  68. pymodaq/extensions/data_mixer/daq_0Dviewer_DataMixer.py +97 -0
  69. pymodaq/extensions/data_mixer/data_mixer.py +262 -0
  70. pymodaq/extensions/data_mixer/model.py +108 -0
  71. pymodaq/extensions/data_mixer/models/__init__.py +0 -0
  72. pymodaq/extensions/data_mixer/models/equation_model.py +91 -0
  73. pymodaq/extensions/data_mixer/models/gaussian_fit_model.py +65 -0
  74. pymodaq/extensions/data_mixer/parser.py +53 -0
  75. pymodaq/extensions/data_mixer/utils.py +23 -0
  76. pymodaq/extensions/h5browser.py +9 -0
  77. pymodaq/extensions/optimizers_base/__init__.py +0 -0
  78. pymodaq/extensions/optimizers_base/optimizer.py +1016 -0
  79. pymodaq/extensions/optimizers_base/thread_commands.py +22 -0
  80. pymodaq/extensions/optimizers_base/utils.py +427 -0
  81. pymodaq/extensions/pid/__init__.py +16 -0
  82. pymodaq/extensions/pid/actuator_controller.py +14 -0
  83. pymodaq/extensions/pid/daq_move_PID.py +154 -0
  84. pymodaq/extensions/pid/pid_controller.py +1016 -0
  85. pymodaq/extensions/pid/utils.py +189 -0
  86. pymodaq/extensions/utils.py +111 -0
  87. pymodaq/icon.ico +0 -0
  88. pymodaq/post_treatment/__init__.py +6 -0
  89. pymodaq/post_treatment/load_and_plot.py +352 -0
  90. pymodaq/resources/__init__.py +0 -0
  91. pymodaq/resources/config_template.toml +57 -0
  92. pymodaq/resources/preset_default.xml +1 -0
  93. pymodaq/resources/setup_plugin.py +73 -0
  94. pymodaq/splash.png +0 -0
  95. pymodaq/utils/__init__.py +0 -0
  96. pymodaq/utils/array_manipulation.py +6 -0
  97. pymodaq/utils/calibration_camera.py +180 -0
  98. pymodaq/utils/chrono_timer.py +203 -0
  99. pymodaq/utils/config.py +53 -0
  100. pymodaq/utils/conftests.py +5 -0
  101. pymodaq/utils/daq_utils.py +158 -0
  102. pymodaq/utils/data.py +128 -0
  103. pymodaq/utils/enums.py +6 -0
  104. pymodaq/utils/exceptions.py +38 -0
  105. pymodaq/utils/gui_utils/__init__.py +10 -0
  106. pymodaq/utils/gui_utils/loader_utils.py +75 -0
  107. pymodaq/utils/gui_utils/utils.py +18 -0
  108. pymodaq/utils/gui_utils/widgets/lcd.py +8 -0
  109. pymodaq/utils/h5modules/__init__.py +2 -0
  110. pymodaq/utils/h5modules/module_saving.py +526 -0
  111. pymodaq/utils/leco/__init__.py +25 -0
  112. pymodaq/utils/leco/daq_move_LECODirector.py +217 -0
  113. pymodaq/utils/leco/daq_xDviewer_LECODirector.py +163 -0
  114. pymodaq/utils/leco/director_utils.py +74 -0
  115. pymodaq/utils/leco/leco_director.py +166 -0
  116. pymodaq/utils/leco/pymodaq_listener.py +364 -0
  117. pymodaq/utils/leco/rpc_method_definitions.py +43 -0
  118. pymodaq/utils/leco/utils.py +74 -0
  119. pymodaq/utils/logger.py +6 -0
  120. pymodaq/utils/managers/__init__.py +0 -0
  121. pymodaq/utils/managers/batchscan_manager.py +346 -0
  122. pymodaq/utils/managers/modules_manager.py +589 -0
  123. pymodaq/utils/managers/overshoot_manager.py +242 -0
  124. pymodaq/utils/managers/preset_manager.py +229 -0
  125. pymodaq/utils/managers/preset_manager_utils.py +262 -0
  126. pymodaq/utils/managers/remote_manager.py +484 -0
  127. pymodaq/utils/math_utils.py +6 -0
  128. pymodaq/utils/messenger.py +6 -0
  129. pymodaq/utils/parameter/__init__.py +10 -0
  130. pymodaq/utils/parameter/utils.py +6 -0
  131. pymodaq/utils/scanner/__init__.py +5 -0
  132. pymodaq/utils/scanner/scan_config.py +16 -0
  133. pymodaq/utils/scanner/scan_factory.py +259 -0
  134. pymodaq/utils/scanner/scan_selector.py +477 -0
  135. pymodaq/utils/scanner/scanner.py +324 -0
  136. pymodaq/utils/scanner/scanners/_1d_scanners.py +174 -0
  137. pymodaq/utils/scanner/scanners/_2d_scanners.py +299 -0
  138. pymodaq/utils/scanner/scanners/__init__.py +1 -0
  139. pymodaq/utils/scanner/scanners/sequential.py +224 -0
  140. pymodaq/utils/scanner/scanners/tabular.py +319 -0
  141. pymodaq/utils/scanner/utils.py +110 -0
  142. pymodaq/utils/svg/__init__.py +6 -0
  143. pymodaq/utils/svg/svg_renderer.py +20 -0
  144. pymodaq/utils/svg/svg_view.py +35 -0
  145. pymodaq/utils/svg/svg_viewer2D.py +50 -0
  146. pymodaq/utils/tcp_ip/__init__.py +6 -0
  147. pymodaq/utils/tcp_ip/mysocket.py +12 -0
  148. pymodaq/utils/tcp_ip/serializer.py +13 -0
  149. pymodaq/utils/tcp_ip/tcp_server_client.py +772 -0
  150. pymodaq-5.1.6.dist-info/METADATA +238 -0
  151. pymodaq-5.1.6.dist-info/RECORD +154 -0
  152. pymodaq-5.1.6.dist-info/WHEEL +4 -0
  153. pymodaq-5.1.6.dist-info/entry_points.txt +7 -0
  154. pymodaq-5.1.6.dist-info/licenses/LICENSE +21 -0
@@ -0,0 +1,299 @@
1
+ # -*- coding: utf-8 -*-
2
+ """
3
+ Created the 05/12/2022
4
+
5
+ @author: Sebastien Weber
6
+ """
7
+ from typing import List, Tuple, TYPE_CHECKING
8
+
9
+ import numpy as np
10
+ from pymodaq_data.data import Axis, DataDistribution
11
+ from pymodaq_utils.logger import set_logger, get_module_name
12
+ from pymodaq_utils import math_utils as mutils
13
+ from pymodaq_utils import config as configmod
14
+ from pymodaq.utils.scanner.scan_selector import Selector
15
+
16
+ from ..scan_factory import ScannerFactory, ScannerBase, ScanParameterManager
17
+
18
+ logger = set_logger(get_module_name(__file__))
19
+ config = configmod.Config()
20
+
21
+ if TYPE_CHECKING:
22
+ from pymodaq.control_modules.daq_move import DAQ_Move
23
+
24
+
25
+ class Scan2DBase(ScannerBase):
26
+ params = [{'title': 'Ax1:', 'name': 'axis1', 'type': 'group',
27
+ 'children':[]
28
+ },
29
+ {'title': 'Ax2:', 'name': 'axis2', 'type': 'group',
30
+ 'children':[]
31
+ },
32
+ ]
33
+ axes = ('axis1','axis2')
34
+ n_axes = 2
35
+ def __init__(self, actuators: List['DAQ_Move'] = None, display_units=True, **_ignored):
36
+ super().__init__(actuators=actuators, display_units=display_units)
37
+ self.axes_unique = []
38
+
39
+
40
+ @ScannerFactory.register()
41
+ class Scan2DLinear(Scan2DBase):
42
+
43
+ params = [{'title': 'Ax1:', 'name': 'axis1', 'type': 'group',
44
+ 'children':[
45
+ {'title': 'Start Ax1:', 'name': 'start_axis1', 'type': 'float',
46
+ 'value': 0.},
47
+ {'title': 'Stop Ax1:', 'name': 'stop_axis1', 'type': 'float',
48
+ 'value': 1.},
49
+ {'title': 'Step Ax1:', 'name': 'step_axis1', 'type': 'float',
50
+ 'value': 0.1},
51
+ ]},
52
+ {'title': 'Ax2:', 'name': 'axis2', 'type': 'group',
53
+ 'children':[
54
+ {'title': 'Start Ax2:', 'name': 'start_axis2', 'type': 'float',
55
+ 'value': 0.},
56
+ {'title': 'Stop Ax2:', 'name': 'stop_axis2', 'type': 'float',
57
+ 'value': 1.},
58
+ {'title': 'Step Ax2:', 'name': 'step_axis2', 'type': 'float',
59
+ 'value': 0.1},
60
+ ]},
61
+ ]
62
+ n_axes = 2
63
+ distribution = DataDistribution['uniform']
64
+ scan_type = 'Scan2D'
65
+ scan_subtype = 'Linear'
66
+
67
+ def __init__(self, actuators: List['DAQ_Move'] = None, display_units=True, **_ignored):
68
+ super().__init__(actuators=actuators, display_units=display_units)
69
+
70
+ def set_units(self):
71
+ """ Update settings units depending on the scanner type and the display_units boolean"""
72
+ if len(self.actuators) > 0:
73
+ for child in self.settings.child('axis1').children():
74
+ child.setOpts(
75
+ suffix='' if not self.display_units else self.actuators[0].units)
76
+ if len(self.actuators) > 1:
77
+ for child in self.settings.child('axis2').children():
78
+ child.setOpts(
79
+ suffix='' if not self.display_units else self.actuators[1].units)
80
+
81
+ def get_pos(self):
82
+ starts = np.array([self.settings[ax, f'start_{ax}'] for ax in self.axes])
83
+ stops = np.array([self.settings[ax, f'stop_{ax}'] for ax in self.axes])
84
+ steps = np.array([self.settings[ax, f'step_{ax}'] for ax in self.axes])
85
+ return starts, stops, steps
86
+
87
+ def evaluate_steps(self) -> int:
88
+ starts, stops, steps = self.get_pos()
89
+ n_steps = 1
90
+ for ind in range(starts.size):
91
+ n_steps *= np.abs((stops[ind] - starts[ind]) / steps[ind]) + 1
92
+ return int(n_steps)
93
+
94
+ def set_scan(self):
95
+ starts, stops, steps = self.get_pos()
96
+ if np.any(np.abs(steps) < 1e-12) or \
97
+ np.any(np.sign(stops - starts) != np.sign(steps)) or \
98
+ np.any(starts == stops):
99
+
100
+ return np.array([starts])
101
+
102
+ else:
103
+ axis_1_unique = mutils.linspace_step(starts[0], stops[0], steps[0])
104
+ axis_2_unique = mutils.linspace_step(starts[1], stops[1], steps[1])
105
+
106
+ positions = []
107
+ for ind_x, pos1 in enumerate(axis_1_unique):
108
+ for ind_y, pos2 in enumerate(axis_2_unique):
109
+ positions.append([pos1, pos2])
110
+
111
+ self.get_info_from_positions(np.array(positions))
112
+
113
+ def set_settings_titles(self):
114
+ if len(self.actuators) == 2:
115
+ for i,ax in enumerate(self.axes):
116
+ title = self.actuators[i].title
117
+ self.settings.child(ax).setOpts(title=title)
118
+ self.settings.child(ax, f'start_{ax}').setOpts(title=f'{title} start:')
119
+ self.settings.child(ax, f'stop_{ax}').setOpts(title=f'{title} stop:')
120
+ self.settings.child(ax, f'step_{ax}').setOpts(title=f'{title} step:')
121
+
122
+ def get_nav_axes(self) -> List[Axis]:
123
+ return [Axis(label=f'{act.title}',
124
+ units=f'{act.units}',
125
+ data=self.axes_unique[ind],
126
+ index=ind) for ind, act in enumerate(self.actuators)]
127
+
128
+ def get_scan_shape(self) -> Tuple[int]:
129
+ return tuple([len(axis) for axis in self.axes_unique])
130
+
131
+ def get_indexes_from_scan_index(self, scan_index: int) -> Tuple[int]:
132
+ """To be reimplemented. Calculations of indexes within the scan"""
133
+ return tuple(self.axes_indexes[scan_index])
134
+
135
+ def update_from_scan_selector(self, scan_selector: Selector):
136
+ coordinates = scan_selector.get_coordinates()
137
+ if coordinates.shape == (2, 2):
138
+ for i,ax in enumerate(self.axes):
139
+ self.settings.child(ax,f'start_{ax}').setValue(coordinates[0, i])
140
+ self.settings.child(ax,f'stop_{ax}').setValue(coordinates[1, i])
141
+
142
+
143
+ @ScannerFactory.register()
144
+ class Scan2DLinearBF(Scan2DLinear):
145
+ scan_subtype = 'LinearBackForce'
146
+
147
+ def __init__(self, actuators: List['DAQ_Move'] = None, display_units=True, **_ignored):
148
+ super().__init__(actuators=actuators, display_units=display_units)
149
+
150
+ def set_scan(self):
151
+ starts, stops, steps = self.get_pos()
152
+ if np.any(np.abs(steps) < 1e-12) or \
153
+ np.any(np.sign(stops - starts) != np.sign(steps)) or \
154
+ np.any(starts == stops):
155
+
156
+ return np.array([starts])
157
+
158
+ else:
159
+ axis_1_unique = mutils.linspace_step(starts[0], stops[0], steps[0])
160
+ axis_2_unique = mutils.linspace_step(starts[1], stops[1], steps[1])
161
+
162
+ positions = []
163
+ for ind_x, pos1 in enumerate(axis_1_unique):
164
+ for ind_y, pos2 in enumerate(axis_2_unique):
165
+ if not mutils.odd_even(ind_x):
166
+ positions.append([pos1, pos2])
167
+ else:
168
+ positions.append([pos1, axis_2_unique[len(axis_2_unique) - ind_y - 1]])
169
+
170
+ self.get_info_from_positions(np.array(positions))
171
+
172
+
173
+ @ScannerFactory.register()
174
+ class Scan2DRandom(Scan2DLinear):
175
+ scan_subtype = 'Random'
176
+
177
+ def __init__(self, actuators: List['DAQ_Move'] = None, display_units=True, **_ignored):
178
+ super().__init__(actuators=actuators, display_units=display_units)
179
+
180
+ def set_scan(self):
181
+ super().set_scan()
182
+ np.random.shuffle(self.positions)
183
+ self.get_info_from_positions(self.positions)
184
+
185
+
186
+ @ScannerFactory.register()
187
+ class Scan2DSpiral(Scan2DLinear):
188
+ scan_subtype = 'Spiral'
189
+ params = [{'title': 'Npts/axis', 'name': 'npts_by_axis', 'type': 'int', 'min': 1,
190
+ 'value': 10},
191
+ {'title': 'Ax1:', 'name': 'axis1', 'type': 'group',
192
+ 'children': [
193
+ {'title': 'Center Ax1:', 'name': 'center_axis1', 'type': 'float',
194
+ 'value': 0.},
195
+ {'title': 'Rmax Ax1:', 'name': 'rmax_axis1', 'type': 'float',
196
+ 'value': 5.},
197
+ {'title': 'Step Ax1:', 'name': 'step_axis1', 'type': 'float',
198
+ 'value': 0., 'readonly': True},
199
+ ]},
200
+ {'title': 'Ax2:', 'name': 'axis2', 'type': 'group',
201
+ 'children': [
202
+ {'title': 'Center Ax2:', 'name': 'center_axis2', 'type': 'float',
203
+ 'value': 0.},
204
+ {'title': 'Rmax Ax2:', 'name': 'rmax_axis2', 'type': 'float',
205
+ 'value': 5.},
206
+ {'title': 'Step Ax2:', 'name': 'step_axis2', 'type': 'float',
207
+ 'value': 0., 'readonly': True},
208
+ ]},
209
+ ]
210
+
211
+ def __init__(self, actuators: List['DAQ_Move'] = None, display_units=True, **_ignored):
212
+ super().__init__(actuators=actuators, display_units=display_units)
213
+
214
+ def set_settings_titles(self):
215
+ if len(self.actuators) == 2:
216
+ for i,ax in enumerate(self.axes):
217
+ title = self.actuators[i].title
218
+ self.settings.child(ax).setOpts(title=title)
219
+ self.settings.child(ax, f'center_{ax}').setOpts(title=f'{title} center:')
220
+ self.settings.child(ax, f'rmax_{ax}').setOpts(title=f'{title} rmax:')
221
+ self.settings.child(ax, f'step_{ax}').setOpts(title=f'{title} step:')
222
+
223
+ def value_changed(self, param):
224
+ starts, rmaxs, rsteps = self.get_pos()
225
+ for i,ax in enumerate(self.axes):
226
+ self.settings.child(ax,f'step_{ax}').setValue(rsteps[i])
227
+ # self.settings.child('step_axis2').setValue(rsteps[1])
228
+
229
+ def get_pos(self):
230
+ """Get centers, radius and n steps from settings
231
+
232
+ Returns
233
+ ----------
234
+ centers: np.ndarray
235
+ containing the center positions of the scan
236
+ rmaxs: np.ndarray
237
+ containing the maximum radius (ellipse axes) in each direction
238
+ r_steps: np.ndarray
239
+ steps size in both directions
240
+ """
241
+ centers = np.array([self.settings[ax, f'center_{ax}'] for ax in self.axes])
242
+ rmaxs = np.array([self.settings[ax, f'rmax_{ax}'] for ax in self.axes])
243
+ r_steps = 2 * rmaxs / self.settings['npts_by_axis']
244
+ return centers, rmaxs, r_steps
245
+
246
+ def evaluate_steps(self) -> int:
247
+ return int(self.settings['npts_by_axis'] + 1) ** 2
248
+
249
+ def set_scan(self):
250
+ starts, rmaxs, rsteps = self.get_pos()
251
+
252
+ if np.any(np.array(rmaxs) == 0) or np.any(np.abs(rmaxs) < 1e-12) or np.any(np.abs(rsteps) < 1e-12):
253
+ positions = np.array([starts])
254
+
255
+ else:
256
+ Nlin = self.settings['npts_by_axis'] / 2
257
+ axis_1_indexes = [0]
258
+ axis_2_indexes = [0]
259
+ ind = 0
260
+ flag = True
261
+
262
+ while flag:
263
+ if mutils.odd_even(ind):
264
+ step = 1
265
+ else:
266
+ step = -1
267
+ if flag:
268
+
269
+ for ind_step in range(ind):
270
+ axis_1_indexes.append(axis_1_indexes[-1] + step)
271
+ axis_2_indexes.append(axis_2_indexes[-1])
272
+ if len(axis_1_indexes) >= (2 * Nlin + 1) ** 2:
273
+ flag = False
274
+ break
275
+ if flag:
276
+ for ind_step in range(ind):
277
+ axis_1_indexes.append(axis_1_indexes[-1])
278
+ axis_2_indexes.append(axis_2_indexes[-1] + step)
279
+ if len(axis_1_indexes) >= (2 * Nlin + 1) ** 2:
280
+ flag = False
281
+ break
282
+ ind += 1
283
+
284
+ positions = []
285
+ for ind in range(len(axis_1_indexes)):
286
+ positions.append(np.array([axis_1_indexes[ind] * rsteps[0] + starts[0],
287
+ axis_2_indexes[ind] * rsteps[1] + starts[1]]))
288
+
289
+ self.get_info_from_positions(np.array(positions))
290
+
291
+ def update_from_scan_selector(self, scan_selector: Selector):
292
+ coordinates = scan_selector.get_coordinates()
293
+ if coordinates.shape == (2, 2):
294
+ for i,ax in enumerate(self.axes):
295
+ self.settings.child(ax, f'center_{ax}').setValue(
296
+ (coordinates[0, i] + coordinates[1, i]) / 2)
297
+ self.settings.child(ax, f'rmax_{ax}').setValue(
298
+ (coordinates[0, i] - coordinates[1, i]) / 2)
299
+
@@ -0,0 +1 @@
1
+
@@ -0,0 +1,224 @@
1
+ # -*- coding: utf-8 -*-
2
+ """
3
+ Created the 05/12/2022
4
+
5
+ @author: Sebastien Weber
6
+ """
7
+ from typing import List, Tuple, TYPE_CHECKING, Iterable
8
+
9
+ import numpy as np
10
+
11
+ from qtpy import QtCore, QtWidgets
12
+ from pymodaq_data.data import Axis, DataDistribution
13
+ from pymodaq_utils.logger import set_logger, get_module_name
14
+ from pymodaq_utils import math_utils as mutils
15
+ from pymodaq_utils import config as configmod
16
+ from pymodaq_data import Q_
17
+
18
+ from pymodaq_gui import utils as gutils
19
+ from ..scan_factory import ScannerFactory, ScannerBase, ScanParameterManager
20
+ from pymodaq_gui.parameter import utils as putils
21
+ from pymodaq_gui.parameter.pymodaq_ptypes import TableViewCustom
22
+ from pymodaq.utils.scanner.scan_selector import Selector
23
+
24
+ logger = set_logger(get_module_name(__file__))
25
+ config = configmod.Config()
26
+
27
+
28
+ if TYPE_CHECKING:
29
+ from pymodaq.control_modules.daq_move import DAQ_Move
30
+
31
+
32
+ class TableModelSequential(gutils.TableModel):
33
+ """Table Model for the Model/View Qt framework dedicated to the Sequential scan mode"""
34
+ def __init__(self, data, **kwargs):
35
+ header = ['Actuator', 'Start', 'Stop', 'Step']
36
+ if 'header' in kwargs:
37
+ header = kwargs.pop('header')
38
+ editable = [False, True, True, True]
39
+ if 'editable' in kwargs:
40
+ editable = kwargs.pop('editable')
41
+ super().__init__(data, header, editable=editable, cast=str, **kwargs)
42
+
43
+ def __repr__(self):
44
+ return f'{self.__class__.__name__} from module {self.__class__.__module__}'
45
+
46
+ def validate_data(self, row, col, value):
47
+ """
48
+ make sure the values and signs of the start, stop and step values are "correct"
49
+ Parameters
50
+ ----------
51
+ row: (int) row within the table that is to be changed
52
+ col: (int) col within the table that is to be changed
53
+ value: (float) new value for the value defined by row and col
54
+
55
+ Returns
56
+ -------
57
+ bool: True is the new value is fine (change some other values if needed) otherwise False
58
+ """
59
+ start = Q_(self.data(self.index(row, 1), QtCore.Qt.DisplayRole))
60
+ stop = Q_(self.data(self.index(row, 2), QtCore.Qt.DisplayRole))
61
+ step = Q_(self.data(self.index(row, 3), QtCore.Qt.DisplayRole))
62
+ value = Q_(value)
63
+ isstep = False
64
+ if col == 1: # the start
65
+ start = value
66
+ elif col == 2: # the stop
67
+ stop = value
68
+ elif col == 3: # the step
69
+ isstep = True
70
+ step = value
71
+ try:
72
+ if np.abs(step).magnitude < 1e-12 or start == stop:
73
+ return False
74
+ if np.sign(stop - start) != np.sign(step):
75
+ if isstep:
76
+ self._data[row][2] = str(-stop)
77
+ else:
78
+ self._data[row][3] = str(-step)
79
+ except (TypeError, ValueError):
80
+ return False
81
+ return True
82
+
83
+
84
+ @ScannerFactory.register()
85
+ class SequentialScanner(ScannerBase):
86
+ scan_type = 'Sequential'
87
+ scan_subtype = 'Linear'
88
+ save_settings = False # not easy to save table content in a toml...
89
+ params = [
90
+ {'title': 'Sequences', 'name': 'seq_table', 'type': 'table_view',
91
+ 'delegate': gutils.SpinBoxDelegate},
92
+ ]
93
+ distribution = DataDistribution['uniform']
94
+ n_axes = 1
95
+
96
+ def __init__(self, actuators: List['DAQ_Move'], display_units=True, **_ignored):
97
+
98
+ self.table_model: TableModelSequential = None
99
+ self.table_view: TableViewCustom = None
100
+ super().__init__(actuators, display_units=display_units)
101
+ self.delegates: Iterable[gutils.SpinBoxDelegate] = []
102
+ self.update_model()
103
+
104
+ def set_units(self):
105
+ pass
106
+
107
+ @property
108
+ def actuators(self):
109
+ return self._actuators
110
+
111
+ @actuators.setter
112
+ def actuators(self, actuators):
113
+ self._actuators = actuators
114
+ base_path = self.actuators_name + [self.scan_type, self.scan_subtype]
115
+ self.config_saver_loader.base_path = base_path
116
+ self.update_model()
117
+
118
+ def update_model(self, init_data=None):
119
+ if init_data is None:
120
+ if self.table_model is not None:
121
+ init_data = []
122
+ names = [row[0] for row in self.table_model.get_data_all()]
123
+ for act in self._actuators:
124
+ if act.title in names:
125
+ ind_row = names.index(act.title)
126
+ init_data.append(self.table_model.get_data_all()[ind_row])
127
+ else:
128
+ if self.display_units:
129
+ init_data = [[act.title, f'0. {act.units}', f'1. {act.units}', f'0.1 {act.units}'] for act in self._actuators]
130
+ else:
131
+ init_data.append([act.title, '0.', '1.', '0.1'])
132
+ else:
133
+ if self.display_units:
134
+ init_data = [[act.title, f'0. {act.units}', f'1. {act.units}', f'0.1 {act.units}'] for act in self._actuators]
135
+ else:
136
+ init_data = [[act.title, '0.', '1.', '0.1'] for act in self._actuators]
137
+ self.table_model = TableModelSequential(init_data, )
138
+ self.table_view = putils.get_widget_from_tree(self.settings_tree, TableViewCustom)[0]
139
+ self.settings.child('seq_table').setValue(self.table_model)
140
+ self.n_axes = len(self._actuators)
141
+ self.update_table_view()
142
+
143
+ def get_pos(self):
144
+ starts = [Q_(self.table_model.get_data(ind, 1))
145
+ for ind in range(self.table_model.rowCount(None))]
146
+ stops = [Q_(self.table_model.get_data(ind, 2))
147
+ for ind in range(self.table_model.rowCount(None))]
148
+ steps = [Q_(self.table_model.get_data(ind, 3))
149
+ for ind in range(self.table_model.rowCount(None))]
150
+ return starts, stops, steps
151
+
152
+ def evaluate_steps(self) -> int:
153
+ starts, stops, steps = self.get_pos()
154
+ n_steps = 1
155
+ for ind in range(len(starts)):
156
+ n_steps *= (np.abs((stops[ind] - starts[ind]) / steps[ind]) + 1).magnitude
157
+ return int(n_steps)
158
+
159
+ @staticmethod
160
+ def pos_above_stops(positions, steps, stops):
161
+ state = []
162
+ for pos, step, stop in zip(positions, steps, stops):
163
+ if step >= 0:
164
+ state.append(pos > stop)
165
+ else:
166
+ state.append(pos < stop)
167
+ return state
168
+
169
+ def update_table_view(self):
170
+ self.table_view.horizontalHeader().setSectionResizeMode(QtWidgets.QHeaderView.Stretch)
171
+ #self.table_view.horizontalHeader().setStretchLastSection(True)
172
+ self.table_view.setSelectionBehavior(QtWidgets.QTableView.SelectRows)
173
+ self.table_view.setSelectionMode(QtWidgets.QTableView.SingleSelection)
174
+ self.delegates = [] # ItemDelegates should have parents and be instance attribute to work with setItemDelegateForColumn
175
+ for ind_actuator, actuator in enumerate(self.actuators):
176
+
177
+ self.delegates.append(gutils.SpinBoxDelegate(self.table_view,
178
+ units=actuator.units if self.display_units else None))
179
+ self.table_view.setItemDelegateForRow(
180
+ ind_actuator, self.delegates[-1])
181
+
182
+ self.table_view.setDragEnabled(True)
183
+ self.table_view.setDropIndicatorShown(True)
184
+ self.table_view.setAcceptDrops(True)
185
+ self.table_view.viewport().setAcceptDrops(True)
186
+ self.table_view.setDefaultDropAction(QtCore.Qt.MoveAction)
187
+ self.table_view.setDragDropMode(QtWidgets.QTableView.InternalMove)
188
+ self.table_view.setDragDropOverwriteMode(False)
189
+
190
+ def set_scan(self):
191
+ starts, stops, steps = self.get_pos()
192
+ all_positions = [starts.copy()]
193
+ positions = starts.copy()
194
+ state = self.pos_above_stops(positions, steps, stops)
195
+ if len(state) != 0:
196
+ while not state[0]:
197
+ if not np.any(np.array(state)):
198
+ positions[-1] += steps[-1]
199
+
200
+ else:
201
+ indexes_true = np.where(np.array(state))
202
+ positions[indexes_true[-1][0]] = starts[indexes_true[-1][0]]
203
+ positions[indexes_true[-1][0] - 1] += steps[indexes_true[-1][0] - 1]
204
+
205
+ state = self.pos_above_stops(positions, steps, stops)
206
+ if not np.any(np.array(state)):
207
+ all_positions.append(positions.copy())
208
+ all_positions = np.array([[elt.magnitude for elt in positions] for positions in all_positions])
209
+ self.get_info_from_positions(all_positions)
210
+
211
+ def get_nav_axes(self) -> List[Axis]:
212
+ return [Axis(label=f'{act.title}', units=act.units, data=self.axes_unique[ind], index=ind)
213
+ for ind, act in enumerate(self.actuators)]
214
+
215
+ def get_indexes_from_scan_index(self, scan_index: int) -> Tuple[int]:
216
+ """To be reimplemented. Calculations of indexes within the scan"""
217
+ return tuple(self.axes_indexes[scan_index])
218
+
219
+ def get_scan_shape(self) -> Tuple[int]:
220
+ return tuple([len(axis) for axis in self.axes_unique])
221
+
222
+ def update_from_scan_selector(self, scan_selector: Selector):
223
+ coordinates = scan_selector.get_coordinates()
224
+ pass