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,224 @@
1
+ # -*- coding: utf-8 -*-
2
+ """
3
+ Created the 03/11/2022
4
+
5
+ @author: Sebastien Weber
6
+ """
7
+ from collections import OrderedDict
8
+ from pyqtgraph import PlotCurveItem
9
+ from qtpy.QtCore import QObject, Signal, Slot
10
+ from pymodaq.utils.plotting.utils.plot_utils import Data0DWithHistory
11
+ from pymodaq.utils.managers.roi_manager import ROIManager
12
+ from pymodaq.utils.plotting.items.crosshair import Crosshair
13
+ from pymodaq.utils.logger import set_logger, get_module_name
14
+ import pymodaq.utils.daq_utils as utils
15
+ from pymodaq.utils.logger import set_logger, get_module_name
16
+
17
+
18
+ logger = set_logger(get_module_name(__file__))
19
+ IMAGE_TYPES = ['red', 'green', 'blue']
20
+ COLOR_LIST = utils.plot_colors
21
+ COLORS_DICT = dict(red=(255, 0, 0), green=(0, 255, 0), blue=(0, 0, 255), spread=(128, 128, 128))
22
+
23
+
24
+ def curve_item_factory(pen='red'):
25
+ """
26
+ Create a PlotCurveItem with the given pen
27
+ Parameters
28
+ ----------
29
+ pen: any type of arguments accepted by pyqtgraph.function.mkColor or one of the COLORS_DICT key
30
+
31
+ Returns
32
+ -------
33
+ PlotCurveItem
34
+ """
35
+ if isinstance(pen, str):
36
+ if pen in COLORS_DICT:
37
+ pen = COLORS_DICT[pen]
38
+ return PlotCurveItem(pen=pen)
39
+
40
+
41
+ class LineoutPlotter(QObject):
42
+ """Base class to manage and display data filtered out into lineouts (1D, 0D)
43
+
44
+ Should be inherited and subclass some methods as appropriate
45
+
46
+ Parameters
47
+ ----------
48
+ graph_widgets: OrderedDict
49
+ Includes plotwidgets to display data
50
+ roi_manager:
51
+ The ROIManager to create ROIs and manage their properties
52
+ crosshair:
53
+ The Crosshair object
54
+ """
55
+
56
+ roi_changed = Signal(dict)
57
+ crosshair_lineout_plotted = Signal(dict)
58
+ roi_lineout_plotted = Signal(dict)
59
+
60
+ lineout_widgets = ['int'] # should be reimplemented see viewer2D
61
+
62
+ def __init__(self, graph_widgets: OrderedDict, roi_manager: ROIManager, crosshair: Crosshair):
63
+ super().__init__()
64
+
65
+ self._roi_manager = roi_manager
66
+ self._crosshair = crosshair
67
+
68
+ self._lineout_widgets = graph_widgets['lineouts']
69
+
70
+ self.integrated_data = Data0DWithHistory()
71
+
72
+ self._roi_curves = OrderedDict()
73
+ self._crosshair_curves = OrderedDict()
74
+ self._data_integrated = []
75
+
76
+ self.setup_crosshair()
77
+
78
+ self._roi_manager.new_ROI_signal.connect(self.add_ROI)
79
+ self._roi_manager.remove_ROI_signal.connect(self.remove_ROI)
80
+ self._roi_manager.roi_value_changed.connect(self.update_roi)
81
+
82
+ def plot_roi_lineouts(self, roi_dicts):
83
+ self.integrated_data.add_datas({roi_key: roi_dicts[roi_key].int_data for roi_key in roi_dicts})
84
+ for roi_key, lineout_data in roi_dicts.items():
85
+ if roi_key in self._roi_curves:
86
+ self._roi_curves[roi_key]['int'].setData(self.integrated_data.xaxis,
87
+ self.integrated_data.datas[roi_key])
88
+ self.plot_other_lineouts(roi_dicts)
89
+
90
+ logger.debug('roi lineouts plotted')
91
+ self.roi_lineout_plotted.emit(roi_dicts)
92
+
93
+ def plot_other_lineouts(self, roi_dicts):
94
+ raise NotImplementedError
95
+
96
+ def plot_crosshair_lineouts(self, crosshair_dict):
97
+ self.plot_other_crosshair_lineouts(crosshair_dict)
98
+
99
+ logger.debug('crosshair lineouts plotted')
100
+ self.crosshair_lineout_plotted.emit(crosshair_dict)
101
+
102
+ def plot_other_crosshair_lineouts(self, crosshair_dict):
103
+ raise NotImplementedError
104
+
105
+ def get_lineout_widget(self, name):
106
+ if name not in self.lineout_widgets:
107
+ raise KeyError(f'The lineout_widget reference should be within {self.lineout_widgets} not {name}')
108
+ return self._lineout_widgets[name]
109
+
110
+ @Slot(str, tuple)
111
+ def update_roi(self, roi_key, param_changed):
112
+ param, param_value = param_changed
113
+
114
+ if param.name() == 'Color':
115
+ for curve in self._roi_curves[roi_key].values():
116
+ curve.setPen(param_value)
117
+
118
+ self.roi_changed.emit(self._roi_manager.ROIs)
119
+
120
+ @Slot(str)
121
+ def remove_ROI(self, roi_name):
122
+ index = int(roi_name.split('_')[1])
123
+ self.remove_roi_lineout_items(index)
124
+ self.roi_changed.emit(self._roi_manager.ROIs)
125
+
126
+ @Slot(int, str)
127
+ def add_ROI(self, newindex, roi_type):
128
+ item = self._roi_manager.get_roi_from_index(newindex)
129
+ item.sigRegionChangeFinished.connect(lambda: self.roi_changed.emit(self._roi_manager.ROIs))
130
+ item_param = self._roi_manager.settings.child('ROIs', 'ROI_{:02d}'.format(newindex))
131
+ color = item_param.child('Color').value()
132
+
133
+ self.add_roi_lineout_items(newindex, color)
134
+ self.roi_changed.emit(self._roi_manager.ROIs)
135
+
136
+ def add_roi_lineout_items(self, index, pen):
137
+ """
138
+ Add specifics lineouts generated from ROIs
139
+ Parameters
140
+ ----------
141
+ index: (int) index of the ROI generating these lineouts
142
+ pen: (str, tuple) any argument able to generate a QPen, see pyqtgraph.functions.mkPen
143
+ """
144
+ self._roi_curves[f'ROI_{index:02d}'] = \
145
+ {curv_key: curve_item_factory(pen) for curv_key in self.lineout_widgets}
146
+ self.add_lineout_items(*self._roi_curves[f'ROI_{index:02d}'].values())
147
+
148
+ def remove_roi_lineout_items(self, index):
149
+ """
150
+ Remove specifics lineouts generated from ROI referenced by a unique integer
151
+ Parameters
152
+ ----------
153
+ index: (int) index of the ROI generating these lineouts
154
+ """
155
+ items = self._roi_curves.pop(f'ROI_{index:02d}')
156
+ self.remove_lineout_items(*items.values())
157
+
158
+ def add_lineout_items(self, *curve_items):
159
+ """
160
+ Add Curve items sequentially to lineouts widgets: (hor, ver and int)
161
+ Parameters
162
+ ----------
163
+ curve_items: (PlotCurveItem) at most 3 of them
164
+ """
165
+ for ind, curve_item in enumerate(curve_items):
166
+ self.get_lineout_widget(self.lineout_widgets[ind]).addItem(curve_item)
167
+
168
+ def remove_lineout_items(self, *curve_items):
169
+ """
170
+ Remove Curve items sequentially to lineouts widgets: (hor, ver and int)
171
+ Parameters
172
+ ----------
173
+ curve_items: (PlotCurveItem) at most 3 of them
174
+ """
175
+
176
+ for ind, curve_item in enumerate(curve_items):
177
+ self.get_lineout_widget(self.lineout_widgets[ind]).removeItem(curve_item)
178
+
179
+ @Slot(bool)
180
+ def roi_clicked(self, isroichecked=True):
181
+ self._roi_manager.roiwidget.setVisible(isroichecked)
182
+
183
+ for k, roi in self._roi_manager.ROIs.items():
184
+ roi.setVisible(isroichecked)
185
+ for item in self.get_roi_curves_triplet()[k].values():
186
+ item.setVisible(isroichecked)
187
+
188
+ @Slot(bool)
189
+ def crosshair_clicked(self, iscrosshairchecked=True):
190
+ for image_key in IMAGE_TYPES:
191
+ self.show_crosshair_curves(image_key, iscrosshairchecked)
192
+
193
+ def get_roi_curves_triplet(self):
194
+ """
195
+ Get the dictionary (one key by ROI) containing dicts with ROI PlotCurveItem
196
+
197
+ Example:
198
+ --------
199
+ >>> roi_dict_triplet = self.get_roi_cruves_triplet()
200
+ >>> hor_curve = roi_dict_triplet['ROI_00']['hor'] # where 'hor' is an entry of self.lineout_widgets
201
+ """
202
+ return self._roi_curves
203
+
204
+ def get_crosshair_curves_triplet(self):
205
+ """
206
+ Get the dictionary (one key by ImageItem, see IMAGE_TYPES) containing dicts with PlotCurveItem
207
+
208
+ Example:
209
+ --------
210
+ >>> crosshair_dict_triplet = self.get_crosshair_curves_triplet()
211
+ >>> hor_curve = crosshair_dict_triplet['blue']['hor'] # where 'hor' is an entry of self.lineout_widgets
212
+ """
213
+ return self._crosshair_curves
214
+
215
+ def get_crosshair_curve_triplet(self, curve_name):
216
+ return self._crosshair_curves[curve_name]
217
+
218
+ def setup_crosshair(self):
219
+ """to reimplement if needed"""
220
+ pass
221
+
222
+ def show_crosshair_curves(self, curve_key, show=True):
223
+ """to reimplement if needed"""
224
+ pass
@@ -1,14 +1,160 @@
1
+ from collections.abc import Iterable
2
+
3
+ import copy
4
+ from numbers import Real, Number
5
+ from typing import List, Union
6
+ from typing import Iterable as IterableType
7
+
8
+ from easydict import EasyDict as edict
1
9
  from multipledispatch import dispatch
