pymodaq 4.1.5__py3-none-any.whl → 4.2.1__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.

Potentially problematic release.


This version of pymodaq might be problematic. Click here for more details.

Files changed (80) hide show
  1. pymodaq/__init__.py +23 -4
  2. pymodaq/control_modules/daq_move.py +32 -73
  3. pymodaq/control_modules/daq_viewer.py +73 -98
  4. pymodaq/control_modules/daq_viewer_ui.py +2 -1
  5. pymodaq/control_modules/move_utility_classes.py +17 -7
  6. pymodaq/control_modules/utils.py +153 -5
  7. pymodaq/control_modules/viewer_utility_classes.py +31 -20
  8. pymodaq/dashboard.py +23 -5
  9. pymodaq/examples/tcp_client.py +97 -0
  10. pymodaq/extensions/__init__.py +4 -0
  11. pymodaq/extensions/bayesian/__init__.py +2 -0
  12. pymodaq/extensions/bayesian/bayesian_optimisation.py +673 -0
  13. pymodaq/extensions/bayesian/utils.py +403 -0
  14. pymodaq/extensions/daq_scan.py +4 -4
  15. pymodaq/extensions/daq_scan_ui.py +2 -1
  16. pymodaq/extensions/pid/pid_controller.py +12 -7
  17. pymodaq/extensions/pid/utils.py +9 -26
  18. pymodaq/extensions/utils.py +3 -0
  19. pymodaq/post_treatment/load_and_plot.py +42 -19
  20. pymodaq/resources/VERSION +1 -1
  21. pymodaq/resources/config_template.toml +9 -24
  22. pymodaq/resources/setup_plugin.py +1 -1
  23. pymodaq/utils/config.py +103 -5
  24. pymodaq/utils/daq_utils.py +35 -134
  25. pymodaq/utils/data.py +614 -95
  26. pymodaq/utils/enums.py +17 -1
  27. pymodaq/utils/factory.py +2 -2
  28. pymodaq/utils/gui_utils/custom_app.py +5 -2
  29. pymodaq/utils/gui_utils/dock.py +33 -4
  30. pymodaq/utils/gui_utils/utils.py +14 -1
  31. pymodaq/utils/h5modules/backends.py +9 -1
  32. pymodaq/utils/h5modules/data_saving.py +254 -57
  33. pymodaq/utils/h5modules/saving.py +1 -0
  34. pymodaq/utils/leco/__init__.py +25 -0
  35. pymodaq/utils/leco/daq_move_LECODirector.py +172 -0
  36. pymodaq/utils/leco/daq_xDviewer_LECODirector.py +170 -0
  37. pymodaq/utils/leco/desktop.ini +2 -0
  38. pymodaq/utils/leco/director_utils.py +58 -0
  39. pymodaq/utils/leco/leco_director.py +88 -0
  40. pymodaq/utils/leco/pymodaq_listener.py +279 -0
  41. pymodaq/utils/leco/utils.py +41 -0
  42. pymodaq/utils/managers/action_manager.py +20 -6
  43. pymodaq/utils/managers/parameter_manager.py +6 -4
  44. pymodaq/utils/managers/roi_manager.py +63 -54
  45. pymodaq/utils/math_utils.py +1 -1
  46. pymodaq/utils/plotting/data_viewers/__init__.py +3 -1
  47. pymodaq/utils/plotting/data_viewers/base.py +286 -0
  48. pymodaq/utils/plotting/data_viewers/viewer.py +29 -202
  49. pymodaq/utils/plotting/data_viewers/viewer0D.py +94 -47
  50. pymodaq/utils/plotting/data_viewers/viewer1D.py +341 -174
  51. pymodaq/utils/plotting/data_viewers/viewer1Dbasic.py +1 -1
  52. pymodaq/utils/plotting/data_viewers/viewer2D.py +271 -181
  53. pymodaq/utils/plotting/data_viewers/viewerND.py +26 -22
  54. pymodaq/utils/plotting/items/crosshair.py +3 -3
  55. pymodaq/utils/plotting/items/image.py +2 -1
  56. pymodaq/utils/plotting/plotter/plotter.py +94 -0
  57. pymodaq/utils/plotting/plotter/plotters/__init__.py +0 -0
  58. pymodaq/utils/plotting/plotter/plotters/matplotlib_plotters.py +134 -0
  59. pymodaq/utils/plotting/plotter/plotters/qt_plotters.py +78 -0
  60. pymodaq/utils/plotting/utils/axes_viewer.py +1 -1
  61. pymodaq/utils/plotting/utils/filter.py +194 -147
  62. pymodaq/utils/plotting/utils/lineout.py +13 -11
  63. pymodaq/utils/plotting/utils/plot_utils.py +89 -12
  64. pymodaq/utils/scanner/__init__.py +0 -3
  65. pymodaq/utils/scanner/scan_config.py +1 -9
  66. pymodaq/utils/scanner/scan_factory.py +10 -36
  67. pymodaq/utils/scanner/scanner.py +3 -2
  68. pymodaq/utils/scanner/scanners/_1d_scanners.py +7 -5
  69. pymodaq/utils/scanner/scanners/_2d_scanners.py +36 -49
  70. pymodaq/utils/scanner/scanners/sequential.py +10 -4
  71. pymodaq/utils/scanner/scanners/tabular.py +10 -5
  72. pymodaq/utils/slicing.py +1 -1
  73. pymodaq/utils/tcp_ip/serializer.py +38 -5
  74. pymodaq/utils/tcp_ip/tcp_server_client.py +25 -17
  75. {pymodaq-4.1.5.dist-info → pymodaq-4.2.1.dist-info}/METADATA +4 -2
  76. {pymodaq-4.1.5.dist-info → pymodaq-4.2.1.dist-info}/RECORD +79 -63
  77. pymodaq/resources/config_scan_template.toml +0 -42
  78. {pymodaq-4.1.5.dist-info → pymodaq-4.2.1.dist-info}/WHEEL +0 -0
  79. {pymodaq-4.1.5.dist-info → pymodaq-4.2.1.dist-info}/entry_points.txt +0 -0
  80. {pymodaq-4.1.5.dist-info → pymodaq-4.2.1.dist-info}/licenses/LICENSE +0 -0
