pymodaq 4.1.4__py3-none-any.whl → 4.2.0__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 (80) hide show
  1. pymodaq/__init__.py +41 -4
  2. pymodaq/control_modules/daq_move.py +33 -74
  3. pymodaq/control_modules/daq_viewer.py +73 -98
  4. pymodaq/control_modules/daq_viewer_ui.py +2 -1
  5. pymodaq/control_modules/move_utility_classes.py +17 -7
  6. pymodaq/control_modules/utils.py +153 -5
  7. pymodaq/control_modules/viewer_utility_classes.py +31 -20
  8. pymodaq/dashboard.py +23 -5
  9. pymodaq/examples/tcp_client.py +97 -0
  10. pymodaq/extensions/__init__.py +4 -0
  11. pymodaq/extensions/bayesian/__init__.py +2 -0
  12. pymodaq/extensions/bayesian/bayesian_optimisation.py +673 -0
  13. pymodaq/extensions/bayesian/utils.py +403 -0
  14. pymodaq/extensions/daq_scan.py +4 -4
  15. pymodaq/extensions/daq_scan_ui.py +2 -1
  16. pymodaq/extensions/pid/pid_controller.py +12 -7
  17. pymodaq/extensions/pid/utils.py +9 -26
  18. pymodaq/extensions/utils.py +3 -0
  19. pymodaq/post_treatment/load_and_plot.py +42 -19
  20. pymodaq/resources/VERSION +1 -1
  21. pymodaq/resources/config_template.toml +9 -24
  22. pymodaq/resources/setup_plugin.py +1 -1
  23. pymodaq/utils/config.py +103 -5
  24. pymodaq/utils/daq_utils.py +37 -138
  25. pymodaq/utils/data.py +614 -95
  26. pymodaq/utils/enums.py +17 -1
  27. pymodaq/utils/factory.py +2 -2
  28. pymodaq/utils/gui_utils/custom_app.py +5 -2
  29. pymodaq/utils/gui_utils/dock.py +33 -4
  30. pymodaq/utils/gui_utils/file_io.py +3 -2
  31. pymodaq/utils/gui_utils/utils.py +14 -1
  32. pymodaq/utils/h5modules/backends.py +9 -1
  33. pymodaq/utils/h5modules/data_saving.py +254 -57
  34. pymodaq/utils/h5modules/saving.py +1 -0
  35. pymodaq/utils/leco/daq_move_LECODirector.py +172 -0
  36. pymodaq/utils/leco/daq_xDviewer_LECODirector.py +170 -0
  37. pymodaq/utils/leco/desktop.ini +2 -0
  38. pymodaq/utils/leco/director_utils.py +58 -0
  39. pymodaq/utils/leco/leco_director.py +88 -0
  40. pymodaq/utils/leco/pymodaq_listener.py +279 -0
  41. pymodaq/utils/leco/utils.py +41 -0
  42. pymodaq/utils/managers/action_manager.py +20 -6
  43. pymodaq/utils/managers/parameter_manager.py +6 -4
  44. pymodaq/utils/managers/roi_manager.py +64 -55
  45. pymodaq/utils/math_utils.py +1 -1
  46. pymodaq/utils/plotting/data_viewers/__init__.py +3 -1
  47. pymodaq/utils/plotting/data_viewers/base.py +286 -0
  48. pymodaq/utils/plotting/data_viewers/viewer.py +29 -202
  49. pymodaq/utils/plotting/data_viewers/viewer0D.py +94 -47
  50. pymodaq/utils/plotting/data_viewers/viewer1D.py +341 -174
  51. pymodaq/utils/plotting/data_viewers/viewer1Dbasic.py +1 -1
  52. pymodaq/utils/plotting/data_viewers/viewer2D.py +271 -181
  53. pymodaq/utils/plotting/data_viewers/viewerND.py +26 -22
  54. pymodaq/utils/plotting/items/crosshair.py +3 -3
  55. pymodaq/utils/plotting/items/image.py +2 -1
  56. pymodaq/utils/plotting/plotter/plotter.py +94 -0
  57. pymodaq/utils/plotting/plotter/plotters/__init__.py +0 -0
  58. pymodaq/utils/plotting/plotter/plotters/matplotlib_plotters.py +134 -0
  59. pymodaq/utils/plotting/plotter/plotters/qt_plotters.py +78 -0
  60. pymodaq/utils/plotting/utils/axes_viewer.py +1 -1
  61. pymodaq/utils/plotting/utils/filter.py +194 -147
  62. pymodaq/utils/plotting/utils/lineout.py +13 -11
  63. pymodaq/utils/plotting/utils/plot_utils.py +89 -12
  64. pymodaq/utils/scanner/__init__.py +0 -3
  65. pymodaq/utils/scanner/scan_config.py +1 -9
  66. pymodaq/utils/scanner/scan_factory.py +10 -36
  67. pymodaq/utils/scanner/scanner.py +3 -2
  68. pymodaq/utils/scanner/scanners/_1d_scanners.py +7 -5
  69. pymodaq/utils/scanner/scanners/_2d_scanners.py +36 -49
  70. pymodaq/utils/scanner/scanners/sequential.py +10 -4
  71. pymodaq/utils/scanner/scanners/tabular.py +10 -5
  72. pymodaq/utils/slicing.py +1 -1
  73. pymodaq/utils/tcp_ip/serializer.py +38 -5
  74. pymodaq/utils/tcp_ip/tcp_server_client.py +25 -17
  75. {pymodaq-4.1.4.dist-info → pymodaq-4.2.0.dist-info}/METADATA +4 -2
  76. {pymodaq-4.1.4.dist-info → pymodaq-4.2.0.dist-info}/RECORD +79 -64
  77. {pymodaq-4.1.4.dist-info → pymodaq-4.2.0.dist-info}/WHEEL +1 -1
  78. pymodaq/resources/config_scan_template.toml +0 -42
  79. {pymodaq-4.1.4.dist-info → pymodaq-4.2.0.dist-info}/entry_points.txt +0 -0
  80. {pymodaq-4.1.4.dist-info → pymodaq-4.2.0.dist-info}/licenses/LICENSE +0 -0