2
- from pymodaq.daq_utils.plotting.items.axis_scaled import AxisItem_Scaled
3
- from qtpy import QtGui, QtCore
4
- import pyqtgraph as pg
5
10
  import numpy as np
11
+ import pyqtgraph as pg
12
+ from qtpy import QtGui, QtCore, QtWidgets
6
13
  from scipy.spatial import Delaunay as Triangulation
7
- import copy
8
- from easydict import EasyDict as edict
9
14
 
10
- from pymodaq.daq_utils import daq_utils as utils
11
- from pymodaq.daq_utils.messenger import deprecation_msg
15
+ from pymodaq.utils import data as data_mod
16
+ from pymodaq.utils.plotting.items.axis_scaled import AxisItem_Scaled
17
+ from pymodaq.utils.plotting.data_viewers.viewer1Dbasic import Viewer1DBasic
18
+ from pymodaq.utils import daq_utils as utils
19
+ from pymodaq.utils.messenger import deprecation_msg
20
+
21
+
22
+ class Point:
23
+ def __init__(self, *elt: IterableType[float]):
24
+ """Initialize a geometric point in an arbitrary number of dimensions
25
+
26
+ Parameters
27
+ ----------
28
+ elt: either a tuple of floats, passed as multiple parameters or a single Iterable parameter
29
+ """
30
+ if len(elt) == 1 and isinstance(elt[0], Iterable):
31
+ elt = elt[0]
32
+
33
+ self._coordinates = np.atleast_1d(np.squeeze(elt))
34
+ self._ndim = len(elt)
35
+
36
+ @property
37
+ def coordinates(self):
38
+ return self._coordinates
39
+
40
+ def copy(self):
41
+ return Point(self.coordinates.copy())
42
+
43
+ def __getitem__(self, item: int):
44
+ return self._coordinates[item]
45
+
46
+ def __setitem__(self, key: int, value: float):
47
+ self._coordinates[key] = value
48
+
49
+ def __len__(self):
50
+ return self._ndim
51
+
52
+ def _compare_length(self, other: 'Point'):
53
+ if len(self) != len(other):
54
+ raise ValueError('Those points should be expressed in the same coordinate system and dimensions')
55
+
56
+ def __add__(self, other: Union['Point', 'Vector']):
57
+ self._compare_length(other)
58
+ return Point(*(self._coordinates + other._coordinates))
59
+
60
+ def __sub__(self, other: 'Point'):
61
+ self._compare_length(other)
62
+ return Point(*(self._coordinates - other._coordinates))
63
+
64
+ def __repr__(self):
65
+ return f'Point({self.coordinates})'
66
+
67
+
68
+ class Vector:
69
+ def __init__(self, coordinates: Union[Point, np.ndarray], origin: Point = None):
70
+ if isinstance(coordinates, Point):
71
+ self._coordinates = coordinates.coordinates
72
+ else:
73
+ self._coordinates = coordinates
74
+
75
+ if origin is None:
76
+ origin = np.zeros((len(coordinates)))
77
+ else:
78
+ self._compare_length(origin)
79
+
80
+ self._origin = origin
81
+
82
+ def _compare_length(self, other: 'Point'):
83
+ if len(self) != len(other):
84
+ raise ValueError('Those Points/Vectors should be expressed in the same coordinate system and dimensions')
85
+
86
+ @property
87
+ def origin(self):
88
+ return self._origin
89
+
90
+ @property
91
+ def coordinates(self):
92
+ return self._coordinates
93
+
94
+ def copy(self):
95
+ return Vector(self.coordinates.copy(), origin=self.origin.copy())
96
+
97
+ def __len__(self):
98
+ return len(self._coordinates)
99
+
100
+ def norm(self):
101
+ return np.linalg.norm(self._coordinates)
102
+
103
+ def unit_vector(self):
104
+ return self * (1 / self.norm())
105
+
106
+ def __add__(self, other: 'Vector'):
107
+ self._compare_length(other)
108
+ return Vector(self.coordinates + other.coordinates, origin=self.origin.copy())
109
+
110
+ def __sub__(self, other: 'Vector'):
111
+ self._compare_length(other)
112
+ return Vector(self.coordinates - other.coordinates, origin=self.origin.copy())
113
+
114
+ def __mul__(self, other: Number):
115
+ if not isinstance(other, Number):
116
+ raise TypeError(f'Cannot multiply a vector with {other}')
117
+ return Vector(other * self.coordinates, origin=self.origin.copy())
118
+
119
+ def dot(self, other: 'Vector'):
120
+ self._compare_length(other)
121
+ return np.dot(self.coordinates, other.coordinates)
122
+
123
+ def cross(self, other: 'Vector'):
124
+ self._compare_length(other)
125
+ return np.cross(self.coordinates, other.coordinates)
126
+
127
+ def __repr__(self):
128
+ return f'Vector({self.coordinates})/Origin({self.origin.coordinates})'
129
+
130
+
131
+ def get_sub_segmented_positions(spacing: float, points: List[Point]) -> List[np.ndarray]:
132
+ """Get Points coordinates spaced in between subsequent Points
133
+
134
+ Parameters
135
+ ----------
136
+ spacing: float
137
+ Distance between two subpoints
138
+ points: List[Point]
139
+ List of Points in arbitrary dimension forming segments one want to sample with a distance equal to spacing
140
+
141
+ Returns
142
+ -------
143
+ List[np.ndarray]: The list of the coordinates of the points
144
+ """
145
+ positions = []
146
+ for ind in range(len(points) - 1):
147
+ vect = Vector(points[ind+1]-points[ind], origin=points[ind])
148
+ npts = 0
149
+ while npts * spacing < vect.norm():
150
+ positions.append(
151
+ (vect.origin + vect.unit_vector() * npts * spacing).coordinates)
152
+ npts += 1
153
+
154
+ # # add_last point not taken into account
155
+ positions.append(points[-1].coordinates)
156
+ return positions
157
+
12
158
 
