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,480 @@
1
+ import importlib
2
+ import time
3
+ from typing import Callable, Union, List, Tuple, TYPE_CHECKING
4
+ from abc import abstractproperty
5
+
6
+ import numpy as np
7
+ from qtpy import QtWidgets, QtCore
8
+ from qtpy.QtCore import QObject, Slot, QThread, Signal
9
+ import sys
10
+ from typing import List, Dict
11
+ from collections import OrderedDict
12
+ from pyqtgraph import ROI, RectROI, PolyLineROI, Point, LinearRegionItem
13
+ from abc import ABC, abstractmethod
14
+ from pymodaq.utils.parameter import Parameter, ParameterTree
15
+ from pymodaq.utils.managers.parameter_manager import ParameterManager
16
+ from pymodaq.utils.logger import set_logger, get_module_name
17
+ from pymodaq.utils.gui_utils import DockArea, Dock
18
+ from pymodaq.utils.plotting.utils.plot_utils import QVector
19
+ from pymodaq.utils import daq_utils as utils
20
+ from pymodaq.utils import gui_utils as gutils
21
+ from pymodaq.utils.enums import BaseEnum, enum_checker
22
+ from pymodaq.utils.parameter.pymodaq_ptypes import TableViewCustom
23
+ from pymodaq.utils.parameter import utils as putils
24
+ from pymodaq.utils.plotting.data_viewers.viewer import ViewerBase
25
+ from pymodaq.utils.factory import ObjectFactory
26
+ from pymodaq.utils.data import DataDim
27
+
28
+ logger = set_logger(get_module_name(__file__))
29
+
30
+
31
+ class Selector:
32
+ """Base class defining the interface for a Selector"""
33
+
34
+ @abstractmethod
35
+ def get_header(self):
36
+ ...
37
+
38
+ @abstractmethod
39
+ def get_coordinates(self) -> np.ndarray:
40
+ """Returns coordinates as a ndarray
41
+
42
+ Particular implementation and returned array shape depends on the selector.
43
+ """
44
+ ...
45
+
46
+ @abstractmethod
47
+ def set_coordinates(self, coordinates: np.ndarray):
48
+ """Set the coordinates of the selector using the input ndarray
49
+
50
+ Particular implementation depends on the selector.
51
+ """
52
+ ...
53
+
54
+
55
+ class SelectorFactory(ObjectFactory):
56
+ """Factory class registering and storing Selectors"""
57
+
58
+
59
+ @SelectorFactory.register('PolyLines')
60
+ class PolyLineROI(Selector, PolyLineROI):
61
+
62
+ def __init__(self, *args, **kwargs):
63
+ super().__init__(positions=[(0, 0), (10, 10)], *args, **kwargs)
64
+
65
+ def get_header(self):
66
+ return ['x', 'y']
67
+
68
+ def get_coordinates(self) -> np.ndarray:
69
+ return np.array([[vertex.x(), vertex.y()] for vertex in self.get_vertex()])
70
+
71
+ def set_coordinates(self, coordinates: np.ndarray):
72
+ self.setPoints(coordinates)
73
+
74
+ def get_vertex(self):
75
+ return [h['item'].pos() for h in self.handles]
76
+
77
+ def get_vectors(self):
78
+ imgPts = self.get_vertex()
79
+ d = []
80
+ for i in range(len(imgPts) - 1):
81
+ d.append(QVector(imgPts[i], Point(imgPts[i + 1])))
82
+ return d
83
+
84
+ def getArrayIndexes(self, spacing=1, **kwds):
85
+ imgPts = self.get_vertex()
86
+ positions = []
87
+ for i in range(len(imgPts) - 1):
88
+ d = Point(imgPts[i + 1] - imgPts[i])
89
+ o = Point(imgPts[i])
90
+ vect = Point(d.norm())
91
+ Npts = 0
92
+ while Npts * spacing < d.length():
93
+ positions.append(((o + Npts * spacing * vect).x(), (o + Npts * spacing * vect).y()))
94
+ Npts += 1
95
+ # add_last point not taken into account
96
+ positions.append((imgPts[-1].x(), imgPts[-1].y()))
97
+ return positions
98
+
99
+
100
+ @SelectorFactory.register('RectangularROI')
101
+ class RectangularRoi(Selector, RectROI):
102
+
103
+ def __init__(self, *args, **kwargs):
104
+ super().__init__([0, 0], [10, 10], *args, invertible=True, **kwargs)
105
+
106
+ def get_header(self):
107
+ return ['x', 'y']
108
+
109
+ def get_coordinates(self) -> np.ndarray:
110
+ """Returns bottom/left and top/right positions of the Rectangular ROI"""
111
+ coordinates = [[self.pos().x(), self.pos().y()],
112
+ [self.pos().x() + self.size().x(), self.pos().y() + self.size().y()]]
113
+ return np.array(coordinates)
114
+
115
+ def set_coordinates(self, coordinates: np.ndarray):
116
+ if len(coordinates) != 0:
117
+ self.setPos(coordinates[0, :], finish=False)
118
+ self.setSize(coordinates[1, :] - coordinates[0, :])
119
+
120
+
121
+ @SelectorFactory.register('LinearROI')
122
+ class LinearRegionItem(Selector, LinearRegionItem):
123
+
124
+ def __init__(self, *args, **kwargs):
125
+ super().__init__(*args, **kwargs)
126
+
127
+ def get_header(self):
128
+ return ['x']
129
+
130
+ def get_coordinates(self) -> np.ndarray:
131
+ """Returns left and right positions of the Linear Region"""
132
+ coordinates = [self.getRegion()]
133
+ return np.array(coordinates).T
134
+
135
+ def set_coordinates(self, coordinates: np.ndarray):
136
+ self.setRegion(coordinates[:, 0])
137
+
138
+
139
+ class SelectorWrapper(Selector):
140
+ """Wrapper around real implementation of Selector objects but having the same interface
141
+
142
+ Mandatory because signal can only be emitted with one signature and not with child classes
143
+ Hence this single wrapper of all real implementation of Selector
144
+ """
145
+ def __init__(self, selector: Selector):
146
+ self._selector: Selector = selector
147
+
148
+ def __call__(self, *args, **kwargs):
149
+ return self._selector
150
+
151
+ @property
152
+ def name(self):
153
+ return self._selector.__class__
154
+
155
+ def get_header(self):
156
+ return self._selector.get_header()
157
+
158
+ def get_coordinates(self):
159
+ return self._selector.get_coordinates()
160
+
161
+ def set_coordinates(self, coordinates: np.ndarray):
162
+ self._selector.set_coordinates(coordinates)
163
+
164
+
165
+ class TableModel(gutils.TableModel):
166
+ """Table Model for the Model/View Qt framework dedicated to the Tabular scan mode"""
167
+ def __init__(self, data, header_names=None, **kwargs):
168
+ if header_names is None:
169
+ if 'header' in kwargs: # when saved as XML the header will be saved and restored here
170
+ header_names = [h for h in kwargs['header']]
171
+ kwargs.pop('header')
172
+ else:
173
+ raise Exception('Invalid header')
174
+
175
+ header = [name for name in header_names]
176
+ editable = [True for _ in header_names]
177
+ super().__init__(data, header, editable=editable, **kwargs)
178
+
179
+ def data_as_ndarray(self):
180
+ return np.array(self.raw_data)
181
+
182
+ def __len__(self):
183
+ return len(self._data)
184
+
185
+ def add_data(self, row, data=None):
186
+ if data is not None:
187
+ self.insert_data(row, [float(d) for d in data])
188
+ else:
189
+ self.insert_data(row, [0. for name in self.header])
190
+
191
+ def remove_data(self, row):
192
+ self.remove_row(row)
193
+
194
+ def __repr__(self):
195
+ return f'{self.__class__.__name__} from module {self.__class__.__module__}'
196
+
197
+ def validate_data(self, row, col, value):
198
+ return True
199
+
200
+
201
+ class SelectorItem:
202
+ """An object storing a viewer to display selectors and a name to reference it
203
+
204
+ If the name is not given, constructs one from a unique index
205
+ """
206
+ _index: int = 0
207
+
208
+ def __init__(self, viewer: ViewerBase, name: str = None):
209
+ self.viewer = viewer
210
+ if name is None:
211
+ name = f'{self.viewer.title}_{self._index:03d}'
212
+ self.name = name
213
+
214
+ SelectorItem._index += 1
215
+
216
+
217
+ selector_factory = SelectorFactory()
218
+
219
+
220
+ class ScanSelector(ParameterManager, QObject):
221
+ """Allows selection of a given 2D viewer to get scan info
222
+
223
+ respectively scan2D or scan Tabular from respectively a rectangular ROI or a polyline
224
+
225
+ Parameters
226
+ ----------
227
+ viewer_items: dict
228
+ where the keys are the titles of the sources while the values are dict with keys
229
+ * viewers: list of plotitems
230
+ * names: list of viewer titles
231
+
232
+ selector_type: str
233
+ either 'PolyLines' corresponding to a polyline ROI or 'Rectangle' for a rect Roi
234
+ positions: list
235
+ a sequence of 2 floats sequence [(x1,y1),(x2,y2),(x3,y3),...]
236
+
237
+ """
238
+ scan_select_signal = Signal(SelectorWrapper)
239
+
240
+ params = [
241
+ {'title': 'Scan options', 'name': 'scan_options', 'type': 'group', 'children': [
242
+ {'title': 'Sources:', 'name': 'sources', 'type': 'list', },
243
+ {'title': 'Selector type:', 'name': 'selector_type', 'type': 'list',
244
+ 'limits': selector_factory.keys},
245
+ ]},
246
+ {'title': 'Coordinates:', 'name': 'coordinates', 'type': 'table_view', 'visible': True,
247
+ 'delegate': gutils.SpinBoxDelegate,},
248
+ # ]},
249
+ ]
250
+
251
+ def __init__(self, viewer_items: List[SelectorItem] = None, positions: List = None):
252
+ QObject.__init__(self)
253
+ ParameterManager.__init__(self, 'selector_settings')
254
+
255
+ self.table_model: TableModel = None
256
+ self.table_view: TableViewCustom = None
257
+
258
+ self.selector: Selector = None
259
+ self.selector_source: ViewerBase = None
260
+
261
+ self.update_selector_type()
262
+
263
+ if viewer_items is None:
264
+ viewer_items = []
265
+
266
+ self.viewers_items = viewer_items
267
+ self.sources_names = [item.name for item in viewer_items]
268
+ if len(viewer_items) != 0:
269
+ self.selector_source = viewer_items[0].viewer
270
+ else:
271
+ self.selector_source = None
272
+
273
+ # self.remove_selector()
274
+ # self.update_selector_type()
275
+
276
+ if positions is not None:
277
+ self.selector.set_coordinates(positions)
278
+
279
+ @property
280
+ def selector_type(self) -> str:
281
+ return self.settings['scan_options', 'selector_type']
282
+
283
+ @selector_type.setter
284
+ def selector_type(self, selector_type: str):
285
+ if selector_type not in selector_factory.keys:
286
+ raise TypeError(f'{selector_type} is an unknown Selector Type')
287
+ self.settings.child('scan_options', 'selector_type').setValue(selector_type)
288
+
289
+ @property
290
+ def source_name(self) -> str:
291
+ return self.settings['scan_options', 'sources']
292
+
293
+ @source_name.setter
294
+ def source_name(self, source: str):
295
+ if source in self.settings.child('scan_options', 'sources').opts['limits']:
296
+ self.settings.child('scan_options', 'sources').setValue(source)
297
+
298
+ def update_model(self, init_data=None):
299
+ if init_data is None:
300
+ init_data = [[0. for _ in self.selector.get_header()]]
301
+
302
+ self.table_model = TableModel(init_data, self.selector.get_header())
303
+ self.table_view = putils.get_widget_from_tree(self.settings_tree, TableViewCustom)[0]
304
+ self.settings.child('coordinates').setValue(self.table_model)
305
+ self.update_table_view()
306
+
307
+ def update_model_data(self, data: np.ndarray):
308
+ self.table_model.set_data_all(data)
309
+
310
+ def update_table_view(self):
311
+ self.table_view.horizontalHeader().setSectionResizeMode(QtWidgets.QHeaderView.ResizeToContents)
312
+ self.table_view.horizontalHeader().setStretchLastSection(True)
313
+ self.table_view.setSelectionBehavior(QtWidgets.QTableView.SelectRows)
314
+ self.table_view.setSelectionMode(QtWidgets.QTableView.SingleSelection)
315
+ styledItemDelegate = QtWidgets.QStyledItemDelegate()
316
+ styledItemDelegate.setItemEditorFactory(gutils.SpinBoxDelegate())
317
+ self.table_view.setItemDelegate(styledItemDelegate)
318
+
319
+ self.table_view.setDragEnabled(False)
320
+ self.table_view.setDropIndicatorShown(False)
321
+ self.table_view.setAcceptDrops(False)
322
+ self.table_view.viewport().setAcceptDrops(False)
323
+ self.table_view.setDefaultDropAction(QtCore.Qt.MoveAction)
324
+ self.table_view.setDragDropMode(QtWidgets.QTableView.InternalMove)
325
+ self.table_view.setDragDropOverwriteMode(False)
326
+
327
+ @property
328
+ def viewers_items(self):
329
+ return self._viewers_items
330
+
331
+ @viewers_items.setter
332
+ def viewers_items(self, items: List[SelectorItem]):
333
+ self._viewers_items = items
334
+ self.sources_names = [item.name for item in items]
335
+ self.selector_source = items[0].viewer
336
+ self.settings.child('scan_options', 'sources').setOpts(limits=self.sources_names)
337
+
338
+ def show(self, visible=True):
339
+ self.show_selector(visible)
340
+ if visible:
341
+ self.widget.show()
342
+ else:
343
+ self.widget.hide()
344
+
345
+ def hide(self):
346
+ self.show(False)
347
+
348
+ def value_changed(self, param):
349
+
350
+ if param.name() == 'sources' and param.value() is not None:
351
+ self.remove_selector()
352
+ self.selector_source = \
353
+ utils.find_objects_in_list_from_attr_name_val(
354
+ self.viewers_items, 'name', param.value(), return_first=True)[0].viewer
355
+ self.update_selector_type()
356
+
357
+ if param.name() == 'selector_type':
358
+ self.update_selector_type()
359
+ self.selector.sigRegionChangeFinished.emit(self.selector)
360
+
361
+ if param.name() == 'coordinates':
362
+ self.selector.set_coordinates(param.value().data_as_ndarray())
363
+
364
+ def remove_selector(self):
365
+ if self.selector_source is not None:
366
+ try:
367
+ self.selector_source.image_widget.plotitem.removeItem(self.selector)
368
+ except Exception as e:
369
+ logger.exception(str(e))
370
+ pass
371
+
372
+ def update_selector_type(self):
373
+ self.remove_selector()
374
+ mod = importlib.import_module('.scan_selector', 'pymodaq.utils.plotting')
375
+ self.selector = selector_factory.create(self.settings['scan_options', 'selector_type'])
376
+
377
+ if self.selector_source is not None and self.selector is not None:
378
+ self.selector.sigRegionChangeFinished.connect(self.update_scan)
379
+ self.selector_source.plotitem.addItem(self.selector)
380
+ self.show_selector()
381
+ self.update_model(self.selector.get_coordinates())
382
+
383
+ def show_selector(self, visible=True):
384
+ self.selector.setVisible(visible)
385
+
386
+ def update_scan(self):
387
+ if self.selector_source is not None:
388
+ self.update_model_data(self.selector.get_coordinates())
389
+ self.scan_select_signal.emit(SelectorWrapper(self.selector))
390
+
391
+
392
+ def main_fake_scan():
393
+ from pymodaq.utils.plotting.data_viewers.viewer2D import Viewer2D
394
+ from pymodaq.control_modules.daq_viewer import DAQ_Viewer
395
+
396
+ class UI:
397
+ def __init__(self):
398
+ pass
399
+
400
+ class FakeDaqScan:
401
+
402
+ def __init__(self, area):
403
+ self.area = area
404
+ self.detector_modules = None
405
+ self.ui = UI()
406
+ self.dock = Dock('2D scan', size=(500, 300), closable=False)
407
+
408
+ form = QtWidgets.QWidget()
409
+ self.ui.scan2D_graph = Viewer2D(form)
410
+ self.dock.addWidget(form)
411
+ self.area.addDock(self.dock)
412
+
413
+ app = QtWidgets.QApplication(sys.argv)
414
+ win = QtWidgets.QMainWindow()
415
+ area = DockArea()
416
+
417
+ win.setCentralWidget(area)
418
+ win.resize(1000, 500)
419
+ win.setWindowTitle('pymodaq main')
420
+ fake = FakeDaqScan(area)
421
+
422
+ prog = DAQ_Viewer(area, title="Testing", daq_type='DAQ2D')#, parent_scan=fake)
423
+ prog.init_hardware_ui(True)
424
+ QThread.msleep(1000)
425
+ QtWidgets.QApplication.processEvents()
426
+ prog2 = DAQ_Viewer(area, title="Testing2", daq_type='DAQ2D')#, parent_scan=fake)
427
+ prog2.init_hardware_ui(True)
428
+ QThread.msleep(1000)
429
+ QtWidgets.QApplication.processEvents()
430
+
431
+ fake.detector_modules = [prog, prog2]
432
+ items = OrderedDict()
433
+ items[prog.title] = dict(viewers=[view for view in prog.ui.viewers],
434
+ names=[view.title for view in prog.ui.viewers],
435
+ )
436
+ items[prog2.title] = dict(viewers=[view for view in prog2.ui.viewers],
437
+ names=[view.title for view in prog2.ui.viewers])
438
+ items["DaqScan"] = dict(viewers=[fake.ui.scan2D_graph],
439
+ names=["DaqScan"])
440
+
441
+ selector = ScanSelector(items, scan_type='PolyLines', positions=[(10, -10), (4, 4), (80, 50)])
442
+
443
+ win.show()
444
+
445
+
446
+ def main_navigator():
447
+ from pymodaq.utils.plotting.navigator import Navigator
448
+ from pymodaq.control_modules.daq_viewer import DAQ_Viewer
449
+ app = QtWidgets.QApplication(sys.argv)
450
+ widg = QtWidgets.QWidget()
451
+ navigator = Navigator(widg, h5file_path=r'C:\Data\2023\20230320\Dataset_20230320_001.h5')
452
+
453
+ widg.show()
454
+ navigator.list_2D_scans()
455
+
456
+ win = QtWidgets.QMainWindow()
457
+ area = DockArea()
458
+ win.setCentralWidget(area)
459
+ win.resize(1000, 500)
460
+ win.setWindowTitle('PyMoDAQ Viewer')
461
+ win.show()
462
+
463
+ viewer = DAQ_Viewer(area, title="Testing", daq_type='DAQ2D')
464
+ viewer.init_hardware_ui(True)
465
+ time.sleep(1)
466
+ QtWidgets.QApplication.processEvents()
467
+
468
+ items = [SelectorItem(viewer=navigator.viewer, name="Navigator")]
469
+ for _viewer_dock, _viewer in zip(viewer.viewers_docks, viewer.viewers):
470
+ items.append(SelectorItem(viewer=_viewer, name=_viewer_dock.title()))
471
+
472
+ scan_selector = ScanSelector(viewer_items=items)
473
+ scan_selector.settings_tree.show()
474
+
475
+ sys.exit(app.exec_())
476
+
477
+
478
+ if __name__ == '__main__':
479
+ # main_fake_scan()
480
+ main_navigator()
@@ -0,0 +1,88 @@
1
+ # -*- coding: utf-8 -*-
2
+ """
3
+ Created the 26/01/2023
4
+
5
+ @author: Sebastien Weber
6
+ """
7
+ from typing import List
8
+
9
+ from qtpy import QtWidgets, QtCore
10
+
11
+ from pymodaq.utils.plotting.data_viewers.viewer1Dbasic import Viewer1DBasic
12
+ from pymodaq.utils.data import Axis
13
+ from pymodaq.utils.math_utils import find_index
14
+
15
+
16
+ class AxesViewer(QtCore.QObject):
17
+ navigation_changed = QtCore.Signal()
18
+
19
+ def __init__(self, parent_widget: QtWidgets.QWidget):
20
+ super().__init__()
21
+ self._axes: List[Axis]
22
+ self.parent = parent_widget
23
+ self.parent.setLayout(QtWidgets.QVBoxLayout())
24
+ self.nav_axes_viewers: List[Viewer1DBasic] = []
25
+
26
+ def clear_viewers(self):
27
+ while len(self.nav_axes_viewers) != 0:
28
+ viewer = self.nav_axes_viewers.pop(0)
29
+ self.parent.layout().removeWidget(viewer.parent)
30
+ viewer.parent.close()
31
+
32
+ def add_viewers(self, nviewers: int):
33
+ widgets = []
34
+ for ind in range(nviewers):
35
+ widgets.append(QtWidgets.QWidget())
36
+ self.parent.layout().addWidget(widgets[-1])
37
+ self.nav_axes_viewers.append(Viewer1DBasic(widgets[-1], show_line=True))
38
+
39
+ def set_nav_viewers(self, axes: List[Axis]):
40
+ self._axes = axes
41
+ if len(self.nav_axes_viewers) != len(axes):
42
+ self.clear_viewers()
43
+ self.add_viewers(len(axes))
44
+
45
+ for ind in range(len(axes)):
46
+ self.nav_axes_viewers[ind].roi_line_signal.connect(self._emit_nav_signal)
47
+ self.nav_axes_viewers[ind].show_data([axes[ind].data])
48
+ self.nav_axes_viewers[ind].set_axis_label(dict(orientation='bottom',
49
+ label='Scan index',
50
+ units=''))
51
+ self.nav_axes_viewers[ind].set_axis_label(dict(orientation='left',
52
+ label=axes[ind].label,
53
+ units=axes[ind].units))
54
+
55
+ def _emit_nav_signal(self):
56
+ self.navigation_changed.emit()
57
+
58
+ def get_crosshairs(self):
59
+ return tuple([viewer.get_line_position() for viewer in self.nav_axes_viewers])
60
+
61
+ def get_indexes(self):
62
+ return [int(cross) for cross in self.get_crosshairs()]
63
+
64
+ def setVisible(self, show=True):
65
+ """convenience method to show or hide the paretn widget"""
66
+ self.parent.setVisible(show)
67
+
68
+
69
+ if __name__ == '__main__':
70
+ import sys
71
+ import numpy as np
72
+ app = QtWidgets.QApplication(sys.argv)
73
+
74
+ widget = QtWidgets.QWidget()
75
+ prog = AxesViewer(widget)
76
+ widget.show()
77
+ labels = ['']
78
+ N = 2
79
+ axes = [Axis(label=f'Axis{ind:02d}', units='s', data=np.random.rand(50)) for ind in range(N)]
80
+ prog.set_nav_viewers(axes)
81
+
82
+ def print_positions():
83
+ print(prog.get_crosshairs())
84
+
85
+ prog.navigation_changed.connect(print_positions)
86
+
87
+ sys.exit(app.exec_())
88
+