@@ -14,6 +14,7 @@ from pymodaq.utils.plotting.items.crosshair import Crosshair
14
14
  from pymodaq.utils.plotting.items.image import UniformImageItem
15
15
  from pymodaq.utils.plotting.data_viewers.viewer1Dbasic import Viewer1DBasic
16
16
  from pymodaq.utils.logger import set_logger, get_module_name
17
+ from pymodaq.utils.data import DataFromRoi, DataToExport, Axis, DataWithAxes
17
18
 
18
19
 
19
20
  from pymodaq.post_treatment.process_to_scalar import DataProcessorFactory
@@ -47,7 +48,7 @@ class Filter:
47
48
  if filtered_data is not None and self._slot_to_send_data is not None:
48
49
  self._slot_to_send_data(filtered_data)
49
50
 
50
- def _filter_data(self, data: data_mod.DataFromPlugins):
51
+ def _filter_data(self, data: data_mod.DataFromPlugins) -> DataToExport:
51
52
  raise NotImplementedError
52
53
 
53
54
 
@@ -67,18 +68,22 @@ class Filter1DFromCrosshair(Filter):
67
68
  def update_axis(self, axis: data_mod.Axis):
68
69
  self._axis = axis
69
70
 
70
- def _filter_data(self, data: data_mod.DataFromPlugins):
71
- data_dict = dict([])
71
+ def _filter_data(self, data: data_mod.DataFromPlugins) -> DataToExport:
72
+ dte = DataToExport('Crosshair')
72
73
  if data is not None:
73
74
  axis = data.get_axis_from_index(0, create=False)[0]
74
75
  if axis is not None:
75
76
  self.update_axis(axis)
76
77
 
77
78
  self._x, self._y = self.crosshair.get_positions()
78
- ind_x = self._axis.find_index(self._x)
79
- for label, dat in zip(data.labels, data.data):
80
- data_dict[label] = dict(pos=self._axis.get_data()[ind_x], value=dat[ind_x])
81
- return data_dict
79
+ dwa = data.isig[data.axes[0].find_indexes([self._x])[0]]
80
+ dwa.axes = [Axis('x', data=np.array([self._x]))]
81
+ dte.append(dwa)
82
+ # for label, dat in zip(data.labels, data.data):
83
+ # dte.append(DataFromRoi('crosshair', data=[np.array([dat[ind_x]]) for dat in data.data],
84
+ # axes=[Axis(data=np.array([self._axis.get_data()[ind_x]]))],
85
+ # labels=data.labels))
86
+ return dte
82
87
 
83
88
 
84
89
  class Filter2DFromCrosshair(Filter):
@@ -107,70 +112,95 @@ class Filter2DFromCrosshair(Filter):
107
112
  if activate:
108
113
  self.crosshair.crosshair_dragged.emit(*self.crosshair.get_positions())
109
114
 
110
- def _filter_data(self, datas: data_mod.DataFromPlugins):
111
- data_dict = dict([])
112
- if datas is not None:
115
+ def _filter_data(self, dwa: data_mod.DataFromPlugins) -> DataToExport:
116
+ dte = DataToExport('Crosshair')
117
+ if dwa is not None:
113
118
  self._x, self._y = self.crosshair.get_positions()