13
159
  class QVector(QtCore.QLineF):
14
160
  def __init__(self, *elt):
@@ -253,13 +399,35 @@ def makePolygons(tri):
253
399
 
254
400
 
255
401
  class Data0DWithHistory:
402
+ """Object to store scalar values and keep a history of a given length to them"""
256
403
  def __init__(self, Nsamples=200):
257
404
  super().__init__()
258
405
  self._datas = dict([])
259
- self.Nsamples = Nsamples
406
+ self._Nsamples = Nsamples
260
407
  self._xaxis = None
261
408
  self._data_length = 0
262
409
 
410
+ @property
411
+ def size(self):
412
+ return self._data_length
413
+
414
+ @property
415
+ def length(self):
416
+ return self._Nsamples
417
+
418
+ @length.setter
419
+ def length(self, history_length: int):
420
+ if history_length > 0:
421
+ self._Nsamples = history_length
422
+
423
+ def __len__(self):
424
+ return self.length
425
+
426
+ @dispatch(data_mod.DataWithAxes)
427
+ def add_datas(self, data: data_mod.DataRaw):
428
+ datas = {data.labels[ind]: data.data[ind] for ind in range(len(data))}
429
+ self.add_datas(datas)
430
+
263
431
  @dispatch(list)
264
432
  def add_datas(self, datas: list):