@@ -11,14 +11,6 @@ from pymodaq.utils.config import BaseConfig, getitem_recursive
11
11
 
12
12
  class ScanConfig(BaseConfig):
13
13
  """Main class to deal with configuration values for this plugin"""
14
- config_template_path = Path(__file__).parent.parent.parent.joinpath('resources/config_scan_template.toml')
14
+ config_template_path = None
15
15
  config_name = f"scanner_settings"
16
16
 
17
- def __setitem__(self, key, value):
18
- if isinstance(key, tuple):
19
- dic = getitem_recursive(self._config, *key, ndepth=1, create_if_missing=True)
20
- if value is None: # means the setting is a group
21
- value = {}
22
- dic[key[-1]] = value
23
- else:
24
- self._config[key] = value
@@ -81,11 +81,14 @@ class ScannerBase(ScanParameterManager, metaclass=ABCMeta):
81
81
  super().__init__()
82
82
  self.positions: np.ndarray = None
83
83
  self.n_steps = 1
84
- self._actuators: List[DAQ_Move] = None
84
+ self.config = ScanConfig()
85
+ base_path = [act.title for act in actuators] + [self.scan_type, self.scan_subtype]
85
86
 
86
- self.actuators = actuators
87
+ self.config_saver_loader = configmod.ConfigSaverLoader(self.settings,
88
+ self.config,
89
+ base_path)
87
90
 
88
- self.config = ScanConfig()
91
+ self.actuators: List[DAQ_Move] = actuators
89
92
 
90
93
  self.set_settings_titles()
91
94
  self.set_settings_values()
@@ -93,32 +96,12 @@ class ScannerBase(ScanParameterManager, metaclass=ABCMeta):
93
96
  if self.check_steps():
94
97
  self.set_scan()
95
98
 
96
-
97
99
  def set_settings_titles(self):
98
100
  """Update the settings accordingly with the selected actuators"""
99
101
  ...
100
102
 
101
103
  def set_settings_values(self, param: Parameter = None):
102
- if param is None:
103
- param = self.settings
104
- for child in param.children():
105
- if len(child.children()) == 0: #means it is not a group parameter
106
- path = self.actuators_name
107
- path_scan = [self.scan_type, self.scan_subtype]
108
- path_param = get_param_path(child)[1:]
109
- path.extend(path_scan)
110
- path.extend(path_param)
111
- try:
112
- child.setValue(self.config(*path)) # first try to load the config including the actuators name
113
- except configmod.ConfigError as e:
114
- try:
115
- path = path_scan
116
- path.extend(path_param)
117
- child.setValue(self.config(*path)) # then without the actuators name
118
- except Exception as e:
119
- pass
120
- else:
121
- self.set_settings_values(child)
104
+ self.config_saver_loader.load_config(param)
122
105
 
123
106
  @property
124
107
  def actuators(self) -> List[DAQ_Move]:
@@ -127,6 +110,8 @@ class ScannerBase(ScanParameterManager, metaclass=ABCMeta):
127
110
  @actuators.setter
128
111
  def actuators(self, actuators: List[DAQ_Move]):
129
112
  self._actuators = actuators
113
+ base_path = self.actuators_name + [self.scan_type, self.scan_subtype]
114
+ self.config_saver_loader.base_path = base_path
130
115
 
131
116
  @property
132
117
  def actuators_name(self) -> List[str]:
@@ -198,18 +183,7 @@ class ScannerBase(ScanParameterManager, metaclass=ABCMeta):
198
183
 
199
184
  def save_scan_parameters(self):
200
185
  if self.save_settings:
201
- path_actuators = self.actuators_name
202
- path_scan = [self.scan_type, self.scan_subtype]
203
- path_actuators.extend(path_scan)
204
- for param in iter_children_params(self.settings, []):
205
- path = path_actuators[:]
206
- path_param = get_param_path(param)[1:]
207
- path.extend(path_param)
208
- try:
209
- self.config[tuple(path)] = param.value()
210
- except Exception as e:
211
- pass
212
- self.config.save()
186
+ self.config_saver_loader.save_config()
213
187
 
214
188
  @abstractmethod
215
189
  def update_from_scan_selector(self, scan_selector: Selector):
@@ -81,7 +81,8 @@ class Scanner(QObject, ParameterManager):
81
81
  def set_scanner(self):
82
82
  try:
83
83
  self._scanner: ScannerBase = scanner_factory.get(self.settings['scan_type'],
84
- self.settings['scan_sub_type'], actuators=self.actuators)
84
+ self.settings['scan_sub_type'],
85
+ actuators=self.actuators)
85
86
 
86
87
  while True:
87
88
  child = self._scanner_settings_widget.layout().takeAt(0)
@@ -93,7 +94,7 @@ class Scanner(QObject, ParameterManager):
93
94
  self._scanner_settings_widget.layout().addWidget(self._scanner.settings_tree)
94
95
  self._scanner.settings.sigTreeStateChanged.connect(self._update_steps)
95
96
 
96
- except ValueError:
97
+ except ValueError as e:
97
98
  pass
98
99
 
99
100
  @property
@@ -4,7 +4,7 @@ Created the 05/12/2022
4
4
 
5
5
  @author: Sebastien Weber
6
6
  """
7
- from typing import List, Tuple, Any
7
+ from typing import List, Tuple, Any, TYPE_CHECKING
8
8
  import re
9
9
  import numpy as np
10
10
  from pymodaq.utils.data import Axis, DataDistribution
@@ -15,6 +15,8 @@ from pymodaq.utils.plotting.scan_selector import Selector
15
15
 
16
16
  from ..scan_factory import ScannerFactory, ScannerBase, ScanParameterManager
17
17
 
18
+ if TYPE_CHECKING:
19
+ from pymodaq.control_modules.daq_move import DAQ_Move
18
20
 
19
21
  logger = set_logger(get_module_name(__file__))
20
22
  config = configmod.Config()
@@ -59,8 +61,8 @@ class Scan1DLinear(Scan1DBase):
59
61
  n_axes = 1
60
62
  distribution = DataDistribution['uniform']
61
63
 
62
- def __init__(self, actuators: List = None, **_ignored):
63
- ScannerBase.__init__(self, actuators=actuators)
64
+ def __init__(self, actuators: List['DAQ_Move'] = None, **_ignored):
65
+ super().__init__(actuators=actuators)
64
66
 
65
67
  def set_scan(self):
66
68
  self.positions = mutils.linspace_step(self.settings['start'], self.settings['stop'],
@@ -123,7 +125,7 @@ class Scan1DSparse(Scan1DBase):
123
125
  distribution = DataDistribution['uniform'] # because in 1D it doesn't matter is spread or
124
126
  # uniform, one can easily plot both types on a regulat 1D plot
125
127
 
126
- def __init__(self, actuators: List = None, **_ignored):
128
+ def __init__(self, actuators: List['DAQ_Move'] = None, **_ignored):
127
129
  super().__init__(actuators=actuators)
128
130
  self.settings.child('parsed_string').setOpts(tip=self.__doc__)
129
131
 
@@ -176,7 +178,7 @@ try:
176
178
  ]
177
179
  distribution = DataDistribution['spread']
178
180
 
179
- def __init__(self, actuators: List = None, **_ignored):
181
+ def __init__(self, actuators: List['DAQ_Move'] = None, **_ignored):
180
182
  super().__init__(actuators=actuators)
181
183
 
182
184
  def set_scan(self):
@@ -4,7 +4,7 @@ Created the 05/12/2022
4
4
 
5
5
  @author: Sebastien Weber
6
6
  """
