pymodaq 3.6.12__py3-none-any.whl → 4.0.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.
- pymodaq/__init__.py +13 -6
- pymodaq/control_modules/__init__.py +0 -7
- pymodaq/control_modules/daq_move.py +965 -2
- pymodaq/control_modules/daq_move_ui.py +319 -0
- pymodaq/control_modules/daq_viewer.py +1573 -3
- pymodaq/control_modules/daq_viewer_ui.py +393 -0
- pymodaq/control_modules/mocks.py +51 -0
- pymodaq/control_modules/move_utility_classes.py +709 -8
- pymodaq/control_modules/utils.py +256 -0
- pymodaq/control_modules/viewer_utility_classes.py +663 -6
- pymodaq/daq_utils.py +89 -0
- pymodaq/dashboard.py +91 -72
- pymodaq/examples/custom_app.py +12 -11
- pymodaq/examples/custom_viewer.py +10 -10
- pymodaq/examples/function_plotter.py +16 -13
- pymodaq/examples/nonlinearscanner.py +8 -6
- pymodaq/examples/parameter_ex.py +7 -7
- pymodaq/examples/preset_MockCamera.xml +1 -0
- pymodaq/extensions/__init__.py +16 -0
- pymodaq/extensions/console.py +76 -0
- pymodaq/{daq_logger.py → extensions/daq_logger.py} +115 -65
- pymodaq/extensions/daq_scan.py +1339 -0
- pymodaq/extensions/daq_scan_ui.py +240 -0
- pymodaq/extensions/h5browser.py +23 -0
- pymodaq/{pid → extensions/pid}/__init__.py +4 -2
- pymodaq/{pid → extensions/pid}/daq_move_PID.py +2 -2
- pymodaq/{pid → extensions/pid}/pid_controller.py +48 -36
- pymodaq/{pid → extensions/pid}/utils.py +52 -6
- pymodaq/extensions/utils.py +40 -0
- pymodaq/post_treatment/__init__.py +6 -0
- pymodaq/{daq_analysis → post_treatment/daq_analysis}/daq_analysis_main.py +17 -17
- pymodaq/{daq_measurement → post_treatment/daq_measurement}/daq_measurement_main.py +8 -14
- pymodaq/post_treatment/load_and_plot.py +219 -0
- pymodaq/post_treatment/process_to_scalar.py +263 -0
- pymodaq/resources/QtDesigner_Ressources/Icon_Library/run_all.png +0 -0
- pymodaq/resources/QtDesigner_Ressources/Icon_Library/stop_all.png +0 -0
- pymodaq/resources/QtDesigner_Ressources/QtDesigner_ressources.bat +1 -1
- pymodaq/resources/QtDesigner_Ressources/QtDesigner_ressources.qrc +1 -0
- pymodaq/resources/QtDesigner_Ressources/QtDesigner_ressources_rc.py +109784 -109173
- pymodaq/resources/QtDesigner_Ressources/icons.svg +142 -0
- pymodaq/resources/VERSION +1 -1
- pymodaq/resources/config_template.toml +32 -13
- pymodaq/resources/preset_default.xml +1 -1
- pymodaq/{daq_utils → utils}/Tuto innosetup/script_full_setup.iss +1 -1
- pymodaq/utils/__init__.py +0 -29
- pymodaq/utils/abstract/__init__.py +48 -0
- pymodaq/{daq_utils → utils}/abstract/logger.py +7 -3
- pymodaq/utils/array_manipulation.py +379 -8
- pymodaq/{daq_utils → utils}/calibration_camera.py +6 -6
- pymodaq/{daq_utils → utils}/chrono_timer.py +1 -1
- pymodaq/utils/config.py +448 -0
- pymodaq/utils/conftests.py +5 -0
- pymodaq/utils/daq_utils.py +828 -8
- pymodaq/utils/data.py +1873 -7
- pymodaq/{daq_utils → utils}/db/db_logger/db_logger.py +86 -47
- pymodaq/{daq_utils → utils}/db/db_logger/db_logger_models.py +31 -10
- pymodaq/{daq_utils → utils}/enums.py +12 -7
- pymodaq/utils/exceptions.py +37 -0
- pymodaq/utils/factory.py +82 -0
- pymodaq/{daq_utils → utils}/gui_utils/__init__.py +1 -1
- pymodaq/utils/gui_utils/custom_app.py +129 -0
- pymodaq/utils/gui_utils/file_io.py +66 -0
- pymodaq/{daq_utils → utils}/gui_utils/layout.py +2 -2
- pymodaq/{daq_utils → utils}/gui_utils/utils.py +13 -3
- pymodaq/{daq_utils → utils}/gui_utils/widgets/__init__.py +2 -2
- pymodaq/utils/gui_utils/widgets/label.py +24 -0
- pymodaq/{daq_utils → utils}/gui_utils/widgets/lcd.py +12 -7
- pymodaq/{daq_utils → utils}/gui_utils/widgets/push.py +66 -2
- pymodaq/{daq_utils → utils}/gui_utils/widgets/qled.py +6 -4
- pymodaq/utils/gui_utils/widgets/spinbox.py +24 -0
- pymodaq/{daq_utils → utils}/gui_utils/widgets/table.py +2 -2
- pymodaq/utils/h5modules/__init__.py +1 -0
- pymodaq/{daq_utils/h5backend.py → utils/h5modules/backends.py} +200 -112
- pymodaq/utils/h5modules/browsing.py +683 -0
- pymodaq/utils/h5modules/data_saving.py +839 -0
- pymodaq/utils/h5modules/h5logging.py +110 -0
- pymodaq/utils/h5modules/module_saving.py +350 -0
- pymodaq/utils/h5modules/saving.py +914 -0
- pymodaq/utils/h5modules/utils.py +85 -0
- pymodaq/utils/logger.py +64 -6
- pymodaq/utils/managers/action_manager.py +460 -0
- pymodaq/{daq_utils → utils}/managers/batchscan_manager.py +144 -112
- pymodaq/{daq_utils → utils}/managers/modules_manager.py +188 -114
- pymodaq/{daq_utils → utils}/managers/overshoot_manager.py +3 -3
- pymodaq/utils/managers/parameter_manager.py +110 -0
- pymodaq/{daq_utils → utils}/managers/preset_manager.py +17 -13
- pymodaq/{daq_utils → utils}/managers/preset_manager_utils.py +8 -7
- pymodaq/{daq_utils → utils}/managers/remote_manager.py +7 -6
- pymodaq/{daq_utils → utils}/managers/roi_manager.py +148 -57
- pymodaq/utils/math_utils.py +546 -10
- pymodaq/{daq_utils → utils}/messenger.py +5 -1
- pymodaq/utils/parameter/__init__.py +2 -15
- pymodaq/{daq_utils → utils}/parameter/ioxml.py +12 -6
- pymodaq/{daq_utils → utils}/parameter/pymodaq_ptypes/__init__.py +1 -3
- pymodaq/{daq_utils → utils}/parameter/pymodaq_ptypes/filedir.py +1 -1
- pymodaq/{daq_utils → utils}/parameter/pymodaq_ptypes/itemselect.py +3 -0
- pymodaq/{daq_utils → utils}/parameter/pymodaq_ptypes/led.py +1 -1
- pymodaq/utils/parameter/pymodaq_ptypes/pixmap.py +161 -0
- pymodaq/{daq_utils → utils}/parameter/pymodaq_ptypes/slide.py +1 -1
- pymodaq/{daq_utils → utils}/parameter/pymodaq_ptypes/table.py +1 -1
- pymodaq/utils/parameter/utils.py +206 -11
- pymodaq/utils/plotting/data_viewers/__init__.py +6 -0
- pymodaq/utils/plotting/data_viewers/viewer.py +393 -0
- pymodaq/utils/plotting/data_viewers/viewer0D.py +251 -0
- pymodaq/utils/plotting/data_viewers/viewer1D.py +574 -0
- pymodaq/{daq_utils → utils}/plotting/data_viewers/viewer1Dbasic.py +8 -3
- pymodaq/{daq_utils → utils}/plotting/data_viewers/viewer2D.py +292 -357
- pymodaq/{daq_utils → utils}/plotting/data_viewers/viewer2D_basic.py +58 -75
- pymodaq/utils/plotting/data_viewers/viewerND.py +738 -0
- pymodaq/{daq_utils → utils}/plotting/gant_chart.py +2 -2
- pymodaq/{daq_utils → utils}/plotting/items/axis_scaled.py +4 -2
- pymodaq/{daq_utils → utils}/plotting/items/image.py +8 -6
- pymodaq/utils/plotting/navigator.py +355 -0
- pymodaq/utils/plotting/scan_selector.py +480 -0
- pymodaq/utils/plotting/utils/axes_viewer.py +88 -0
- pymodaq/utils/plotting/utils/filter.py +538 -0
- pymodaq/utils/plotting/utils/lineout.py +224 -0
- pymodaq/{daq_utils → utils}/plotting/utils/plot_utils.py +196 -84
- pymodaq/{daq_utils → utils}/plotting/utils/signalND.py +21 -13
- pymodaq/utils/plotting/widgets.py +76 -0
- pymodaq/utils/scanner/__init__.py +10 -0
- pymodaq/utils/scanner/scan_factory.py +204 -0
- pymodaq/utils/scanner/scanner.py +271 -0
- pymodaq/utils/scanner/scanners/_1d_scanners.py +117 -0
- pymodaq/utils/scanner/scanners/_2d_scanners.py +293 -0
- pymodaq/utils/scanner/scanners/sequential.py +192 -0
- pymodaq/utils/scanner/scanners/tabular.py +294 -0
- pymodaq/utils/scanner/utils.py +83 -0
- pymodaq/utils/slicing.py +47 -0
- pymodaq/utils/svg/__init__.py +6 -0
- pymodaq/utils/svg/svg_renderer.py +20 -0
- pymodaq/utils/svg/svg_view.py +35 -0
- pymodaq/utils/svg/svg_viewer2D.py +51 -0
- pymodaq/{daq_utils → utils}/tcp_server_client.py +36 -37
- pymodaq/{daq_utils → utils}/tree_layout/tree_layout_main.py +50 -35
- pymodaq/utils/units.py +216 -0
- pymodaq-4.0.1.dist-info/METADATA +159 -0
- {pymodaq-3.6.12.dist-info → pymodaq-4.0.1.dist-info}/RECORD +167 -170
- {pymodaq-3.6.12.dist-info → pymodaq-4.0.1.dist-info}/WHEEL +1 -2
- pymodaq-4.0.1.dist-info/entry_points.txt +8 -0
- pymodaq/daq_move/daq_move_gui.py +0 -279
- pymodaq/daq_move/daq_move_gui.ui +0 -534
- pymodaq/daq_move/daq_move_main.py +0 -1042
- pymodaq/daq_move/process_from_QtDesigner_DAQ_Move_GUI.bat +0 -2
- pymodaq/daq_move/utility_classes.py +0 -671
- pymodaq/daq_scan.py +0 -2160
- pymodaq/daq_utils/array_manipulation.py +0 -386
- pymodaq/daq_utils/config.py +0 -273
- pymodaq/daq_utils/conftests.py +0 -7
- pymodaq/daq_utils/custom_parameter_tree.py +0 -9
- pymodaq/daq_utils/daq_enums.py +0 -133
- pymodaq/daq_utils/daq_utils.py +0 -1402
- pymodaq/daq_utils/exceptions.py +0 -71
- pymodaq/daq_utils/gui_utils/custom_app.py +0 -103
- pymodaq/daq_utils/gui_utils/file_io.py +0 -75
- pymodaq/daq_utils/gui_utils/widgets/spinbox.py +0 -9
- pymodaq/daq_utils/h5exporter_hyperspy.py +0 -115
- pymodaq/daq_utils/h5exporters.py +0 -242
- pymodaq/daq_utils/h5modules.py +0 -1559
- pymodaq/daq_utils/h5utils.py +0 -241
- pymodaq/daq_utils/managers/action_manager.py +0 -236
- pymodaq/daq_utils/managers/parameter_manager.py +0 -57
- pymodaq/daq_utils/math_utils.py +0 -705
- pymodaq/daq_utils/parameter/__init__.py +0 -1
- pymodaq/daq_utils/parameter/oldpymodaq_ptypes.py +0 -1626
- pymodaq/daq_utils/parameter/pymodaq_ptypes/pixmap.py +0 -85
- pymodaq/daq_utils/parameter/utils.py +0 -136
- pymodaq/daq_utils/plotting/data_viewers/__init__.py +0 -0
- pymodaq/daq_utils/plotting/data_viewers/process_from_QtDesigner_0DViewer_GUI.bat +0 -2
- pymodaq/daq_utils/plotting/data_viewers/viewer0D.py +0 -204
- pymodaq/daq_utils/plotting/data_viewers/viewer0D_GUI.py +0 -89
- pymodaq/daq_utils/plotting/data_viewers/viewer0D_GUI.ui +0 -131
- pymodaq/daq_utils/plotting/data_viewers/viewer1D.py +0 -781
- pymodaq/daq_utils/plotting/data_viewers/viewerND.py +0 -894
- pymodaq/daq_utils/plotting/data_viewers/viewerbase.py +0 -64
- pymodaq/daq_utils/plotting/items/__init__.py +0 -0
- pymodaq/daq_utils/plotting/navigator.py +0 -500
- pymodaq/daq_utils/plotting/scan_selector.py +0 -289
- pymodaq/daq_utils/plotting/utils/__init__.py +0 -0
- pymodaq/daq_utils/plotting/utils/filter.py +0 -236
- pymodaq/daq_utils/plotting/viewer0D/__init__.py +0 -0
- pymodaq/daq_utils/plotting/viewer0D/viewer0D_main.py +0 -4
- pymodaq/daq_utils/plotting/viewer1D/__init__.py +0 -0
- pymodaq/daq_utils/plotting/viewer1D/viewer1D_main.py +0 -4
- pymodaq/daq_utils/plotting/viewer1D/viewer1Dbasic.py +0 -4
- pymodaq/daq_utils/plotting/viewer2D/viewer_2D_basic.py +0 -4
- pymodaq/daq_utils/plotting/viewer2D/viewer_2D_main.py +0 -4
- pymodaq/daq_utils/plotting/viewerND/__init__.py +0 -0
- pymodaq/daq_utils/plotting/viewerND/viewerND_main.py +0 -4
- pymodaq/daq_utils/scanner.py +0 -1289
- pymodaq/daq_utils/tree_layout/__init__.py +0 -0
- pymodaq/daq_viewer/__init__.py +0 -0
- pymodaq/daq_viewer/daq_gui_settings.py +0 -237
- pymodaq/daq_viewer/daq_gui_settings.ui +0 -441
- pymodaq/daq_viewer/daq_viewer_main.py +0 -2225
- pymodaq/daq_viewer/process_from_QtDesigner_DAQ_GUI_settings.bat +0 -2
- pymodaq/daq_viewer/utility_classes.py +0 -673
- pymodaq/examples/logger_image/__init__.py +0 -0
- pymodaq/examples/logger_image/logger_displayer.py +0 -121
- pymodaq/examples/logger_image/setup.svg +0 -3119
- pymodaq/examples/logger_image/setup_svg.py +0 -114
- pymodaq/h5browser.py +0 -39
- pymodaq/utils/scanner.py +0 -15
- pymodaq-3.6.12.dist-info/METADATA +0 -39
- pymodaq-3.6.12.dist-info/entry_points.txt +0 -8
- pymodaq-3.6.12.dist-info/top_level.txt +0 -1
- /pymodaq/{daq_analysis → post_treatment/daq_analysis}/__init__.py +0 -0
- /pymodaq/{daq_measurement → post_treatment/daq_measurement}/__init__.py +0 -0
- /pymodaq/{daq_measurement → post_treatment/daq_measurement}/daq_measurement_GUI.py +0 -0
- /pymodaq/{daq_measurement → post_treatment/daq_measurement}/daq_measurement_GUI.ui +0 -0
- /pymodaq/{daq_measurement → post_treatment/daq_measurement}/process_from_QtDesigner_DAQ_Measurement_GUI.bat +0 -0
- /pymodaq/{daq_utils → utils}/Tuto innosetup/Tuto innosetup.odt +0 -0
- /pymodaq/{daq_utils → utils}/Tuto innosetup/Tuto innosetup.pdf +0 -0
- /pymodaq/{daq_move → utils/db}/__init__.py +0 -0
- /pymodaq/{daq_utils → utils/db/db_logger}/__init__.py +0 -0
- /pymodaq/{daq_utils → utils}/gui_utils/dock.py +0 -0
- /pymodaq/{daq_utils → utils}/gui_utils/list_picker.py +0 -0
- /pymodaq/{daq_utils/abstract → utils/managers}/__init__.py +0 -0
- /pymodaq/{daq_utils → utils}/parameter/pymodaq_ptypes/bool.py +0 -0
- /pymodaq/{daq_utils → utils}/parameter/pymodaq_ptypes/date.py +0 -0
- /pymodaq/{daq_utils → utils}/parameter/pymodaq_ptypes/list.py +0 -0
- /pymodaq/{daq_utils → utils}/parameter/pymodaq_ptypes/numeric.py +0 -0
- /pymodaq/{daq_utils → utils}/parameter/pymodaq_ptypes/tableview.py +0 -0
- /pymodaq/{daq_utils → utils}/parameter/pymodaq_ptypes/text.py +0 -0
- /pymodaq/{daq_utils/db → utils/plotting}/__init__.py +0 -0
- /pymodaq/{daq_utils → utils}/plotting/image_viewer.py +0 -0
- /pymodaq/{daq_utils/db/db_logger → utils/plotting/items}/__init__.py +0 -0
- /pymodaq/{daq_utils → utils}/plotting/items/crosshair.py +0 -0
- /pymodaq/{daq_utils/managers → utils/plotting/utils}/__init__.py +0 -0
- /pymodaq/{daq_utils → utils}/qvariant.py +0 -0
- /pymodaq/{daq_utils/plotting/viewer2D → utils/scanner/scanners}/__init__.py +0 -0
- /pymodaq/{daq_utils/plotting → utils/tree_layout}/__init__.py +0 -0
- {pymodaq-3.6.12.dist-info → pymodaq-4.0.1.dist-info/licenses}/LICENSE +0 -0
|
@@ -0,0 +1,293 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
"""
|
|
3
|
+
Created the 05/12/2022
|
|
4
|
+
|
|
5
|
+
@author: Sebastien Weber
|
|
6
|
+
"""
|
|
7
|
+
from typing import List, Tuple
|
|
8
|
+
|
|
9
|
+
import numpy as np
|
|
10
|
+
from pymodaq.utils.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.plotting.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
|
+
|
|
22
|
+
@ScannerFactory.register('Scan2D', 'Linear')
|
|
23
|
+
class Scan2DLinear(ScannerBase):
|
|
24
|
+
params = [{'title': 'Start Ax1:', 'name': 'start_axis1', 'type': 'float',
|
|
25
|
+
'value': config('scan', 'scan2D', 'linear', 'start1')},
|
|
26
|
+
{'title': 'Start Ax2:', 'name': 'start_axis2', 'type': 'float',
|
|
27
|
+
'value': config('scan', 'scan2D', 'linear', 'start2')},
|
|
28
|
+
{'title': 'Step Ax1:', 'name': 'step_axis1', 'type': 'float',
|
|
29
|
+
'value': config('scan', 'scan2D', 'linear', 'step1')},
|
|
30
|
+
{'title': 'Step Ax2:', 'name': 'step_axis2', 'type': 'float',
|
|
31
|
+
'value': config('scan', 'scan2D', 'linear', 'step2')},
|
|
32
|
+
{'title': 'Stop Ax1:', 'name': 'stop_axis1', 'type': 'float',
|
|
33
|
+
'value': config('scan', 'scan2D', 'linear', 'stop1')},
|
|
34
|
+
{'title': 'Stop Ax2:', 'name': 'stop_axis2', 'type': 'float',
|
|
35
|
+
'value': config('scan', 'scan2D', 'linear', 'stop2')},
|
|
36
|
+
]
|
|
37
|
+
n_axes = 2
|
|
38
|
+
distribution = DataDistribution['uniform']
|
|
39
|
+
|
|
40
|
+
def __init__(self, actuators: List = None, **_ignored):
|
|
41
|
+
super().__init__(actuators=actuators)
|
|
42
|
+
|
|
43
|
+
def get_pos(self):
|
|
44
|
+
starts = np.array([self.settings['start_axis1'], self.settings['start_axis2']])
|
|
45
|
+
stops = np.array([self.settings['stop_axis1'], self.settings['stop_axis2']])
|
|
46
|
+
steps = np.array([self.settings['step_axis1'], self.settings['step_axis2']])
|
|
47
|
+
return starts, stops, steps
|
|
48
|
+
|
|
49
|
+
def evaluate_steps(self) -> int:
|
|
50
|
+
starts, stops, steps = self.get_pos()
|
|
51
|
+
n_steps = 1
|
|
52
|
+
for ind in range(starts.size):
|
|
53
|
+
n_steps *= np.abs((stops[ind] - starts[ind]) / steps[ind]) + 1
|
|
54
|
+
return int(n_steps)
|
|
55
|
+
|
|
56
|
+
def set_scan(self):
|
|
57
|
+
starts, stops, steps = self.get_pos()
|
|
58
|
+
if np.any(np.abs(steps) < 1e-12) or \
|
|
59
|
+
np.any(np.sign(stops - starts) != np.sign(steps)) or \
|
|
60
|
+
np.any(starts == stops):
|
|
61
|
+
|
|
62
|
+
return np.array([starts])
|
|
63
|
+
|
|
64
|
+
else:
|
|
65
|
+
axis_1_unique = mutils.linspace_step(starts[0], stops[0], steps[0])
|
|
66
|
+
axis_2_unique = mutils.linspace_step(starts[1], stops[1], steps[1])
|
|
67
|
+
|
|
68
|
+
positions = []
|
|
69
|
+
for ind_x, pos1 in enumerate(axis_1_unique):
|
|
70
|
+
for ind_y, pos2 in enumerate(axis_2_unique):
|
|
71
|
+
positions.append([pos1, pos2])
|
|
72
|
+
|
|
73
|
+
self.get_info_from_positions(np.array(positions))
|
|
74
|
+
|
|
75
|
+
def set_settings_titles(self):
|
|
76
|
+
if len(self.actuators) == 2:
|
|
77
|
+
self.settings.child('start_axis1').setOpts(title=f'{self.actuators[0].title} start:')
|
|
78
|
+
self.settings.child('stop_axis1').setOpts(title=f'{self.actuators[0].title} stop:')
|
|
79
|
+
self.settings.child('step_axis1').setOpts(title=f'{self.actuators[0].title} step:')
|
|
80
|
+
self.settings.child('start_axis2').setOpts(title=f'{self.actuators[1].title} start:')
|
|
81
|
+
self.settings.child('stop_axis2').setOpts(title=f'{self.actuators[1].title} stop:')
|
|
82
|
+
self.settings.child('step_axis2').setOpts(title=f'{self.actuators[1].title} step:')
|
|
83
|
+
|
|
84
|
+
def get_nav_axes(self) -> List[Axis]:
|
|
85
|
+
return [Axis(label=f'{act.title}',
|
|
86
|
+
units=f'{act.units}',
|
|
87
|
+
data=self.axes_unique[ind],
|
|
88
|
+
index=ind) for ind, act in enumerate(self.actuators)]
|
|
89
|
+
|
|
90
|
+
def get_scan_shape(self) -> Tuple[int]:
|
|
91
|
+
return tuple([len(axis) for axis in self.axes_unique])
|
|
92
|
+
|
|
93
|
+
def get_indexes_from_scan_index(self, scan_index: int) -> Tuple[int]:
|
|
94
|
+
"""To be reimplemented. Calculations of indexes within the scan"""
|
|
95
|
+
return tuple(self.axes_indexes[scan_index])
|
|
96
|
+
|
|
97
|
+
def update_from_scan_selector(self, scan_selector: Selector):
|
|
98
|
+
coordinates = scan_selector.get_coordinates()
|
|
99
|
+
if coordinates.shape == (2, 2):
|
|
100
|
+
self.settings.child('start_axis1').setValue(coordinates[0, 0])
|
|
101
|
+
self.settings.child('start_axis2').setValue(coordinates[0, 1])
|
|
102
|
+
self.settings.child('stop_axis1').setValue(coordinates[1, 0])
|
|
103
|
+
self.settings.child('stop_axis2').setValue(coordinates[1, 1])
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
@ScannerFactory.register('Scan2D', 'LinearBack&Force')
|
|
107
|
+
class Scan2DLinearBF(Scan2DLinear):
|
|
108
|
+
def __init__(self, actuators: List = None, **_ignored):
|
|
109
|
+
super().__init__(actuators=actuators)
|
|
110
|
+
|
|
111
|
+
def set_scan(self):
|
|
112
|
+
starts, stops, steps = self.get_pos()
|
|
113
|
+
if np.any(np.abs(steps) < 1e-12) or \
|
|
114
|
+
np.any(np.sign(stops - starts) != np.sign(steps)) or \
|
|
115
|
+
np.any(starts == stops):
|
|
116
|
+
|
|
117
|
+
return np.array([starts])
|
|
118
|
+
|
|
119
|
+
else:
|
|
120
|
+
axis_1_unique = mutils.linspace_step(starts[0], stops[0], steps[0])
|
|
121
|
+
axis_2_unique = mutils.linspace_step(starts[1], stops[1], steps[1])
|
|
122
|
+
|
|
123
|
+
positions = []
|
|
124
|
+
for ind_x, pos1 in enumerate(axis_1_unique):
|
|
125
|
+
for ind_y, pos2 in enumerate(axis_2_unique):
|
|
126
|
+
if not mutils.odd_even(ind_x):
|
|
127
|
+
positions.append([pos1, pos2])
|
|
128
|
+
else:
|
|
129
|
+
positions.append([pos1, axis_2_unique[len(axis_2_unique) - ind_y - 1]])
|
|
130
|
+
|
|
131
|
+
self.get_info_from_positions(np.array(positions))
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
@ScannerFactory.register('Scan2D', 'Random')
|
|
135
|
+
class Scan2DRandom(Scan2DLinear):
|
|
136
|
+
def __init__(self, actuators: List = None, **_ignored):
|
|
137
|
+
super().__init__(actuators=actuators)
|
|
138
|
+
|
|
139
|
+
def set_scan(self):
|
|
140
|
+
super().set_scan()
|
|
141
|
+
np.random.shuffle(self.positions)
|
|
142
|
+
self.get_info_from_positions(self.positions)
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
@ScannerFactory.register('Scan2D', 'Spiral')
|
|
146
|
+
class Scan2DSpiral(Scan2DLinear):
|
|
147
|
+
params = [{'title': 'Center Ax1:', 'name': 'center_axis1', 'type': 'float',
|
|
148
|
+
'value': config('scan', 'scan2D', 'spiral', 'center1')},
|
|
149
|
+
{'title': 'Center Ax2:', 'name': 'center_axis2', 'type': 'float',
|
|
150
|
+
'value': config('scan', 'scan2D', 'spiral', 'center2')},
|
|
151
|
+
{'title': 'Rmax Ax1:', 'name': 'rmax_axis1', 'type': 'float',
|
|
152
|
+
'value': config('scan', 'scan2D', 'spiral', 'rmax1')},
|
|
153
|
+
{'title': 'Rmax Ax2:', 'name': 'rmax_axis2', 'type': 'float',
|
|
154
|
+
'value': config('scan', 'scan2D', 'spiral', 'rmax2')},
|
|
155
|
+
{'title': 'Npts/axis', 'name': 'npts_by_axis', 'type': 'int', 'min': 1,
|
|
156
|
+
'value': config('scan', 'scan2D', 'spiral', 'npts')},
|
|
157
|
+
{'title': 'Step Ax1:', 'name': 'step_axis1', 'type': 'float', 'value': 0., 'readonly': True},
|
|
158
|
+
{'title': 'Step Ax2:', 'name': 'step_axis2', 'type': 'float', 'value': 0., 'readonly': True},
|
|
159
|
+
]
|
|
160
|
+
|
|
161
|
+
def __init__(self, actuators: List = None, **_ignored):
|
|
162
|
+
super().__init__(actuators=actuators)
|
|
163
|
+
|
|
164
|
+
def set_settings_titles(self):
|
|
165
|
+
if len(self.actuators) == 2:
|
|
166
|
+
self.settings.child('center_axis1').setOpts(title=f'Center {self.actuators[0].title}:')
|
|
167
|
+
self.settings.child('rmax_axis1').setOpts(title=f'Rmax {self.actuators[0].title}:')
|
|
168
|
+
self.settings.child('step_axis1').setOpts(title=f'Step {self.actuators[0].title}:')
|
|
169
|
+
self.settings.child('center_axis2').setOpts(title=f'Center {self.actuators[1].title}:')
|
|
170
|
+
self.settings.child('rmax_axis2').setOpts(title=f'Rmax {self.actuators[1].title}:')
|
|
171
|
+
self.settings.child('step_axis2').setOpts(title=f'Step {self.actuators[1].title}:')
|
|
172
|
+
|
|
173
|
+
def value_changed(self, param):
|
|
174
|
+
starts, rmaxs, rsteps = self.get_pos()
|
|
175
|
+
self.settings.child('step_axis1').setValue(rsteps[0])
|
|
176
|
+
self.settings.child('step_axis2').setValue(rsteps[1])
|
|
177
|
+
|
|
178
|
+
def get_pos(self):
|
|
179
|
+
"""Get centers, radius and n steps from settings
|
|
180
|
+
|
|
181
|
+
Returns
|
|
182
|
+
----------
|
|
183
|
+
centers: np.ndarray
|
|
184
|
+
containing the center positions of the scan
|
|
185
|
+
rmaxs: np.ndarray
|
|
186
|
+
containing the maximum radius (ellipse axes) in each direction
|
|
187
|
+
r_steps: np.ndarray
|
|
188
|
+
steps size in both directions
|
|
189
|
+
"""
|
|
190
|
+
centers = np.array([self.settings['center_axis1'], self.settings['center_axis2']])
|
|
191
|
+
rmaxs = np.array([self.settings['rmax_axis1'], self.settings['rmax_axis2']])
|
|
192
|
+
r_steps = 2 * rmaxs / self.settings['npts_by_axis']
|
|
193
|
+
return centers, rmaxs, r_steps
|
|
194
|
+
|
|
195
|
+
def evaluate_steps(self) -> int:
|
|
196
|
+
return int(self.settings['npts_by_axis'] + 1) ** 2
|
|
197
|
+
|
|
198
|
+
def set_scan(self):
|
|
199
|
+
starts, rmaxs, rsteps = self.get_pos()
|
|
200
|
+
|
|
201
|
+
if np.any(np.array(rmaxs) == 0) or np.any(np.abs(rmaxs) < 1e-12) or np.any(np.abs(rsteps) < 1e-12):
|
|
202
|
+
positions = np.array([starts])
|
|
203
|
+
|
|
204
|
+
else:
|
|
205
|
+
Nlin = self.settings['npts_by_axis'] / 2
|
|
206
|
+
axis_1_indexes = [0]
|
|
207
|
+
axis_2_indexes = [0]
|
|
208
|
+
ind = 0
|
|
209
|
+
flag = True
|
|
210
|
+
|
|
211
|
+
while flag:
|
|
212
|
+
if mutils.odd_even(ind):
|
|
213
|
+
step = 1
|
|
214
|
+
else:
|
|
215
|
+
step = -1
|
|
216
|
+
if flag:
|
|
217
|
+
|
|
218
|
+
for ind_step in range(ind):
|
|
219
|
+
axis_1_indexes.append(axis_1_indexes[-1] + step)
|
|
220
|
+
axis_2_indexes.append(axis_2_indexes[-1])
|
|
221
|
+
if len(axis_1_indexes) >= (2 * Nlin + 1) ** 2:
|
|
222
|
+
flag = False
|
|
223
|
+
break
|
|
224
|
+
if flag:
|
|
225
|
+
for ind_step in range(ind):
|
|
226
|
+
axis_1_indexes.append(axis_1_indexes[-1])
|
|
227
|
+
axis_2_indexes.append(axis_2_indexes[-1] + step)
|
|
228
|
+
if len(axis_1_indexes) >= (2 * Nlin + 1) ** 2:
|
|
229
|
+
flag = False
|
|
230
|
+
break
|
|
231
|
+
ind += 1
|
|
232
|
+
|
|
233
|
+
positions = []
|
|
234
|
+
for ind in range(len(axis_1_indexes)):
|
|
235
|
+
positions.append(np.array([axis_1_indexes[ind] * rsteps[0] + starts[0],
|
|
236
|
+
axis_2_indexes[ind] * rsteps[1] + starts[1]]))
|
|
237
|
+
|
|
238
|
+
self.get_info_from_positions(np.array(positions))
|
|
239
|
+
|
|
240
|
+
def update_from_scan_selector(self, scan_selector: Selector):
|
|
241
|
+
coordinates = scan_selector.get_coordinates()
|
|
242
|
+
if coordinates.shape == (2, 2):
|
|
243
|
+
self.settings.child('center_axis1').setValue((coordinates[0, 0] + coordinates[1, 0]) / 2)
|
|
244
|
+
self.settings.child('center_axis2').setValue((coordinates[0, 1] + coordinates[1, 1]) / 2)
|
|
245
|
+
self.settings.child('rmax_axis1').setValue(abs(coordinates[1, 0] - coordinates[0, 0]) / 2)
|
|
246
|
+
self.settings.child('rmax_axis2').setValue(abs(coordinates[1, 1] - coordinates[0, 1]) / 2)
|
|
247
|
+
|
|
248
|
+
|
|
249
|
+
try:
|
|
250
|
+
import adaptive
|
|
251
|
+
|
|
252
|
+
@ScannerFactory.register('Scan2D', 'Adaptive')
|
|
253
|
+
class Scan2DAdaptive(Scan2DLinear):
|
|
254
|
+
params = [
|
|
255
|
+
{'title': 'Loss type', 'name': 'scan_loss', 'type': 'list',
|
|
256
|
+
'limits': ['default', 'curvature', 'uniform'],
|
|
257
|
+
'tip': 'Type of loss used by the algo. to determine next points'},
|
|
258
|
+
|
|
259
|
+
{'title': 'Start Ax1:', 'name': 'start_axis1', 'type': 'float',
|
|
260
|
+
'value': config('scan', 'scan2D', 'linear', 'start1')},
|
|
261
|
+
{'title': 'Start Ax2:', 'name': 'start_axis2', 'type': 'float',
|
|
262
|
+
'value': config('scan', 'scan2D', 'linear', 'start2')},
|
|
263
|
+
{'title': 'Stop Ax1:', 'name': 'stop_axis1', 'type': 'float',
|
|
264
|
+
'value': config('scan', 'scan2D', 'linear', 'stop1')},
|
|
265
|
+
{'title': 'Stop Ax2:', 'name': 'stop_axis2', 'type': 'float',
|
|
266
|
+
'value': config('scan', 'scan2D', 'linear', 'stop2')},
|
|
267
|
+
]
|
|
268
|
+
distribution = DataDistribution['spread']
|
|
269
|
+
|
|
270
|
+
def __init__(self, actuators: List = None, **_ignored):
|
|
271
|
+
super().__init__(actuators=actuators)
|
|
272
|
+
|
|
273
|
+
def set_scan(self):
|
|
274
|
+
|
|
275
|
+
self.axes_unique = [np.array([]), np.array([])]
|
|
276
|
+
self.axes_indexes = np.array([], dtype=int)
|
|
277
|
+
self.positions = np.zeros((0, 2))
|
|
278
|
+
|
|
279
|
+
def evaluate_steps(self) -> int:
|
|
280
|
+
return 1
|
|
281
|
+
|
|
282
|
+
def get_nav_axes(self) -> List[Axis]:
|
|
283
|
+
return [Axis(label=f'{act.mod_name} axis',
|
|
284
|
+
units=f'{act.units}',
|
|
285
|
+
data=self.positions[:, ind],
|
|
286
|
+
index=ind) for ind, act in enumerate(self.actuators)]
|
|
287
|
+
|
|
288
|
+
def get_scan_shape(self) -> Tuple[int]:
|
|
289
|
+
return () # unknown shape
|
|
290
|
+
|
|
291
|
+
except ModuleNotFoundError:
|
|
292
|
+
logger.info('adaptive module is not present, no adaptive scan possible')
|
|
293
|
+
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
"""
|
|
3
|
+
Created the 05/12/2022
|
|
4
|
+
|
|
5
|
+
@author: Sebastien Weber
|
|
6
|
+
"""
|
|
7
|
+
from typing import List, Tuple
|
|
8
|
+
|
|
9
|
+
import numpy as np
|
|
10
|
+
|
|
11
|
+
from qtpy import QtCore, QtWidgets
|
|
12
|
+
from pymodaq.utils.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.utils import gui_utils as gutils
|
|
17
|
+
from ..scan_factory import ScannerFactory, ScannerBase, ScanParameterManager
|
|
18
|
+
from pymodaq.utils.parameter import utils as putils
|
|
19
|
+
from pymodaq.utils.parameter.pymodaq_ptypes import TableViewCustom
|
|
20
|
+
from pymodaq.utils.plotting.scan_selector import Selector
|
|
21
|
+
|
|
22
|
+
logger = set_logger(get_module_name(__file__))
|
|
23
|
+
config = configmod.Config()
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class TableModelSequential(gutils.TableModel):
|
|
27
|
+
"""Table Model for the Model/View Qt framework dedicated to the Sequential scan mode"""
|
|
28
|
+
def __init__(self, data, **kwargs):
|
|
29
|
+
header = ['Actuator', 'Start', 'Stop', 'Step']
|
|
30
|
+
if 'header' in kwargs:
|
|
31
|
+
header = kwargs.pop('header')
|
|
32
|
+
editable = [False, True, True, True]
|
|
33
|
+
if 'editable' in kwargs:
|
|
34
|
+
editable = kwargs.pop('editable')
|
|
35
|
+
super().__init__(data, header, editable=editable, **kwargs)
|
|
36
|
+
|
|
37
|
+
def __repr__(self):
|
|
38
|
+
return f'{self.__class__.__name__} from module {self.__class__.__module__}'
|
|
39
|
+
|
|
40
|
+
def validate_data(self, row, col, value):
|
|
41
|
+
"""
|
|
42
|
+
make sure the values and signs of the start, stop and step values are "correct"
|
|
43
|
+
Parameters
|
|
44
|
+
----------
|
|
45
|
+
row: (int) row within the table that is to be changed
|
|
46
|
+
col: (int) col within the table that is to be changed
|
|
47
|
+
value: (float) new value for the value defined by row and col
|
|
48
|
+
|
|
49
|
+
Returns
|
|
50
|
+
-------
|
|
51
|
+
bool: True is the new value is fine (change some other values if needed) otherwise False
|
|
52
|
+
"""
|
|
53
|
+
start = self.data(self.index(row, 1), QtCore.Qt.DisplayRole)
|
|
54
|
+
stop = self.data(self.index(row, 2), QtCore.Qt.DisplayRole)
|
|
55
|
+
step = self.data(self.index(row, 3), QtCore.Qt.DisplayRole)
|
|
56
|
+
isstep = False
|
|
57
|
+
if col == 1: # the start
|
|
58
|
+
start = value
|
|
59
|
+
elif col == 2: # the stop
|
|
60
|
+
stop = value
|
|
61
|
+
elif col == 3: # the step
|
|
62
|
+
isstep = True
|
|
63
|
+
step = value
|
|
64
|
+
|
|
65
|
+
if np.abs(step) < 1e-12 or start == stop:
|
|
66
|
+
return False
|
|
67
|
+
if np.sign(stop - start) != np.sign(step):
|
|
68
|
+
if isstep:
|
|
69
|
+
self._data[row][2] = -stop
|
|
70
|
+
else:
|
|
71
|
+
self._data[row][3] = -step
|
|
72
|
+
return True
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
@ScannerFactory.register('Sequential', 'Linear')
|
|
76
|
+
class SequentialScanner(ScannerBase):
|
|
77
|
+
params = [
|
|
78
|
+
{'title': 'Sequences', 'name': 'seq_table', 'type': 'table_view', 'delegate': gutils.SpinBoxDelegate},
|
|
79
|
+
]
|
|
80
|
+
distribution = DataDistribution['uniform']
|
|
81
|
+
n_axes = 1
|
|
82
|
+
|
|
83
|
+
def __init__(self, actuators: List[str]):
|
|
84
|
+
|
|
85
|
+
self.table_model: TableModelSequential = None
|
|
86
|
+
self.table_view: TableViewCustom = None
|
|
87
|
+
super().__init__(actuators)
|
|
88
|
+
self.update_model()
|
|
89
|
+
|
|
90
|
+
@property
|
|
91
|
+
def actuators(self):
|
|
92
|
+
return self._actuators
|
|
93
|
+
|
|
94
|
+
@actuators.setter
|
|
95
|
+
def actuators(self, actuators_name):
|
|
96
|
+
self._actuators = actuators_name
|
|
97
|
+
self.update_model()
|
|
98
|
+
|
|
99
|
+
def update_model(self, init_data=None):
|
|
100
|
+
if init_data is None:
|
|
101
|
+
if self.table_model is not None:
|
|
102
|
+
init_data = []
|
|
103
|
+
names = [row[0] for row in self.table_model.get_data_all()]
|
|
104
|
+
for act in self._actuators:
|
|
105
|
+
if act.title in names:
|
|
106
|
+
ind_row = names.index(act.title)
|
|
107
|
+
init_data.append(self.table_model.get_data_all()[ind_row])
|
|
108
|
+
else:
|
|
109
|
+
init_data.append([act.title, 0., 1., 0.1])
|
|
110
|
+
else:
|
|
111
|
+
init_data = [[act.title, 0., 1., 0.1] for act in self._actuators]
|
|
112
|
+
self.table_model = TableModelSequential(init_data, )
|
|
113
|
+
self.table_view = putils.get_widget_from_tree(self.settings_tree, TableViewCustom)[0]
|
|
114
|
+
self.settings.child('seq_table').setValue(self.table_model)
|
|
115
|
+
self.n_axes = len(self._actuators)
|
|
116
|
+
self.update_table_view()
|
|
117
|
+
|
|
118
|
+
def get_pos(self):
|
|
119
|
+
starts = np.array([self.table_model.get_data(ind, 1) for ind in range(self.table_model.rowCount(None))])
|
|
120
|
+
stops = np.array([self.table_model.get_data(ind, 2) for ind in range(self.table_model.rowCount(None))])
|
|
121
|
+
steps = np.array([self.table_model.get_data(ind, 3) for ind in range(self.table_model.rowCount(None))])
|
|
122
|
+
return starts, stops, steps
|
|
123
|
+
|
|
124
|
+
def evaluate_steps(self) -> int:
|
|
125
|
+
starts, stops, steps = self.get_pos()
|
|
126
|
+
n_steps = 1
|
|
127
|
+
for ind in range(starts.size):
|
|
128
|
+
n_steps *= np.abs((stops[ind] - starts[ind]) / steps[ind]) + 1
|
|
129
|
+
return int(n_steps)
|
|
130
|
+
|
|
131
|
+
@staticmethod
|
|
132
|
+
def pos_above_stops(positions, steps, stops):
|
|
133
|
+
state = []
|
|
134
|
+
for pos, step, stop in zip(positions, steps, stops):
|
|
135
|
+
if step >= 0:
|
|
136
|
+
state.append(pos > stop)
|
|
137
|
+
else:
|
|
138
|
+
state.append(pos < stop)
|
|
139
|
+
return state
|
|
140
|
+
|
|
141
|
+
def update_table_view(self):
|
|
142
|
+
self.table_view.horizontalHeader().setSectionResizeMode(QtWidgets.QHeaderView.ResizeToContents)
|
|
143
|
+
self.table_view.horizontalHeader().setStretchLastSection(True)
|
|
144
|
+
self.table_view.setSelectionBehavior(QtWidgets.QTableView.SelectRows)
|
|
145
|
+
self.table_view.setSelectionMode(QtWidgets.QTableView.SingleSelection)
|
|
146
|
+
styledItemDelegate = QtWidgets.QStyledItemDelegate()
|
|
147
|
+
styledItemDelegate.setItemEditorFactory(gutils.SpinBoxDelegate())
|
|
148
|
+
self.table_view.setItemDelegate(styledItemDelegate)
|
|
149
|
+
|
|
150
|
+
self.table_view.setDragEnabled(True)
|
|
151
|
+
self.table_view.setDropIndicatorShown(True)
|
|
152
|
+
self.table_view.setAcceptDrops(True)
|
|
153
|
+
self.table_view.viewport().setAcceptDrops(True)
|
|
154
|
+
self.table_view.setDefaultDropAction(QtCore.Qt.MoveAction)
|
|
155
|
+
self.table_view.setDragDropMode(QtWidgets.QTableView.InternalMove)
|
|
156
|
+
self.table_view.setDragDropOverwriteMode(False)
|
|
157
|
+
|
|
158
|
+
def set_scan(self):
|
|
159
|
+
starts, stops, steps = self.get_pos()
|
|
160
|
+
all_positions = [starts.copy()]
|
|
161
|
+
positions = starts.copy()
|
|
162
|
+
state = self.pos_above_stops(positions, steps, stops)
|
|
163
|
+
if len(state) != 0:
|
|
164
|
+
while not state[0]:
|
|
165
|
+
if not np.any(np.array(state)):
|
|
166
|
+
positions[-1] += steps[-1]
|
|
167
|
+
|
|
168
|
+
else:
|
|
169
|
+
indexes_true = np.where(np.array(state))
|
|
170
|
+
positions[indexes_true[-1][0]] = starts[indexes_true[-1][0]]
|
|
171
|
+
positions[indexes_true[-1][0] - 1] += steps[indexes_true[-1][0] - 1]
|
|
172
|
+
|
|
173
|
+
state = self.pos_above_stops(positions, steps, stops)
|
|
174
|
+
if not np.any(np.array(state)):
|
|
175
|
+
all_positions.append(positions.copy())
|
|
176
|
+
|
|
177
|
+
self.get_info_from_positions(np.array(all_positions))
|
|
178
|
+
|
|
179
|
+
def get_nav_axes(self) -> List[Axis]:
|
|
180
|
+
return [Axis(label=f'{act.title}', units=act.units, data=self.axes_unique[ind], index=ind)
|
|
181
|
+
for ind, act in enumerate(self.actuators)]
|
|
182
|
+
|
|
183
|
+
def get_indexes_from_scan_index(self, scan_index: int) -> Tuple[int]:
|
|
184
|
+
"""To be reimplemented. Calculations of indexes within the scan"""
|
|
185
|
+
return tuple(self.axes_indexes[scan_index])
|
|
186
|
+
|
|
187
|
+
def get_scan_shape(self) -> Tuple[int]:
|
|
188
|
+
return tuple([len(axis) for axis in self.axes_unique])
|
|
189
|
+
|
|
190
|
+
def update_from_scan_selector(self, scan_selector: Selector):
|
|
191
|
+
coordinates = scan_selector.get_coordinates()
|
|
192
|
+
pass
|