114
- data_type = datas.distribution
115
- for data_index in range(len(self._image_keys)):
116
- if data_index < len(datas.data):
117
- data = datas.data[data_index]
118
- image_type = self._image_keys[data_index]
119
- if data_type == 'uniform':
120
- data_dict[image_type] = self.get_data_from_uniform(image_type, data)
121
- elif data_type == 'spread':
122
- data_dict[image_type] = self.get_data_from_spread(image_type, data)
123
- return data_dict
124
-
125
- def get_data_from_uniform(self, data_key, data):
126
- hor_axis, ver_axis = \
127
- np.linspace(0, self._graph_items[data_key].width() - 1, self._graph_items[data_key].width()),\
128
- np.linspace(0, self._graph_items[data_key].height() - 1, self._graph_items[data_key].height())
129
-
130
- indx, indy = self.mapfromview(self._x, self._y, data_key)
119
+ data_type = dwa.distribution
120
+ if data_type == 'uniform':
121
+ dte = self.get_data_from_uniform(dwa)
122
+ elif data_type == 'spread':
123
+ dte = self.get_data_from_spread(dwa)
124
+ return dte
125
+
126
+ def get_data_from_uniform(self, dwa: DataWithAxes) -> DataToExport:
127
+ indx, indy = self.mapfromview(self._x, self._y, 'red')
131
128
 
132
129
  data_H_index = slice(None, None, 1)
133
130
  data_V_index = slice(None, None, 1)
134
131
  H_indexes = (utils.rint(indy), data_H_index)
135
132
  V_indexes = (data_V_index, utils.rint(indx))
133
+ dte = DataToExport('Crosshair')
134
+ try:
135
+ if not (0 <= utils.rint(indy) < dwa.shape[0]):
136
+ raise IndexError
137
+ dwa_hor = dwa.isig[H_indexes]
138
+ dwa_hor.labels = [f'Crosshair/{label}' for label in dwa_hor.labels]
139
+ dwa_hor.name = 'hor'
140
+ dte.append(dwa_hor)
141
+ except IndexError:
142
+ pass
143
+ try:
144
+ if not (0 <= utils.rint(indx) < dwa.shape[1]):
145
+ raise IndexError
146
+ dwa_ver = dwa.isig[V_indexes]
147
+ dwa_ver.labels = [f'Crosshair/{label}' for label in dwa_ver.labels]
148
+ dwa_ver.name = 'ver'
149
+ dte.append(dwa_ver)
150
+ except IndexError:
151
+ pass
152
+ try:
153
+ if not (0 <= utils.rint(indy) < dwa.shape[0]) \
154
+ or \
155
+ not (0 <= utils.rint(indx) < dwa.shape[1]):
156
+ raise IndexError
157
+ dwa_int = dwa.isig[utils.rint(indy), utils.rint(indx)]
158
+ dwa_int.labels = [f'Crosshair/{label}' for label in dwa_int.labels]
159
+ dwa_int.name = 'int'
160
+ dte.append(dwa_int)
161
+ except IndexError:
162
+ pass
163
+ return dte
136
164
 
137
- out_of_bounds = False
138
- if 0 <= H_indexes[0] < len(ver_axis):
139
- hor_data = data[H_indexes]
140
- else:
141
- out_of_bounds = True
142
- hor_data = np.zeros(hor_axis.shape)
143
- if 0 <= V_indexes[1] < len(hor_axis):
144
- ver_data = data[V_indexes]
145
- else:
146
- out_of_bounds = True
147
- ver_data = np.zeros(ver_axis.shape)
148
- if out_of_bounds:
149
- ind_data = 0.
150
- else:
151
- ind_data = data[utils.rint(indy), utils.rint(indx)]
152
- return LineoutData(hor_axis=hor_axis, ver_axis=ver_axis, hor_data=hor_data, ver_data=ver_data,
153
- int_data=ind_data)
165
+ def get_data_from_spread(self, dwa: DataWithAxes) -> DataToExport:
154
166
 
155
- def get_data_from_spread(self, data_key, data):
156
167
  data_H_index = slice(None, None, 1)
157
168
  data_V_index = slice(None, None, 1)
158
- posx, posy = self.mapfromview(self._x, self._y, data_key)
169
+ posx, posy = self.mapfromview(self._x, self._y, 'red')
170
+
171
+ hor_data = []
172
+ ver_data = []
173
+ int_data = []
174
+ hor_axis = None
175
+ ver_axis = None
176
+
177
+ for ind, data_key in enumerate(self._graph_items):
178
+ if ind < len(dwa):
179
+ points, data = self._graph_items[data_key].get_points_at(axis='y', val=posy)
180
+ x_sorted_indexes = np.argsort(points[:, 0])
181
+ hor_axis = points[x_sorted_indexes, 0][data_H_index]
159
182
 
160
- points, data = self._graph_items[data_key].get_points_at(axis='y', val=posy)
161
- x_sorted_indexes = np.argsort(points[:, 0])
162
- hor_axis = points[x_sorted_indexes, 0][data_H_index]
183
+ hor_data.append(data[x_sorted_indexes][data_H_index])
163
184
 