7
- from typing import List, Tuple
7
+ from typing import List, Tuple, TYPE_CHECKING
8
8
 
9
9
  import numpy as np
10
10
  from pymodaq.utils.data import Axis, DataDistribution
@@ -18,6 +18,9 @@ from ..scan_factory import ScannerFactory, ScannerBase, ScanParameterManager
18
18
  logger = set_logger(get_module_name(__file__))
19
19
  config = configmod.Config()
20
20
 
21
+ if TYPE_CHECKING:
22
+ from pymodaq.control_modules.daq_move import DAQ_Move
23
+
21
24
 
22
25
  class Scan2DBase(ScannerBase):
23
26
  params = [{'title': 'Ax1:', 'name': 'axis1', 'type': 'group',
@@ -29,7 +32,7 @@ class Scan2DBase(ScannerBase):
29
32
  ]
30
33
  axes = ('axis1','axis2')
31
34
  n_axes = 2
32
- def __init__(self, actuators: List = None, **_ignored):
35
+ def __init__(self, actuators: List['DAQ_Move'] = None, **_ignored):
33
36
  super().__init__(actuators=actuators)
34
37
  self.axes_unique = []
35
38
 
@@ -40,20 +43,20 @@ class Scan2DLinear(Scan2DBase):
40
43
  params = [{'title': 'Ax1:', 'name': 'axis1', 'type': 'group',
41
44
  'children':[
42
45
  {'title': 'Start Ax1:', 'name': 'start_axis1', 'type': 'float',
43
- 'value': config('scan', 'scan2D', 'linear', 'start1')},
46
+ 'value': 0.},
44
47
  {'title': 'Stop Ax1:', 'name': 'stop_axis1', 'type': 'float',
45
- 'value': config('scan', 'scan2D', 'linear', 'stop1')},
48
+ 'value': 1.},
46
49
  {'title': 'Step Ax1:', 'name': 'step_axis1', 'type': 'float',
47
- 'value': config('scan', 'scan2D', 'linear', 'step1')},
50
+ 'value': 0.1},
48
51
  ]},
49
52
  {'title': 'Ax2:', 'name': 'axis2', 'type': 'group',
50
53
  'children':[
51
54
  {'title': 'Start Ax2:', 'name': 'start_axis2', 'type': 'float',
52
- 'value': config('scan', 'scan2D', 'linear', 'start2')},
55
+ 'value': 0.},
53
56
  {'title': 'Stop Ax2:', 'name': 'stop_axis2', 'type': 'float',
54
- 'value': config('scan', 'scan2D', 'linear', 'stop2')},
57
+ 'value': 1.},
55
58
  {'title': 'Step Ax2:', 'name': 'step_axis2', 'type': 'float',
56
- 'value': config('scan', 'scan2D', 'linear', 'step2')},
59
+ 'value': 0.1},
57
60
  ]},
58
61
  ]
59
62
  n_axes = 2
@@ -61,13 +64,13 @@ class Scan2DLinear(Scan2DBase):
61
64
  scan_type = 'Scan2D'
62
65
  scan_subtype = 'Linear'
63
66
 
64
- def __init__(self, actuators: List = None, **_ignored):
67
+ def __init__(self, actuators: List['DAQ_Move'] = None, **_ignored):
65
68
  super().__init__(actuators=actuators)
66
69
 
67
70
  def get_pos(self):
68
- starts = np.array([self.settings[ax,f'start_{ax}'] for ax in self.axes])
69
- stops = np.array([self.settings[ax,f'stop_{ax}'] for ax in self.axes])
70
- steps = np.array([self.settings[ax,f'step_{ax}'] for ax in self.axes])
71
+ starts = np.array([self.settings[ax, f'start_{ax}'] for ax in self.axes])
72
+ stops = np.array([self.settings[ax, f'stop_{ax}'] for ax in self.axes])
73
+ steps = np.array([self.settings[ax, f'step_{ax}'] for ax in self.axes])
71
74
  return starts, stops, steps
72
75
 
73
76
  def evaluate_steps(self) -> int:
@@ -101,10 +104,9 @@ class Scan2DLinear(Scan2DBase):
101
104
  for i,ax in enumerate(self.axes):
102
105
  title = self.actuators[i].title
103
106
  self.settings.child(ax).setOpts(title=title)
