pymodaq 3.6.13__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.13.dist-info → pymodaq-4.0.1.dist-info}/RECORD +167 -170
  139. {pymodaq-3.6.13.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 -686
  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.13.dist-info/METADATA +0 -39
  205. pymodaq-3.6.13.dist-info/entry_points.txt +0 -8
  206. pymodaq-3.6.13.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.13.dist-info → pymodaq-4.0.1.dist-info/licenses}/LICENSE +0 -0
@@ -0,0 +1,738 @@
1
+ from abc import ABCMeta, abstractmethod, abstractproperty
2
+ import sys
3
+ from typing import List, Tuple, Union
4
+
5
+ import numpy as np
6
+ from scipy.spatial import QhullError
7
+ from scipy.spatial import Delaunay as Triangulation
8
+ from qtpy import QtWidgets
9
+ from qtpy.QtCore import QObject, Slot, Signal, QRectF, QPointF
10
+
11
+ from pymodaq.utils.logger import set_logger, get_module_name
12
+ from pymodaq.utils.gui_utils.dock import DockArea, Dock
13
+ from pymodaq.utils.plotting.data_viewers.viewer1D import Viewer1D
14
+ from pymodaq.utils.plotting.utils.axes_viewer import AxesViewer
15
+ from pymodaq.utils.plotting.data_viewers.viewer2D import Viewer2D
16
+ from pymodaq.utils.plotting.data_viewers.viewer0D import Viewer0D
17
+ import pymodaq.utils.daq_utils as utils
18
+ import pymodaq.utils.math_utils as mutils
19
+ from pymodaq.utils.data import DataRaw, Axis, DataDistribution, DataWithAxes, DataDim, DataCalculated
20
+
21
+ from pymodaq.utils.plotting.data_viewers.viewer import ViewerBase
22
+ from pymodaq.utils.managers.action_manager import ActionManager
23
+ from pymodaq.utils.managers.parameter_manager import ParameterManager
24
+ from pymodaq.post_treatment.process_to_scalar import DataProcessorFactory
25
+ from pymodaq.utils.managers.roi_manager import SimpleRectROI, LinearROI
26
+
27
+
28
+ logger = set_logger(get_module_name(__file__))
29
+ data_processors = DataProcessorFactory()
30
+
31
+ DEBUG_VIEWER = False
32
+
33
+
34
+ class BaseDataDisplayer(QObject):
35
+ data_dim_signal = Signal(str)
36
+ processor_changed = Signal(object)
37
+ distribution: DataDistribution = abstractproperty()
38
+
39
+ def __init__(self, viewer0D: Viewer0D, viewer1D: Viewer1D, viewer2D: Viewer2D, navigator1D: Viewer1D,
40
+ navigator2D: Viewer2D, axes_viewer: AxesViewer):
41
+ super().__init__()
42
+ self._viewer0D = viewer0D
43
+ self._viewer1D = viewer1D
44
+ self._viewer2D = viewer2D
45
+ self._navigator1D = navigator1D
46
+ self._navigator2D = navigator2D
47
+ self._axes_viewer = axes_viewer
48
+
49
+ self._data: DataWithAxes = None
50
+ self._nav_limits: tuple = (0, 10, None, None)
51
+ self._signal_at: tuple = (0, 0)
52
+
53
+ self._filter_type: str = None
54
+ self._processor = None
55
+
56
+ @property
57
+ def data_shape(self):
58
+ return self._data.shape if self._data is not None else None
59
+
60
+ def update_filter(self, filter_type: str):
61
+ if filter_type in self._processor.functions:
62
+ self._filter_type = filter_type
63
+ self.update_nav_data(*self._nav_limits)
64
+
65
+ def update_processor(self, math_processor: DataProcessorFactory):
66
+ self._processor = math_processor
67
+ self.processor_changed.emit(math_processor)
68
+
69
+ def update_data(self, data: DataRaw, force_update=False):
70
+ if self._data is None or self._data.shape != data.shape or force_update:
71
+ self._data = data
72
+ self.init(data)
73
+ else:
74
+ self._data.data = data.data[0]
75
+
76
+ self.data_dim_signal.emit(self._data.get_data_dimension())
77
+
78
+ self.update_viewer_data(*self._signal_at)
79
+ self.update_nav_data(*self._nav_limits)
80
+
81
+ @abstractmethod
82
+ def init_rois(self, data: DataRaw):
83
+ """Init crosshairs and ROIs in viewers if needed"""
84
+ ...
85
+
86
+ @abstractmethod
87
+ def init(self):
88
+ """init viewers or postprocessing once new data are loaded"""
89
+ ...
90
+
91
+ @abstractmethod
92
+ def update_viewer_data(self, **kwargs):
93
+ """ Update the signal display depending on the position of the crosshair in the navigation panels
94
+
95
+ """
96
+ ...
97
+
98
+ @abstractmethod
99
+ def update_nav_data(self, x, y, width=None, height=None):
100
+ """Display navigator data potentially postprocessed from filters in the signal viewers"""
101
+ ...
102
+
103
+ @abstractmethod
104
+ def get_nav_data(self, data: DataWithAxes, x, y, width=None, height=None) -> DataWithAxes:
105
+ """Get filtered data"""
106
+ ...
107
+
108
+ def update_nav_data_from_roi(self, roi: Union[SimpleRectROI, LinearROI]):
109
+ if isinstance(roi, LinearROI):
110
+ x, y = roi.getRegion()
111
+ self._nav_limits = (int(x), int(y), None, None)
112
+ elif isinstance(roi, SimpleRectROI):
113
+ x, y = roi.pos().x(), roi.pos().y()
114
+ width, height = roi.size().x(), roi.size().y()
115
+ self._nav_limits = (int(x), int(y), int(width), int(height))
116
+ self.update_nav_data(*self._nav_limits)
117
+
118
+ @staticmethod
119
+ def get_out_of_range_limits(x, y, width, height):
120
+ if x < 0:
121
+ width = width + x
122
+ x = 0
123
+ if y < 0:
124
+ height = height + y
125
+ y = 0
126
+ return x, y, width, height
127
+
128
+ def update_nav_indexes(self, nav_indexes: List[int]):
129
+ self._data.nav_indexes = nav_indexes
130
+ self.update_data(self._data, force_update=True)
131
+
132
+ def update_nav_limits(self, x, y, width=None, height=None):
133
+ self._nav_limits = x, y, width, height
134
+
135
+
136
+ class UniformDataDisplayer(BaseDataDisplayer):
137
+ """Specialized object to filter and plot linearly spaced data in dedicated viewers
138
+
139
+ Meant for any navigation axes and up to signal data dimensionality of 2 (images)
140
+ """
141
+ distribution = DataDistribution['uniform']
142
+
143
+ def __init__(self, *args, **kwargs):
144
+ super().__init__(*args, **kwargs)
145
+
146
+ def init(self, data: DataRaw):
147
+ if len(data.nav_indexes) > 2:
148
+ self._axes_viewer.set_nav_viewers(self._data.get_nav_axes_with_data())
149
+ processor: DataProcessorFactory = data_processors
150
+ self.update_processor(processor)
151
+
152
+ def init_rois(self, data: DataRaw):
153
+ means = []
154
+ for axis in data.axes_manager.get_nav_axes():
155
+ means.append(axis.mean())
156
+ if len(data.nav_indexes) == 1:
157
+ self._navigator1D.set_crosshair_position(*means)
158
+ elif len(data.nav_indexes) == 2:
159
+ self._navigator2D.set_crosshair_position(*means)
160
+
161
+ mins = []
162
+ maxs = []
163
+ for axis in data.axes_manager.get_signal_axes():
164
+ mins.append(axis.min())
165
+ maxs.append(axis.max())
166
+ if len(data.axes_manager.sig_indexes) == 1:
167
+ self._viewer1D.roi.setPos((mins[0], maxs[0]))
168
+ elif len(data.axes_manager.sig_indexes) > 1:
169
+ self._viewer2D.roi.setPos((0, 0))
170
+ self._viewer2D.roi.setSize((len(data.get_axis_from_index(data.axes_manager.sig_indexes[1])),
171
+ len(data.get_axis_from_index(data.axes_manager.sig_indexes[0]))))
172
+
173
+ def update_viewer_data(self, posx=0, posy=0):
174
+ """ Update the signal display depending on the position of the crosshair in the navigation panels
175
+
176
+ Parameters
177
+ ----------
178
+ posx: float
179
+ from the 1D or 2D Navigator crosshair or from one of the navigation axis viewer (in that case
180
+ nav_axis tells from which navigation axis the position comes from)
181
+ posy: float
182
+ from the 2D Navigator crosshair
183
+ """
184
+ self._signal_at = posx, posy
185
+ if self._data is not None:
186
+ try:
187
+ if len(self._data.nav_indexes) == 0:
188
+ data = self._data
189
+
190
+ elif len(self._data.nav_indexes) == 1:
191
+ nav_axis = self._data.axes_manager.get_nav_axes()[0]
192
+ if posx < nav_axis.min() or posx > nav_axis.max():
193
+ return
194
+ ind_x = nav_axis.find_index(posx)
195
+ logger.debug(f'Getting the data at nav index {ind_x}')
196
+ data = self._data.inav[ind_x]
197
+
198
+ elif len(self._data.nav_indexes) == 2:
199
+ nav_x = self._data.axes_manager.get_nav_axes()[1]
200
+ nav_y = self._data.axes_manager.get_nav_axes()[0]
201
+ if posx < nav_x.min() or posx > nav_x.max():
202
+ return
203
+ if posy < nav_y.min() or posy > nav_y.max():
204
+ return
205
+ ind_x = nav_x.find_index(posx)
206
+ ind_y = nav_y.find_index(posy)
207
+ logger.debug(f'Getting the data at nav indexes {ind_y} and {ind_x}')
208
+ data = self._data.inav[ind_y, ind_x]
209
+ else:
210
+ data = self._data.inav.__getitem__(self._axes_viewer.get_indexes())
211
+
212
+ if len(self._data.axes_manager.sig_shape) == 0: # means 0D data, plot on 0D viewer
213
+ self._viewer0D.show_data(data)
214
+
215
+ elif len(self._data.axes_manager.sig_shape) == 1: # means 1D data, plot on 1D viewer
216
+ self._viewer1D.show_data(data)
217
+
218
+ elif len(self._data.axes_manager.sig_shape) == 2: # means 2D data, plot on 2D viewer
219
+ self._viewer2D.show_data(data)
220
+ if DEBUG_VIEWER:
221
+ x, y, width, height = self.get_out_of_range_limits(*self._nav_limits)
222
+ _data_sig = data.isig[y: y + height, x: x + width]
223
+ self._debug_viewer_2D.show_data(_data_sig)
224
+
225
+ except Exception as e:
226
+ logger.exception(str(e))
227
+
228
+ def update_nav_data(self, x, y, width=None, height=None):
229
+ if self._data is not None and self._filter_type is not None and len(self._data.nav_indexes) != 0:
230
+ nav_data = self.get_nav_data(self._data, x, y, width, height)
231
+ if nav_data is not None:
232
+ nav_data.nav_indexes = () # transform nav axes in sig axes for plotting
233
+ if len(nav_data.shape) < 2:
234
+ self._navigator1D.show_data(nav_data)
235
+ elif len(nav_data.shape) == 2:
236
+ self._navigator2D.show_data(nav_data)
237
+ else:
238
+ self._axes_viewer.set_nav_viewers(self._data.get_nav_axes_with_data())
239
+
240
+ def get_nav_data(self, data: DataRaw, x, y, width=None, height=None):
241
+ try:
242
+ navigator_data = None
243
+ if len(data.axes_manager.sig_shape) == 0: # signal data is 0D
244
+ navigator_data = data
245
+
246
+ elif len(data.axes_manager.sig_shape) == 1: # signal data is 1D
247
+ indx, indy = data.get_axis_from_index(data.sig_indexes[0])[0].find_indexes((x, y))
248
+ navigator_data = self._processor.get(self._filter_type).process(data.isig[indx:indy])
249
+
250
+ elif len(data.axes_manager.sig_shape) == 2: # signal data is 2D
251
+ x, y, width, height = self.get_out_of_range_limits(x, y, width, height)
252
+ if not (width is None or height is None or width < 2 or height < 2):
253
+ navigator_data = self._processor.get(self._filter_type).process(data.isig[y: y + height, x: x + width])
254
+ else:
255
+ navigator_data = None
256
+ else:
257
+ navigator_data = None
258
+
259
+ return navigator_data
260
+
261
+ except Exception as e:
262
+ logger.warning('Could not compute the mathematical function')
263
+ finally:
264
+ return navigator_data
265
+
266
+
267
+ class SpreadDataDisplayer(BaseDataDisplayer):
268
+ """Specialized object to filter and plot non uniformly spaced data in dedicated viewers
269
+
270
+ Meant for any navigation axes and up to signal data dimensionality of 2 (images)
271
+ """
272
+ distribution = DataDistribution['spread']
273
+
274
+ def __init__(self, *args, **kwargs):
275
+ super().__init__(*args, **kwargs)
276
+
277
+ self.triangulation = True
278
+
279
+ def init(self, data: DataWithAxes):
280
+ processor = data_processors # if len(data.axes_manager.sig_shape) > 1 else math_processors1D
281
+ self.update_processor(processor)
282
+
283
+ def init_rois(self, data: DataRaw):
284
+ pass
285
+
286
+ def update_viewer_data(self, posx=0, posy=0):
287
+ """ Update the signal display depending on the position of the crosshair in the navigation panels
288
+
289
+ Spread data can be customly represented using:
290
+ if signal data is 0D:
291
+ * A viewer 1D with non-linearly spaced data points (for 1 navigation axis)
292
+ * A viewer 2D with its SpreadImage item (for 2 navigation axis)
293
+ * A double panel: viewer for signal data and viewer 1D for all nav axes as a function of index in the data
294
+ otherwise:
295
+ * A double panel: viewer for signal data and viewer 1D for all nav axes as a function of index in the data
296
+ series
297
+
298
+ Parameters
299
+ ----------
300
+ posx: float
301
+ from the 1D or 2D Navigator crosshair or from one of the navigation axis viewer (in that case
302
+ nav_axis tells from which navigation axis the position comes from)
303
+ posy: float
304
+ from the 2D Navigator crosshair
305
+ """
306
+ self._signal_at = posx, posy
307
+
308
+ if self._data is not None:
309
+ try:
310
+ nav_axes = sorted(self._data.get_nav_axes_with_data(), key=lambda axis: axis.spread_order)
311
+
312
+ if len(nav_axes) == 1:
313
+ # signal data plotted as a function of nav_axes[0] so get the index corresponding to
314
+ # the position posx
315
+ ind_nav = nav_axes[0].find_index(posx)
316
+ data = self._data.inav[ind_nav]
317
+
318
+ elif len(nav_axes) == 2 and self.triangulation:
319
+ # signal data plotted as a function of nav_axes[0] and nav_axes[1] so get the common
320
+ # index corresponding to the position posx and posy
321
+ ind_nav, x0, y0 = mutils.find_common_index(nav_axes[0].data, nav_axes[1].data, posx, posy)
322
+ data = self._data.inav[ind_nav]
323
+ else:
324
+ # navigation plotted as a function of index all nav_axes so get the index corresponding to
325
+ # the position posx
326
+ data = self._data.inav[int(posx)]
327
+
328
+ if len(self._data.axes_manager.sig_shape) == 0: # means 0D data, plot on 0D viewer
329
+ self._viewer0D.show_data(data)
330
+
331
+ elif len(self._data.axes_manager.sig_shape) == 1: # means 1D data, plot on 1D viewer
332
+ self._viewer1D.show_data(data)
333
+
334
+ elif len(self._data.axes_manager.sig_shape) == 2: # means 2D data, plot on 2D viewer
335
+ self._viewer2D.show_data(data)
336
+ if DEBUG_VIEWER:
337
+ x, y, width, height = self.get_out_of_range_limits(*self._nav_limits)
338
+ _data_sig = data.isig[y: y + height, x: x + width]
339
+ self._debug_viewer_2D.show_data(_data_sig)
340
+
341
+ except Exception as e:
342
+ logger.exception(str(e))
343
+
344
+ def update_nav_data(self, x, y, width=None, height=None):
345
+ if self._data is not None and self._filter_type is not None and len(self._data.nav_indexes) != 0:
346
+ nav_data = self.get_nav_data(self._data, x, y, width, height)
347
+ if nav_data is not None:
348
+ nav_axes = nav_data.get_nav_axes_with_data()
349
+ if len(nav_axes) < 2:
350
+ self._navigator1D.show_data(nav_data)
351
+ elif len(nav_axes) == 2:
352
+ try:
353
+ Triangulation(np.array([axis.get_data() for axis in nav_data.get_nav_axes()]))
354
+ self._navigator2D.show_data(nav_data)
355
+ except QhullError as e:
356
+ self.triangulation = False
357
+ self._navigator2D.setVisible(False)
358
+ self._navigator1D.setVisible(True)
359
+ data_arrays = [axis.get_data() for axis in nav_axes]
360
+ labels = [axis.label for axis in nav_axes]
361
+ nav_data = DataCalculated('nav', data=data_arrays, labels=labels)
362
+ self._navigator1D.show_data(nav_data)
363
+ else:
364
+ data_arrays = [axis.get_data() for axis in nav_axes]
365
+ labels = [axis.label for axis in nav_axes]
366
+ nav_data = DataCalculated('nav', data=data_arrays, labels=labels)
367
+ self._navigator1D.show_data(nav_data)
368
+
369
+ def get_nav_data(self, data: DataRaw, x, y, width=None, height=None):
370
+ try:
371
+ navigator_data = None
372
+ if len(data.axes_manager.sig_shape) == 0: # signal data is 0D
373
+ navigator_data = data
374
+
375
+ elif len(data.axes_manager.sig_shape) == 1: # signal data is 1D
376
+ ind_x = data.get_axis_from_index(data.sig_indexes[0])[0].find_index(x)
377
+ ind_y = data.get_axis_from_index(data.sig_indexes[0])[0].find_index(y)
378
+ navigator_data = self._processor.get(self._filter_type).process(data.isig[ind_x:ind_y])
379
+
380
+ elif len(data.axes_manager.sig_shape) == 2: # signal data is 2D
381
+ x, y, width, height = self.get_out_of_range_limits(x, y, width, height)
382
+ if not (width is None or height is None or width < 2 or height < 2):
383
+ navigator_data = self._processor.get(self._filter_type).process(data.isig[y: y + height, x: x + width])
384
+ else:
385
+ navigator_data = None
386
+ else:
387
+ navigator_data = None
388
+
389
+ return navigator_data
390
+
391
+ except Exception as e:
392
+ logger.warning('Could not compute the mathematical function')
393
+ finally:
394
+ return navigator_data
395
+
396
+ def get_nav_position(self, posx=0, posy=None):
397
+ """
398
+ crosshair position from the "spread" data viewer. Should return scan index where the scan was closest to posx,
399
+ posy coordinates
400
+ Parameters
401
+ ----------
402
+ posx
403
+ posy
404
+
405
+ See Also
406
+ --------
407
+ update_viewer_data
408
+ """
409
+ # todo adapt to new layout
410
+
411
+ nav_axes = self.get_selected_axes()
412
+ if len(nav_axes) != 0:
413
+ if 'datas' in nav_axes[0]:
414
+ datas = nav_axes[0]['datas']
415
+ xaxis = datas[0]
416
+ if len(datas) > 1:
417
+ yaxis = datas[1]
418
+ ind_scan = utils.find_common_index(xaxis, yaxis, posx, posy)
419
+ else:
420
+ ind_scan = mutils.find_index(xaxis, posx)[0]
421
+
422
+ self.navigator1D.ui.crosshair.set_crosshair_position(ind_scan[0])
423
+
424
+
425
+ class ViewerND(ParameterManager, ActionManager, ViewerBase):
426
+ params = [
427
+ {'title': 'Set data spread 1D-0D', 'name': 'set_data_spread1D0D', 'type': 'action', 'visible': False},
428
+ {'title': 'Set data spread 1D-1D', 'name': 'set_data_spread1D1D', 'type': 'action', 'visible': False},
429
+ {'title': 'Set data spread 1D-2D', 'name': 'set_data_spread1D2D', 'type': 'action', 'visible': False},
430
+ {'title': 'Set data spread 2D-0D', 'name': 'set_data_spread2D0D', 'type': 'action', 'visible': False},
431
+ {'title': 'Set data spread 2D-1D', 'name': 'set_data_spread2D1D', 'type': 'action', 'visible': False},
432
+ {'title': 'Set data spread 2D-2D', 'name': 'set_data_spread2D2D', 'type': 'action', 'visible': False},
433
+ {'title': 'Set data spread 3D-0D', 'name': 'set_data_spread3D0D', 'type': 'action', 'visible': False},
434
+ {'title': 'Set data 4D', 'name': 'set_data_4D', 'type': 'action', 'visible': False},
435
+ {'title': 'Set data 3D', 'name': 'set_data_3D', 'type': 'action', 'visible': False},
436
+ {'title': 'Set data 2D', 'name': 'set_data_2D', 'type': 'action', 'visible': False},
437
+ {'title': 'Set data 1D', 'name': 'set_data_1D', 'type': 'action', 'visible': False},
438
+ {'title': 'Signal shape', 'name': 'data_shape_settings', 'type': 'group', 'children': [
439
+ {'title': 'Initial Data shape:', 'name': 'data_shape_init', 'type': 'str', 'value': "",
440
+ 'readonly': True},
441
+ {'title': 'Axes shape:', 'name': 'nav_axes_shapes', 'type': 'group', 'children': [],
442
+ 'readonly': True},
443
+ {'title': 'Data shape:', 'name': 'data_shape', 'type': 'str', 'value': "", 'readonly': True},
444
+ {'title': 'Navigator axes:', 'name': 'navigator_axes', 'type': 'itemselect'},
445
+ {'title': 'Set Nav axes:', 'name': 'set_nav_axes', 'type': 'action', 'visible': True},
446
+ ]},
447
+ ]
448
+
449
+ def __init__(self, parent_widget: QtWidgets.QWidget, title=''):
450
+ ViewerBase.__init__(self, parent_widget, title=title)
451
+ ActionManager.__init__(self, toolbar=QtWidgets.QToolBar())
452
+ ParameterManager.__init__(self)
453
+
454
+ self._area = None
455
+ self._data = None
456
+
457
+ self.viewer0D: Viewer0D = None
458
+ self.viewer1D: Viewer1D = None
459
+ self.viewer2D: Viewer2D = None
460
+ self.navigator1D: Viewer1D = None
461
+ self.navigator2D: Viewer2D = None
462
+ self.axes_viewer: AxesViewer = None
463
+
464
+ self.setup_widgets()
465
+
466
+ self.data_displayer: BaseDataDisplayer = None
467
+
468
+ self.setup_actions()
469
+
470
+ self.connect_things()
471
+
472
+ self.prepare_ui()
473
+
474
+ def update_data_displayer(self, distribution: DataDistribution):
475
+ if distribution.name == 'uniform':
476
+ self.data_displayer = UniformDataDisplayer(self.viewer0D, self.viewer1D, self.viewer2D,
477
+ self.navigator1D, self.navigator2D,
478
+ self.axes_viewer)
479
+ else:
480
+ self.data_displayer = SpreadDataDisplayer(self.viewer0D, self.viewer1D, self.viewer2D,
481
+ self.navigator1D, self.navigator2D,
482
+ self.axes_viewer)
483
+
484
+ self.navigator1D.crosshair.crosshair_dragged.connect(self.data_displayer.update_viewer_data)
485
+ self.navigator2D.crosshair_dragged.connect(self.data_displayer.update_viewer_data)
486
+ self.axes_viewer.navigation_changed.connect(self.data_displayer.update_viewer_data)
487
+ self.data_displayer.data_dim_signal.connect(self.update_data_dim)
488
+
489
+ self.viewer1D.roi.sigRegionChanged.connect(self.data_displayer.update_nav_data_from_roi)
490
+ self.viewer2D.roi.sigRegionChanged.connect(self.data_displayer.update_nav_data_from_roi)
491
+
492
+ self.get_action('filters').currentTextChanged.connect(self.data_displayer.update_filter)
493
+ self.data_displayer.processor_changed.connect(self.update_filters)
494
+
495
+ def _show_data(self, data: DataRaw, **kwargs):
496
+ force_update = False
497
+ self.settings.child('data_shape_settings', 'data_shape_init').setValue(str(data.shape))
498
+ self.settings.child('data_shape_settings', 'navigator_axes').setValue(
499
+ dict(all_items=[str(ax.index) for ax in data.axes],
500
+ selected=[str(ax.index) for ax in data.get_nav_axes()]))
501
+
502
+ if self._data is None or self._data.dim != data.dim or self._data.nav_indexes != data.nav_indexes:
503
+ force_update = True
504
+ if 'force_update' in kwargs:
505
+ force_update = kwargs['force_update']
506
+
507
+ if self.data_displayer is None or data.distribution != self.data_displayer.distribution:
508
+ self.update_data_displayer(data.distribution)
509
+
510
+ self.data_displayer.update_data(data, force_update=force_update)
511
+ self._data = data
512
+
513
+ if force_update:
514
+ self.update_widget_visibility(data)
515
+ self.data_displayer.init_rois(data)
516
+ self.data_to_export_signal.emit(self.data_to_export)
517
+
518
+ def set_data_test(self, data_shape='3D'):
519
+ if 'spread' in data_shape:
520
+ data_tri = np.load('../../../resources/triangulation_data.npy')
521
+ axes = [Axis(data=data_tri[:, 0], index=0, label='x_axis', units='xunits', spread_order=0)]
522
+
523
+ if 'spread2D' in data_shape or 'spread3D' in data_shape:
524
+ axes.append(Axis(data=data_tri[:, 1], index=0, label='y_axis', units='yunits', spread_order=1))
525
+ if data_shape == 'spread2D0D':
526
+ data = data_tri[:, 2]
527
+ elif data_shape == 'spread2D1D':
528
+ x = np.linspace(-50, 50, 100)
529
+ data = np.zeros((data_tri.shape[0], len(x)))
530
+ for ind in range(data_tri.shape[0]):
531
+ data[ind, :] = data_tri[ind, 2] * mutils.gauss1D(x, 0.01*ind - 10, 20)
532
+ axes.append(Axis(data=x, index=1, label='sig_axis'))
533
+ elif data_shape == 'spread2D2D':
534
+ x = np.linspace(-50, 50, 100)
535
+ y = np.linspace(-200, 200, 75)
536
+ data = np.zeros((data_tri.shape[0], len(y), len(x)))
537
+ for ind in range(data_tri.shape[0]):
538
+ #data[ind, :] = data_tri[ind, 2] * mutils.gauss2D(0.01*x, 0.1*ind - 20, 20, y, 0.1*ind-20, 10)
539
+ data[ind, :] = mutils.gauss2D(x, 10*data_tri[ind, 0], 20, y, 20*data_tri[ind, 1], 30)
540
+ axes.append(Axis(data=x, index=1, label='sig_axis0'))
541
+ axes.append(Axis(data=y, index=2, label='sig_axis1'))
542
+ elif data_shape == 'spread3D0D':
543
+ if 'spread2D' in data_shape or 'spread3D' in data_shape:
544
+ axes.append(Axis(data=data_tri[:, 1], index=0, label='z_axis', units='zunits', spread_order=2))
545
+ data = data_tri[:, 2]
546
+
547
+ else:
548
+ if data_shape == 'spread1D0D':
549
+ data = data_tri[:, 2]
550
+ elif data_shape == 'spread1D1D':
551
+ x = np.linspace(-50, 50, 100)
552
+ data = np.zeros((data_tri.shape[0], len(x)))
553
+ for ind in range(data_tri.shape[0]):
554
+ data[ind, :] = data_tri[ind, 2] * mutils.gauss1D(x, 0.01 * ind - 10, 20)
555
+ axes.append(Axis(data=x, index=1, label='sig_axis'))
556
+ elif data_shape == 'spread1D2D':
557
+ x = np.linspace(-50, 50, 100)
558
+ y = np.linspace(-200, 200, 75)
559
+ data = np.zeros((data_tri.shape[0], len(y), len(x)))
560
+ for ind in range(data_tri.shape[0]):
561
+ # data[ind, :] = data_tri[ind, 2] * mutils.gauss2D(0.01*x, 0.1*ind - 20, 20, y, 0.1*ind-20, 10)
562
+ data[ind, :] = mutils.gauss2D(x, 10 * data_tri[ind, 0], 20, y, 20 * data_tri[ind, 1], 30)
563
+ axes.append(Axis(data=x, index=1, label='sig_axis0'))
564
+ axes.append(Axis(data=y, index=2, label='sig_axis1'))
565
+
566
+ dataraw = DataRaw('NDdata', distribution='spread', dim='DataND',
567
+ data=[data], nav_indexes=(0, ),
568
+ axes=axes)
569
+ else:
570
+ x = mutils.linspace_step(-10, 10, 0.2)
571
+ y = mutils.linspace_step(-30, 30, 2)
572
+ t = mutils.linspace_step(-200, 200, 2)
573
+ z = mutils.linspace_step(-50, 50, 0.5)
574
+ data = np.zeros((len(y), len(x), len(t), len(z)))
575
+ amp = mutils.gauss2D(x, 0, 5, y, 0, 4) + 0.1 * np.random.rand(len(y), len(x))
576
+ amp = np.ones((len(y), len(x), len(t), len(z)))
577
+ for indx in range(len(x)):
578
+ for indy in range(len(y)):
579
+ data[indy, indx, :, :] = amp[indy, indx] * (
580
+ mutils.gauss2D(z, -50 + indx * 1, 20,
581
+ t, 0 + 2 * indy, 30)
582
+ + np.random.rand(len(t), len(z)) / 10)
583
+
584
+ if data_shape == '4D':
585
+ dataraw = DataRaw('NDdata', data=data, dim='DataND', nav_indexes=[0, 1],
586
+ axes=[Axis(data=y, index=0, label='y_axis', units='yunits'),
587
+ Axis(data=x, index=1, label='x_axis', units='xunits'),
588
+ Axis(data=t, index=2, label='t_axis', units='tunits'),
589
+ Axis(data=z, index=3, label='z_axis', units='zunits')])
590
+ elif data_shape == '3D':
591
+ data = [np.sum(data, axis=2)]
592
+ dataraw = DataRaw('NDdata', data=data, dim='DataND', nav_indexes=[0, 1],
593
+ axes=[Axis(data=y, index=0, label='y_axis', units='yunits'),
594
+ Axis(data=x, index=1, label='x_axis', units='xunits'),
595
+ Axis(data=t, index=2, label='t_axis', units='tunits')])
596
+ elif data_shape == '2D':
597
+ data = [np.sum(data, axis=(2, 3))]
598
+ dataraw = DataRaw('NDdata', data=data, dim='DataND', nav_indexes=[0, 1],
599
+ axes=[Axis(data=y, index=0, label='y_axis', units='yunits'),
600
+ Axis(data=x, index=1, label='x_axis', units='xunits')])
601
+ elif data_shape == '1D':
602
+ data = [np.sum(data, axis=(0, 1, 2))]
603
+ dataraw = DataRaw('NDdata', data=data, dim='DataND', nav_indexes=[],
604
+ axes=[Axis(data=z, index=0, label='z_axis', units='zunits')])
605
+ self._show_data(dataraw, force_update=True)
606
+
607
+ def update_widget_visibility(self, data: DataRaw = None):
608
+ if data is None:
609
+ data = self._data
610
+ self.viewer0D.setVisible(len(data.shape) - len(data.nav_indexes) == 0)
611
+ self.viewer1D.setVisible(len(data.shape) - len(data.nav_indexes) == 1)
612
+ self.viewer2D.setVisible(len(data.shape) - len(data.nav_indexes) == 2)
613
+ self.viewer1D.roi.setVisible(len(data.nav_indexes) != 0)
614
+ self.viewer2D.roi.setVisible(len(data.nav_indexes) != 0)
615
+ self._dock_navigation.setVisible(len(data.nav_indexes) != 0)
616
+ nav_axes = data.get_nav_axes()
617
+
618
+ if data.distribution.name == 'uniform':
619
+ self.navigator1D.setVisible(len(nav_axes) == 1)
620
+ self.navigator2D.setVisible(len(nav_axes) == 2)
621
+ self.axes_viewer.setVisible(len(data.nav_indexes) > 2)
622
+ else:
623
+ self.navigator1D.setVisible(len(nav_axes) == 1 or len(nav_axes) > 2)
624
+ self.navigator2D.setVisible(len(nav_axes) == 2 and self.data_displayer.triangulation)
625
+ self.navigator1D.setVisible(len(nav_axes) == 2 and not self.data_displayer.triangulation)
626
+
627
+ def update_filters(self, processor: DataProcessorFactory):
628
+ self.get_action('filters').clear()
629
+ self.get_action('filters').addItems(processor.functions_filtered('DataND'))
630
+
631
+ def show_settings(self, show: bool = True):
632
+ if show:
633
+ self.settings_tree.show()
634
+ else:
635
+ self.settings_tree.hide()
636
+
637
+ def prepare_ui(self):
638
+ self.navigator1D.setVisible(False)
639
+ self.viewer2D.setVisible(False)
640
+ self.navigator1D.setVisible(False)
641
+ self.viewer2D.setVisible(False)
642
+
643
+ def setup_actions(self):
644
+ self.add_action('setaxes', icon_name='cartesian', checkable=True, tip='Change navigation/signal axes')
645
+ self.add_widget('filters', QtWidgets.QComboBox, tip='Filter type to apply to signal data')
646
+
647
+ def reshape_data(self):
648
+ _nav_indexes = [int(index) for index in
649
+ self.settings.child('data_shape_settings', 'navigator_axes').value()['selected']]
650
+ self.update_widget_visibility()
651
+ self.data_displayer.update_nav_indexes(_nav_indexes)
652
+
653
+ def connect_things(self):
654
+ self.settings.child('set_data_1D').sigActivated.connect(lambda: self.set_data_test('1D'))
655
+ self.settings.child('set_data_2D').sigActivated.connect(lambda: self.set_data_test('2D'))
656
+ self.settings.child('set_data_3D').sigActivated.connect(lambda: self.set_data_test('3D'))
657
+ self.settings.child('set_data_4D').sigActivated.connect(lambda: self.set_data_test('4D'))
658
+ self.settings.child('set_data_spread2D0D').sigActivated.connect(lambda: self.set_data_test('spread2D0D'))
659
+ self.settings.child('set_data_spread2D1D').sigActivated.connect(lambda: self.set_data_test('spread2D1D'))
660
+ self.settings.child('set_data_spread2D2D').sigActivated.connect(lambda: self.set_data_test('spread2D2D'))
661
+ self.settings.child('set_data_spread1D0D').sigActivated.connect(lambda: self.set_data_test('spread1D0D'))
662
+ self.settings.child('set_data_spread1D1D').sigActivated.connect(lambda: self.set_data_test('spread1D1D'))
663
+ self.settings.child('set_data_spread1D2D').sigActivated.connect(lambda: self.set_data_test('spread1D2D'))
664
+ self.settings.child('set_data_spread3D0D').sigActivated.connect(lambda: self.set_data_test('spread3D0D'))
665
+ self.settings.child('data_shape_settings', 'set_nav_axes').sigActivated.connect(self.reshape_data)
666
+
667
+ self.navigator1D.get_action('crosshair').trigger()
668
+ self.connect_action('setaxes', self.show_settings)
669
+
670
+ def setup_widgets(self):
671
+ self.parent.setLayout(QtWidgets.QVBoxLayout())
672
+ self.parent.layout().addWidget(self.toolbar)
673
+
674
+ self._area = DockArea()
675
+ self.parent.layout().addWidget(self._area)
676
+
677
+ viewer0D_widget = QtWidgets.QWidget()
678
+ self.viewer0D = Viewer0D(viewer0D_widget)
679
+
680
+ viewer1D_widget = QtWidgets.QWidget()
681
+ self.viewer1D = Viewer1D(viewer1D_widget)
682
+ self.viewer1D.roi = LinearROI()
683
+ self.viewer1D.view.plotitem.addItem(self.viewer1D.roi)
684
+
685
+ viewer2D_widget = QtWidgets.QWidget()
686
+ self.viewer2D = Viewer2D(viewer2D_widget)
687
+ self.viewer2D.roi = SimpleRectROI(centered=True)
688
+ self.viewer2D.view.plotitem.addItem(self.viewer2D.roi)
689
+
690
+ self.viewer2D.set_action_visible('flip_ud', False)
691
+ self.viewer2D.set_action_visible('flip_lr', False)
692
+ self.viewer2D.set_action_visible('rotate', False)
693
+ self.viewer2D.get_action('autolevels').trigger()
694
+
695
+ self._dock_signal = Dock('Signal')
696
+ self._dock_signal.addWidget(viewer0D_widget)
697
+ self._dock_signal.addWidget(viewer1D_widget)
698
+ self._dock_signal.addWidget(viewer2D_widget)
699
+
700
+ navigator1D_widget = QtWidgets.QWidget()
701
+ self.navigator1D = Viewer1D(navigator1D_widget)
702
+ navigator2D_widget = QtWidgets.QWidget()
703
+ self.navigator2D = Viewer2D(navigator2D_widget)
704
+ self.navigator2D.get_action('autolevels').trigger()
705
+ self.navigator2D.get_action('crosshair').trigger()
706
+
707
+ nav_axes_widget = QtWidgets.QWidget()
708
+ nav_axes_widget.setVisible(False)
709
+ self.axes_viewer = AxesViewer(nav_axes_widget)
710
+
711
+ self._dock_navigation = Dock('Navigation')
712
+ self._dock_navigation.addWidget(navigator1D_widget)
713
+ self._dock_navigation.addWidget(navigator2D_widget)
714
+ self._dock_navigation.addWidget(nav_axes_widget)
715
+
716
+ self._area.addDock(self._dock_navigation)
717
+ self._area.addDock(self._dock_signal, 'right', self._dock_navigation)
718
+
719
+ def update_data_dim(self, dim: str):
720
+ self.settings.child('data_shape_settings', 'data_shape').setValue(dim)
721
+
722
+
723
+ def main():
724
+ app = QtWidgets.QApplication(sys.argv)
725
+ widget = QtWidgets.QWidget()
726
+ prog = ViewerND(widget)
727
+ for child in prog.settings.children():
728
+ if 'set_data_' in child.name():
729
+ child.show(True)
730
+ prog.show_settings()
731
+
732
+ widget.show()
733
+ sys.exit(app.exec_())
734
+
735
+
736
+ if __name__ == '__main__':
737
+ main()
738
+