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.

Files changed (233) hide show
  1. pymodaq/__init__.py +13 -6
  2. pymodaq/control_modules/__init__.py +0 -7
  3. pymodaq/control_modules/daq_move.py +965 -2
  4. pymodaq/control_modules/daq_move_ui.py +319 -0
  5. pymodaq/control_modules/daq_viewer.py +1573 -3
  6. pymodaq/control_modules/daq_viewer_ui.py +393 -0
  7. pymodaq/control_modules/mocks.py +51 -0
  8. pymodaq/control_modules/move_utility_classes.py +709 -8
  9. pymodaq/control_modules/utils.py +256 -0
  10. pymodaq/control_modules/viewer_utility_classes.py +663 -6
  11. pymodaq/daq_utils.py +89 -0
  12. pymodaq/dashboard.py +91 -72
  13. pymodaq/examples/custom_app.py +12 -11
  14. pymodaq/examples/custom_viewer.py +10 -10
  15. pymodaq/examples/function_plotter.py +16 -13
  16. pymodaq/examples/nonlinearscanner.py +8 -6
  17. pymodaq/examples/parameter_ex.py +7 -7
  18. pymodaq/examples/preset_MockCamera.xml +1 -0
  19. pymodaq/extensions/__init__.py +16 -0
  20. pymodaq/extensions/console.py +76 -0
  21. pymodaq/{daq_logger.py → extensions/daq_logger.py} +115 -65
  22. pymodaq/extensions/daq_scan.py +1339 -0
  23. pymodaq/extensions/daq_scan_ui.py +240 -0
  24. pymodaq/extensions/h5browser.py +23 -0
  25. pymodaq/{pid → extensions/pid}/__init__.py +4 -2
  26. pymodaq/{pid → extensions/pid}/daq_move_PID.py +2 -2
  27. pymodaq/{pid → extensions/pid}/pid_controller.py +48 -36
  28. pymodaq/{pid → extensions/pid}/utils.py +52 -6
  29. pymodaq/extensions/utils.py +40 -0
  30. pymodaq/post_treatment/__init__.py +6 -0
  31. pymodaq/{daq_analysis → post_treatment/daq_analysis}/daq_analysis_main.py +17 -17
  32. pymodaq/{daq_measurement → post_treatment/daq_measurement}/daq_measurement_main.py +8 -14
  33. pymodaq/post_treatment/load_and_plot.py +219 -0
  34. pymodaq/post_treatment/process_to_scalar.py +263 -0
  35. pymodaq/resources/QtDesigner_Ressources/Icon_Library/run_all.png +0 -0
  36. pymodaq/resources/QtDesigner_Ressources/Icon_Library/stop_all.png +0 -0
  37. pymodaq/resources/QtDesigner_Ressources/QtDesigner_ressources.bat +1 -1
  38. pymodaq/resources/QtDesigner_Ressources/QtDesigner_ressources.qrc +1 -0
  39. pymodaq/resources/QtDesigner_Ressources/QtDesigner_ressources_rc.py +109784 -109173
  40. pymodaq/resources/QtDesigner_Ressources/icons.svg +142 -0
  41. pymodaq/resources/VERSION +1 -1
  42. pymodaq/resources/config_template.toml +32 -13
  43. pymodaq/resources/preset_default.xml +1 -1
  44. pymodaq/{daq_utils → utils}/Tuto innosetup/script_full_setup.iss +1 -1
  45. pymodaq/utils/__init__.py +0 -29
  46. pymodaq/utils/abstract/__init__.py +48 -0
  47. pymodaq/{daq_utils → utils}/abstract/logger.py +7 -3
  48. pymodaq/utils/array_manipulation.py +379 -8
  49. pymodaq/{daq_utils → utils}/calibration_camera.py +6 -6
  50. pymodaq/{daq_utils → utils}/chrono_timer.py +1 -1
  51. pymodaq/utils/config.py +448 -0
  52. pymodaq/utils/conftests.py +5 -0
  53. pymodaq/utils/daq_utils.py +828 -8
  54. pymodaq/utils/data.py +1873 -7
  55. pymodaq/{daq_utils → utils}/db/db_logger/db_logger.py +86 -47
  56. pymodaq/{daq_utils → utils}/db/db_logger/db_logger_models.py +31 -10
  57. pymodaq/{daq_utils → utils}/enums.py +12 -7
  58. pymodaq/utils/exceptions.py +37 -0
  59. pymodaq/utils/factory.py +82 -0
  60. pymodaq/{daq_utils → utils}/gui_utils/__init__.py +1 -1
  61. pymodaq/utils/gui_utils/custom_app.py +129 -0
  62. pymodaq/utils/gui_utils/file_io.py +66 -0
  63. pymodaq/{daq_utils → utils}/gui_utils/layout.py +2 -2
  64. pymodaq/{daq_utils → utils}/gui_utils/utils.py +13 -3
  65. pymodaq/{daq_utils → utils}/gui_utils/widgets/__init__.py +2 -2
  66. pymodaq/utils/gui_utils/widgets/label.py +24 -0
  67. pymodaq/{daq_utils → utils}/gui_utils/widgets/lcd.py +12 -7
  68. pymodaq/{daq_utils → utils}/gui_utils/widgets/push.py +66 -2
  69. pymodaq/{daq_utils → utils}/gui_utils/widgets/qled.py +6 -4
  70. pymodaq/utils/gui_utils/widgets/spinbox.py +24 -0
  71. pymodaq/{daq_utils → utils}/gui_utils/widgets/table.py +2 -2
  72. pymodaq/utils/h5modules/__init__.py +1 -0
  73. pymodaq/{daq_utils/h5backend.py → utils/h5modules/backends.py} +200 -112
  74. pymodaq/utils/h5modules/browsing.py +683 -0
  75. pymodaq/utils/h5modules/data_saving.py +839 -0
  76. pymodaq/utils/h5modules/h5logging.py +110 -0
  77. pymodaq/utils/h5modules/module_saving.py +350 -0
  78. pymodaq/utils/h5modules/saving.py +914 -0
  79. pymodaq/utils/h5modules/utils.py +85 -0
  80. pymodaq/utils/logger.py +64 -6
  81. pymodaq/utils/managers/action_manager.py +460 -0
  82. pymodaq/{daq_utils → utils}/managers/batchscan_manager.py +144 -112
  83. pymodaq/{daq_utils → utils}/managers/modules_manager.py +188 -114
  84. pymodaq/{daq_utils → utils}/managers/overshoot_manager.py +3 -3
  85. pymodaq/utils/managers/parameter_manager.py +110 -0
  86. pymodaq/{daq_utils → utils}/managers/preset_manager.py +17 -13
  87. pymodaq/{daq_utils → utils}/managers/preset_manager_utils.py +8 -7
  88. pymodaq/{daq_utils → utils}/managers/remote_manager.py +7 -6
  89. pymodaq/{daq_utils → utils}/managers/roi_manager.py +148 -57
  90. pymodaq/utils/math_utils.py +546 -10
  91. pymodaq/{daq_utils → utils}/messenger.py +5 -1
  92. pymodaq/utils/parameter/__init__.py +2 -15
  93. pymodaq/{daq_utils → utils}/parameter/ioxml.py +12 -6
  94. pymodaq/{daq_utils → utils}/parameter/pymodaq_ptypes/__init__.py +1 -3
  95. pymodaq/{daq_utils → utils}/parameter/pymodaq_ptypes/filedir.py +1 -1
  96. pymodaq/{daq_utils → utils}/parameter/pymodaq_ptypes/itemselect.py +3 -0
  97. pymodaq/{daq_utils → utils}/parameter/pymodaq_ptypes/led.py +1 -1
  98. pymodaq/utils/parameter/pymodaq_ptypes/pixmap.py +161 -0
  99. pymodaq/{daq_utils → utils}/parameter/pymodaq_ptypes/slide.py +1 -1
  100. pymodaq/{daq_utils → utils}/parameter/pymodaq_ptypes/table.py +1 -1
  101. pymodaq/utils/parameter/utils.py +206 -11
  102. pymodaq/utils/plotting/data_viewers/__init__.py +6 -0
  103. pymodaq/utils/plotting/data_viewers/viewer.py +393 -0
  104. pymodaq/utils/plotting/data_viewers/viewer0D.py +251 -0
  105. pymodaq/utils/plotting/data_viewers/viewer1D.py +574 -0
  106. pymodaq/{daq_utils → utils}/plotting/data_viewers/viewer1Dbasic.py +8 -3
  107. pymodaq/{daq_utils → utils}/plotting/data_viewers/viewer2D.py +292 -357
  108. pymodaq/{daq_utils → utils}/plotting/data_viewers/viewer2D_basic.py +58 -75
  109. pymodaq/utils/plotting/data_viewers/viewerND.py +738 -0
  110. pymodaq/{daq_utils → utils}/plotting/gant_chart.py +2 -2
  111. pymodaq/{daq_utils → utils}/plotting/items/axis_scaled.py +4 -2
  112. pymodaq/{daq_utils → utils}/plotting/items/image.py +8 -6
  113. pymodaq/utils/plotting/navigator.py +355 -0
  114. pymodaq/utils/plotting/scan_selector.py +480 -0
  115. pymodaq/utils/plotting/utils/axes_viewer.py +88 -0
  116. pymodaq/utils/plotting/utils/filter.py +538 -0
  117. pymodaq/utils/plotting/utils/lineout.py +224 -0
  118. pymodaq/{daq_utils → utils}/plotting/utils/plot_utils.py +196 -84
  119. pymodaq/{daq_utils → utils}/plotting/utils/signalND.py +21 -13
  120. pymodaq/utils/plotting/widgets.py +76 -0
  121. pymodaq/utils/scanner/__init__.py +10 -0
  122. pymodaq/utils/scanner/scan_factory.py +204 -0
  123. pymodaq/utils/scanner/scanner.py +271 -0
  124. pymodaq/utils/scanner/scanners/_1d_scanners.py +117 -0
  125. pymodaq/utils/scanner/scanners/_2d_scanners.py +293 -0
  126. pymodaq/utils/scanner/scanners/sequential.py +192 -0
  127. pymodaq/utils/scanner/scanners/tabular.py +294 -0
  128. pymodaq/utils/scanner/utils.py +83 -0
  129. pymodaq/utils/slicing.py +47 -0
  130. pymodaq/utils/svg/__init__.py +6 -0
  131. pymodaq/utils/svg/svg_renderer.py +20 -0
  132. pymodaq/utils/svg/svg_view.py +35 -0
  133. pymodaq/utils/svg/svg_viewer2D.py +51 -0
  134. pymodaq/{daq_utils → utils}/tcp_server_client.py +36 -37
  135. pymodaq/{daq_utils → utils}/tree_layout/tree_layout_main.py +50 -35
  136. pymodaq/utils/units.py +216 -0
  137. pymodaq-4.0.1.dist-info/METADATA +159 -0
  138. {pymodaq-3.6.12.dist-info → pymodaq-4.0.1.dist-info}/RECORD +167 -170
  139. {pymodaq-3.6.12.dist-info → pymodaq-4.0.1.dist-info}/WHEEL +1 -2
  140. pymodaq-4.0.1.dist-info/entry_points.txt +8 -0
  141. pymodaq/daq_move/daq_move_gui.py +0 -279
  142. pymodaq/daq_move/daq_move_gui.ui +0 -534
  143. pymodaq/daq_move/daq_move_main.py +0 -1042
  144. pymodaq/daq_move/process_from_QtDesigner_DAQ_Move_GUI.bat +0 -2
  145. pymodaq/daq_move/utility_classes.py +0 -671
  146. pymodaq/daq_scan.py +0 -2160
  147. pymodaq/daq_utils/array_manipulation.py +0 -386
  148. pymodaq/daq_utils/config.py +0 -273
  149. pymodaq/daq_utils/conftests.py +0 -7
  150. pymodaq/daq_utils/custom_parameter_tree.py +0 -9
  151. pymodaq/daq_utils/daq_enums.py +0 -133
  152. pymodaq/daq_utils/daq_utils.py +0 -1402
  153. pymodaq/daq_utils/exceptions.py +0 -71
  154. pymodaq/daq_utils/gui_utils/custom_app.py +0 -103
  155. pymodaq/daq_utils/gui_utils/file_io.py +0 -75
  156. pymodaq/daq_utils/gui_utils/widgets/spinbox.py +0 -9
  157. pymodaq/daq_utils/h5exporter_hyperspy.py +0 -115
  158. pymodaq/daq_utils/h5exporters.py +0 -242
  159. pymodaq/daq_utils/h5modules.py +0 -1559
  160. pymodaq/daq_utils/h5utils.py +0 -241
  161. pymodaq/daq_utils/managers/action_manager.py +0 -236
  162. pymodaq/daq_utils/managers/parameter_manager.py +0 -57
  163. pymodaq/daq_utils/math_utils.py +0 -705
  164. pymodaq/daq_utils/parameter/__init__.py +0 -1
  165. pymodaq/daq_utils/parameter/oldpymodaq_ptypes.py +0 -1626
  166. pymodaq/daq_utils/parameter/pymodaq_ptypes/pixmap.py +0 -85
  167. pymodaq/daq_utils/parameter/utils.py +0 -136
  168. pymodaq/daq_utils/plotting/data_viewers/__init__.py +0 -0
  169. pymodaq/daq_utils/plotting/data_viewers/process_from_QtDesigner_0DViewer_GUI.bat +0 -2
  170. pymodaq/daq_utils/plotting/data_viewers/viewer0D.py +0 -204
  171. pymodaq/daq_utils/plotting/data_viewers/viewer0D_GUI.py +0 -89
  172. pymodaq/daq_utils/plotting/data_viewers/viewer0D_GUI.ui +0 -131
  173. pymodaq/daq_utils/plotting/data_viewers/viewer1D.py +0 -781
  174. pymodaq/daq_utils/plotting/data_viewers/viewerND.py +0 -894
  175. pymodaq/daq_utils/plotting/data_viewers/viewerbase.py +0 -64
  176. pymodaq/daq_utils/plotting/items/__init__.py +0 -0
  177. pymodaq/daq_utils/plotting/navigator.py +0 -500
  178. pymodaq/daq_utils/plotting/scan_selector.py +0 -289
  179. pymodaq/daq_utils/plotting/utils/__init__.py +0 -0
  180. pymodaq/daq_utils/plotting/utils/filter.py +0 -236
  181. pymodaq/daq_utils/plotting/viewer0D/__init__.py +0 -0
  182. pymodaq/daq_utils/plotting/viewer0D/viewer0D_main.py +0 -4
  183. pymodaq/daq_utils/plotting/viewer1D/__init__.py +0 -0
  184. pymodaq/daq_utils/plotting/viewer1D/viewer1D_main.py +0 -4
  185. pymodaq/daq_utils/plotting/viewer1D/viewer1Dbasic.py +0 -4
  186. pymodaq/daq_utils/plotting/viewer2D/viewer_2D_basic.py +0 -4
  187. pymodaq/daq_utils/plotting/viewer2D/viewer_2D_main.py +0 -4
  188. pymodaq/daq_utils/plotting/viewerND/__init__.py +0 -0
  189. pymodaq/daq_utils/plotting/viewerND/viewerND_main.py +0 -4
  190. pymodaq/daq_utils/scanner.py +0 -1289
  191. pymodaq/daq_utils/tree_layout/__init__.py +0 -0
  192. pymodaq/daq_viewer/__init__.py +0 -0
  193. pymodaq/daq_viewer/daq_gui_settings.py +0 -237
  194. pymodaq/daq_viewer/daq_gui_settings.ui +0 -441
  195. pymodaq/daq_viewer/daq_viewer_main.py +0 -2225
  196. pymodaq/daq_viewer/process_from_QtDesigner_DAQ_GUI_settings.bat +0 -2
  197. pymodaq/daq_viewer/utility_classes.py +0 -673
  198. pymodaq/examples/logger_image/__init__.py +0 -0
  199. pymodaq/examples/logger_image/logger_displayer.py +0 -121
  200. pymodaq/examples/logger_image/setup.svg +0 -3119
  201. pymodaq/examples/logger_image/setup_svg.py +0 -114
  202. pymodaq/h5browser.py +0 -39
  203. pymodaq/utils/scanner.py +0 -15
  204. pymodaq-3.6.12.dist-info/METADATA +0 -39
  205. pymodaq-3.6.12.dist-info/entry_points.txt +0 -8
  206. pymodaq-3.6.12.dist-info/top_level.txt +0 -1
  207. /pymodaq/{daq_analysis → post_treatment/daq_analysis}/__init__.py +0 -0
  208. /pymodaq/{daq_measurement → post_treatment/daq_measurement}/__init__.py +0 -0
  209. /pymodaq/{daq_measurement → post_treatment/daq_measurement}/daq_measurement_GUI.py +0 -0
  210. /pymodaq/{daq_measurement → post_treatment/daq_measurement}/daq_measurement_GUI.ui +0 -0
  211. /pymodaq/{daq_measurement → post_treatment/daq_measurement}/process_from_QtDesigner_DAQ_Measurement_GUI.bat +0 -0
  212. /pymodaq/{daq_utils → utils}/Tuto innosetup/Tuto innosetup.odt +0 -0
  213. /pymodaq/{daq_utils → utils}/Tuto innosetup/Tuto innosetup.pdf +0 -0
  214. /pymodaq/{daq_move → utils/db}/__init__.py +0 -0
  215. /pymodaq/{daq_utils → utils/db/db_logger}/__init__.py +0 -0
  216. /pymodaq/{daq_utils → utils}/gui_utils/dock.py +0 -0
  217. /pymodaq/{daq_utils → utils}/gui_utils/list_picker.py +0 -0
  218. /pymodaq/{daq_utils/abstract → utils/managers}/__init__.py +0 -0
  219. /pymodaq/{daq_utils → utils}/parameter/pymodaq_ptypes/bool.py +0 -0
  220. /pymodaq/{daq_utils → utils}/parameter/pymodaq_ptypes/date.py +0 -0
  221. /pymodaq/{daq_utils → utils}/parameter/pymodaq_ptypes/list.py +0 -0
  222. /pymodaq/{daq_utils → utils}/parameter/pymodaq_ptypes/numeric.py +0 -0
  223. /pymodaq/{daq_utils → utils}/parameter/pymodaq_ptypes/tableview.py +0 -0
  224. /pymodaq/{daq_utils → utils}/parameter/pymodaq_ptypes/text.py +0 -0
  225. /pymodaq/{daq_utils/db → utils/plotting}/__init__.py +0 -0
  226. /pymodaq/{daq_utils → utils}/plotting/image_viewer.py +0 -0
  227. /pymodaq/{daq_utils/db/db_logger → utils/plotting/items}/__init__.py +0 -0
  228. /pymodaq/{daq_utils → utils}/plotting/items/crosshair.py +0 -0
  229. /pymodaq/{daq_utils/managers → utils/plotting/utils}/__init__.py +0 -0
  230. /pymodaq/{daq_utils → utils}/qvariant.py +0 -0
  231. /pymodaq/{daq_utils/plotting/viewer2D → utils/scanner/scanners}/__init__.py +0 -0
  232. /pymodaq/{daq_utils/plotting → utils/tree_layout}/__init__.py +0 -0
  233. {pymodaq-3.6.12.dist-info → pymodaq-4.0.1.dist-info/licenses}/LICENSE +0 -0