104
- self.settings.child(ax,f'start_{ax}').setOpts(title=f'{title} start:')
105
- self.settings.child(ax,f'stop_{ax}').setOpts(title=f'{title} stop:')
106
- self.settings.child(ax,f'step_{ax}').setOpts(title=f'{title} step:')
107
-
107
+ self.settings.child(ax, f'start_{ax}').setOpts(title=f'{title} start:')
108
+ self.settings.child(ax, f'stop_{ax}').setOpts(title=f'{title} stop:')
109
+ self.settings.child(ax, f'step_{ax}').setOpts(title=f'{title} step:')
108
110
 
109
111
  def get_nav_axes(self) -> List[Axis]:
110
112
  return [Axis(label=f'{act.title}',
@@ -127,12 +129,11 @@ class Scan2DLinear(Scan2DBase):
127
129
  self.settings.child(ax,f'stop_{ax}').setValue(coordinates[1, i])
128
130
 
129
131
 
130
-
131
132
  @ScannerFactory.register()
132
133
  class Scan2DLinearBF(Scan2DLinear):
133
134
  scan_subtype = 'LinearBackForce'
134
135
 
135
- def __init__(self, actuators: List = None, **_ignored):
136
+ def __init__(self, actuators: List['DAQ_Move'] = None, **_ignored):
136
137
  super().__init__(actuators=actuators)
137
138
 
138
139
  def set_scan(self):
@@ -162,7 +163,7 @@ class Scan2DLinearBF(Scan2DLinear):
162
163
  class Scan2DRandom(Scan2DLinear):
163
164
  scan_subtype = 'Random'
164
165
 
165
- def __init__(self, actuators: List = None, **_ignored):
166
+ def __init__(self, actuators: List['DAQ_Move'] = None, **_ignored):
166
167
  super().__init__(actuators=actuators)
167
168
 
168
169
  def set_scan(self):
@@ -175,28 +176,28 @@ class Scan2DRandom(Scan2DLinear):
175
176
  class Scan2DSpiral(Scan2DLinear):
176
177
  scan_subtype = 'Spiral'
177
178
  params = [{'title': 'Npts/axis', 'name': 'npts_by_axis', 'type': 'int', 'min': 1,
178
- 'value': config('scan', 'scan2D', 'spiral', 'npts')},
179
+ 'value': 10},
179
180
  {'title': 'Ax1:', 'name': 'axis1', 'type': 'group',
180
181
  'children': [
181
182
  {'title': 'Center Ax1:', 'name': 'center_axis1', 'type': 'float',
182
- 'value': config('scan', 'scan2D', 'linear', 'start1')},
183
+ 'value': 0.},
183
184
  {'title': 'Rmax Ax1:', 'name': 'rmax_axis1', 'type': 'float',
184
- 'value': config('scan', 'scan2D', 'linear', 'stop1')},
185
+ 'value': 5.},
185
186
  {'title': 'Step Ax1:', 'name': 'step_axis1', 'type': 'float',
186
187
  'value': 0., 'readonly': True},
187
188
  ]},
188
189
  {'title': 'Ax2:', 'name': 'axis2', 'type': 'group',
189
190
  'children': [
190
191
  {'title': 'Center Ax2:', 'name': 'center_axis2', 'type': 'float',
191
- 'value': config('scan', 'scan2D', 'linear', 'start2')},
192
+ 'value': 0.},
192
193
  {'title': 'Rmax Ax2:', 'name': 'rmax_axis2', 'type': 'float',
193
- 'value': config('scan', 'scan2D', 'linear', 'stop2')},
194
+ 'value': 5.},
194
195
  {'title': 'Step Ax2:', 'name': 'step_axis2', 'type': 'float',
195
196
  'value': 0., 'readonly': True},
196
197
  ]},
197
198
  ]
198
199
 
199
- def __init__(self, actuators: List = None, **_ignored):
200
+ def __init__(self, actuators: List['DAQ_Move'] = None, **_ignored):
200
201
  super().__init__(actuators=actuators)
201
202
 
202
203
  def set_settings_titles(self):
@@ -204,17 +205,9 @@ class Scan2DSpiral(Scan2DLinear):
204
205
  for i,ax in enumerate(self.axes):
205
206
  title = self.actuators[i].title
206
207
  self.settings.child(ax).setOpts(title=title)