164
- hor_data = data[x_sorted_indexes][data_H_index]
185
+ points, data = self._graph_items[data_key].get_points_at(axis='x', val=posx)
186
+ y_sorted_indexes = np.argsort(points[:, 1])
187
+ ver_axis = points[y_sorted_indexes, 1][data_V_index]
165
188
 
166
- points, data = self._graph_items[data_key].get_points_at(axis='x', val=posx)
167
- y_sorted_indexes = np.argsort(points[:, 1])
168
- ver_axis = points[y_sorted_indexes, 1][data_V_index]
189
+ ver_data.append(data[y_sorted_indexes][data_V_index])
169
190
 
170
- ver_data = data[y_sorted_indexes][data_V_index]
191
+ int_data.append(np.array([self._graph_items[data_key].get_val_at((posx, posy))]))
171
192
 
172
- return LineoutData(hor_axis=hor_axis, ver_axis=ver_axis, hor_data=hor_data, ver_data=ver_data,
173
- int_data=self._graph_items[data_key].get_val_at((posx, posy)))
193
+ dte = DataToExport('Crosshair')
194
+ if len(hor_data) > 0 and len(hor_axis) > 0:
195
+ dte.append(DataFromRoi('hor', data=hor_data,
196
+ axes=[Axis(dwa.axes[1].label, dwa.axes[1].units, data=hor_axis)]),)
197
+ if len(ver_data) > 0 and len(ver_axis) > 0:
198
+ dte.append(DataFromRoi('ver', data=ver_data,
199
+ axes=[Axis(dwa.axes[0].label, dwa.axes[0].units, data=ver_axis)]))
200
+ if len(int_data) > 0:
201
+ dte.append(DataFromRoi('int', data=int_data))
202
+
203
+ return dte
174
204
 
175
205
  def mapfromview(self, x, y, item_key='red'):
