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