207
- self.settings.child(ax,f'center_{ax}').setOpts(title=f'{title} center:')
208
- self.settings.child(ax,f'rmax_{ax}').setOpts(title=f'{title} rmax:')
209
- self.settings.child(ax,f'step_{ax}').setOpts(title=f'{title} step:')
210
-
211
-
212
- # self.settings.child('center_axis1').setOpts(title=f'Center {self.actuators[0].title}:')
213
- # self.settings.child('rmax_axis1').setOpts(title=f'Rmax {self.actuators[0].title}:')
214
- # self.settings.child('step_axis1').setOpts(title=f'Step {self.actuators[0].title}:')
215
- # self.settings.child('center_axis2').setOpts(title=f'Center {self.actuators[1].title}:')
216
- # self.settings.child('rmax_axis2').setOpts(title=f'Rmax {self.actuators[1].title}:')
217
- # self.settings.child('step_axis2').setOpts(title=f'Step {self.actuators[1].title}:')
208
+ self.settings.child(ax, f'center_{ax}').setOpts(title=f'{title} center:')
209
+ self.settings.child(ax, f'rmax_{ax}').setOpts(title=f'{title} rmax:')
210
+ self.settings.child(ax, f'step_{ax}').setOpts(title=f'{title} step:')
218
211
 
219
212
  def value_changed(self, param):
220
213
  starts, rmaxs, rsteps = self.get_pos()
@@ -234,10 +227,8 @@ class Scan2DSpiral(Scan2DLinear):
234
227
  r_steps: np.ndarray
235
228
  steps size in both directions
236
229
  """
237
- centers = np.array([self.settings[ax,f'center_{ax}'] for ax in self.axes])
238
- rmaxs = np.array([self.settings[ax,f'rmax_{ax}'] for ax in self.axes])
239
- # centers = np.array([self.settings['center_axis1'], self.settings['center_axis2']])
240
- # rmaxs = np.array([self.settings['rmax_axis1'], self.settings['rmax_axis2']])
230
+ centers = np.array([self.settings[ax, f'center_{ax}'] for ax in self.axes])
231
+ rmaxs = np.array([self.settings[ax, f'rmax_{ax}'] for ax in self.axes])
241
232
  r_steps = 2 * rmaxs / self.settings['npts_by_axis']
242
233
  return centers, rmaxs, r_steps
243
234
 
@@ -290,14 +281,10 @@ class Scan2DSpiral(Scan2DLinear):
290
281
  coordinates = scan_selector.get_coordinates()
291
282
  if coordinates.shape == (2, 2):
292
283
  for i,ax in enumerate(self.axes):
293
- self.settings.child(ax,f'center_{ax}').setValue((coordinates[0, i] + coordinates[1, i]) / 2)
294
- self.settings.child(ax,f'rmax_{ax}').setValue((coordinates[0, i] - coordinates[1, i]) / 2)
295
- # self.settings.child(ax,f'center_{ax}').setValue((coordinates[0, i] - coordinates[1, i]) / 2)
296
- # self.settings.child(ax,f'rmax_{ax}').setValue(coordinates[1, i])
297
- # self.settings.child('center_axis1').setValue((coordinates[0, 0] + coordinates[1, 0]) / 2)
298
- # self.settings.child('center_axis2').setValue((coordinates[0, 1] + coordinates[1, 1]) / 2)
299
- # self.settings.child('rmax_axis1').setValue(abs(coordinates[1, 0] - coordinates[0, 0]) / 2)
300
- # self.settings.child('rmax_axis2').setValue(abs(coordinates[1, 1] - coordinates[0, 1]) / 2)
284
+ self.settings.child(ax, f'center_{ax}').setValue(
285
+ (coordinates[0, i] + coordinates[1, i]) / 2)
286
+ self.settings.child(ax, f'rmax_{ax}').setValue(
287
+ (coordinates[0, i] - coordinates[1, i]) / 2)
301
288
 
302
289
 
303
290
  try:
@@ -333,7 +320,7 @@ try:
333
320
  ]
334
321
  distribution = DataDistribution['spread']
335
322
 
336
- def __init__(self, actuators: List = None, **_ignored):
323
+ def __init__(self, actuators: List['DAQ_Move'] = None, **_ignored):
337
324
  super().__init__(actuators=actuators)
338
325
 
339
326
  def set_scan(self):
@@ -4,7 +4,7 @@ Created the 05/12/2022
4
4
 
5
5
  @author: Sebastien Weber
6
6
  """
7
- from typing import List, Tuple
7
+ from typing import List, Tuple, TYPE_CHECKING
8
8
 
9
9
  import numpy as np
10
10
 
@@ -23,6 +23,10 @@ logger = set_logger(get_module_name(__file__))
23
23
  config = configmod.Config()
24
24
 
25
25
 
26
+ if TYPE_CHECKING:
27
+ from pymodaq.control_modules.daq_move import DAQ_Move
28
+
29
+
26
30
  class TableModelSequential(gutils.TableModel):