@@ -0,0 +1,110 @@
1
+ # -*- coding: utf-8 -*-
2
+ """
3
+ Created the 15/11/2022
4
+
5
+ @author: Sebastien Weber
6
+ """
7
+
8
+ import logging
9
+ import numpy as np
10
+
11
+ from pymodaq.utils.logger import set_logger, get_module_name, get_module_name
12
+ from pymodaq.utils.config import Config
13
+
14
+ from pymodaq.utils.abstract.logger import AbstractLogger
15
+ from pymodaq.utils import daq_utils as utils
16
+ from .saving import H5Saver
17
+
18
+
19
+ config = Config()
20
+
21
+ logger = set_logger(get_module_name(__file__))
22
+
23
+
24
+ class H5LogHandler(logging.StreamHandler):
25
+ def __init__(self, h5saver):
26
+ super().__init__()
27
+ self.h5saver = h5saver
28
+ formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
29
+ self.setFormatter(formatter)
30
+
31
+ def emit(self, record):
32
+ msg = self.format(record)
33
+ self.h5saver.add_log(msg)
34
+
35
+
36
+ class H5Logger(AbstractLogger):
37
+ def __init__(self, *args, **kwargs):
38
+ self.h5saver = H5Saver(*args, save_type='logger', **kwargs)
39
+
40
+ def close(self):
41
+ self.h5saver.close_file()
42
+
43
+ @property
44
+ def settings_tree(self):
45
+ return self.h5saver.settings_tree
46
+
47
+ @property
48
+ def settings(self):
49
+ return self.h5saver.settings
50
+
51
+ def init_logger(self, settings):
52
+ self.h5saver.init_file(update_h5=True, metadata=dict(settings=settings))
53
+ self.h5saver.flush()
54
+ return True
55
+
56
+ def get_handler(self):
57
+ return H5LogHandler(self.h5saver)
58
+
59
+ def add_detector(self, name, settings):
60
+ if name not in self.h5saver.raw_group.children_name():
61
+ group = self.h5saver.add_det_group(self.h5saver.raw_group, name, settings)
62
+ self.h5saver.add_navigation_axis(np.array([0.0, ]),
63
+ group, 'time_axis', enlargeable=True,
64
+ title='Time axis',
65
+ metadata=dict(label='Time axis', units='s', nav_index=0))
66
+
67
+ def add_actuator(self, name, settings):
68
+ if name not in self.h5saver.raw_group.children_name():
69
+ group = self.h5saver.add_move_group(self.h5saver.raw_group, name, settings)
70
+ self.h5saver.add_navigation_axis(np.array([0.0, ]),
71
+ group, 'time_axis', enlargeable=True,
72
+ title='Time axis',
73
+ metadata=dict(label='Time axis', units='s', nav_index=0))
74
+
75
+ def add_data(self, data):
76
+ name = data['name']
77
+ group = self.h5saver.get_group_by_title(self.h5saver.raw_group, name)
78
+ time_array = self.h5saver.get_node(group, 'Logger_time_axis')
79
+ time_array.append(np.array([data['acq_time_s']]))
80
+
81
+ data_types = ['data0D', 'data1D']
82
+ if self.settings['save_2D']:
83
+ data_types.extend(['data2D', 'dataND'])
84
+
85
+ for data_type in data_types:
86
+ if data_type in data.keys() and len(data[data_type]) != 0:
87
+ if not self.h5saver.is_node_in_group(group, data_type):
88
+ data_group = self.h5saver.add_data_group(group, data_type, metadata=dict(type='scan'))
89
+ else:
90
+ data_group = self.h5saver.get_node(group, utils.capitalize(data_type))
91
+ for ind_channel, channel in enumerate(data[data_type]):
92
+ channel_group = self.h5saver.get_group_by_title(data_group, channel)
93
+ if channel_group is None:
94
+ channel_group = self.h5saver.add_CH_group(data_group, title=channel)
95
+ data_array = self.h5saver.add_data(channel_group, data[data_type][channel],
96
+ scan_type='scan1D', enlargeable=True)
97
+ else:
98
+ data_array = self.h5saver.get_node(channel_group, 'Data')
99
+ if data_type == 'data0D' and not isinstance(data[data_type][channel]['data'], np.ndarray):
100
+ #this is a security as accessing an element in an array can be converted
101
+ # to a scalar... Made some other attempts but found this is the most reliable here.
102
+ logger.debug('Some data seems to not be properly formated as ndarrays')
103
+ data_array.append(np.array([data[data_type][channel]['data']]))
104
+ else:
105
+ data_array.append(data[data_type][channel]['data'])
106
+ self.h5saver.flush()
107
+ self.settings.child('N_saved').setValue(self.settings.child('N_saved').value() + 1)
108
+
109
+ def stop_logger(self):
110
+ self.h5saver.flush()
@@ -0,0 +1,350 @@
1
+ # -*- coding: utf-8 -*-
2
+ """
3
+ Created the 23/11/2022
4
+
5
+ @author: Sebastien Weber
6
+ """
7
+ from __future__ import annotations
8
+
9
+ from typing import Union, List, Dict, Tuple, TYPE_CHECKING
10
+ import xml.etree.ElementTree as ET
11
+
12
+
13
+ import numpy as np
14
+
15
+ from pymodaq.utils.abstract import ABCMeta, abstract_attribute, abstractmethod
16
+ from pymodaq.utils.daq_utils import capitalize
17
+ from pymodaq.utils.data import Axis, DataDim, DataWithAxes, DataToExport, DataDistribution
18
+ from .saving import H5SaverLowLevel
19
+ from .backends import GROUP, CARRAY, Node, GroupType
20
+ from .data_saving import DataToExportSaver, AxisSaverLoader, DataToExportTimedSaver, DataToExportExtendedSaver
21
+ from pymodaq.utils.parameter import ioxml
22
+
23
+ if TYPE_CHECKING:
24
+ from pymodaq.extensions.daq_scan import DAQScan
25
+ from pymodaq.control_modules.daq_viewer import DAQ_Viewer
26
+ from pymodaq.control_modules.daq_move import DAQ_Move
27
+
28
+
29
+ class ModuleSaver(metaclass=ABCMeta):
30
+ """Abstract base class to save info and data from main modules (DAQScan, DAQViewer, DAQMove, ...)"""
31
+ group_type: GroupType = abstract_attribute()
32
+ _module = abstract_attribute()
33
+ _h5saver: H5SaverLowLevel = abstract_attribute()
34
+ _module_group: GROUP = abstract_attribute()
35
+ main_module = True
36
+
37
+ def get_set_node(self, where: Union[Node, str] = None, name: str = None) -> GROUP:
38
+ """Get the node corresponding to this particular Module instance
39
+
40
+ Parameters
41
+ ----------
42
+ where: Union[Node, str]
43
+ the path of a given node or the node itself
44
+ new: bool
45
+ if True force the creation of a new indexed node of this class type
46
+ if False return the last node (or create one if None)
47
+
48
+ Returns
49
+ -------
50
+ GROUP: the Node associated with this module which should be a GROUP node
51
+ """
52
+ if where is None:
53
+ where = self._h5saver.raw_group
54
+ if name is None:
55
+ name = self._module.title
56
+ group = self._h5saver.get_node_from_title(where, name)
57
+ if group is not None:
58
+ self._module_group = group
59
+ return group # if I got one I return it else I create one
60
+
61
+ self._module_group = self._add_module(where)
62
+ return self._module_group
63
+
64
+ def get_last_node(self, where: Union[Node, str] = None):
65
+ """Get the last node corresponding to this particular Module instance
66
+
67
+ Parameters
68
+ ----------
69
+ where: Union[Node, str]
70
+ the path of a given node or the node itself
71
+ new: bool
72
+ if True force the creation of a new indexed node of this class type
73
+ if False return the last node (or create one if None)
74
+
75
+ Returns
76
+ -------
77
+ GROUP: the Node associated with this module which should be a GROUP node
78
+ """
79
+ if where is None:
80
+ where = self._h5saver.raw_group
81
+
82
+ group = self._h5saver.get_last_group(where, self.group_type)
83
+ self._module_group = group
84
+ return self._module_group
85
+
86
+ @abstractmethod
87
+ def _add_module(self, where: Union[Node, str] = None, metadata={}):
88
+ ...
89
+
90
+ @property
91
+ def module(self):
92
+ return self._module
93
+
94
+ @property
95
+ def module_group(self):
96
+ return self._module_group
97
+
98
+ @property
99
+ def h5saver(self):
100
+ return self._h5saver
101
+
102
+ @h5saver.setter
103
+ def h5saver(self, _h5saver: H5SaverLowLevel):
104
+ self._h5saver = _h5saver
105
+ self.update_after_h5changed()
106
+
107
+ @abstractmethod
108
+ def update_after_h5changed(self):
109
+ ...
110
+
111
+ def get_last_node_index(self, where: Union[Node, str] = None):
112
+ node = self.get_last_node(where)
113
+ return int(node.name.split(capitalize(self.group_type.name))[1])
114
+
115
+ def get_next_node_name(self, where: Union[Node, str] = None):
116
+ index = self.get_last_node_index(where)
117
+ return f'{capitalize(self.group_type.name)}{index+1:03d}'
118
+
119
+
120
+ class DetectorSaver(ModuleSaver):
121
+ """Implementation of the ModuleSaver class dedicated to DAQ_Viewer modules
122
+
123
+ Parameters
124
+ ----------
125
+ module
126
+ """
127
+ group_type = GroupType['detector']
128
+
129
+ def __init__(self, module: DAQ_Viewer):
130
+ self._datatoexport_saver: DataToExportSaver = None
131
+
132
+ self._module: 'DAQ_Viewer' = module
133
+ self._module_group: GROUP = None
134
+ self._h5saver = None
135
+
136
+ def update_after_h5changed(self, ):
137
+ self._datatoexport_saver = DataToExportSaver(self.h5saver)
138
+
139
+ def _add_module(self, where: Union[Node, str] = None, metadata={}) -> Node:
140
+ """
141
+
142
+ Parameters
143
+ ----------
144
+ where: Union[Node, str]
145
+ the path of a given node or the node itself
146
+ metadata: dict
147
+
148
+ Returns
149
+ -------
150
+
151
+ """
152
+ if where is None:
153
+ where = self._h5saver.raw_group
154
+
155
+ settings_xml = ET.Element('All_settings', type='group')
156
+ settings_xml.append(ioxml.walk_parameters_to_xml(param=self._module.settings))
157
+ if self.main_module:
158
+ saver_xml = ET.SubElement(settings_xml, 'H5Saver', type='group')
159
+ saver_xml.append(ioxml.walk_parameters_to_xml(param=self._h5saver.settings))
160
+
161
+ if self._module.ui is not None:
162
+ for ind, viewer in enumerate(self._module.viewers):
163
+ if hasattr(viewer, 'roi_manager'):
164
+ roi_xml = ET.SubElement(settings_xml, f'ROI_Viewer_{ind:02d}', type='group')
165
+ roi_xml.append(ioxml.walk_parameters_to_xml(param=viewer.roi_manager.settings))
166
+
167
+ return self._h5saver.add_det_group(where, title=self._module.title, settings_as_xml=ET.tostring(settings_xml),
168
+ metadata=metadata)
169
+
170
+ def add_data(self, where: Union[Node, str], data: DataToExport):
171
+ self._datatoexport_saver.add_data(where, data)
172
+
173
+ def add_bkg(self, where: Union[Node, str], data_bkg: DataToExport):
174
+ self._datatoexport_saver.add_bkg(where, data_bkg)
175
+
176
+ def add_external_h5(self, other_h5data: H5SaverLowLevel):
177
+ if other_h5data is not None:
178
+ external_group = self._h5saver.add_group('external_data', 'external_h5', self.module_group)
179
+ try:
180
+ if not other_h5data.isopen:
181
+ h5saver = H5SaverLowLevel()
182
+ h5saver.init_file(addhoc_file_path=other_h5data.filename)
183
+ h5_file = h5saver.h5_file
184
+ else:
185
+ h5_file = other_h5data
186
+ h5_file.copy_children(h5_file.get_node('/'), external_group, recursive=True)
187
+ h5_file.flush()
188
+ h5_file.close()
189
+
190
+ except Exception as e:
191
+ self.logger.exception(str(e))
192
+
193
+
194
+ class DetectorEnlargeableSaver(DetectorSaver):
195
+ """Implementation of the ModuleSaver class dedicated to DAQ_Viewer modules in order to save enlargeable data
196
+
197
+ Parameters
198
+ ----------
199
+ module
200
+ """
201
+ group_type = GroupType['detector']
202
+
203
+ def __init__(self, module: DAQ_Viewer):
204
+ super().__init__(module)
205
+ self._datatoexport_saver: DataToExportTimedSaver = None
206
+
207
+ def update_after_h5changed(self, ):
208
+ self._datatoexport_saver = DataToExportTimedSaver(self.h5saver)
209
+
210
+
211
+ class DetectorExtendedSaver(DetectorSaver):
212
+ """Implementation of the ModuleSaver class dedicated to DAQ_Viewer modules in order to save enlargeable data
213
+
214
+ Parameters
215
+ ----------
216
+ module
217
+ """
218
+ group_type = GroupType['detector']
219
+
220
+ def __init__(self, module: DAQ_Viewer, extended_shape: Tuple[int]):
221
+ super().__init__(module)
222
+ self._extended_shape = extended_shape
223
+ self._datatoexport_saver: DataToExportExtendedSaver = None
224
+
225
+ def update_after_h5changed(self, ):
226
+ self._datatoexport_saver = DataToExportExtendedSaver(self.h5saver, self._extended_shape)
227
+
228
+ def add_data(self, where: Union[Node, str], data: DataToExport, indexes: Tuple[int],
229
+ distribution=DataDistribution['uniform']):
230
+ self._datatoexport_saver.add_data(where, data, indexes=indexes, distribution=distribution)
231
+
232
+ def add_nav_axes(self, where: Union[Node, str], axes: List[Axis]):
233
+ self._datatoexport_saver.add_nav_axes(where, axes)
234
+
235
+
236
+ class ActuatorSaver(ModuleSaver):
237
+ """Implementation of the ModuleSaver class dedicated to DAQ_Move modules
238
+
239
+ Parameters
240
+ ----------
241
+ h5saver
242
+ module
243
+ """
244
+ group_type = GroupType['actuator']
245
+
246
+ def __init__(self, module: DAQ_Move):
247
+ self._axis_saver = None
248
+ self._module_group: GROUP = None
249
+ self._module: DAQ_Move = module
250
+ self._h5saver = None
251
+
252
+ def update_after_h5changed(self):
253
+ self._axis_saver = AxisSaverLoader(self.h5saver)
254
+
255
+ def _add_module(self, where: Union[Node, str] = None, metadata={}):
256
+ if where is None:
257
+ where = self._h5saver.raw_group
258
+
259
+ settings_xml = ET.Element('All_settings')
260
+ settings_xml.append(ioxml.walk_parameters_to_xml(param=self._module.settings))
261
+
262
+ return self._h5saver.add_act_group(where, title=self._module.title, settings_as_xml=ET.tostring(settings_xml),
263
+ metadata=metadata)
264
+
265
+
266
+ class ScanSaver(ModuleSaver):
267
+ """Implementation of the ModuleSaver class dedicated to DAQScan module
268
+
269
+ Parameters
270
+ ----------
271
+ h5saver
272
+ module
273
+ """
274
+ group_type = GroupType['scan']
275
+
276
+ def __init__(self, module):
277
+ self._module_group: GROUP = None
278
+ self._module: 'DAQScan' = module
279
+ self._h5saver = None
280
+
281
+ def update_after_h5changed(self):
282
+ for module in self._module.modules_manager.modules_all:
283
+ if hasattr(module, 'module_and_data_saver'):
284
+ module.module_and_data_saver.h5saver = self.h5saver
285
+
286
+ def get_set_node(self, where: Union[Node, str] = None, new=False) -> GROUP:
287
+ """Get the last group scan node
288
+
289
+ Get the last Scan Group or create one
290
+ get the last Scan Group if:
291
+ * there is one already created
292
+ * new is False
293
+
294
+ Parameters
295
+ ----------
296
+ where: Union[Node, str]
297
+ the path of a given node or the node itself
298
+ new: bool
299
+
300
+ Returns
301
+ -------
302
+ GROUP: the GROUP associated with this module
303
+ """
304
+ self._module_group = self.get_last_node(where)
305
+ new = new or (self._module_group is None)
306
+ if new:
307
+ self._module_group = self._add_module(where)
308
+ for module in self._module.modules_manager.modules:
309
+ module.module_and_data_saver.main_module = False
310
+ module.module_and_data_saver.get_set_node(self._module_group)
311
+ return self._module_group
312
+
313
+ def _add_module(self, where: Union[Node, str] = None, metadata={}) -> Node:
314
+ """
315
+
316
+ Parameters
317
+ ----------
318
+ where: Union[Node, str]
319
+ the path of a given node or the node itself
320
+ metadata: dict
321
+
322
+ Returns
323
+ -------
324
+
325
+ """
326
+ if where is None:
327
+ where = self._h5saver.raw_group
328
+
329
+ settings_xml = ET.Element('All_settings', type='group')
330
+ settings_xml.append(ioxml.walk_parameters_to_xml(param=self._module.settings))
331
+ if self.main_module:
332
+ saver_xml = ET.SubElement(settings_xml, 'H5Saver', type='group')
333
+ saver_xml.append(ioxml.walk_parameters_to_xml(param=self._h5saver.settings))
334
+
335
+ return self._h5saver.add_scan_group(where, title=self._module.title,
336
+ settings_as_xml=ET.tostring(settings_xml),
337
+ metadata=metadata)
338
+
339
+ def add_nav_axes(self, axes: List[Axis]):
340
+ for detector in self._module.modules_manager.detectors:
341
+ detector.module_and_data_saver.add_nav_axes(self._module_group, axes)
342
+
343
+ def add_data(self, indexes: Tuple[int] = None, distribution=DataDistribution['uniform']):
344
+ for detector in self._module.modules_manager.detectors:
345
+ try:
346
+ detector.insert_data(indexes, where=self._module_group, distribution=distribution)
347
+ except Exception as e:
348
+ pass
349
+
350
+