176
206
  """
@@ -207,39 +237,53 @@ class Filter1DFromRois(Filter):
207
237
  def update_axis(self, axis: data_mod.Axis):
208
238
  self._axis = axis
209
239
 
210
- def _filter_data(self, data: data_mod.DataFromPlugins) -> dict:
211
- data_dict = dict([])
240
+ def _filter_data(self, data: data_mod.DataFromPlugins) -> DataToExport:
241
+ dte = DataToExport('roi1D')
212
242
  try:
213
243
  axis = data.get_axis_from_index(0, create=False)[0]
214
244
  if axis is not None:
215
245
  self.update_axis(axis)
216
246
  if data is not None:
217
247
  for roi_key, roi in self._ROIs.items():
218
- try:
219
- data_index = data.labels.index(self._roi_settings['ROIs', roi_key, 'use_channel'])
220
- except ValueError:
221
- data_index = 0
222
- data_dict[roi_key] = self.get_data_from_roi(roi, self._roi_settings.child('ROIs', roi_key),
223
- data, data_index)
248
+ if self._roi_settings['ROIs', roi_key, 'use_channel'] == 'All':
249
+ data_index = list(range(len(data.labels)))
250
+ else:
251
+ try:
252
+ data_index = [data.labels.index(self._roi_settings['ROIs', roi_key,
253
+ 'use_channel'])]
254
+ except ValueError:
255
+ data_index = [0]
256
+ dte_tmp = self.get_data_from_roi(roi, self._roi_settings.child('ROIs', roi_key),
257
+ data)
258
+ if self._roi_settings['ROIs', roi_key, 'use_channel'] == 'All':
259
+ dte.append(dte_tmp.data)
260
+ else:
261
+ for index in data_index:
262
+ for dwa in dte_tmp.data:
263
+ dte.append(dwa.pop(index))
264
+
224
265
  except Exception as e:
225
266
  pass
226
- return data_dict
267
+ finally:
268
+ return dte
227
269
 
228
- def get_data_from_roi(self, roi: LinearROI, roi_param: Parameter, data: data_mod.DataWithAxes, data_index=0):
270
+ def get_data_from_roi(self, roi: LinearROI, roi_param: Parameter, data: data_mod.DataWithAxes) -> DataToExport:
229
271
  if data is not None:
272
+ dte = DataToExport('ROI1D')
230
273
  _slice = self.get_slice_from_roi(roi, data)
231
- sub_data = data.isig[_slice]
274
+ sub_data: DataFromRoi = data.isig[_slice]
275
+ sub_data.name = 'HorData'
276
+ sub_data.origin = roi_param.name()
277
+ sub_data.labels = [f'{roi_param.name()}/{label}' for label in sub_data.labels]
278
+ dte.append(sub_data)
232
279
  if sub_data.size != 0:
233
280
  processed_data = data_processors.get(roi_param['math_function']).process(sub_data)
234
281
  else:
235
282
  processed_data = None
236
- if processed_data is None:
237
- return LineoutData()
238
- else:
239
- if len(sub_data.axes) == 0:
240
- pass
241
- return LineoutData(hor_axis=sub_data.axes[0], hor_data=sub_data.data[data_index],
242
- int_data=processed_data.data[data_index])
283
+ if processed_data is not None:
284
+ processed_data.name = 'IntData'
285
+ dte.append(processed_data)
286
+ return dte
243
287
 
244
288
  def get_slice_from_roi(self, roi: RectROI, data: data_mod.DataWithAxes) -> slice:
245
289
  ind_x_min, ind_x_max = data.get_axis_from_index(data.sig_indexes[0])[0].find_indexes(roi.getRegion())
@@ -269,39 +313,47 @@ class Filter2DFromRois(Filter):
269
313
  self.axes = (0, 1)
270
314
  self._ROIs = roi_manager.ROIs
271
315
 
272
- def _filter_data(self, data: data_mod.DataFromPlugins) -> dict:
273
- data_dict = dict([])
274
- try:
275
- if data is not None:
316
+ def _filter_data(self, dwa: data_mod.DataFromPlugins) -> DataToExport:
317
+ dte = DataToExport('ROI')
318
+ if dwa is not None:
319
+ try:
320
+ labels = []
276
321
  for roi_key, roi in self._ROIs.items():
277
- image_key = self._roi_settings['ROIs', roi_key, 'use_channel']
278
- image_index = self._image_keys.index(image_key)
279
-
280
- sub_data = data.deepcopy()
281
- sub_data.data = [data[image_index]]
282
- data_dict[roi_key] = self.get_xydata_from_roi(roi, sub_data,
283
- self._roi_settings['ROIs', roi_key, 'math_function'])
284
- except Exception as e:
285
- pass
286
- return data_dict
287
-
288
- def get_slices_from_roi(self, roi: RectROI, data: data_mod.DataWithAxes) -> Tuple[slice]:
322
+ label = self._roi_settings['ROIs', roi_key, 'use_channel']
323
+ if label is not None:
324
+ if label != 'All':
325
+ sub_data = dwa.deepcopy()
326
+ sub_data.data = [dwa[dwa.labels.index(label)]]
327
+ sub_data.labels = [label]
328
+ else:
329
+ sub_data = dwa
330
+ dte_temp = self.get_xydata_from_roi(roi, sub_data,
331
+ self._roi_settings['ROIs',
332
+ roi_key, 'math_function'])
333
+
334
+ dte.append(dte_temp)
335
+ except Exception as e:
336
+ logger.warning(f'Issue with the ROI: {str(e)}')
337
+ return dte
338
+
339
+ def get_slices_from_roi(self, roi: RectROI, data_shape: tuple) -> Tuple[slice, slice]:
289
340
  x, y = roi.pos().x(), roi.pos().y()
290
341
  width, height = roi.size().x(), roi.size().y()
291
- size_x = data.get_axis_from_index(1)[0].size
292
- size_y = data.get_axis_from_index(0)[0].size
342
+ size_y, size_x = data_shape
293
343
  ind_x_min = int(min(max(x, 0), size_x))
294
344
  ind_y_min = int(min(max(y, 0), size_y))
295
345
  ind_x_max = int(max(0, min(x+width, size_x)))
296
346
  ind_y_max = int(max(0, min(y+height, size_y)))
297
-
298
347
  return slice(ind_y_min,ind_y_max), slice(ind_x_min, ind_x_max)
299
348
 
300
- def get_xydata_from_roi(self, roi, data: data_mod.DataWithAxes, math_function: str):
301
-
302
- if data is not None:
303
- if data.distribution.name == 'spread':
304
- xvals, yvals, data = self.get_xydata_spread(data, roi)
349
+ def get_xydata_from_roi(self, roi: RectROI, dwa: DataWithAxes, math_function: str) -> DataToExport:
350
+ dte = DataToExport(roi.name)
351
+ if dwa is not None:
352
+ labels = [f'{roi.name}/{label}' for label in dwa.labels]
353
+ if dwa.distribution.name == 'spread':
354
+ xvals, yvals, data = self.get_xydata_spread(dwa, roi)
355
+ if len(data) == 0:
356
+ return dte
305
357
  ind_xaxis = np.argsort(xvals)
306
358
  ind_yaxis = np.argsort(yvals)
307
359
  xvals = xvals[ind_xaxis]
@@ -309,34 +361,51 @@ class Filter2DFromRois(Filter):
309
361
  data_H = data[ind_xaxis]
310
362
  data_V = data[ind_yaxis]
311
363
  int_data = np.array([np.mean(data)])
312
- math_data = int_data
313
- else:
314
- xvals, yvals, data_array = self.get_xydata(data.data[0], roi)
315
- slices = self.get_slices_from_roi(roi, data)
316
- sub_data = data.isig[slices[0], slices[1]]
317
- data_H = np.mean(data_array, axis=0)
318
- data_V = np.mean(data_array, axis=1)
319
- int_data = np.array([np.mean(data_array)])
320
- math_data = data_processors.get(math_function).process(sub_data).data
321
-
322
- return LineoutData(hor_axis=xvals, ver_axis=yvals, hor_data=data_H, ver_data=data_V, int_data=int_data,
323
- math_data=math_data)
324
-
325
- def get_xydata(self, data: np.ndarray, roi: RectROI):
326
- data, coords = self.data_from_roi(data, roi)
327
364
 
328
- if data is not None:
329
- xvals = np.linspace(np.min(np.min(coords[1, :, :])), np.max(np.max(coords[1, :, :])),
330
- data.shape[1])
331
- yvals = np.linspace(np.min(np.min(coords[0, :, :])), np.max(np.max(coords[0, :, :])),
332
- data.shape[0])
333
- else:
334
- xvals = yvals = data = np.array([])
335
- return xvals, yvals, data
336
-
337
- def data_from_roi(self, data, roi):
338
- data, coords = roi.getArrayRegion(data, self._graph_item, self.axes, returnMappedCoords=True)
339
- return data, coords
365
+ _x_axis = dwa.get_axis_from_index_spread(0, 0)
366
+ x_axis = Axis(_x_axis.label, _x_axis.units, data=xvals, index=0, spread_order=0)
367
+ _y_axis = dwa.get_axis_from_index_spread(0, 1)
368
+ y_axis = Axis(_y_axis.label, _y_axis.units, data=yvals, index=0, spread_order=0)
369
+ sub_data_hor = DataFromRoi('hor', distribution='spread', data=[data_H], axes=[x_axis],)
370
+ sub_data_ver = DataFromRoi('ver', distribution='spread', data=[data_V], axes=[y_axis])
371
+ math_data = DataFromRoi('int', data=int_data)
372
+ else:
373
+ slices = self.get_slices_from_roi(roi, dwa.shape)
374
+ sub_data: DataFromRoi = dwa.isig[slices[0], slices[1]]
375
+ sub_data_hor = sub_data.mean(0)
376
+ sub_data_ver = sub_data.mean(1)
377
+ math_data = data_processors.get(math_function).process(sub_data)
378
+
379
+ sub_data_hor.name = 'hor'
380
+ sub_data_hor.origin = roi.name
381
+ sub_data_hor.labels = labels
382
+ sub_data_ver.name = 'ver'
383
+ sub_data_ver.origin = roi.name
384
+ sub_data_ver.labels = labels
385
+ math_data.name = 'int'
386
+ math_data.origin = roi.name
387
+ math_data.labels = labels
388
+
389
+ dte.append([sub_data_hor, sub_data_ver, math_data])
390
+ return dte
391
+
392
+ #TODO possibly not used anymore to be deleted
393
+ #
394
+ # def get_xydata(self, data: np.ndarray, roi: RectROI):
395
+ # data, coords = self.data_from_roi(data, roi)
396
+ #
397
+ # if data is not None:
398
+ # xvals = np.linspace(np.min(np.min(coords[1, :, :])), np.max(np.max(coords[1, :, :])),
399
+ # data.shape[1])
400
+ # yvals = np.linspace(np.min(np.min(coords[0, :, :])), np.max(np.max(coords[0, :, :])),
401
+ # data.shape[0])
402
+ # else:
403
+ # xvals = yvals = data = np.array([])
404
+ # return xvals, yvals, data
405
+ #
406
+ # def data_from_roi(self, data, roi):
407
+ # data, coords = roi.getArrayRegion(data, self._graph_item, self.axes, returnMappedCoords=True)
408
+ # return data, coords
340
409
 
341
410
  def get_xydata_spread(self, data, roi):
342
411
  xvals = []
@@ -355,28 +424,6 @@ class Filter2DFromRois(Filter):
355
424
  return xvals, yvals, data_out
356
425
 
357
426
 
358
- class LineoutData:
359
- def __init__(self, hor_axis=np.array([]), ver_axis=np.array([]), hor_data=np.array([]), ver_data=np.array([]),
360
- int_data: np.ndarray = None, math_data: List[np.ndarray] = None):
361
- super().__init__()
362
- if len(hor_axis) != len(hor_data):
363
- raise ValueError(f'Horizontal lineout data and axis must have the same size')
364
- if len(ver_axis) != len(ver_data):
365
- raise ValueError(f'Horizontal lineout data and axis must have the same size')
366
-
367
- self.hor_axis = hor_axis
368
- self.ver_axis = ver_axis
369
- self.hor_data = hor_data
370
- self.ver_data = ver_data
371
- if int_data is None:
372
- self.int_data = np.array([np.sum(self.ver_data)])
373
- else:
374
- self.int_data = int_data
375
- if math_data is None:
376
- math_data = self.int_data
377
- self.math_data = math_data
378
-
379
-
380
427
  class FourierFilterer(QObject):
381
428
  filter_changed = Signal(dict)
382
429
 
@@ -13,7 +13,7 @@ from pymodaq.utils.plotting.items.crosshair import Crosshair
13
13
  from pymodaq.utils.logger import set_logger, get_module_name
14
14
  import pymodaq.utils.daq_utils as utils
15
15
  from pymodaq.utils.logger import set_logger, get_module_name
16
-
16
+ from pymodaq.utils.data import DataCalculated
17
17
 
18
18
  logger = set_logger(get_module_name(__file__))
19
19
  IMAGE_TYPES = ['red', 'green', 'blue']
@@ -81,14 +81,15 @@ class LineoutPlotter(QObject):
81
81
 
82
82
  def plot_roi_lineouts(self, roi_dicts):
83
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
84
 
90
- logger.debug('roi lineouts plotted')
91
- self.roi_lineout_plotted.emit(roi_dicts)
85
+ # for roi_key, lineout_data in roi_dicts.items():
86
+ # if roi_key in self._roi_curves:
87
+ # self._roi_curves[roi_key]['int'].setData(self.integrated_data.xaxis,
88
+ # self.integrated_data.datas[roi_key])
89
+ # self.plot_other_lineouts(roi_dicts)
90
+ #
91
+ # logger.debug('roi lineouts plotted')
92
+ # self.roi_lineout_plotted.emit(roi_dicts)
92
93
 
93
94
  def plot_other_lineouts(self, roi_dicts):
94
95
  raise NotImplementedError
@@ -112,8 +113,9 @@ class LineoutPlotter(QObject):
112
113
  param, param_value = param_changed
113
114
 
114
115
  if param.name() == 'Color':
115
- for curve in self._roi_curves[roi_key].values():
116
- curve.setPen(param_value)
116
+ if roi_key in self._roi_curves:
117
+ for curve in self._roi_curves[roi_key].values():
118
+ curve.setPen(param_value)
117
119
 
118
120
  self.roi_changed.emit(self._roi_manager.ROIs)
119
121
 
@@ -130,7 +132,7 @@ class LineoutPlotter(QObject):
130
132
  item_param = self._roi_manager.settings.child('ROIs', 'ROI_{:02d}'.format(newindex))
131
133
  color = item_param.child('Color').value()
132
134
 
133
- self.add_roi_lineout_items(newindex, color)
135
+ #self.add_roi_lineout_items(newindex, color)
134
136
  self.roi_changed.emit(self._roi_manager.ROIs)
135
137
 
136
138
  def add_roi_lineout_items(self, index, pen):
@@ -1,8 +1,9 @@
1
1
  from collections.abc import Iterable
2
+ from dataclasses import dataclass, field
2
3
 
3
4
  import copy
4
5
  from numbers import Real, Number
5
- from typing import List, Union
6
+ from typing import List, Union, Tuple
6
7
  from typing import Iterable as IterableType
7
8
 
8
9
  from easydict import EasyDict as edict
@@ -13,10 +14,15 @@ from qtpy import QtGui, QtCore, QtWidgets
13
14
  from scipy.spatial import Delaunay as Triangulation
14
15
 
15
16
  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
17
+ from pymodaq.utils.managers.roi_manager import LinearROI, RectROI, EllipseROI, pgROI, pgLinearROI
18
+
19
+
20
+ def make_dashed_pens(color: tuple, nstyle=3):
21
+ pens = [dict(color=color)]
22
+ if nstyle > 1:
23
+ for ind in range(nstyle - 1):
24
+ pens.append(dict(color=color, dash=np.array([5, 5]) * (ind + 1)))
25
+ return pens
20
26
 
21
27
 
22
28
  class Point:
@@ -30,7 +36,7 @@ class Point:
30
36
  if len(elt) == 1 and isinstance(elt[0], Iterable):
31
37
  elt = elt[0]
32
38
 
33
- self._coordinates = np.atleast_1d(np.squeeze(elt))
39
+ self._coordinates: np.ndarray = np.atleast_1d(np.squeeze(elt))
34
40
  self._ndim = len(elt)
35
41
 
36
42
  @property
@@ -40,8 +46,8 @@ class Point:
40
46
  def copy(self):
41
47
  return Point(self.coordinates.copy())
42
48
 
43
- def __getitem__(self, item: int):
44
- return self._coordinates[item]
49
+ def __getitem__(self, item: int) -> float:
50
+ return float(self._coordinates[item])
45
51
 
46
52
  def __setitem__(self, key: int, value: float):
47
53
  self._coordinates[key] = value
@@ -53,6 +59,12 @@ class Point:
53
59
  if len(self) != len(other):
54
60
  raise ValueError('Those points should be expressed in the same coordinate system and dimensions')
55
61
 
62
+ def __eq__(self, other):
63
+ if isinstance(other, Point):
64
+ return np.allclose(self.coordinates, other.coordinates)
65
+ else:
66
+ return False
67
+
56
68
  def __add__(self, other: Union['Point', 'Vector']):
57
69
  self._compare_length(other)
58
70
  return Point(*(self._coordinates + other._coordinates))
@@ -403,6 +415,7 @@ class Data0DWithHistory:
403
415
  def __init__(self, Nsamples=200):
404
416
  super().__init__()
405
417
  self._datas = dict([])
418
+ self.last_data: data_mod.DataRaw = None
406
419
  self._Nsamples = Nsamples
407
420
  self._xaxis = None
408
421
  self._data_length = 0
@@ -424,19 +437,21 @@ class Data0DWithHistory:
424
437
  return self.length
425
438
 
426
439
  @dispatch(data_mod.DataWithAxes)
427
- def add_datas(self, data: data_mod.DataRaw):
440
+ def add_datas(self, data: data_mod.DataWithAxes):
441
+ self.last_data = data
428
442
  datas = {data.labels[ind]: data.data[ind] for ind in range(len(data))}
429
443
  self.add_datas(datas)
430
444
 
431
445
  @dispatch(list)
432
- def add_datas(self, datas: list):
446
+ def add_datas(self, data: list):
433
447
  """
