pymodaq 5.0.18__py3-none-any.whl → 5.1.0__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.
- pymodaq/__init__.py +23 -11
- pymodaq/control_modules/__init__.py +1 -0
- pymodaq/control_modules/daq_move.py +451 -246
- pymodaq/control_modules/daq_move_ui/__init__.py +0 -0
- pymodaq/control_modules/daq_move_ui/factory.py +48 -0
- pymodaq/control_modules/{daq_move_ui.py → daq_move_ui/ui_base.py} +168 -210
- pymodaq/control_modules/daq_move_ui/uis/__init__.py +0 -0
- pymodaq/control_modules/daq_move_ui/uis/binary.py +139 -0
- pymodaq/control_modules/daq_move_ui/uis/original.py +120 -0
- pymodaq/control_modules/daq_move_ui/uis/relative.py +124 -0
- pymodaq/control_modules/daq_move_ui/uis/simple.py +126 -0
- pymodaq/control_modules/daq_viewer.py +113 -101
- pymodaq/control_modules/daq_viewer_ui.py +41 -31
- pymodaq/control_modules/mocks.py +2 -2
- pymodaq/control_modules/move_utility_classes.py +113 -41
- pymodaq/control_modules/thread_commands.py +137 -0
- pymodaq/control_modules/ui_utils.py +72 -0
- pymodaq/control_modules/utils.py +107 -63
- pymodaq/control_modules/viewer_utility_classes.py +13 -17
- pymodaq/dashboard.py +1294 -625
- pymodaq/examples/qt_less_standalone_module.py +48 -11
- pymodaq/extensions/__init__.py +8 -3
- pymodaq/extensions/adaptive/__init__.py +2 -0
- pymodaq/extensions/adaptive/adaptive_optimization.py +179 -0
- pymodaq/extensions/adaptive/loss_function/_1d_loss_functions.py +73 -0
- pymodaq/extensions/adaptive/loss_function/_2d_loss_functions.py +73 -0
- pymodaq/extensions/adaptive/loss_function/__init__.py +3 -0
- pymodaq/extensions/adaptive/loss_function/loss_factory.py +110 -0
- pymodaq/extensions/adaptive/utils.py +123 -0
- pymodaq/extensions/bayesian/__init__.py +1 -1
- pymodaq/extensions/bayesian/acquisition/__init__.py +2 -0
- pymodaq/extensions/bayesian/acquisition/acquisition_function_factory.py +80 -0
- pymodaq/extensions/bayesian/acquisition/base_acquisition_function.py +105 -0
- pymodaq/extensions/bayesian/bayesian_optimization.py +143 -0
- pymodaq/extensions/bayesian/utils.py +71 -297
- pymodaq/extensions/daq_logger/daq_logger.py +7 -12
- pymodaq/extensions/daq_logger/h5logging.py +1 -1
- pymodaq/extensions/daq_scan.py +30 -55
- pymodaq/extensions/data_mixer/__init__.py +0 -0
- pymodaq/extensions/data_mixer/daq_0Dviewer_DataMixer.py +97 -0
- pymodaq/extensions/data_mixer/data_mixer.py +262 -0
- pymodaq/extensions/data_mixer/model.py +108 -0
- pymodaq/extensions/data_mixer/models/__init__.py +0 -0
- pymodaq/extensions/data_mixer/models/equation_model.py +91 -0
- pymodaq/extensions/data_mixer/models/gaussian_fit_model.py +65 -0
- pymodaq/extensions/data_mixer/parser.py +53 -0
- pymodaq/extensions/data_mixer/utils.py +23 -0
- pymodaq/extensions/h5browser.py +3 -34
- pymodaq/extensions/optimizers_base/__init__.py +0 -0
- pymodaq/extensions/optimizers_base/optimizer.py +1016 -0
- pymodaq/extensions/optimizers_base/thread_commands.py +22 -0
- pymodaq/extensions/optimizers_base/utils.py +427 -0
- pymodaq/extensions/pid/actuator_controller.py +3 -2
- pymodaq/extensions/pid/daq_move_PID.py +107 -30
- pymodaq/extensions/pid/pid_controller.py +613 -287
- pymodaq/extensions/pid/utils.py +8 -5
- pymodaq/extensions/utils.py +17 -2
- pymodaq/resources/config_template.toml +57 -0
- pymodaq/resources/preset_default.xml +1 -1
- pymodaq/utils/config.py +10 -4
- pymodaq/utils/daq_utils.py +14 -0
- pymodaq/utils/data.py +1 -0
- pymodaq/utils/gui_utils/loader_utils.py +25 -15
- pymodaq/utils/h5modules/module_saving.py +134 -22
- pymodaq/utils/leco/daq_move_LECODirector.py +123 -84
- pymodaq/utils/leco/daq_xDviewer_LECODirector.py +84 -97
- pymodaq/utils/leco/director_utils.py +32 -16
- pymodaq/utils/leco/leco_director.py +104 -27
- pymodaq/utils/leco/pymodaq_listener.py +186 -97
- pymodaq/utils/leco/rpc_method_definitions.py +43 -0
- pymodaq/utils/leco/utils.py +25 -25
- pymodaq/utils/managers/batchscan_manager.py +12 -11
- pymodaq/utils/managers/modules_manager.py +74 -33
- pymodaq/utils/managers/overshoot_manager.py +11 -10
- pymodaq/utils/managers/preset_manager.py +100 -64
- pymodaq/utils/managers/preset_manager_utils.py +163 -107
- pymodaq/utils/managers/remote_manager.py +21 -16
- pymodaq/utils/scanner/scan_factory.py +12 -3
- pymodaq/utils/scanner/scan_selector.py +1 -3
- pymodaq/utils/scanner/scanner.py +35 -6
- pymodaq/utils/scanner/scanners/_1d_scanners.py +15 -46
- pymodaq/utils/scanner/scanners/_2d_scanners.py +21 -68
- pymodaq/utils/scanner/scanners/sequential.py +50 -31
- pymodaq/utils/scanner/scanners/tabular.py +45 -28
- {pymodaq-5.0.18.dist-info → pymodaq-5.1.0.dist-info}/METADATA +7 -6
- pymodaq-5.1.0.dist-info/RECORD +154 -0
- {pymodaq-5.0.18.dist-info → pymodaq-5.1.0.dist-info}/entry_points.txt +0 -2
- pymodaq/extensions/bayesian/bayesian_optimisation.py +0 -690
- pymodaq/utils/leco/desktop.ini +0 -2
- pymodaq-5.0.18.dist-info/RECORD +0 -121
- {pymodaq-5.0.18.dist-info → pymodaq-5.1.0.dist-info}/WHEEL +0 -0
- {pymodaq-5.0.18.dist-info → pymodaq-5.1.0.dist-info}/licenses/LICENSE +0 -0
|
@@ -18,6 +18,9 @@ DAQ_1DViewer_Det_types = get_plugins('daq_1Dviewer')
|
|
|
18
18
|
DAQ_2DViewer_Det_types = get_plugins('daq_2Dviewer')
|
|
19
19
|
DAQ_NDViewer_Det_types = get_plugins('daq_NDviewer')
|
|
20
20
|
|
|
21
|
+
# Fixed names that will sort the plugin in remote/mock
|
|
22
|
+
REMOTE_ITEMS = {'LECODirector', 'TCPServer'}
|
|
23
|
+
MOCK_ITEMS = {}
|
|
21
24
|
|
|
22
25
|
def iterative_show_pb(params):
|
|
23
26
|
for param in params:
|
|
@@ -27,6 +30,136 @@ def iterative_show_pb(params):
|
|
|
27
30
|
iterative_show_pb(param['children'])
|
|
28
31
|
|
|
29
32
|
|
|
33
|
+
def find_last_index(list_children:list=[], name_prefix ='',format_string='02.0f'):
|
|
34
|
+
# Custom function to find last available index
|
|
35
|
+
child_indexes = ([int(par.name()[len(name_prefix) + 1:]) for par in list_children if name_prefix in par.name()])
|
|
36
|
+
if child_indexes == []:
|
|
37
|
+
newindex = 0
|
|
38
|
+
else:
|
|
39
|
+
newindex = max(child_indexes) + 1
|
|
40
|
+
return f'{newindex:{format_string}}'
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def categorize_items(item_list, remote_items=None, mock_items=None):
|
|
44
|
+
"""
|
|
45
|
+
Core function: categorize any list of items into Mock/Plugin/Remote.
|
|
46
|
+
|
|
47
|
+
Args:
|
|
48
|
+
item_list: List of items to categorize
|
|
49
|
+
remote_items: Custom set of remote items (optional)
|
|
50
|
+
mock_items: Custom set of mock items (optional)
|
|
51
|
+
|
|
52
|
+
Returns: dict {category: [items]} with only non-empty categories
|
|
53
|
+
"""
|
|
54
|
+
remote_items = remote_items or REMOTE_ITEMS
|
|
55
|
+
mock_items = mock_items or MOCK_ITEMS
|
|
56
|
+
|
|
57
|
+
categorized = {'Remote': [], 'Mock': [], 'Plugin': []}
|
|
58
|
+
|
|
59
|
+
for item in item_list:
|
|
60
|
+
if item in remote_items:
|
|
61
|
+
categorized['Remote'].append(item)
|
|
62
|
+
elif item in mock_items or 'mock' in item.lower():
|
|
63
|
+
categorized['Mock'].append(item)
|
|
64
|
+
else:
|
|
65
|
+
categorized['Plugin'].append(item)
|
|
66
|
+
|
|
67
|
+
# Return only non-empty categories
|
|
68
|
+
return {k: v for k, v in categorized.items() if v}
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def add_category_layers(dimension_dict, remote_items=None, mock_items=None):
|
|
72
|
+
"""
|
|
73
|
+
Add category layers to a dimension dictionary.
|
|
74
|
+
Uses categorize_items for each dimension.
|
|
75
|
+
|
|
76
|
+
Args:
|
|
77
|
+
dimension_dict: {dimension: [items]}
|
|
78
|
+
|
|
79
|
+
Returns: {dimension: {category: [items]}}
|
|
80
|
+
"""
|
|
81
|
+
result = {}
|
|
82
|
+
|
|
83
|
+
for dimension, items in dimension_dict.items():
|
|
84
|
+
# Reuse the core categorization function
|
|
85
|
+
result[dimension] = categorize_items(items, remote_items, mock_items)
|
|
86
|
+
|
|
87
|
+
return result
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
def make_move_params(typ):
|
|
91
|
+
params = daq_move_params
|
|
92
|
+
iterative_show_pb(params)
|
|
93
|
+
|
|
94
|
+
parent_module = utils.find_dict_in_list_from_key_val(DAQ_Move_Stage_type, 'name', typ)
|
|
95
|
+
class_ = getattr(getattr(parent_module['module'], 'daq_move_' + typ),
|
|
96
|
+
'DAQ_Move_' + typ)
|
|
97
|
+
params_hardware = getattr(class_, 'params')
|
|
98
|
+
iterative_show_pb(params_hardware)
|
|
99
|
+
|
|
100
|
+
for main_child in params:
|
|
101
|
+
if main_child['name'] == 'move_settings':
|
|
102
|
+
main_child['children'] = params_hardware
|
|
103
|
+
controller_dict = get_param_dict_from_name(params_hardware, 'controller_ID')
|
|
104
|
+
controller_dict['value'] = random.randint(0, 9999)
|
|
105
|
+
|
|
106
|
+
elif main_child['name'] == 'main_settings':
|
|
107
|
+
typ_dict = get_param_dict_from_name(main_child['children'], 'move_type')
|
|
108
|
+
typ_dict['value'] = typ
|
|
109
|
+
|
|
110
|
+
return params
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
def make_viewer_params(typ):
|
|
114
|
+
params = daq_viewer_params
|
|
115
|
+
iterative_show_pb(params)
|
|
116
|
+
|
|
117
|
+
for main_child in params:
|
|
118
|
+
if main_child['name'] == 'main_settings':
|
|
119
|
+
for child in main_child['children']:
|
|
120
|
+
if child['name'] == 'DAQ_type':
|
|
121
|
+
child['value'] = typ[0:5]
|
|
122
|
+
if child['name'] == 'detector_type':
|
|
123
|
+
child['value'] = typ[6:]
|
|
124
|
+
if child['name'] == 'controller_status':
|
|
125
|
+
child['visible'] = True
|
|
126
|
+
|
|
127
|
+
if '0D' in typ:
|
|
128
|
+
parent_module = utils.find_dict_in_list_from_key_val(DAQ_0DViewer_Det_types, 'name', typ[6:])
|
|
129
|
+
class_ = getattr(getattr(parent_module['module'], 'daq_0Dviewer_' + typ[6:]), 'DAQ_0DViewer_' + typ[6:])
|
|
130
|
+
elif '1D' in typ:
|
|
131
|
+
parent_module = utils.find_dict_in_list_from_key_val(DAQ_1DViewer_Det_types, 'name', typ[6:])
|
|
132
|
+
class_ = getattr(getattr(parent_module['module'], 'daq_1Dviewer_' + typ[6:]), 'DAQ_1DViewer_' + typ[6:])
|
|
133
|
+
elif '2D' in typ:
|
|
134
|
+
parent_module = utils.find_dict_in_list_from_key_val(DAQ_2DViewer_Det_types, 'name', typ[6:])
|
|
135
|
+
class_ = getattr(getattr(parent_module['module'], 'daq_2Dviewer_' + typ[6:]), 'DAQ_2DViewer_' + typ[6:])
|
|
136
|
+
elif 'ND' in typ:
|
|
137
|
+
parent_module = utils.find_dict_in_list_from_key_val(DAQ_NDViewer_Det_types, 'name', typ[6:])
|
|
138
|
+
class_ = getattr(getattr(parent_module['module'], 'daq_NDviewer_' + typ[6:]), 'DAQ_NDViewer_' + typ[6:])
|
|
139
|
+
for main_child in params:
|
|
140
|
+
if main_child['name'] == 'main_settings':
|
|
141
|
+
for child in main_child['children']:
|
|
142
|
+
if child['name'] == 'axes':
|
|
143
|
+
child['visible'] = True
|
|
144
|
+
|
|
145
|
+
params_hardware = getattr(class_, 'params')
|
|
146
|
+
iterative_show_pb(params_hardware)
|
|
147
|
+
|
|
148
|
+
for main_child in params:
|
|
149
|
+
# Was this condition useful?
|
|
150
|
+
# if main_child['name'] == 'detector_settings':
|
|
151
|
+
# while len(main_child['children']) > 0:
|
|
152
|
+
# for child in main_child['children']:
|
|
153
|
+
# main_child['children'].remove(child)
|
|
154
|
+
|
|
155
|
+
# main_child['children'].extend(params_hardware)
|
|
156
|
+
if main_child['name'] == 'detector_settings':
|
|
157
|
+
main_child['children'] = params_hardware
|
|
158
|
+
controller_dict = get_param_dict_from_name(main_child['children'], 'controller_ID')
|
|
159
|
+
controller_dict['value'] = random.randint(0, 9999)
|
|
160
|
+
|
|
161
|
+
return params
|
|
162
|
+
|
|
30
163
|
class PresetScalableGroupMove(GroupParameter):
|
|
31
164
|
"""
|
|
32
165
|
|
|
|
@@ -44,10 +177,10 @@ class PresetScalableGroupMove(GroupParameter):
|
|
|
44
177
|
def __init__(self, **opts):
|
|
45
178
|
opts['type'] = 'groupmove'
|
|
46
179
|
opts['addText'] = "Add"
|
|
47
|
-
opts['
|
|
180
|
+
opts['addMenu'] = categorize_items([mov['name'] for mov in DAQ_Move_Stage_type])
|
|
48
181
|
super().__init__(**opts)
|
|
49
182
|
|
|
50
|
-
def addNew(self, typ):
|
|
183
|
+
def addNew(self, typ:tuple):
|
|
51
184
|
"""
|
|
52
185
|
Add a child.
|
|
53
186
|
|
|
@@ -57,47 +190,21 @@ class PresetScalableGroupMove(GroupParameter):
|
|
|
57
190
|
=============== ===========
|
|
58
191
|
"""
|
|
59
192
|
name_prefix = 'move'
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
'DAQ_Move_' + typ)
|
|
74
|
-
params_hardware = getattr(class_, 'params')
|
|
75
|
-
iterative_show_pb(params_hardware)
|
|
76
|
-
|
|
77
|
-
for main_child in params:
|
|
78
|
-
if main_child['name'] == 'move_settings':
|
|
79
|
-
main_child['children'] = params_hardware
|
|
80
|
-
controller_dict = get_param_dict_from_name(params_hardware, 'controller_ID')
|
|
81
|
-
controller_dict['value'] = random.randint(0, 9999)
|
|
82
|
-
|
|
83
|
-
elif main_child['name'] == 'main_settings':
|
|
84
|
-
typ_dict = get_param_dict_from_name(main_child['children'], 'move_type')
|
|
85
|
-
typ_dict['value'] = typ
|
|
86
|
-
|
|
87
|
-
child = {'title': 'Actuator {:02.0f}'.format(newindex),
|
|
88
|
-
'name': f'{name_prefix}{newindex:02.0f}',
|
|
89
|
-
'type': 'group',
|
|
90
|
-
'removable': True, 'renamable': False,
|
|
91
|
-
'children': [
|
|
92
|
-
{'title': 'Name:', 'name': 'name', 'type': 'str',
|
|
93
|
-
'value': 'Move {:02.0f}'.format(newindex)},
|
|
94
|
-
{'title': 'Init?:', 'name': 'init', 'type': 'bool', 'value': True},
|
|
95
|
-
{'title': 'Settings:', 'name': 'params', 'type': 'group', 'children': params},
|
|
96
|
-
]}
|
|
97
|
-
|
|
193
|
+
typ = typ[-1] #Only need last entry here
|
|
194
|
+
new_index = find_last_index(self.children(), name_prefix, format_string='02.0f')
|
|
195
|
+
params = make_move_params(typ)
|
|
196
|
+
child = {'title': f'Actuator {new_index}',
|
|
197
|
+
'name': f'{name_prefix}{new_index}',
|
|
198
|
+
'type': 'group',
|
|
199
|
+
'removable': True, 'renamable': False,
|
|
200
|
+
'children': [
|
|
201
|
+
{'title': 'Name:', 'name': 'name', 'type': 'str',
|
|
202
|
+
'value': f'Move {new_index}'},
|
|
203
|
+
{'title': 'Init?:', 'name': 'init', 'type': 'bool', 'value': True},
|
|
204
|
+
{'title': 'Settings:', 'name': 'params', 'type': 'group', 'children': params},
|
|
205
|
+
]}
|
|
98
206
|
self.addChild(child)
|
|
99
207
|
|
|
100
|
-
|
|
101
208
|
registerParameterType('groupmove', PresetScalableGroupMove, override=True)
|
|
102
209
|
|
|
103
210
|
|
|
@@ -116,20 +223,17 @@ class PresetScalableGroupDet(GroupParameter):
|
|
|
116
223
|
def __init__(self, **opts):
|
|
117
224
|
opts['type'] = 'groupdet'
|
|
118
225
|
opts['addText'] = "Add"
|
|
119
|
-
options =
|
|
120
|
-
for name in [plugin['name'] for plugin in DAQ_0DViewer_Det_types]
|
|
121
|
-
|
|
122
|
-
for name in [plugin['name'] for plugin in
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
for name in [plugin['name'] for plugin in DAQ_NDViewer_Det_types]:
|
|
127
|
-
options.append('DAQND/' + name)
|
|
128
|
-
opts['addList'] = options
|
|
226
|
+
options = {
|
|
227
|
+
'DAQ0D': [name for name in [plugin['name'] for plugin in DAQ_0DViewer_Det_types]],
|
|
228
|
+
'DAQ1D': [name for name in [plugin['name'] for plugin in DAQ_1DViewer_Det_types]],
|
|
229
|
+
'DAQ2D': [name for name in [plugin['name'] for plugin in DAQ_2DViewer_Det_types]],
|
|
230
|
+
'DAQND': [name for name in [plugin['name'] for plugin in DAQ_NDViewer_Det_types]],
|
|
231
|
+
}
|
|
232
|
+
opts['addMenu'] = add_category_layers(options)
|
|
129
233
|
|
|
130
234
|
super().__init__(**opts)
|
|
131
235
|
|
|
132
|
-
def addNew(self, typ):
|
|
236
|
+
def addNew(self, typ:tuple):
|
|
133
237
|
"""
|
|
134
238
|
Add a child.
|
|
135
239
|
|
|
@@ -140,63 +244,15 @@ class PresetScalableGroupDet(GroupParameter):
|
|
|
140
244
|
"""
|
|
141
245
|
try:
|
|
142
246
|
name_prefix = 'det'
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
params = daq_viewer_params
|
|
151
|
-
iterative_show_pb(params)
|
|
152
|
-
|
|
153
|
-
for main_child in params:
|
|
154
|
-
if main_child['name'] == 'main_settings':
|
|
155
|
-
for child in main_child['children']:
|
|
156
|
-
if child['name'] == 'DAQ_type':
|
|
157
|
-
child['value'] = typ[0:5]
|
|
158
|
-
if child['name'] == 'detector_type':
|
|
159
|
-
child['value'] = typ[6:]
|
|
160
|
-
if child['name'] == 'controller_status':
|
|
161
|
-
child['visible'] = True
|
|
162
|
-
|
|
163
|
-
if '0D' in typ:
|
|
164
|
-
parent_module = utils.find_dict_in_list_from_key_val(DAQ_0DViewer_Det_types, 'name', typ[6:])
|
|
165
|
-
class_ = getattr(getattr(parent_module['module'], 'daq_0Dviewer_' + typ[6:]), 'DAQ_0DViewer_' + typ[6:])
|
|
166
|
-
elif '1D' in typ:
|
|
167
|
-
parent_module = utils.find_dict_in_list_from_key_val(DAQ_1DViewer_Det_types, 'name', typ[6:])
|
|
168
|
-
class_ = getattr(getattr(parent_module['module'], 'daq_1Dviewer_' + typ[6:]), 'DAQ_1DViewer_' + typ[6:])
|
|
169
|
-
elif '2D' in typ:
|
|
170
|
-
parent_module = utils.find_dict_in_list_from_key_val(DAQ_2DViewer_Det_types, 'name', typ[6:])
|
|
171
|
-
class_ = getattr(getattr(parent_module['module'], 'daq_2Dviewer_' + typ[6:]), 'DAQ_2DViewer_' + typ[6:])
|
|
172
|
-
elif 'ND' in typ:
|
|
173
|
-
parent_module = utils.find_dict_in_list_from_key_val(DAQ_NDViewer_Det_types, 'name', typ[6:])
|
|
174
|
-
class_ = getattr(getattr(parent_module['module'], 'daq_NDviewer_' + typ[6:]), 'DAQ_NDViewer_' + typ[6:])
|
|
175
|
-
for main_child in params:
|
|
176
|
-
if main_child['name'] == 'main_settings':
|
|
177
|
-
for child in main_child['children']:
|
|
178
|
-
if child['name'] == 'axes':
|
|
179
|
-
child['visible'] = True
|
|
180
|
-
|
|
181
|
-
params_hardware = getattr(class_, 'params')
|
|
182
|
-
iterative_show_pb(params_hardware)
|
|
183
|
-
|
|
184
|
-
for main_child in params:
|
|
185
|
-
if main_child['name'] == 'detector_settings':
|
|
186
|
-
while len(main_child['children']) > 0:
|
|
187
|
-
for child in main_child['children']:
|
|
188
|
-
main_child['children'].remove(child)
|
|
189
|
-
|
|
190
|
-
main_child['children'].extend(params_hardware)
|
|
191
|
-
controller_dict = get_param_dict_from_name(main_child['children'], 'controller_ID')
|
|
192
|
-
controller_dict['value'] = random.randint(0, 9999)
|
|
193
|
-
|
|
194
|
-
child = {'title': 'Det {:02.0f}'.format(newindex), 'name': f'{name_prefix}{newindex:02.0f}',
|
|
195
|
-
'type': 'group', 'children': [
|
|
196
|
-
{'title': 'Name:', 'name': 'name', 'type': 'str', 'value': 'Det {:02.0f}'.format(newindex)},
|
|
247
|
+
typ = "/".join((typ[0],typ[-1])) #Only need first and last element to retrieve associated plugin
|
|
248
|
+
new_index = find_last_index(list_children=self.children(), name_prefix=name_prefix, format_string='02.0f')
|
|
249
|
+
params = make_viewer_params(typ)
|
|
250
|
+
child = {'title': f'Det {new_index}', 'name': f'{name_prefix}{new_index}',
|
|
251
|
+
'type': 'group', 'children': [
|
|
252
|
+
{'title': 'Name:', 'name': 'name', 'type': 'str', 'value': f'Det {new_index}'},
|
|
197
253
|
{'title': 'Init?:', 'name': 'init', 'type': 'bool', 'value': True},
|
|
198
254
|
{'title': 'Settings:', 'name': 'params', 'type': 'group', 'children': params},
|
|
199
|
-
], 'removable': True, 'renamable': False}
|
|
255
|
+
], 'removable': True, 'renamable': False}
|
|
200
256
|
|
|
201
257
|
self.addChild(child)
|
|
202
258
|
except Exception as e:
|
|
@@ -3,6 +3,7 @@ import sys
|
|
|
3
3
|
|
|
4
4
|
from qtpy.QtCore import QObject, Signal
|
|
5
5
|
from qtpy import QtGui, QtWidgets
|
|
6
|
+
from qtpy.QtWidgets import QMessageBox, QDialogButtonBox, QDialog
|
|
6
7
|
|
|
7
8
|
|
|
8
9
|
from pymodaq.utils.config import get_set_remote_path
|
|
@@ -153,9 +154,9 @@ class ShortcutSelection(QtWidgets.QDialog):
|
|
|
153
154
|
hor_layout.addWidget(label)
|
|
154
155
|
hor_layout.addWidget(self.label)
|
|
155
156
|
|
|
156
|
-
buttonBox =
|
|
157
|
-
buttonBox.addButton(
|
|
158
|
-
buttonBox.addButton(
|
|
157
|
+
buttonBox = QDialogButtonBox()
|
|
158
|
+
buttonBox.addButton(QDialogButtonBox.StandardButton.Ok)
|
|
159
|
+
buttonBox.addButton(QDialogButtonBox.StandardButton.Cancel)
|
|
159
160
|
layout.addWidget(self.label)
|
|
160
161
|
layout.addWidget(buttonBox)
|
|
161
162
|
|
|
@@ -244,9 +245,9 @@ class JoystickButtonsSelection(QtWidgets.QDialog):
|
|
|
244
245
|
|
|
245
246
|
layout.addWidget(self.settings_tree)
|
|
246
247
|
|
|
247
|
-
buttonBox =
|
|
248
|
-
buttonBox.addButton(
|
|
249
|
-
buttonBox.addButton(
|
|
248
|
+
buttonBox = QDialogButtonBox()
|
|
249
|
+
buttonBox.addButton(QDialogButtonBox.StandardButton.Ok)
|
|
250
|
+
buttonBox.addButton(QDialogButtonBox.StandardButton.Cancel)
|
|
250
251
|
layout.addWidget(buttonBox)
|
|
251
252
|
|
|
252
253
|
buttonBox.accepted.connect(self.accept)
|
|
@@ -261,13 +262,17 @@ class RemoteManager(QObject):
|
|
|
261
262
|
self.actuators = actuators
|
|
262
263
|
self.detectors = detectors
|
|
263
264
|
if msgbox:
|
|
264
|
-
msgBox =
|
|
265
|
+
msgBox = QMessageBox()
|
|
265
266
|
msgBox.setText("Preset Manager?")
|
|
266
267
|
msgBox.setInformativeText("What do you want to do?")
|
|
267
|
-
cancel_button = msgBox.addButton(
|
|
268
|
-
new_button = msgBox.addButton(
|
|
269
|
-
|
|
270
|
-
|
|
268
|
+
cancel_button = msgBox.addButton(QMessageBox.StandardButton.Cancel)
|
|
269
|
+
new_button = msgBox.addButton(
|
|
270
|
+
"New", QMessageBox.ButtonRole.ActionRole
|
|
271
|
+
)
|
|
272
|
+
modify_button = msgBox.addButton(
|
|
273
|
+
"Modify", QMessageBox.ButtonRole.AcceptRole
|
|
274
|
+
)
|
|
275
|
+
msgBox.setDefaultButton(QMessageBox.StandardButton.Cancel)
|
|
271
276
|
ret = msgBox.exec()
|
|
272
277
|
|
|
273
278
|
if msgBox.clickedButton() == new_button:
|
|
@@ -443,7 +448,7 @@ class RemoteManager(QObject):
|
|
|
443
448
|
"""
|
|
444
449
|
|
|
445
450
|
"""
|
|
446
|
-
dialog =
|
|
451
|
+
dialog = QDialog()
|
|
447
452
|
vlayout = QtWidgets.QVBoxLayout()
|
|
448
453
|
tree = ParameterTree()
|
|
449
454
|
# tree.setMinimumWidth(400)
|
|
@@ -452,18 +457,18 @@ class RemoteManager(QObject):
|
|
|
452
457
|
|
|
453
458
|
vlayout.addWidget(tree)
|
|
454
459
|
dialog.setLayout(vlayout)
|
|
455
|
-
buttonBox =
|
|
460
|
+
buttonBox = QDialogButtonBox(parent=dialog)
|
|
456
461
|
|
|
457
|
-
buttonBox.addButton(
|
|
462
|
+
buttonBox.addButton("Save", QDialogButtonBox.ButtonRole.AcceptRole)
|
|
458
463
|
buttonBox.accepted.connect(dialog.accept)
|
|
459
|
-
buttonBox.addButton(
|
|
464
|
+
buttonBox.addButton("Cancel", QDialogButtonBox.ButtonRole.RejectRole)
|
|
460
465
|
buttonBox.rejected.connect(dialog.reject)
|
|
461
466
|
|
|
462
467
|
vlayout.addWidget(buttonBox)
|
|
463
468
|
dialog.setWindowTitle('Fill in information about the actions and their shortcuts')
|
|
464
469
|
res = dialog.exec()
|
|
465
470
|
|
|
466
|
-
if res ==
|
|
471
|
+
if res == QDialog.DialogCode.Accepted:
|
|
467
472
|
# save preset parameters in a xml file
|
|
468
473
|
ioxml.parameter_to_xml_file(
|
|
469
474
|
self.remote_params, os.path.join(remote_path, self.remote_params.child('filename').value()))
|
|
@@ -20,10 +20,10 @@ from pymodaq_utils import math_utils as mutils
|
|
|
20
20
|
from pymodaq_utils import config as configmod
|
|
21
21
|
|
|
22
22
|
from pymodaq_gui.managers.parameter_manager import ParameterManager, Parameter
|
|
23
|
-
|
|
24
23
|
from pymodaq_data.data import Axis, DataDistribution
|
|
25
24
|
|
|
26
25
|
from pymodaq.utils.scanner.scan_config import ScanConfig
|
|
26
|
+
|
|
27
27
|
try:
|
|
28
28
|
from pymodaq_gui.config_saver_loader import ConfigSaverLoader
|
|
29
29
|
except ModuleNotFoundError:
|
|
@@ -38,8 +38,9 @@ if TYPE_CHECKING:
|
|
|
38
38
|
|
|
39
39
|
|
|
40
40
|
logger = set_logger(get_module_name(__file__))
|
|
41
|
-
config = configmod.Config()
|
|
42
41
|
|
|
42
|
+
config_utils = configmod.Config()
|
|
43
|
+
config = ControlModulesConfig()
|
|
43
44
|
|
|
44
45
|
class ScanParameterManager(ParameterManager):
|
|
45
46
|
settings_name = 'scanner_settings'
|
|
@@ -86,11 +87,12 @@ class ScannerBase(ScanParameterManager, metaclass=ABCMeta):
|
|
|
86
87
|
distribution: DataDistribution = abstract_attribute()
|
|
87
88
|
save_settings = True
|
|
88
89
|
|
|
89
|
-
def __init__(self, actuators: List[DAQ_Move] = None):
|
|
90
|
+
def __init__(self, actuators: List[DAQ_Move] = None, display_units=True):
|
|
90
91
|
super().__init__()
|
|
91
92
|
self.positions: np.ndarray = None
|
|
92
93
|
self.n_steps = 1
|
|
93
94
|
self.config = ScanConfig()
|
|
95
|
+
self.display_units = display_units
|
|
94
96
|
base_path = [act.title for act in actuators] + [self.scan_type, self.scan_subtype]
|
|
95
97
|
|
|
96
98
|
self.config_saver_loader = ConfigSaverLoader(self.settings,
|
|
@@ -101,10 +103,17 @@ class ScannerBase(ScanParameterManager, metaclass=ABCMeta):
|
|
|
101
103
|
|
|
102
104
|
self.set_settings_titles()
|
|
103
105
|
self.set_settings_values()
|
|
106
|
+
if len(actuators) > 0:
|
|
107
|
+
self.set_units()
|
|
104
108
|
|
|
105
109
|
if self.check_steps():
|
|
106
110
|
self.set_scan()
|
|
107
111
|
|
|
112
|
+
@abstractmethod
|
|
113
|
+
def set_units(self):
|
|
114
|
+
""" Update settings units depending on the scanner type and the display_units boolean"""
|
|
115
|
+
...
|
|
116
|
+
|
|
108
117
|
def set_settings_titles(self):
|
|
109
118
|
"""Update the settings accordingly with the selected actuators"""
|
|
110
119
|
...
|
|
@@ -311,9 +311,7 @@ class ScanSelector(ParameterManager, QObject):
|
|
|
311
311
|
self.table_view.horizontalHeader().setStretchLastSection(True)
|
|
312
312
|
self.table_view.setSelectionBehavior(QtWidgets.QTableView.SelectRows)
|
|
313
313
|
self.table_view.setSelectionMode(QtWidgets.QTableView.SingleSelection)
|
|
314
|
-
|
|
315
|
-
styledItemDelegate.setItemEditorFactory(gutils.SpinBoxDelegate())
|
|
316
|
-
self.table_view.setItemDelegate(styledItemDelegate)
|
|
314
|
+
self.table_view.setItemDelegate(gutils.SpinBoxDelegate())
|
|
317
315
|
|
|
318
316
|
self.table_view.setDragEnabled(False)
|
|
319
317
|
self.table_view.setDropIndicatorShown(False)
|
pymodaq/utils/scanner/scanner.py
CHANGED
|
@@ -5,6 +5,7 @@ from collections import OrderedDict
|
|
|
5
5
|
from qtpy.QtCore import QObject, Signal
|
|
6
6
|
from qtpy import QtWidgets
|
|
7
7
|
|
|
8
|
+
from pymodaq_gui.messenger import messagebox
|
|
8
9
|
from pymodaq_utils.logger import set_logger, get_module_name
|
|
9
10
|
from pymodaq_utils.config import Config
|
|
10
11
|
import pymodaq_utils.utils as utils
|
|
@@ -15,13 +16,16 @@ from pymodaq.utils.scanner.scan_factory import ScannerFactory, ScannerBase
|
|
|
15
16
|
from pymodaq.utils.scanner.utils import ScanInfo
|
|
16
17
|
from pymodaq.utils.scanner.scan_selector import Selector
|
|
17
18
|
from pymodaq.utils.data import DataToExport, DataActuator
|
|
19
|
+
from pymodaq.utils.config import Config as ControlModulesConfig
|
|
18
20
|
|
|
19
21
|
if TYPE_CHECKING:
|
|
20
22
|
from pymodaq.control_modules.daq_move import DAQ_Move
|
|
21
23
|
|
|
22
24
|
|
|
23
25
|
logger = set_logger(get_module_name(__file__))
|
|
24
|
-
|
|
26
|
+
|
|
27
|
+
config_utils = Config()
|
|
28
|
+
config = ControlModulesConfig()
|
|
25
29
|
scanner_factory = ScannerFactory()
|
|
26
30
|
|
|
27
31
|
|
|
@@ -50,6 +54,12 @@ class Scanner(QObject, ParameterManager):
|
|
|
50
54
|
'limits': scanner_factory.scan_types()},
|
|
51
55
|
{'title': 'Scan subtype:', 'name': 'scan_sub_type', 'type': 'list',
|
|
52
56
|
'limits': scanner_factory.scan_sub_types(scanner_factory.scan_types()[0])},
|
|
57
|
+
{'title': 'Units handling', 'name': 'units_handling', 'type': 'group', 'children': [
|
|
58
|
+
{'title': 'Display units', 'name': 'display_units', 'type': 'bool', 'value': True},
|
|
59
|
+
{'title': 'Default units', 'name': 'common_units', 'type': 'str', 'value': '', 'visible': False,
|
|
60
|
+
'readonly': True},
|
|
61
|
+
]},
|
|
62
|
+
|
|
53
63
|
]
|
|
54
64
|
|
|
55
65
|
def __init__(self, parent_widget: QtWidgets.QWidget = None, scanner_items=OrderedDict([]),
|
|
@@ -82,9 +92,11 @@ class Scanner(QObject, ParameterManager):
|
|
|
82
92
|
|
|
83
93
|
def set_scanner(self):
|
|
84
94
|
try:
|
|
85
|
-
self._scanner: ScannerBase = scanner_factory.get(
|
|
86
|
-
|
|
87
|
-
|
|
95
|
+
self._scanner: ScannerBase = scanner_factory.get(
|
|
96
|
+
self.settings['scan_type'],
|
|
97
|
+
self.settings['scan_sub_type'],
|
|
98
|
+
actuators=self.actuators,
|
|
99
|
+
display_units=self.settings['units_handling', 'display_units'])
|
|
88
100
|
|
|
89
101
|
while True:
|
|
90
102
|
child = self._scanner_settings_widget.layout().takeAt(0)
|
|
@@ -111,10 +123,25 @@ class Scanner(QObject, ParameterManager):
|
|
|
111
123
|
if param.name() == 'scan_type':
|
|
112
124
|
self.settings.child('scan_sub_type').setOpts(
|
|
113
125
|
limits=scanner_factory.scan_sub_types(param.value()))
|
|
114
|
-
if param.name() in ['
|
|
126
|
+
if param.name() in ['scan_sub_type']:
|
|
115
127
|
self.set_scanner()
|
|
116
128
|
self.settings.child('scan_type').setOpts(tip=self._scanner.__doc__)
|
|
117
129
|
self.settings.child('scan_sub_type').setOpts(tip=self._scanner.__doc__)
|
|
130
|
+
elif param.name() == 'display_units':
|
|
131
|
+
if not param.value() and len(self.actuators) > 0:
|
|
132
|
+
|
|
133
|
+
units = set([act.units for act in self.actuators])
|
|
134
|
+
if len(units) > 1:
|
|
135
|
+
messagebox(title='Info',
|
|
136
|
+
text='Could not use the same units for all settings as units are not compatible')
|
|
137
|
+
param.setValue(True)
|
|
138
|
+
self.settings.child('units_handling', 'common_units').show(False)
|
|
139
|
+
else:
|
|
140
|
+
self.settings.child('units_handling', 'common_units').setValue(list(units)[0])
|
|
141
|
+
self.settings.child('units_handling', 'common_units').show(True)
|
|
142
|
+
else:
|
|
143
|
+
self.settings.child('units_handling', 'common_units').show(False)
|
|
144
|
+
self.set_scanner()
|
|
118
145
|
|
|
119
146
|
self.settings.child('n_steps').setValue(self._scanner.evaluate_steps())
|
|
120
147
|
|
|
@@ -245,10 +272,12 @@ def main():
|
|
|
245
272
|
from pymodaq.utils.parameter import ParameterTree
|
|
246
273
|
app = QtWidgets.QApplication(sys.argv)
|
|
247
274
|
|
|
275
|
+
units = ['nm', 'kW', 'ms']
|
|
276
|
+
|
|
248
277
|
class MoveMock:
|
|
249
278
|
def __init__(self, ind: int = 0):
|
|
250
279
|
self.title = f'act_{ind}'
|
|
251
|
-
self.units =
|
|
280
|
+
self.units = units[ind]
|
|
252
281
|
|
|
253
282
|
actuators = [MoveMock(ind) for ind in range(3)]
|
|
254
283
|
|
|
@@ -32,8 +32,14 @@ class Scan1DBase(ScannerBase):
|
|
|
32
32
|
n_axes = 1
|
|
33
33
|
distribution = DataDistribution['uniform']
|
|
34
34
|
|
|
35
|
-
def __init__(self, actuators: List = None, **_ignored):
|
|
36
|
-
super().__init__(actuators=actuators)
|
|
35
|
+
def __init__(self, actuators: List = None, display_units=True, **_ignored):
|
|
36
|
+
super().__init__(actuators=actuators, display_units=display_units)
|
|
37
|
+
|
|
38
|
+
def set_units(self):
|
|
39
|
+
""" Update settings units depending on the scanner type and the display_units boolean"""
|
|
40
|
+
for child in self.settings.children():
|
|
41
|
+
child.setOpts(
|
|
42
|
+
suffix='' if not self.display_units else self.actuators[0].units)
|
|
37
43
|
|
|
38
44
|
def get_nav_axes(self) -> List[Axis]:
|
|
39
45
|
return [Axis(label=f'{self.actuators[0].title}',
|
|
@@ -64,8 +70,9 @@ class Scan1DLinear(Scan1DBase):
|
|
|
64
70
|
n_axes = 1
|
|
65
71
|
distribution = DataDistribution['uniform']
|
|
66
72
|
|
|
67
|
-
def __init__(self, actuators: List['DAQ_Move'] = None, **_ignored):
|
|
68
|
-
super().__init__(actuators=actuators)
|
|
73
|
+
def __init__(self, actuators: List['DAQ_Move'] = None, display_units=True, **_ignored):
|
|
74
|
+
super().__init__(actuators=actuators, display_units=display_units)
|
|
75
|
+
|
|
69
76
|
|
|
70
77
|
def set_scan(self):
|
|
71
78
|
self.positions = mutils.linspace_step(self.settings['start'], self.settings['stop'],
|
|
@@ -96,8 +103,8 @@ class Scan1DRandom(Scan1DLinear):
|
|
|
96
103
|
|
|
97
104
|
scan_subtype = 'Random'
|
|
98
105
|
|
|
99
|
-
def __init__(self, actuators: List = None, **_ignored):
|
|
100
|
-
super().__init__(actuators=actuators)
|
|
106
|
+
def __init__(self, actuators: List = None, display_units=True, **_ignored):
|
|
107
|
+
super().__init__(actuators=actuators, display_units=display_units)
|
|
101
108
|
|
|
102
109
|
def set_scan(self):
|
|
103
110
|
self.positions = mutils.linspace_step(self.settings['start'], self.settings['stop'],
|
|
@@ -128,8 +135,8 @@ class Scan1DSparse(Scan1DBase):
|
|
|
128
135
|
distribution = DataDistribution['uniform'] # because in 1D it doesn't matter is spread or
|
|
129
136
|
# uniform, one can easily plot both types on a regulat 1D plot
|
|
130
137
|
|
|
131
|
-
def __init__(self, actuators: List['DAQ_Move'] = None, **_ignored):
|
|
132
|
-
super().__init__(actuators=actuators)
|
|
138
|
+
def __init__(self, actuators: List['DAQ_Move'] = None, display_units=True, **_ignored):
|
|
139
|
+
super().__init__(actuators=actuators, display_units=display_units)
|
|
133
140
|
self.settings.child('parsed_string').setOpts(tip=self.__doc__)
|
|
134
141
|
|
|
135
142
|
def set_scan(self):
|
|
@@ -165,41 +172,3 @@ class Scan1DSparse(Scan1DBase):
|
|
|
165
172
|
if len(self.actuators) == 1:
|
|
166
173
|
self.settings.child('parsed_string').setOpts(title=f'{self.actuators[0].title} Parsed string:')
|
|
167
174
|
|
|
168
|
-
try:
|
|
169
|
-
import adaptive
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
@ScannerFactory.register()
|
|
173
|
-
class Scan1DAdaptive(Scan1DBase):
|
|
174
|
-
|
|
175
|
-
scan_subtype = 'Adaptive'
|
|
176
|
-
params = [
|
|
177
|
-
{'title': 'Loss type', 'name': 'scan_loss', 'type': 'list',
|
|
178
|
-
'limits': ['default', 'curvature', 'uniform'], 'tip': 'Type of loss used by the algo. to determine next points'},
|
|
179
|
-
{'title': 'Start:', 'name': 'start', 'type': 'float', 'value': 0.},
|
|
180
|
-
{'title': 'Stop:', 'name': 'stop', 'type': 'float', 'value': 1.},
|
|
181
|
-
]
|
|
182
|
-
distribution = DataDistribution['spread']
|
|
183
|
-
|
|
184
|
-
def __init__(self, actuators: List['DAQ_Move'] = None, **_ignored):
|
|
185
|
-
super().__init__(actuators=actuators)
|
|
186
|
-
|
|
187
|
-
def set_scan(self):
|
|
188
|
-
self.axes_unique = [np.array([])]
|
|
189
|
-
self.axes_indexes = np.array([], dtype=int)
|
|
190
|
-
self.positions = np.array([self.settings['start'], self.settings['stop']])
|
|
191
|
-
|
|
192
|
-
def evaluate_steps(self) -> int:
|
|
193
|
-
return 1
|
|
194
|
-
|
|
195
|
-
def get_nav_axes(self) -> List[Axis]:
|
|
196
|
-
return [Axis(label=f'{self.actuators[0].mod_name} axis',
|
|
197
|
-
units=f'{self.actuators[0].units}',
|
|
198
|
-
data=self.positions[0])]
|
|
199
|
-
|
|
200
|
-
def get_scan_shape(self) -> Tuple[int]:
|
|
201
|
-
return len(self.positions),
|
|
202
|
-
|
|
203
|
-
except ModuleNotFoundError:
|
|
204
|
-
logger.info('adaptive module is not present, no adaptive scan possible')
|
|
205
|
-
|