265
433
  """
@@ -279,12 +447,12 @@ class Data0DWithHistory:
279
447
  ----------
280
448
  datas: (dict) dictionaary of floats or np.array(float)
281
449
  """
282
- if len(datas) != len(self._datas):
450
+ if datas.keys() != self._datas.keys():
283
451
  self.clear_data()
284
452
 
285
453
  self._data_length += 1
286
454
 
287
- if self._data_length > self.Nsamples:
455
+ if self._data_length > self._Nsamples:
288
456
  self._xaxis += 1
289
457
  else:
290
458
  self._xaxis = np.linspace(0, self._data_length, self._data_length, endpoint=False)
@@ -298,7 +466,7 @@ class Data0DWithHistory:
298
466
  else:
299
467
  self._datas[data_key] = np.concatenate((self._datas[data_key], data))
300
468
 
301
- if self._data_length > self.Nsamples:
469
+ if self._data_length > self._Nsamples:
302
470
  self._datas[data_key] = self._datas[data_key][1:]
303
471
 
304
472
  @property
@@ -315,76 +483,20 @@ class Data0DWithHistory:
315
483
  self._xaxis = np.array([])
316
484
 
317
485
 
318
- class AxisInfosExtractor:
319
-
320
- @staticmethod
321
- @dispatch(np.ndarray)
322
- def extract_axis_info(axis: np.ndarray):
323
- label = ''
324
- units = ''
325
- data = axis
326
-
327
- scaling = 1
328
- offset = 0
329
- if data is not None:
330
- if len(data) > 1:
331
- scaling = data[1] - data[0]
332
- if scaling > 0:
333
- offset = np.min(data)
334
- else:
335
- offset = np.max(data)
336
-
337
- return scaling, offset, label, units
338
-
339
- @staticmethod
340
- @dispatch(utils.Axis)
341
- def extract_axis_info(axis: utils.Axis):
342
- data = None
343
- if 'data' in axis:
344
- data = axis['data']
345
- label = axis['label']
346
- units = axis['units']
347
-
348
- scaling = 1
349
- offset = 0
350
- if data is not None:
351
- if len(data) > 1:
352
- scaling = data[1] - data[0]
353
- if scaling > 0:
354
- offset = np.min(data)
355
- else:
356
- offset = np.max(data)
357
-
358
- return scaling, offset, label, units
359
-
360
- @staticmethod
361
- @dispatch(edict)
362
- def extract_axis_info(axis: edict):
363
- deprecation_msg('edict should not be used to store axis info, use daq_utils.Axis')
364
- data = None
365
- if 'data' in axis:
366
- data = axis['data']
367
- label = axis['label']
368
- units = axis['units']
369
-
370
- scaling = 1
371
- offset = 0
372
- if data is not None:
373
- if len(data) > 1:
374
- scaling = data[1] - data[0]
375
- if scaling > 0:
376
- offset = np.min(data)
377
- else:
378
- offset = np.max(data)
379
-
380
- return scaling, offset, label, units
381
-
382
- @staticmethod
383
- @dispatch(AxisItem_Scaled)
384
- def extract_axis_info(axis: AxisItem_Scaled):
385
- label = axis.axis_label
386
- units = axis.axis_units
387
- scaling = axis.axis_scaling
388
- offset = axis.axis_offset
389
-
390
- return scaling, offset, label, units
486
+ class View_cust(pg.ViewBox):
487
+ """Custom ViewBox used to enable other properties compared to parent class: pg.ViewBox
488
+
489
+ """
490
+ sig_double_clicked = QtCore.Signal(float, float)
491
+
492
+ def __init__(self, parent=None, border=None, lockAspect=False, enableMouse=True, invertY=False,
493
+ enableMenu=True, name=None, invertX=False):
494
+ super().__init__(parent, border, lockAspect, enableMouse, invertY, enableMenu, name, invertX)
495
+
496
+ def mouseClickEvent(self, ev):
497
+ if ev.button() == QtCore.Qt.RightButton and self.menuEnabled():
498
+ ev.accept()
499
+ self.raiseContextMenu(ev)
500
+ if ev.double():
501
+ pos = self.mapToView(ev.pos())
502
+ self.sig_double_clicked.emit(pos.x(), pos.y())
@@ -10,7 +10,7 @@ import collections
10
10
  import copy
