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.
- pymodaq/__init__.py +41 -4
- pymodaq/control_modules/daq_move.py +33 -74
- pymodaq/control_modules/daq_viewer.py +73 -98
- pymodaq/control_modules/daq_viewer_ui.py +2 -1
- pymodaq/control_modules/move_utility_classes.py +17 -7
- pymodaq/control_modules/utils.py +153 -5
- pymodaq/control_modules/viewer_utility_classes.py +31 -20
- pymodaq/dashboard.py +23 -5
- pymodaq/examples/tcp_client.py +97 -0
- pymodaq/extensions/__init__.py +4 -0
- pymodaq/extensions/bayesian/__init__.py +2 -0
- pymodaq/extensions/bayesian/bayesian_optimisation.py +673 -0
- pymodaq/extensions/bayesian/utils.py +403 -0
- pymodaq/extensions/daq_scan.py +4 -4
- pymodaq/extensions/daq_scan_ui.py +2 -1
- pymodaq/extensions/pid/pid_controller.py +12 -7
- pymodaq/extensions/pid/utils.py +9 -26
- pymodaq/extensions/utils.py +3 -0
- pymodaq/post_treatment/load_and_plot.py +42 -19
- pymodaq/resources/VERSION +1 -1
- pymodaq/resources/config_template.toml +9 -24
- pymodaq/resources/setup_plugin.py +1 -1
- pymodaq/utils/config.py +103 -5
- pymodaq/utils/daq_utils.py +37 -138
- pymodaq/utils/data.py +614 -95
- pymodaq/utils/enums.py +17 -1
- pymodaq/utils/factory.py +2 -2
- pymodaq/utils/gui_utils/custom_app.py +5 -2
- pymodaq/utils/gui_utils/dock.py +33 -4
- pymodaq/utils/gui_utils/file_io.py +3 -2
- pymodaq/utils/gui_utils/utils.py +14 -1
- pymodaq/utils/h5modules/backends.py +9 -1
- pymodaq/utils/h5modules/data_saving.py +254 -57
- pymodaq/utils/h5modules/saving.py +1 -0
- pymodaq/utils/leco/daq_move_LECODirector.py +172 -0
- pymodaq/utils/leco/daq_xDviewer_LECODirector.py +170 -0
- pymodaq/utils/leco/desktop.ini +2 -0
- pymodaq/utils/leco/director_utils.py +58 -0
- pymodaq/utils/leco/leco_director.py +88 -0
- pymodaq/utils/leco/pymodaq_listener.py +279 -0
- pymodaq/utils/leco/utils.py +41 -0
- pymodaq/utils/managers/action_manager.py +20 -6
- pymodaq/utils/managers/parameter_manager.py +6 -4
- pymodaq/utils/managers/roi_manager.py +64 -55
- pymodaq/utils/math_utils.py +1 -1
- pymodaq/utils/plotting/data_viewers/__init__.py +3 -1
- pymodaq/utils/plotting/data_viewers/base.py +286 -0
- pymodaq/utils/plotting/data_viewers/viewer.py +29 -202
- pymodaq/utils/plotting/data_viewers/viewer0D.py +94 -47
- pymodaq/utils/plotting/data_viewers/viewer1D.py +341 -174
- pymodaq/utils/plotting/data_viewers/viewer1Dbasic.py +1 -1
- pymodaq/utils/plotting/data_viewers/viewer2D.py +271 -181
- pymodaq/utils/plotting/data_viewers/viewerND.py +26 -22
- pymodaq/utils/plotting/items/crosshair.py +3 -3
- pymodaq/utils/plotting/items/image.py +2 -1
- pymodaq/utils/plotting/plotter/plotter.py +94 -0
- pymodaq/utils/plotting/plotter/plotters/__init__.py +0 -0
- pymodaq/utils/plotting/plotter/plotters/matplotlib_plotters.py +134 -0
- pymodaq/utils/plotting/plotter/plotters/qt_plotters.py +78 -0
- pymodaq/utils/plotting/utils/axes_viewer.py +1 -1
- pymodaq/utils/plotting/utils/filter.py +194 -147
- pymodaq/utils/plotting/utils/lineout.py +13 -11
- pymodaq/utils/plotting/utils/plot_utils.py +89 -12
- pymodaq/utils/scanner/__init__.py +0 -3
- pymodaq/utils/scanner/scan_config.py +1 -9
- pymodaq/utils/scanner/scan_factory.py +10 -36
- pymodaq/utils/scanner/scanner.py +3 -2
- pymodaq/utils/scanner/scanners/_1d_scanners.py +7 -5
- pymodaq/utils/scanner/scanners/_2d_scanners.py +36 -49
- pymodaq/utils/scanner/scanners/sequential.py +10 -4
- pymodaq/utils/scanner/scanners/tabular.py +10 -5
- pymodaq/utils/slicing.py +1 -1
- pymodaq/utils/tcp_ip/serializer.py +38 -5
- pymodaq/utils/tcp_ip/tcp_server_client.py +25 -17
- {pymodaq-4.1.4.dist-info → pymodaq-4.2.0.dist-info}/METADATA +4 -2
- {pymodaq-4.1.4.dist-info → pymodaq-4.2.0.dist-info}/RECORD +79 -64
- {pymodaq-4.1.4.dist-info → pymodaq-4.2.0.dist-info}/WHEEL +1 -1
- pymodaq/resources/config_scan_template.toml +0 -42
- {pymodaq-4.1.4.dist-info → pymodaq-4.2.0.dist-info}/entry_points.txt +0 -0
- {pymodaq-4.1.4.dist-info → pymodaq-4.2.0.dist-info}/licenses/LICENSE +0 -0
|
@@ -1,56 +1,22 @@
|
|
|
1
|
-
from typing import List, Union
|
|
1
|
+
from typing import List, Union
|
|
2
2
|
import numpy as np
|
|
3
3
|
|
|
4
4
|
from qtpy import QtWidgets
|
|
5
|
-
from qtpy.QtCore import QObject, Signal, Slot
|
|
6
|
-
|
|
7
|
-
from pyqtgraph.graphicsItems import InfiniteLine, ROI
|
|
8
5
|
|
|
9
6
|
from pymodaq.utils.logger import set_logger, get_module_name
|
|
10
|
-
from pymodaq.utils.data import DataToExport,
|
|
11
|
-
|
|
12
|
-
from pymodaq.utils.enums import
|
|
13
|
-
from pymodaq.utils.factory import ObjectFactory
|
|
7
|
+
from pymodaq.utils.data import DataToExport, DataWithAxes, Axis, DataSource
|
|
8
|
+
|
|
9
|
+
from pymodaq.utils.enums import enum_checker
|
|
10
|
+
from pymodaq.utils.factory import ObjectFactory
|
|
14
11
|
from pymodaq.utils.plotting import data_viewers
|
|
12
|
+
from pymodaq.utils.plotting.data_viewers.base import ViewerBase, ViewersEnum
|
|
15
13
|
from pymodaq.utils.gui_utils import DockArea, Dock
|
|
16
|
-
from pymodaq.utils.managers.parameter_manager import ParameterManager
|
|
17
14
|
|
|
18
|
-
|
|
19
|
-
from pymodaq.utils.plotting.data_viewers.viewer0D import Viewer0D
|
|
20
|
-
from pymodaq.utils.plotting.data_viewers.viewer1D import Viewer1D
|
|
21
|
-
from pymodaq.utils.plotting.data_viewers.viewer2D import Viewer2D
|
|
22
|
-
from pymodaq.utils.plotting.data_viewers.viewerND import ViewerND
|
|
23
|
-
|
|
24
|
-
config_viewers = {
|
|
25
|
-
}
|
|
15
|
+
config_viewers = {}
|
|
26
16
|
|
|
27
17
|
logger = set_logger(get_module_name(__file__))
|
|
28
18
|
|
|
29
19
|
|
|
30
|
-
class ViewersEnum(BaseEnum):
|
|
31
|
-
"""enum relating a given viewer with data type"""
|
|
32
|
-
Viewer0D = 'Data0D'
|
|
33
|
-
Viewer1D = 'Data1D'
|
|
34
|
-
Viewer2D = 'Data2D'
|
|
35
|
-
ViewerND = 'DataND'
|
|
36
|
-
ViewerSequential = 'DataSequential'
|
|
37
|
-
|
|
38
|
-
def get_dim(self):
|
|
39
|
-
return self.value.split('Data')[1].split('D')[0]
|
|
40
|
-
|
|
41
|
-
def increase_dim(self, ndim: int):
|
|
42
|
-
dim = self.get_dim()
|
|
43
|
-
if dim != 'N':
|
|
44
|
-
dim_as_int = int(dim) + ndim
|
|
45
|
-
if dim_as_int > 2:
|
|
46
|
-
dim = 'N'
|
|
47
|
-
else:
|
|
48
|
-
dim = str(dim_as_int)
|
|
49
|
-
else:
|
|
50
|
-
dim = 'N'
|
|
51
|
-
return ViewersEnum[f'Viewer{dim}D']
|
|
52
|
-
|
|
53
|
-
|
|
54
20
|
def get_viewer_enum_from_axes(Naxes: int):
|
|
55
21
|
if Naxes < 0:
|
|
56
22
|
raise ValueError('Naxes could not be below 0')
|
|
@@ -104,176 +70,35 @@ def create_viewerND(parent: QtWidgets.QWidget, **_ignored):
|
|
|
104
70
|
viewer_factory = ViewerFactory()
|
|
105
71
|
|
|
106
72
|
|
|
107
|
-
class
|
|
108
|
-
"""
|
|
73
|
+
class ViewerDispatcher:
|
|
74
|
+
"""MixIn class to add easy control for adding multuiple data viewers in docks depending on
|
|
75
|
+
data to be plotted
|
|
109
76
|
|
|
110
77
|
Parameters
|
|
111
78
|
----------
|
|
112
|
-
|
|
79
|
+
dockarea: DockArea
|
|
113
80
|
title: str
|
|
81
|
+
next_to_dock: Dock
|
|
82
|
+
(deprecated) has no effect
|
|
83
|
+
direction: str
|
|
84
|
+
either 'right', 'left', 'bottom', 'top'.
|
|
114
85
|
|
|
115
|
-
Attributes
|
|
116
|
-
----------
|
|
117
|
-
view: QObject
|
|
118
|
-
Ui interface of the viewer
|
|
119
|
-
|
|
120
|
-
data_to_export_signal: Signal[DataToExport]
|
|
121
|
-
ROI_changed: Signal
|
|
122
|
-
crosshair_dragged: Signal[float, float]
|
|
123
|
-
crosshair_clicked: Signal[bool]
|
|
124
|
-
sig_double_clicked: Signal[float, float]
|
|
125
|
-
status_signal: Signal[str]
|
|
126
86
|
"""
|
|
127
|
-
data_to_export_signal = Signal(DataToExport)
|
|
128
|
-
_data_to_show_signal = Signal(DataWithAxes)
|
|
129
|
-
|
|
130
|
-
ROI_changed = Signal()
|
|
131
|
-
crosshair_dragged = Signal(float, float) # Crosshair position in units of scaled top/right axes
|
|
132
|
-
status_signal = Signal(str)
|
|
133
|
-
crosshair_clicked = Signal(bool)
|
|
134
|
-
sig_double_clicked = Signal(float, float)
|
|
135
87
|
|
|
136
|
-
def __init__(self,
|
|
137
|
-
|
|
138
|
-
self.title = title if title != '' else self.__class__.__name__
|
|
139
|
-
|
|
140
|
-
self._raw_data = None
|
|
141
|
-
self.data_to_export: DataToExport = DataToExport(name=self.title)
|
|
142
|
-
self.view: Union[Viewer0D, Viewer1D, Viewer2D, ViewerND] = None
|
|
143
|
-
|
|
144
|
-
if parent is None:
|
|
145
|
-
parent = QtWidgets.QWidget()
|
|
146
|
-
parent.show()
|
|
147
|
-
self.parent = parent
|
|
148
|
-
|
|
149
|
-
self._display_temporary = False
|
|
150
|
-
|
|
151
|
-
@property
|
|
152
|
-
def has_action(self):
|
|
153
|
-
"""Convenience method"""
|
|
154
|
-
if hasattr(self.view, 'has_action'):
|
|
155
|
-
return self.view.has_action
|
|
156
|
-
|
|
157
|
-
@property
|
|
158
|
-
def is_action_checked(self):
|
|
159
|
-
"""Convenience method"""
|
|
160
|
-
if hasattr(self.view, 'is_action_checked'):
|
|
161
|
-
return self.view.is_action_checked
|
|
162
|
-
|
|
163
|
-
@property
|
|
164
|
-
def is_action_visible(self):
|
|
165
|
-
"""Convenience method"""
|
|
166
|
-
if hasattr(self.view, 'is_action_visible'):
|
|
167
|
-
return self.view.is_action_visible
|
|
168
|
-
|
|
169
|
-
@property
|
|
170
|
-
def set_action_checked(self):
|
|
171
|
-
"""Convenience method"""
|
|
172
|
-
if hasattr(self.view, 'set_action_checked'):
|
|
173
|
-
return self.view.set_action_checked
|
|
174
|
-
|
|
175
|
-
@property
|
|
176
|
-
def set_action_visible(self):
|
|
177
|
-
"""Convenience method"""
|
|
178
|
-
if hasattr(self.view, 'set_action_visible'):
|
|
179
|
-
return self.view.set_action_visible
|
|
180
|
-
|
|
181
|
-
@property
|
|
182
|
-
def get_action(self):
|
|
183
|
-
"""Convenience method"""
|
|
184
|
-
if hasattr(self.view, 'get_action'):
|
|
185
|
-
return self.view.get_action
|
|
186
|
-
|
|
187
|
-
@property
|
|
188
|
-
def toolbar(self):
|
|
189
|
-
"""Convenience property"""
|
|
190
|
-
if hasattr(self.view, 'toolbar'):
|
|
191
|
-
return self.view.toolbar
|
|
192
|
-
|
|
193
|
-
@property
|
|
194
|
-
def viewer_type(self):
|
|
195
|
-
"""str: the viewer data type see DATA_TYPES"""
|
|
196
|
-
return ViewersEnum[self.__class__.__name__].value
|
|
197
|
-
|
|
198
|
-
def show_data(self, data: DataWithAxes, **kwargs):
|
|
199
|
-
"""Entrypoint to display data into the viewer
|
|
200
|
-
|
|
201
|
-
Parameters
|
|
202
|
-
----------
|
|
203
|
-
data: data_mod.DataFromPlugins
|
|
204
|
-
"""
|
|
205
|
-
if len(data.shape) > 4:
|
|
206
|
-
raise ViewerError(f'Ndarray of dim: {len(data.shape)} cannot be plotted using a {self.viewer_type}')
|
|
207
|
-
|
|
208
|
-
self.data_to_export = DataToExport(name=self.title)
|
|
209
|
-
self._raw_data = data
|
|
210
|
-
|
|
211
|
-
self._display_temporary = False
|
|
212
|
-
|
|
213
|
-
self._show_data(data, **kwargs)
|
|
214
|
-
|
|
215
|
-
def show_data_temp(self, data: DataRaw, **kwargs):
|
|
216
|
-
"""Entrypoint to display temporary data into the viewer
|
|
217
|
-
|
|
218
|
-
No processed data signal is emitted from the viewer
|
|
219
|
-
|
|
220
|
-
Parameters
|
|
221
|
-
----------
|
|
222
|
-
data: data_mod.DataFromPlugins
|
|
223
|
-
"""
|
|
224
|
-
self._display_temporary = True
|
|
225
|
-
self.show_data(data, **kwargs)
|
|
226
|
-
|
|
227
|
-
def _show_data(self, data: DataRaw):
|
|
228
|
-
"""Specific viewers should implement it"""
|
|
229
|
-
raise NotImplementedError
|
|
230
|
-
|
|
231
|
-
def add_attributes_from_view(self):
|
|
232
|
-
"""Convenience function to add attributes from the view to self"""
|
|
233
|
-
for attribute in self.convenience_attributes:
|
|
234
|
-
if hasattr(self.view, attribute):
|
|
235
|
-
setattr(self, attribute, getattr(self.view, attribute))
|
|
236
|
-
|
|
237
|
-
def trigger_action(self, action_name: str):
|
|
238
|
-
"""Convenience function to trigger programmatically one of the action of the related view"""
|
|
239
|
-
if self.has_action(action_name):
|
|
240
|
-
self.get_action(action_name).trigger()
|
|
241
|
-
|
|
242
|
-
def activate_roi(self, activate=True):
|
|
243
|
-
"""Activate the Roi manager using the corresponding action"""
|
|
244
|
-
raise NotImplementedError
|
|
245
|
-
|
|
246
|
-
def setVisible(self, show=True):
|
|
247
|
-
"""convenience method to show or hide the paretn widget"""
|
|
248
|
-
self.parent.setVisible(show)
|
|
249
|
-
|
|
250
|
-
@property
|
|
251
|
-
def roi_target(self) -> Union[InfiniteLine.InfiniteLine, ROI.ROI]:
|
|
252
|
-
"""To be implemented if necessary (Viewer1D and above)"""
|
|
253
|
-
return None
|
|
254
|
-
|
|
255
|
-
def move_roi_target(self, pos: Iterable[float] = None, **kwargs):
|
|
256
|
-
"""move a specific read only ROI at the given position on the viewer"""
|
|
257
|
-
...
|
|
258
|
-
|
|
259
|
-
def show_roi_target(self, show=True):
|
|
260
|
-
"""Show/Hide a specific read only ROI"""
|
|
261
|
-
if self.roi_target is not None:
|
|
262
|
-
self.roi_target.setVisible(show)
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
class ViewerDispatcher:
|
|
266
|
-
"""MixIn class to add easy control for adding multuiple data viewers in docks depending on data to be plotted"""
|
|
267
|
-
|
|
268
|
-
def __init__(self, dockarea: DockArea = None, title: str = '', next_to_dock: Dock = None):
|
|
88
|
+
def __init__(self, dockarea: DockArea = None, title: str = '', next_to_dock: Dock = None,
|
|
89
|
+
direction='right'):
|
|
269
90
|
super().__init__()
|
|
270
91
|
self._title = title
|
|
92
|
+
|
|
271
93
|
self._next_to_dock = next_to_dock
|
|
94
|
+
|
|
272
95
|
if dockarea is None:
|
|
273
96
|
dockarea = DockArea()
|
|
274
97
|
dockarea.show()
|
|
275
98
|
self.dockarea = dockarea
|
|
276
99
|
|
|
100
|
+
self._direction = direction
|
|
101
|
+
|
|
277
102
|
self._viewer_docks = []
|
|
278
103
|
self._viewer_widgets = []
|
|
279
104
|
self._viewer_types = []
|
|
@@ -337,9 +162,10 @@ class ViewerDispatcher:
|
|
|
337
162
|
# self.dockarea.addDock(self.viewer_docks[-1])
|
|
338
163
|
# else:
|
|
339
164
|
# self.dockarea.addDock(self.viewer_docks[-1], 'right', self.viewer_docks[-2])
|
|
340
|
-
self.dockarea.addDock(self.viewer_docks[-1],
|
|
165
|
+
self.dockarea.addDock(self.viewer_docks[-1], self._direction)
|
|
341
166
|
|
|
342
|
-
def update_viewers(self, viewers_type: List[
|
|
167
|
+
def update_viewers(self, viewers_type: List[Union[str, ViewersEnum]],
|
|
168
|
+
viewers_name: List[str] = None, force=False):
|
|
343
169
|
"""
|
|
344
170
|
|
|
345
171
|
Parameters
|
|
@@ -369,7 +195,8 @@ class ViewerDispatcher:
|
|
|
369
195
|
ind_loop = 0
|
|
370
196
|
while len(self.viewers) < len(viewers_type):
|
|
371
197
|
self.add_viewer(viewers_type[Nviewers_to_leave + ind_loop],
|
|
372
|
-
dock_name=viewers_name[Nviewers_to_leave + ind_loop]
|
|
198
|
+
dock_name=viewers_name[Nviewers_to_leave + ind_loop]
|
|
199
|
+
if viewers_name is not None else None)
|
|
373
200
|
ind_loop += 1
|
|
374
201
|
QtWidgets.QApplication.processEvents()
|
|
375
202
|
|
|
@@ -377,9 +204,9 @@ class ViewerDispatcher:
|
|
|
377
204
|
for dock in self.viewer_docks:
|
|
378
205
|
dock.close()
|
|
379
206
|
|
|
380
|
-
def show_data(self, data: DataToExport):
|
|
207
|
+
def show_data(self, data: DataToExport, **kwargs):
|
|
381
208
|
""" Convenience method. Display each dwa in a dedicated data viewer"""
|
|
382
|
-
viewer_types = [ViewersEnum(dwa
|
|
209
|
+
viewer_types = [ViewersEnum.get_viewers_enum_from_data(dwa) for dwa in data]
|
|
383
210
|
if self.viewer_types != viewer_types:
|
|
384
211
|
self.update_viewers(viewer_types)
|
|
385
212
|
for viewer, dwa in zip(self.viewers, data):
|
|
@@ -426,7 +253,7 @@ if __name__ == '__main__':
|
|
|
426
253
|
return dat1, dat2, data
|
|
427
254
|
|
|
428
255
|
import sys
|
|
429
|
-
|
|
256
|
+
|
|
430
257
|
app = QtWidgets.QApplication(sys.argv)
|
|
431
258
|
|
|
432
259
|
dockarea = DockArea()
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
from typing import List, Union
|
|
1
|
+
from typing import List, Union, Dict
|
|
2
2
|
from numbers import Real
|
|
3
3
|
|
|
4
4
|
from qtpy import QtWidgets, QtGui
|
|
@@ -19,7 +19,7 @@ from collections import OrderedDict
|
|
|
19
19
|
import datetime
|
|
20
20
|
|
|
21
21
|
logger = set_logger(get_module_name(__file__))
|
|
22
|
-
PLOT_COLORS = utils.plot_colors
|
|
22
|
+
PLOT_COLORS = [dict(color=color) for color in utils.plot_colors]
|
|
23
23
|
|
|
24
24
|
|
|
25
25
|
class DataDisplayer(QObject):
|
|
@@ -30,9 +30,10 @@ class DataDisplayer(QObject):
|
|
|
30
30
|
updated_item = Signal(list)
|
|
31
31
|
labels_changed = Signal(list)
|
|
32
32
|
|
|
33
|
-
def __init__(self, plotitem: pyqtgraph.PlotItem):
|
|
33
|
+
def __init__(self, plotitem: pyqtgraph.PlotItem, plot_colors=PLOT_COLORS):
|
|
34
34
|
super().__init__()
|
|
35
35
|
self._plotitem = plotitem
|
|
36
|
+
self.colors = plot_colors
|
|
36
37
|
self._plotitem.addLegend()
|
|
37
38
|
self._plot_items: List[pyqtgraph.PlotDataItem] = []
|
|
38
39
|
self._min_lines: List[pyqtgraph.InfiniteLine] = []
|
|
@@ -47,10 +48,18 @@ class DataDisplayer(QObject):
|
|
|
47
48
|
axis = self._plotitem.getAxis('bottom')
|
|
48
49
|
axis.setLabel(text='Samples', units='S')
|
|
49
50
|
|
|
51
|
+
def update_colors(self, colors: List[QtGui.QPen]):
|
|
52
|
+
self.colors[0:len(colors)] = colors
|
|
53
|
+
self.update_data(self._data.last_data, force_update=True)
|
|
54
|
+
|
|
50
55
|
@property
|
|
51
|
-
def legend(self):
|
|
56
|
+
def legend(self) -> pyqtgraph.LegendItem:
|
|
52
57
|
return self._plotitem.legend
|
|
53
58
|
|
|
59
|
+
@property
|
|
60
|
+
def legend_names(self) -> List[str]:
|
|
61
|
+
return [item[1].text for item in self.legend.items]
|
|
62
|
+
|
|
54
63
|
@property
|
|
55
64
|
def axis(self):
|
|
56
65
|
return self._data.xaxis
|
|
@@ -63,49 +72,58 @@ class DataDisplayer(QObject):
|
|
|
63
72
|
def update_axis(self, history_length: int):
|
|
64
73
|
self._data.length = history_length
|
|
65
74
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
75
|
+
@property
|
|
76
|
+
def Ndata(self):
|
|
77
|
+
return len(self._data.last_data) if self._data.last_data is not None else 0
|
|
69
78
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
self._plot_items
|
|
73
|
-
|
|
74
|
-
self._mins = []
|
|
75
|
-
self._maxs = []
|
|
79
|
+
def update_data(self, data: data_mod.DataWithAxes, force_update=False):
|
|
80
|
+
if data is not None:
|
|
81
|
+
if len(data) != len(self._plot_items) or force_update or data.labels != self.legend_names:
|
|
82
|
+
self.update_display_items(data)
|
|
76
83
|
|
|
77
|
-
|
|
84
|
+
self._data.add_datas(data)
|
|
85
|
+
for ind, data_str in enumerate(self._data.datas):
|
|
86
|
+
self._plot_items[ind].setData(self._data.xaxis, self._data.datas[data_str])
|
|
78
87
|
if len(self._mins) != len(self._data.datas):
|
|
79
|
-
self._mins
|
|
80
|
-
self._maxs
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
+
self._mins = []
|
|
89
|
+
self._maxs = []
|
|
90
|
+
|
|
91
|
+
for ind, label in enumerate(self._data.datas):
|
|
92
|
+
if len(self._mins) != len(self._data.datas):
|
|
93
|
+
self._mins.append(float(np.min(self._data.datas[label])))
|
|
94
|
+
self._maxs.append(float(np.max(self._data.datas[label])))
|
|
95
|
+
else:
|
|
96
|
+
self._mins[ind] = min(self._mins[ind], float(np.min(self._data.datas[label])))
|
|
97
|
+
self._maxs[ind] = max(self._maxs[ind], float(np.max(self._data.datas[label])))
|
|
98
|
+
self._min_lines[ind].setValue(self._mins[ind])
|
|
99
|
+
self._max_lines[ind].setValue(self._maxs[ind])
|
|
100
|
+
|
|
101
|
+
def update_display_items(self, data: data_mod.DataWithAxes = None):
|
|
88
102
|
while len(self._plot_items) > 0:
|
|
89
103
|
plot_item = self._plotitem.removeItem(self._plot_items.pop(0))
|
|
90
104
|
self.legend.removeItem(plot_item)
|
|
91
105
|
self._plotitem.removeItem(self._max_lines.pop(0))
|
|
92
106
|
self._plotitem.removeItem(self._min_lines.pop(0))
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
107
|
+
if data is not None:
|
|
108
|
+
for ind in range(len(data)):
|
|
109
|
+
self._plot_items.append(pyqtgraph.PlotDataItem(pen=self.colors[ind]))
|
|
110
|
+
self._plotitem.addItem(self._plot_items[-1])
|
|
111
|
+
self.legend.addItem(self._plot_items[-1], data.labels[ind])
|
|
112
|
+
max_line = pyqtgraph.InfiniteLine(angle=0,
|
|
113
|
+
pen=pyqtgraph.mkPen(color=self.colors[ind]['color'],
|
|
114
|
+
style=Qt.DashLine))
|
|
115
|
+
min_line = pyqtgraph.InfiniteLine(angle=0,
|
|
116
|
+
pen=pyqtgraph.mkPen(color=self.colors[ind]['color'],
|
|
117
|
+
style=Qt.DashLine))
|
|
118
|
+
self._max_lines.append(max_line)
|
|
119
|
+
self._min_lines.append(min_line)
|
|
120
|
+
max_line.setVisible(self._show_lines)
|
|
121
|
+
min_line.setVisible(self._show_lines)
|
|
122
|
+
self._plotitem.addItem(self._max_lines[-1])
|
|
123
|
+
self._plotitem.addItem(self._min_lines[-1])
|
|
124
|
+
|
|
125
|
+
self.updated_item.emit(self._plot_items)
|
|
126
|
+
self.labels_changed.emit(data.labels)
|
|
109
127
|
|
|
110
128
|
def show_min_max(self, show=True):
|
|
111
129
|
self._show_lines = show
|
|
@@ -116,11 +134,14 @@ class DataDisplayer(QObject):
|
|
|
116
134
|
|
|
117
135
|
|
|
118
136
|
class View0D(ActionManager, QObject):
|
|
119
|
-
def __init__(self, parent_widget: QtWidgets.QWidget = None
|
|
137
|
+
def __init__(self, parent_widget: QtWidgets.QWidget = None, show_toolbar=True,
|
|
138
|
+
no_margins=False):
|
|
120
139
|
QObject.__init__(self)
|
|
121
140
|
ActionManager.__init__(self, toolbar=QtWidgets.QToolBar())
|
|
122
141
|
|
|
142
|
+
self.no_margins = no_margins
|
|
123
143
|
self.data_displayer: DataDisplayer = None
|
|
144
|
+
self.other_data_displayers: Dict[str, DataDisplayer] = {}
|
|
124
145
|
self.plot_widget: PlotWidget = PlotWidget()
|
|
125
146
|
self.values_list = QtWidgets.QListWidget()
|
|
126
147
|
|
|
@@ -136,6 +157,8 @@ class View0D(ActionManager, QObject):
|
|
|
136
157
|
self._setup_widgets()
|
|
137
158
|
self._connect_things()
|
|
138
159
|
self._prepare_ui()
|
|
160
|
+
if not show_toolbar:
|
|
161
|
+
self.splitter.setSizes([0,1])
|
|
139
162
|
|
|
140
163
|
self.get_action('Nhistory').setValue(200) #default history length
|
|
141
164
|
|
|
@@ -149,11 +172,17 @@ class View0D(ActionManager, QObject):
|
|
|
149
172
|
'If triggered, will display horizontal dashed lines for min/max of data', checkable=True)
|
|
150
173
|
|
|
151
174
|
def _setup_widgets(self):
|
|
175
|
+
self.splitter = QtWidgets.QSplitter(Qt.Vertical)
|
|
152
176
|
self.parent_widget.setLayout(QtWidgets.QVBoxLayout())
|
|
153
|
-
self.
|
|
177
|
+
if self.no_margins:
|
|
178
|
+
self.parent_widget.layout().setContentsMargins(0, 0, 0, 0)
|
|
179
|
+
|
|
180
|
+
self.parent_widget.layout().addWidget(self.splitter)
|
|
181
|
+
self.splitter.addWidget(self.toolbar)
|
|
182
|
+
self.splitter.setStretchFactor(0, 0)
|
|
154
183
|
|
|
155
184
|
splitter_hor = QtWidgets.QSplitter(Qt.Horizontal)
|
|
156
|
-
self.
|
|
185
|
+
self.splitter.addWidget(splitter_hor)
|
|
157
186
|
|
|
158
187
|
splitter_hor.addWidget(self.plot_widget)
|
|
159
188
|
splitter_hor.addWidget(self.values_list)
|
|
@@ -179,8 +208,11 @@ class View0D(ActionManager, QObject):
|
|
|
179
208
|
def plotitem(self):
|
|
180
209
|
return self.plot_widget.plotItem
|
|
181
210
|
|
|
182
|
-
def display_data(self, data: data_mod.
|
|
183
|
-
|
|
211
|
+
def display_data(self, data: data_mod.DataWithAxes, displayer: str = None, **kwargs):
|
|
212
|
+
if displayer is None:
|
|
213
|
+
self.data_displayer.update_data(data)
|
|
214
|
+
elif displayer in self.other_data_displayers:
|
|
215
|
+
self.other_data_displayers[displayer].update_data(data)
|
|
184
216
|
if self.is_action_checked('show_data_as_list'):
|
|
185
217
|
self.values_list.clear()
|
|
186
218
|
self.values_list.addItems(['{:.03e}'.format(dat[0]) for dat in data])
|
|
@@ -191,6 +223,15 @@ class View0D(ActionManager, QObject):
|
|
|
191
223
|
state = self.is_action_checked('show_data_as_list')
|
|
192
224
|
self.values_list.setVisible(state)
|
|
193
225
|
|
|
226
|
+
def add_data_displayer(self, displayer_name: str, plot_colors=PLOT_COLORS):
|
|
227
|
+
self.other_data_displayers[displayer_name] = DataDisplayer(self.plotitem, plot_colors)
|
|
228
|
+
self.connect_action('clear', self.other_data_displayers[displayer_name].clear_data)
|
|
229
|
+
|
|
230
|
+
def remove_data_displayer(self, displayer_name: str):
|
|
231
|
+
displayer = self.other_data_displayers.pop(displayer_name, None)
|
|
232
|
+
if displayer is not None:
|
|
233
|
+
displayer.update_display_items()
|
|
234
|
+
|
|
194
235
|
|
|
195
236
|
class Viewer0D(ViewerBase):
|
|
196
237
|
"""this plots 0D data on a plotwidget with history. Display as numbers in a table is possible.
|
|
@@ -198,11 +239,17 @@ class Viewer0D(ViewerBase):
|
|
|
198
239
|
Datas and measurements are then exported with the signal data_to_export_signal
|
|
199
240
|
"""
|
|
200
241
|
|
|
201
|
-
def __init__(self, parent=None, title=''):
|
|
242
|
+
def __init__(self, parent=None, title='', show_toolbar=True, no_margins=False):
|
|
202
243
|
super().__init__(parent, title)
|
|
203
|
-
self.view = View0D(self.parent)
|
|
244
|
+
self.view = View0D(self.parent, show_toolbar=show_toolbar, no_margins=no_margins)
|
|
204
245
|
self._labels = []
|
|
205
246
|
|
|
247
|
+
def update_colors(self, colors: list, displayer=None):
|
|
248
|
+
if displayer is None:
|
|
249
|
+
self.view.data_displayer.update_colors(colors)
|
|
250
|
+
elif displayer in self.view.other_data_displayers:
|
|
251
|
+
self.view.other_data_displayers[displayer].update_colors(colors)
|
|
252
|
+
|
|
206
253
|
@property
|
|
207
254
|
def labels(self):
|
|
208
255
|
return self._labels
|
|
@@ -230,7 +277,7 @@ def main_view():
|
|
|
230
277
|
def main():
|
|
231
278
|
app = QtWidgets.QApplication(sys.argv)
|
|
232
279
|
widget = QtWidgets.QWidget()
|
|
233
|
-
prog = Viewer0D(widget)
|
|
280
|
+
prog = Viewer0D(widget, show_toolbar=False)
|
|
234
281
|
from pymodaq.utils.daq_utils import gauss1D
|
|
235
282
|
|
|
236
283
|
x = np.linspace(0, 200, 201)
|