pymagnetos 0.1.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.
- pymagnetos/__init__.py +15 -0
- pymagnetos/cli.py +40 -0
- pymagnetos/core/__init__.py +19 -0
- pymagnetos/core/_config.py +340 -0
- pymagnetos/core/_data.py +132 -0
- pymagnetos/core/_processor.py +905 -0
- pymagnetos/core/config_models.py +57 -0
- pymagnetos/core/gui/__init__.py +6 -0
- pymagnetos/core/gui/_base_mainwindow.py +819 -0
- pymagnetos/core/gui/widgets/__init__.py +19 -0
- pymagnetos/core/gui/widgets/_batch_processing.py +319 -0
- pymagnetos/core/gui/widgets/_configuration.py +167 -0
- pymagnetos/core/gui/widgets/_files.py +129 -0
- pymagnetos/core/gui/widgets/_graphs.py +93 -0
- pymagnetos/core/gui/widgets/_param_content.py +20 -0
- pymagnetos/core/gui/widgets/_popup_progressbar.py +29 -0
- pymagnetos/core/gui/widgets/_text_logger.py +32 -0
- pymagnetos/core/signal_processing.py +1004 -0
- pymagnetos/core/utils.py +85 -0
- pymagnetos/log.py +126 -0
- pymagnetos/py.typed +0 -0
- pymagnetos/pytdo/__init__.py +6 -0
- pymagnetos/pytdo/_config.py +24 -0
- pymagnetos/pytdo/_config_models.py +59 -0
- pymagnetos/pytdo/_tdoprocessor.py +1052 -0
- pymagnetos/pytdo/assets/config_default.toml +84 -0
- pymagnetos/pytdo/gui/__init__.py +26 -0
- pymagnetos/pytdo/gui/_worker.py +106 -0
- pymagnetos/pytdo/gui/main.py +617 -0
- pymagnetos/pytdo/gui/widgets/__init__.py +8 -0
- pymagnetos/pytdo/gui/widgets/_buttons.py +66 -0
- pymagnetos/pytdo/gui/widgets/_configuration.py +78 -0
- pymagnetos/pytdo/gui/widgets/_graphs.py +280 -0
- pymagnetos/pytdo/gui/widgets/_param_content.py +137 -0
- pymagnetos/pyuson/__init__.py +7 -0
- pymagnetos/pyuson/_config.py +26 -0
- pymagnetos/pyuson/_config_models.py +71 -0
- pymagnetos/pyuson/_echoprocessor.py +1901 -0
- pymagnetos/pyuson/assets/config_default.toml +92 -0
- pymagnetos/pyuson/gui/__init__.py +26 -0
- pymagnetos/pyuson/gui/_worker.py +135 -0
- pymagnetos/pyuson/gui/main.py +767 -0
- pymagnetos/pyuson/gui/widgets/__init__.py +7 -0
- pymagnetos/pyuson/gui/widgets/_buttons.py +95 -0
- pymagnetos/pyuson/gui/widgets/_configuration.py +85 -0
- pymagnetos/pyuson/gui/widgets/_graphs.py +248 -0
- pymagnetos/pyuson/gui/widgets/_param_content.py +193 -0
- pymagnetos-0.1.0.dist-info/METADATA +23 -0
- pymagnetos-0.1.0.dist-info/RECORD +51 -0
- pymagnetos-0.1.0.dist-info/WHEEL +4 -0
- pymagnetos-0.1.0.dist-info/entry_points.txt +7 -0
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
"""
|
|
2
|
+
The graphs area that holds all the plots.
|
|
3
|
+
|
|
4
|
+
The plots themselves should be placed on a custom layout by subclass. This Base class
|
|
5
|
+
merely provides plots behavior :
|
|
6
|
+
- mouse coordinates on hover,
|
|
7
|
+
- CRTL+click to zoom in an area.
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from functools import partial
|
|
11
|
+
|
|
12
|
+
import pyqtgraph as pg
|
|
13
|
+
from PyQt6 import QtWidgets
|
|
14
|
+
from PyQt6.QtCore import QEvent, Qt
|
|
15
|
+
from PyQt6.QtGui import QKeyEvent
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class BaseGraphsWidget(QtWidgets.QWidget):
|
|
19
|
+
"""Base class for the graphs area with all the plots."""
|
|
20
|
+
|
|
21
|
+
_plots_list: set[pg.PlotWidget]
|
|
22
|
+
|
|
23
|
+
def __init__(self) -> None:
|
|
24
|
+
super().__init__()
|
|
25
|
+
|
|
26
|
+
# Internal flags
|
|
27
|
+
self._mouse_pan_mode = True
|
|
28
|
+
|
|
29
|
+
# Registered plots
|
|
30
|
+
self._plots_list = set()
|
|
31
|
+
|
|
32
|
+
# Get pens
|
|
33
|
+
self.init_plot_style()
|
|
34
|
+
|
|
35
|
+
def init_plot_style(self) -> None:
|
|
36
|
+
"""Set and store QPen for styling of curves and ROIs."""
|
|
37
|
+
raise NotImplementedError("Subclass must implement this method.")
|
|
38
|
+
|
|
39
|
+
def event(self, ev: QEvent) -> bool:
|
|
40
|
+
"""Handle mouse selection while holding CTRL to make a ROI zoom in plots."""
|
|
41
|
+
# Switch to rectangular zoom selection on the first Ctrl key press event
|
|
42
|
+
if ev.type() == QKeyEvent.Type.KeyPress and ev.key() == Qt.Key.Key_Control:
|
|
43
|
+
if self._mouse_pan_mode:
|
|
44
|
+
self.switch_mouse_pan_mode(False)
|
|
45
|
+
|
|
46
|
+
# Switch back to pan mode on left click when releasing the Ctrl key
|
|
47
|
+
if ev.type() == QKeyEvent.Type.KeyRelease and ev.key() == Qt.Key.Key_Control:
|
|
48
|
+
self.switch_mouse_pan_mode(True)
|
|
49
|
+
|
|
50
|
+
return super().event(ev)
|
|
51
|
+
|
|
52
|
+
def switch_mouse_pan_mode(self, state: bool) -> None:
|
|
53
|
+
"""
|
|
54
|
+
Switch mouse behavior from panning to ROI-zooming when holding CTRL.
|
|
55
|
+
|
|
56
|
+
Parameters
|
|
57
|
+
----------
|
|
58
|
+
state : bool
|
|
59
|
+
If True, all plots are set to pan mode, otherwise they are set in ROI-zoom
|
|
60
|
+
mode.
|
|
61
|
+
"""
|
|
62
|
+
# Get mode
|
|
63
|
+
mode = pg.ViewBox.PanMode if state else pg.ViewBox.RectMode
|
|
64
|
+
self._mouse_pan_mode = state
|
|
65
|
+
|
|
66
|
+
# Set mode for all registered plots
|
|
67
|
+
for plot in self._plots_list:
|
|
68
|
+
plot.getPlotItem().getViewBox().setMouseMode(mode)
|
|
69
|
+
|
|
70
|
+
def init_coordinates_on_hover(self) -> None:
|
|
71
|
+
"""Add x, y coordinates on mouse hover for all registered plots."""
|
|
72
|
+
for plot in self._plots_list:
|
|
73
|
+
self.coordinates_on_hover(plot)
|
|
74
|
+
|
|
75
|
+
def coordinates_on_hover(self, plot) -> None:
|
|
76
|
+
"""Add x, y coordinates on mouse hover."""
|
|
77
|
+
plot.scene().sigMouseMoved.connect(partial(self.mouse_moved_in_plot, plot))
|
|
78
|
+
plot.setLabel("top", "x=, y=")
|
|
79
|
+
plot.getAxis("top").setStyle(showValues=False)
|
|
80
|
+
|
|
81
|
+
def mouse_moved_in_plot(self, plot, evt) -> None:
|
|
82
|
+
"""Define what happens when the mouse moves within a plot."""
|
|
83
|
+
pos = evt
|
|
84
|
+
if plot.getPlotItem().sceneBoundingRect().contains(pos):
|
|
85
|
+
vb = plot.getPlotItem().getViewBox()
|
|
86
|
+
mouse_point = vb.mapSceneToView(pos)
|
|
87
|
+
label_text = f"x={mouse_point.x():0.6f}, y={mouse_point.y():0.6f}"
|
|
88
|
+
plot.setLabel("top", label_text)
|
|
89
|
+
|
|
90
|
+
def clear_all_plots(self) -> None:
|
|
91
|
+
"""Clear plots."""
|
|
92
|
+
for plot in self._plots_list:
|
|
93
|
+
plot.clearPlots()
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Define various parameters to set in a PyQtGraph Parameter Tree.
|
|
3
|
+
|
|
4
|
+
To be able to automatically update them from the configuration file, their name should
|
|
5
|
+
match exactly the one in the configuration file.
|
|
6
|
+
Use the "title" kwarg to set the displayed name on the widget.
|
|
7
|
+
|
|
8
|
+
It is used in the ConfigurationWidget.
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class BaseParamContent:
|
|
13
|
+
PARAMS_TO_PARSE: list[str]
|
|
14
|
+
children_files: list[dict[str, str | bool]] = [
|
|
15
|
+
dict(name="file", type="file", value="", title="Configuration file"),
|
|
16
|
+
dict(name="expid", type="str", value="", readonly=False, title="Experiment ID"),
|
|
17
|
+
dict(name="autoload", type="bool", value=True, title="Load data automatically"),
|
|
18
|
+
]
|
|
19
|
+
children_parameters: list[dict[str, str | bool | list | float | int | None]]
|
|
20
|
+
children_settings: list[dict[str, str | bool | list | float | int | None]]
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"""A standalone progress bar window that emits its progress."""
|
|
2
|
+
|
|
3
|
+
from PyQt6 import QtWidgets
|
|
4
|
+
from PyQt6.QtCore import pyqtSlot
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class PopupProgressBar(QtWidgets.QWidget):
|
|
8
|
+
"""Pop-up progress bar."""
|
|
9
|
+
|
|
10
|
+
def __init__(self, min: int = 0, max: int = 100, title: str = ""):
|
|
11
|
+
# Setup window
|
|
12
|
+
super().__init__()
|
|
13
|
+
self.pbar = QtWidgets.QProgressBar(self)
|
|
14
|
+
self.pbar.setGeometry(30, 40, 500, 75)
|
|
15
|
+
self.pbar.setMinimum(min)
|
|
16
|
+
self.pbar.setMaximum(max)
|
|
17
|
+
|
|
18
|
+
vlayout = QtWidgets.QVBoxLayout(self)
|
|
19
|
+
vlayout.addWidget(self.pbar)
|
|
20
|
+
self.setLayout(vlayout)
|
|
21
|
+
self.setGeometry(300, 300, 550, 100)
|
|
22
|
+
self.setWindowTitle(title)
|
|
23
|
+
|
|
24
|
+
def start_progress(self):
|
|
25
|
+
self.show()
|
|
26
|
+
|
|
27
|
+
@pyqtSlot(int)
|
|
28
|
+
def update_progress(self, idx: int):
|
|
29
|
+
self.pbar.setValue(idx + 1)
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"""A logging handler to print log stream in a text window."""
|
|
2
|
+
|
|
3
|
+
import logging
|
|
4
|
+
|
|
5
|
+
from PyQt6 import QtWidgets
|
|
6
|
+
from PyQt6.QtCore import QObject, pyqtSignal
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class TextLoggerWidget(logging.Handler, QObject):
|
|
10
|
+
"""
|
|
11
|
+
Logger handler to print log in a QTextEdit widget.
|
|
12
|
+
|
|
13
|
+
pyqtSignals
|
|
14
|
+
-------
|
|
15
|
+
sig_append_text : internal, emits the log message to be printed in the text box.
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
sig_append_text = pyqtSignal(str)
|
|
19
|
+
flushOnClose = True
|
|
20
|
+
|
|
21
|
+
def __init__(self, parent):
|
|
22
|
+
super().__init__()
|
|
23
|
+
QObject.__init__(self)
|
|
24
|
+
|
|
25
|
+
self.widget = QtWidgets.QPlainTextEdit(parent)
|
|
26
|
+
self.widget.setReadOnly(True)
|
|
27
|
+
|
|
28
|
+
self.sig_append_text.connect(self.widget.appendPlainText)
|
|
29
|
+
|
|
30
|
+
def emit(self, record: logging.LogRecord) -> None:
|
|
31
|
+
msg = self.format(record)
|
|
32
|
+
self.sig_append_text.emit(msg)
|