11
11
 
12
12
  import math
13
- from pymodaq.daq_utils import daq_utils as utils
13
+ from pymodaq.utils import daq_utils as utils
14
14
 
15
15
 
16
16
  # %%
@@ -61,7 +61,7 @@ def isfloat(number):
61
61
 
62
62
 
63
63
  def iterable_not_string(thing):
64
- return isinstance(thing, collections.Iterable) and not isinstance(thing, str)
64
+ return isinstance(thing, collections.abc.Iterable) and not isinstance(thing, str)
65
65
 
66
66
 
67
67
  class SpecialSlicers(object):
@@ -390,16 +390,6 @@ class DataAxis(object):
390
390
 
391
391
  return my_slice
392
392
 
393
- @property
394
- def index_in_array(self):
395
- if self.axes_manager is not None:
396
- return self.axes_manager._axes.index(self)
397
- else:
398
- raise AttributeError(
399
- "This DataAxis does not belong to an AxesManager"
400
- " and therefore its index_in_array attribute "
401
- " is not defined")
402
-
403
393
  def value2index(self, value, rounding=round):
404
394
  """Return the closest index to the given value if between the limit.
405
395
 
@@ -741,7 +731,7 @@ class AxesManager(object):
741
731
 
742
732
  class Signal(FancySlicing):
743
733
 
744
- def __init__(self, data, **kwds):
734
+ def __init__(self, data: np.ndarray, **kwds):
745
735
  """Create a Signal from a numpy array.