434
448
  Add datas to the history
435
449
  Parameters
436
450
  ----------
437
- datas: (list) list of floats or np.array(float)
451
+ data: (list) list of floats or np.array(float)
438
452
  """
439
- datas = {f'data_{ind:02d}': datas[ind] for ind in range(len(datas))}
453
+ self.last_data = data_mod.DataRaw('Data0D', data=[np.array([dat]) for dat in data])
454
+ datas = {f'data_{ind:02d}': data[ind] for ind in range(len(data))}
440
455
  self.add_datas(datas)
441
456
 
442
457
  @dispatch(dict)
@@ -500,3 +515,65 @@ class View_cust(pg.ViewBox):
500
515
  if ev.double():
501
516
  pos = self.mapToView(ev.pos())
502
517
  self.sig_double_clicked.emit(pos.x(), pos.y())
518
+
519
+
520
+ @dataclass
521
+ class RoiInfo:
522
+ """ DataClass holding info about a given ROI
523
+
524
+ Parameters
525
+ ----------
526
+ origin
527
+ size
528
+ angle
529
+ centered
530
+ color
531
+ roi_class
532
+ index
533
+ """
534
+
535
+ origin: Union[Point, IterableType[float]]
536
+ size: Union[Point, IterableType[float]]
537
+ angle: float = None
538
+ centered: bool = False
539
+ color: Tuple[int, int, int] = (255, 0, 0)
540
+ roi_class: type = None
541
+ index: int = 0
542
+
543
+ @classmethod
544
+ def info_from_linear_roi(cls, roi: LinearROI):
545
+ pos = roi.pos()
546
+ return cls(Point((pos[0],)), size=Point((pos[1] - pos[0],)), color=roi.color,
547
+ roi_class=type(roi), index=roi.index)
548
+
549
+ @classmethod
550
+ def info_from_rect_roi(cls, roi: RectROI):
551
+ return cls(Point(list(roi.pos())[::-1]), size=Point((roi.height(), roi.width())),
552
+ color=roi.color, roi_class=type(roi), index=roi.index)
553
+
554
+ def center_origin(self):
555
+ if not self.centered:
556
+ self.origin += Point((self.size[0] / 2, self.size[1] / 2))
557
+ self.centered = True
558
+
559
+ def to_slices(self) -> IterableType[slice]:
560
+ """Get slices to be used directly to slice DataWithAxes"""
561
+ if issubclass(self.roi_class, pgROI):
562
+ if self.centered:
563
+ return (slice(int(self.origin[0] - self.size[0] / 2),
564
+ int(self.origin[0] + self.size[0] / 2)),
565
+ slice(int(self.origin[1] - self.size[1] / 2),
566
+ int(self.origin[1] + self.size[1] / 2)),
567
+ )
568
+ else:
569
+ return (slice(int(self.origin[0]),
570
+ int(self.origin[0] + self.size[0])),
571
+ slice(int(self.origin[1]),
572
+ int(self.origin[1] + self.size[1])),
573
+ )
574
+ elif issubclass(self.roi_class, pgLinearROI):
575
+ if self.centered:
576
+ return (slice(int(self.origin[0] - self.size[0] / 2),
577
+ int(self.origin[0] + self.size[0] / 2)),)
578
+ else:
579
+ return (slice(int(self.origin[0]), int(self.origin[0] + self.size[0])),)
@@ -1,8 +1,5 @@
1
1
  from importlib import import_module
2
2
  from pathlib import Path
3
- from .utils import register_scanners
4
3
 
5
4
 
6
- register_scanners()
7
-
8
5
  from .scanner import Scanner # import this one after the scanners because they have to first be registered