27
31
  """Table Model for the Model/View Qt framework dedicated to the Sequential scan mode"""
28
32
  def __init__(self, data, **kwargs):
@@ -84,7 +88,7 @@ class SequentialScanner(ScannerBase):
84
88
  distribution = DataDistribution['uniform']
85
89
  n_axes = 1
86
90
 
87
- def __init__(self, actuators: List[str]):
91
+ def __init__(self, actuators: List['DAQ_Move']):
88
92
 
89
93
  self.table_model: TableModelSequential = None
90
94
  self.table_view: TableViewCustom = None
@@ -96,8 +100,10 @@ class SequentialScanner(ScannerBase):
96
100
  return self._actuators
97
101
 
98
102
  @actuators.setter
99
- def actuators(self, actuators_name):
100
- self._actuators = actuators_name
103
+ def actuators(self, actuators):
104
+ self._actuators = actuators
105
+ base_path = self.actuators_name + [self.scan_type, self.scan_subtype]
106
+ self.config_saver_loader.base_path = base_path
101
107
  self.update_model()
102
108
 
103
109
  def update_model(self, init_data=None):
@@ -4,7 +4,7 @@ Created the 05/12/2022
4
4
 
5
5
  @author: Sebastien Weber
6
6
  """
7
- from typing import List, Tuple
7
+ from typing import List, Tuple, TYPE_CHECKING
8
8
 
9
9
  import numpy as np
10
10
 
@@ -20,6 +20,9 @@ from pymodaq.utils.parameter.pymodaq_ptypes import TableViewCustom
20
20
  from pymodaq.utils.plotting.scan_selector import Selector
21
21
  from pymodaq.utils.plotting.utils.plot_utils import Point, get_sub_segmented_positions
22
22
 
23
+ if TYPE_CHECKING:
24
+ from pymodaq.control_modules.daq_move import DAQ_Move
25
+
23
26
 
24
27
  logger = set_logger(get_module_name(__file__))
25
28
  config = configmod.Config()
@@ -103,7 +106,7 @@ class TabularScanner(ScannerBase):
103
106
  ]
104
107
  distribution = DataDistribution['spread']
105
108
 
106
- def __init__(self, actuators: List[str]):
109
+ def __init__(self, actuators: List['DAQ_Move']):
107
110
  self.table_model: TableModelTabular = None
108
111
  self.table_view: TableViewCustom = None
109
112
  super().__init__(actuators=actuators)
@@ -113,8 +116,10 @@ class TabularScanner(ScannerBase):
113
116
  return self._actuators
114
117
 
115
118
  @actuators.setter
116
- def actuators(self, actuators_name):
117
- self._actuators = actuators_name
119
+ def actuators(self, actuators):
120
+ self._actuators = actuators
121
+ base_path = self.actuators_name + [self.scan_type, self.scan_subtype]
122
+ self.config_saver_loader.base_path = base_path
118
123
  self.update_model()
119
124
 
120
125
  def update_model(self, init_data=None):
@@ -218,7 +223,7 @@ class TabularScannerSubSegmented(TabularScanner):
218
223
  'menu': True},
219
224
  ] + TabularScanner.params
220
225
 
221
- def __init__(self, actuators: List[str]):
226
+ def __init__(self, actuators: List['DAQ_Move']):
222
227
  self.table_model: TableModelTabularReadOnly = None
223
228
  self.table_view: TableViewCustom = None
224
229
  self.table_model_points: TableModelTabular = None
pymodaq/utils/slicing.py CHANGED
@@ -17,7 +17,7 @@ class SpecialSlicers(object):
17
17
  self.is_navigation = is_navigation
18
18
  self.obj = obj
19
19
 
20
- def __getitem__(self, slices):
20
+ def __getitem__(self, slices) -> Union['DataWithAxes', 'Axis']:
21
21
  return self.obj._slicer(slices, self.is_navigation)
22
22
 
23
23
 
@@ -4,6 +4,7 @@ Created the 20/10/2023
4
4
 
5
5
  @author: Sebastien Weber
6
6
  """
7
+ from base64 import b64encode, b64decode
7
8
  import numbers
8
9
  from typing import Tuple, List, Union, TYPE_CHECKING, Iterable
9
10
 
@@ -16,6 +17,18 @@ if TYPE_CHECKING:
16
17
  from pymodaq.utils.tcp_ip.mysocket import Socket
17
18
 
18
19
 
20
+ SERIALIZABLE = Union[
21
+ int,
22
+ str,
23
+ numbers.Number,
24
+ list,
25
+ np.ndarray,
26
+ Axis,
27
+ DataWithAxes,
28
+ DataToExport,
29
+ ]
30
+
31
+
19
32
  class SocketString:
20
33
  """Mimic the Socket object but actually using a bytes string not a socket connection
21
34
 
@@ -68,9 +81,10 @@ class SocketString:
68
81
 
69
82
 
70
83
  class Serializer:
71
- """Used to Serialize to bytes python objects, numpy arrays and PyMoDAQ DataWithAxes and DataToExport objects"""
84
+ """Used to Serialize to bytes python objects, numpy arrays and PyMoDAQ DataWithAxes and
85
+ DataToExport objects"""
72
86
 
73
- def __init__(self, obj: Union[int, str, numbers.Number, list, np.ndarray, Axis, DataWithAxes, DataToExport] = None):
87
+ def __init__(self, obj: SERIALIZABLE = None):
74
88
  self._bytes_string = b''
75
89
  self._obj = obj
76
90
 
@@ -107,6 +121,11 @@ class Serializer:
107
121
  return self.list_serialization(self._obj)
108
122
  elif isinstance(self._obj, bool):
109
123
  return self.scalar_serialization(int(self._obj))
124
+ raise ValueError
125
+
126
+ def to_b64_string(self) -> str:
127
+ b = self.to_bytes()
128
+ return b64encode(b).decode()
110
129
 
111
130
  @staticmethod
112
131
  def int_to_bytes(an_integer: int) -> bytes:
@@ -123,17 +142,17 @@ class Serializer:
123
142
  if not isinstance(an_integer, int):
124
143
  raise TypeError(f'{an_integer} should be an integer, not a {type(an_integer)}')
125
144
  elif an_integer < 0:
126
- raise ValueError(f'Can only serialize unsigned integer using this method')
145
+ raise ValueError('Can only serialize unsigned integer using this method')
127
146
  return an_integer.to_bytes(4, 'big')
128
147
 
129
148
  @staticmethod
130
149
  def str_to_bytes(message: str) -> bytes:
131
150
  if not isinstance(message, str):
132
- raise TypeError(f'Can only serialize str object using this method')
151
+ raise TypeError('Can only serialize str object using this method')
133
152
  return message.encode()
134
153
 
135
154
  @classmethod
136
- def str_len_to_bytes(cls, message: str) -> (bytes, bytes):
155
+ def str_len_to_bytes(cls, message: Union[str, bytes]) -> (bytes, bytes):
137
156
  """ Convert a string and its length to two bytes
138
157
  Parameters
139
158
  ----------
@@ -391,6 +410,7 @@ class Serializer:
391
410
  * serialize the origin
392
411
  * serialize the nav_index tuple as a list of int
393
412
  * serialize the list of axis
413
+ * serialize the errors attributes (None or list(np.ndarray))
394
414
  * serialize the list of names of extra attributes
395
415
  * serialize the extra attributes
396
416
  """
@@ -409,6 +429,12 @@ class Serializer:
409
429
  bytes_string += self.string_serialization(dwa.origin)
410
430
  bytes_string += self.list_serialization(list(dwa.nav_indexes))
411
431
  bytes_string += self.list_serialization(dwa.axes)
432
+ if dwa.errors is None:
433
+ errors = [] # have to use this extra attribute as if I force dwa.errors = [], it will be
434
+ #internally modified as None again
435
+ else:
436
+ errors = dwa.errors
437
+ bytes_string += self.list_serialization(errors)
412
438
  bytes_string += self.list_serialization(dwa.extra_attributes)
413
439
  for attribute in dwa.extra_attributes:
414
440
  bytes_string += self.type_and_object_serialization(getattr(dwa, attribute))
@@ -468,6 +494,10 @@ class DeSerializer:
468
494
  bytes_string = SocketString(bytes_string)
469
495
  self._bytes_string = bytes_string
470
496
 
497
+ @classmethod
498
+ def from_b64_string(cls, b64_string: Union[bytes, str]) -> "DeSerializer":
499
+ return cls(b64decode(b64_string))
500
+
471
501
  @staticmethod
472
502
  def bytes_to_string(message: bytes) -> str:
473
503
  return message.decode()
@@ -670,6 +700,9 @@ class DeSerializer:
670
700
  nav_indexes=tuple(self.list_deserialization()),
671
701
  axes=self.list_deserialization(),
672
702
  )
703
+ errors = self.list_deserialization()
704
+ if len(errors) != 0:
705
+ dwa.errors = errors
673
706
  dwa.extra_attributes = self.list_deserialization()
674
707
  for attribute in dwa.extra_attributes:
675
708
  setattr(dwa, attribute, self.object_deserialization())