746
736
 
747
737
  Parameters
@@ -761,6 +751,20 @@ class Signal(FancySlicing):
761
751
  self.inav = SpecialSlicersSignal(self, True)
762
752
  self.isig = SpecialSlicersSignal(self, False)
763
753
 
754
+ def get_data_dimension(self):
755
+ dimension = "("
756
+ for ind, ax in enumerate(self.axes_manager.navigation_shape):
757
+ if ind != len(self.axes_manager.navigation_shape) - 1:
758
+ dimension += str(ax) + ','
759
+ else:
760
+ dimension += str(ax) + '|'
761
+ for ind, ax in enumerate(self.axes_manager.signal_shape):
762
+ if ind != len(self.axes_manager.signal_shape) - 1:
763
+ dimension += str(ax) + ','
764
+ else:
765
+ dimension += str(ax) + ')'
766
+ return dimension
767
+
764
768
  def _remove_axis(self, axes):
765
769
  am = self.axes_manager
766
770
  axes = am[axes]
@@ -789,6 +793,10 @@ class Signal(FancySlicing):
789
793
  def data(self, value):
790
794
  self._data = np.atleast_1d(np.asanyarray(value))
791
795
 
796
+ @property
797
+ def shape(self):
798
+ return self._data.shape
799
+
792
800
  def __repr__(self):
