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.
Files changed (51) hide show
  1. pymagnetos/__init__.py +15 -0
  2. pymagnetos/cli.py +40 -0
  3. pymagnetos/core/__init__.py +19 -0
  4. pymagnetos/core/_config.py +340 -0
  5. pymagnetos/core/_data.py +132 -0
  6. pymagnetos/core/_processor.py +905 -0
  7. pymagnetos/core/config_models.py +57 -0
  8. pymagnetos/core/gui/__init__.py +6 -0
  9. pymagnetos/core/gui/_base_mainwindow.py +819 -0
  10. pymagnetos/core/gui/widgets/__init__.py +19 -0
  11. pymagnetos/core/gui/widgets/_batch_processing.py +319 -0
  12. pymagnetos/core/gui/widgets/_configuration.py +167 -0
  13. pymagnetos/core/gui/widgets/_files.py +129 -0
  14. pymagnetos/core/gui/widgets/_graphs.py +93 -0
  15. pymagnetos/core/gui/widgets/_param_content.py +20 -0
  16. pymagnetos/core/gui/widgets/_popup_progressbar.py +29 -0
  17. pymagnetos/core/gui/widgets/_text_logger.py +32 -0
  18. pymagnetos/core/signal_processing.py +1004 -0
  19. pymagnetos/core/utils.py +85 -0
  20. pymagnetos/log.py +126 -0
  21. pymagnetos/py.typed +0 -0
  22. pymagnetos/pytdo/__init__.py +6 -0
  23. pymagnetos/pytdo/_config.py +24 -0
  24. pymagnetos/pytdo/_config_models.py +59 -0
  25. pymagnetos/pytdo/_tdoprocessor.py +1052 -0
  26. pymagnetos/pytdo/assets/config_default.toml +84 -0
  27. pymagnetos/pytdo/gui/__init__.py +26 -0
  28. pymagnetos/pytdo/gui/_worker.py +106 -0
  29. pymagnetos/pytdo/gui/main.py +617 -0
  30. pymagnetos/pytdo/gui/widgets/__init__.py +8 -0
  31. pymagnetos/pytdo/gui/widgets/_buttons.py +66 -0
  32. pymagnetos/pytdo/gui/widgets/_configuration.py +78 -0
  33. pymagnetos/pytdo/gui/widgets/_graphs.py +280 -0
  34. pymagnetos/pytdo/gui/widgets/_param_content.py +137 -0
  35. pymagnetos/pyuson/__init__.py +7 -0
  36. pymagnetos/pyuson/_config.py +26 -0
  37. pymagnetos/pyuson/_config_models.py +71 -0
  38. pymagnetos/pyuson/_echoprocessor.py +1901 -0
  39. pymagnetos/pyuson/assets/config_default.toml +92 -0
  40. pymagnetos/pyuson/gui/__init__.py +26 -0
  41. pymagnetos/pyuson/gui/_worker.py +135 -0
  42. pymagnetos/pyuson/gui/main.py +767 -0
  43. pymagnetos/pyuson/gui/widgets/__init__.py +7 -0
  44. pymagnetos/pyuson/gui/widgets/_buttons.py +95 -0
  45. pymagnetos/pyuson/gui/widgets/_configuration.py +85 -0
  46. pymagnetos/pyuson/gui/widgets/_graphs.py +248 -0
  47. pymagnetos/pyuson/gui/widgets/_param_content.py +193 -0
  48. pymagnetos-0.1.0.dist-info/METADATA +23 -0
  49. pymagnetos-0.1.0.dist-info/RECORD +51 -0
  50. pymagnetos-0.1.0.dist-info/WHEEL +4 -0
  51. 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)