793
801
  unfolded = ""
794
802
  string = '<'
@@ -0,0 +1,76 @@
1
+ # -*- coding: utf-8 -*-
2
+ """
3
+ Created the 04/11/2022
4
+
5
+ @author: Sebastien Weber
6
+ """
7
+
8
+ import pyqtgraph as pg
9
+ from qtpy import QtWidgets
10
+
11
+ from pymodaq.utils.plotting.utils.plot_utils import View_cust
12
+ from pymodaq.utils.plotting.items.axis_scaled import AXIS_POSITIONS, AxisItem_Scaled
13
+
14
+
15
+ class ImageWidget(pg.GraphicsLayoutWidget):
16
+ """this gives a layout to add imageitems.
17
+ """
18
+
19
+ def __init__(self, parent=None, *args_plotitem, **kwargs_plotitem):
20
+
21
+ super().__init__(parent)
22
+ self.setupUI(*args_plotitem, **kwargs_plotitem)
23
+
24
+ def setAspectLocked(self, lock=True, ratio=1):
25
+ """
26
+ Defines the aspect ratio of the view
27
+ Parameters
28
+ ----------
29
+ lock: (bool) if True aspect ratio is set to ratio, else the aspect ratio is varying when scaling the view
30
+ ratio: (int) aspect ratio between horizontal and vertical axis
31
+ """
32
+ self.plotitem.vb.setAspectLocked(lock=True, ratio=1)
33
+
34
+ def getAxis(self, position):
35
+ return self.plotitem.getAxis(position)
36
+
37
+ def setupUI(self, *args_plotitem, **kwargs_plotitem):
38
+ layout = QtWidgets.QGridLayout()
39
+ # set viewer area
40
+ self.scene_obj = self.scene()
41
+ self.view = View_cust()
42
+ self.plotitem = pg.PlotItem(viewBox=self.view, *args_plotitem, **kwargs_plotitem)
43
+ self.plotItem = self.plotitem # for backcompatibility
44
+ self.setAspectLocked(lock=True, ratio=1)
45
+ self.setCentralItem(self.plotitem)
46
+
47
+ def add_scaled_axis(self, position):
48
+ """
49
+ Add a AxisItem_Scaled to the given position with respect with the plotitem
50
+ Parameters
51
+ ----------
52
+ position: (str) either 'top', 'bottom', 'right' or 'left'
53
+
54
+ Returns
55
+ -------
56
+
57
+ """
58
+ if position not in AXIS_POSITIONS:
59
+ raise ValueError(f'The Axis position {position} should be in {AXIS_POSITIONS}')
60
+ axis = AxisItem_Scaled(position)
61
+ self.plotitem.setAxisItems({position: axis})
62
+ return axis
63
+
64
+
65
+ class PlotWidget(pg.PlotWidget):
66
+ def __init__(self, *args, **kwargs):
67
+ plot_item = pg.PlotItem(viewBox=View_cust())
68
+ super().__init__(*args, plotItem=plot_item, **kwargs)
69
+
70
+ @property
71
+ def view(self):
72
+ return self.getViewBox()
73
+
74
+ @property
75
+ def legend(self):
76
+ return self.plotItem.legend