modusa 0.1.0__py3-none-any.whl → 0.2.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.
- modusa/.DS_Store +0 -0
- modusa/decorators.py +5 -5
- modusa/devtools/generate_template.py +80 -15
- modusa/devtools/main.py +6 -4
- modusa/devtools/templates/{engines.py → engine.py} +8 -7
- modusa/devtools/templates/{generators.py → generator.py} +8 -10
- modusa/devtools/templates/io.py +24 -0
- modusa/devtools/templates/{plugins.py → plugin.py} +7 -6
- modusa/devtools/templates/signal.py +40 -0
- modusa/devtools/templates/test.py +11 -0
- modusa/engines/.DS_Store +0 -0
- modusa/engines/__init__.py +1 -2
- modusa/generators/__init__.py +3 -1
- modusa/generators/audio_waveforms.py +227 -0
- modusa/generators/base.py +14 -25
- modusa/io/__init__.py +9 -0
- modusa/io/audio_converter.py +76 -0
- modusa/io/audio_loader.py +212 -0
- modusa/io/audio_player.py +72 -0
- modusa/io/base.py +43 -0
- modusa/io/plotter.py +430 -0
- modusa/io/youtube_downloader.py +139 -0
- modusa/main.py +15 -17
- modusa/plugins/__init__.py +1 -7
- modusa/signals/__init__.py +4 -6
- modusa/signals/audio_signal.py +421 -175
- modusa/signals/base.py +11 -271
- modusa/signals/frequency_domain_signal.py +329 -0
- modusa/signals/signal_ops.py +158 -0
- modusa/signals/spectrogram.py +465 -0
- modusa/signals/time_domain_signal.py +309 -0
- modusa/utils/excp.py +5 -0
- {modusa-0.1.0.dist-info → modusa-0.2.1.dist-info}/METADATA +16 -11
- modusa-0.2.1.dist-info/RECORD +47 -0
- modusa/devtools/templates/signals.py +0 -63
- modusa/engines/plot_1dsignal.py +0 -130
- modusa/engines/plot_2dmatrix.py +0 -159
- modusa/generators/basic_waveform.py +0 -185
- modusa/plugins/plot_1dsignal.py +0 -59
- modusa/plugins/plot_2dmatrix.py +0 -76
- modusa/plugins/plot_time_domain_signal.py +0 -59
- modusa/signals/signal1d.py +0 -311
- modusa/signals/signal2d.py +0 -226
- modusa/signals/uniform_time_domain_signal.py +0 -212
- modusa-0.1.0.dist-info/RECORD +0 -41
- {modusa-0.1.0.dist-info → modusa-0.2.1.dist-info}/WHEEL +0 -0
- {modusa-0.1.0.dist-info → modusa-0.2.1.dist-info}/entry_points.txt +0 -0
- {modusa-0.1.0.dist-info → modusa-0.2.1.dist-info}/licenses/LICENSE.md +0 -0
modusa/engines/plot_2dmatrix.py
DELETED
|
@@ -1,159 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env python3
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
from modusa import excp
|
|
5
|
-
from modusa.decorators import validate_args_type
|
|
6
|
-
from modusa.engines.base import ModusaEngine
|
|
7
|
-
from typing import Any
|
|
8
|
-
import numpy as np
|
|
9
|
-
import matplotlib.pyplot as plt
|
|
10
|
-
from matplotlib.patches import Rectangle
|
|
11
|
-
from matplotlib.ticker import MaxNLocator
|
|
12
|
-
|
|
13
|
-
class Plot2DMatrixEngine(ModusaEngine):
|
|
14
|
-
"""
|
|
15
|
-
|
|
16
|
-
"""
|
|
17
|
-
|
|
18
|
-
#--------Meta Information----------
|
|
19
|
-
name = "Plot 2D Matrix"
|
|
20
|
-
description = ""
|
|
21
|
-
author_name = "Ankit Anand"
|
|
22
|
-
author_email = "ankit0.anand0@gmail.com"
|
|
23
|
-
created_at = "2025-07-02"
|
|
24
|
-
#----------------------------------
|
|
25
|
-
|
|
26
|
-
def __init__(self):
|
|
27
|
-
super().__init__()
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
@staticmethod
|
|
31
|
-
def compute_centered_extent(r: np.ndarray, c: np.ndarray, origin: str) -> list[float]:
|
|
32
|
-
"""
|
|
33
|
-
|
|
34
|
-
"""
|
|
35
|
-
dc = np.diff(c).mean() if len(c) > 1 else 1
|
|
36
|
-
dr = np.diff(r).mean() if len(r) > 1 else 1
|
|
37
|
-
left = c[0] - dc / 2
|
|
38
|
-
right = c[-1] + dc / 2
|
|
39
|
-
bottom = r[0] - dr / 2
|
|
40
|
-
top = r[-1] + dr / 2
|
|
41
|
-
return [left, right, top, bottom] if origin == "upper" else [left, right, bottom, top]
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
@validate_args_type()
|
|
45
|
-
def run(
|
|
46
|
-
self,
|
|
47
|
-
M: np.ndarray,
|
|
48
|
-
r: np.ndarray,
|
|
49
|
-
c: np.ndarray,
|
|
50
|
-
log_compression_factor: int | float | None,
|
|
51
|
-
ax: plt.Axes | None,
|
|
52
|
-
labels: tuple[str, str, str, str] | None,
|
|
53
|
-
zoom: tuple[float, float, float, float] | None, # (r1, r2, c1, c2)
|
|
54
|
-
highlight: list[tuple[float, float, float, float]] | None,
|
|
55
|
-
cmap: str,
|
|
56
|
-
origin: str, # or "lower"
|
|
57
|
-
show_colorbar: bool,
|
|
58
|
-
cax: plt.Axes | None,
|
|
59
|
-
show_grid: bool,
|
|
60
|
-
tick_mode: str, # "center" or "edge"
|
|
61
|
-
n_ticks: tuple[int, int],
|
|
62
|
-
value_range: tuple[float, float] | None,
|
|
63
|
-
) -> plt.Figure:
|
|
64
|
-
pass
|
|
65
|
-
|
|
66
|
-
# Validate the important args and get the signal that needs to be plotted
|
|
67
|
-
if M.ndim != 2:
|
|
68
|
-
raise excp.InputValueError(f"`M` must have 2 dimension not {M.ndim}")
|
|
69
|
-
if r.ndim != 1 and c.ndim != 1:
|
|
70
|
-
raise excp.InputValueError(f"`r` and `c` must have 2 dimension not r:{r.ndim}, c:{c.ndim}")
|
|
71
|
-
|
|
72
|
-
if r.shape[0] != M.shape[0]:
|
|
73
|
-
raise excp.InputValueError(f"`r` must have shape as `M row` not {r.shape}")
|
|
74
|
-
if c.shape[0] != M.shape[1]:
|
|
75
|
-
raise excp.InputValueError(f"`c` must have shape as `M column` not {c.shape}")
|
|
76
|
-
|
|
77
|
-
# Scale the signal if needed
|
|
78
|
-
if log_compression_factor is not None:
|
|
79
|
-
M = np.log1p(float(log_compression_factor) * M)
|
|
80
|
-
|
|
81
|
-
# Create a figure
|
|
82
|
-
if ax is None:
|
|
83
|
-
fig, ax = plt.subplots(figsize=(15, 4))
|
|
84
|
-
created_fig = True
|
|
85
|
-
else:
|
|
86
|
-
fig = ax.get_figure()
|
|
87
|
-
created_fig = False
|
|
88
|
-
|
|
89
|
-
# Plot the signal with right configurations
|
|
90
|
-
# Compute extent
|
|
91
|
-
extent = Plot2DMatrixEngine.compute_centered_extent(r, c, origin)
|
|
92
|
-
|
|
93
|
-
# Plot image
|
|
94
|
-
im = ax.imshow(
|
|
95
|
-
M,
|
|
96
|
-
aspect="auto",
|
|
97
|
-
cmap=cmap,
|
|
98
|
-
origin=origin,
|
|
99
|
-
extent=extent,
|
|
100
|
-
vmin=value_range[0] if value_range else None,
|
|
101
|
-
vmax=value_range[1] if value_range else None,
|
|
102
|
-
)
|
|
103
|
-
|
|
104
|
-
# Set the ticks and labels
|
|
105
|
-
if tick_mode == "center":
|
|
106
|
-
ax.yaxis.set_major_locator(MaxNLocator(nbins=n_ticks[0]))
|
|
107
|
-
ax.xaxis.set_major_locator(MaxNLocator(nbins=n_ticks[1])) # limits ticks
|
|
108
|
-
|
|
109
|
-
elif tick_mode == "edge":
|
|
110
|
-
dc = np.diff(c).mean() if len(c) > 1 else 1
|
|
111
|
-
dr = np.diff(r).mean() if len(r) > 1 else 1
|
|
112
|
-
ax.set_xticks(np.append(c, c[-1] + dc) - dc / 2)
|
|
113
|
-
ax.set_yticks(np.append(r, r[-1] + dr) - dr / 2)
|
|
114
|
-
|
|
115
|
-
if labels is not None:
|
|
116
|
-
if len(labels) > 0:
|
|
117
|
-
ax.set_title(labels[0])
|
|
118
|
-
if len(labels) > 2:
|
|
119
|
-
ax.set_ylabel(labels[2])
|
|
120
|
-
if len(labels) > 3:
|
|
121
|
-
ax.set_xlabel(labels[3])
|
|
122
|
-
|
|
123
|
-
# Zoom into a region
|
|
124
|
-
if zoom is not None:
|
|
125
|
-
r1, r2, c1, c2 = zoom
|
|
126
|
-
ax.set_xlim(min(c1, c2), max(c1, c2))
|
|
127
|
-
ax.set_ylim(
|
|
128
|
-
(min(r1, r2), max(r1, r2)) if origin == "lower" else (max(r1, r2), min(r1, r2))
|
|
129
|
-
)
|
|
130
|
-
|
|
131
|
-
# Highlight a list of regions
|
|
132
|
-
if highlight is not None:
|
|
133
|
-
for r1, r2, c1, c2 in highlight:
|
|
134
|
-
row_min, row_max = min(r1, r2), max(r1, r2)
|
|
135
|
-
col_min, col_max = min(c1, c2), max(c1, c2)
|
|
136
|
-
width = col_max - col_min
|
|
137
|
-
height = row_max - row_min
|
|
138
|
-
ax.add_patch(Rectangle((col_min, row_min), width, height, color='red', alpha=0.2, zorder=10))
|
|
139
|
-
|
|
140
|
-
# Show colorbar
|
|
141
|
-
if show_colorbar is not None:
|
|
142
|
-
cbar = fig.colorbar(im, ax=ax, cax=cax)
|
|
143
|
-
if len(labels) > 1:
|
|
144
|
-
cbar.set_label(labels[1])
|
|
145
|
-
|
|
146
|
-
# Show grid
|
|
147
|
-
if show_grid:
|
|
148
|
-
ax.grid(True, color="gray", linestyle="--", linewidth=0.5) # TODO
|
|
149
|
-
|
|
150
|
-
# Show/Return the figure as per needed
|
|
151
|
-
if created_fig:
|
|
152
|
-
fig.tight_layout()
|
|
153
|
-
try:
|
|
154
|
-
get_ipython
|
|
155
|
-
plt.close(fig)
|
|
156
|
-
return fig
|
|
157
|
-
except NameError:
|
|
158
|
-
plt.show()
|
|
159
|
-
return fig
|
|
@@ -1,185 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env python3
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
from modusa.decorators import validate_args_type
|
|
5
|
-
from modusa.generators.base import ModusaGenerator
|
|
6
|
-
from modusa.signals import UniformTimeDomainSignal, AudioSignal
|
|
7
|
-
from typing import Any
|
|
8
|
-
import numpy as np
|
|
9
|
-
|
|
10
|
-
class BasicWaveformGenerator(ModusaGenerator):
|
|
11
|
-
"""
|
|
12
|
-
|
|
13
|
-
"""
|
|
14
|
-
|
|
15
|
-
#--------Meta Information----------
|
|
16
|
-
name = ""
|
|
17
|
-
description = ""
|
|
18
|
-
author_name = "Ankit Anand"
|
|
19
|
-
author_email = "ankit0.anand0@gmail.com"
|
|
20
|
-
created_at = "2025-07-04"
|
|
21
|
-
#----------------------------------
|
|
22
|
-
|
|
23
|
-
def __init__(self, signal_cls: Any | None = None):
|
|
24
|
-
if signal_cls is None:
|
|
25
|
-
signal_cls = self.allowed_output_signal_types[0] # Automatically select the first signal
|
|
26
|
-
super().__init__(signal_cls)
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
@property
|
|
30
|
-
def allowed_output_signal_types(self) -> tuple[type, ...]:
|
|
31
|
-
return (UniformTimeDomainSignal, AudioSignal)
|
|
32
|
-
|
|
33
|
-
#----------------------------
|
|
34
|
-
# Generate functions
|
|
35
|
-
#----------------------------
|
|
36
|
-
|
|
37
|
-
def generate_example(self):
|
|
38
|
-
"""
|
|
39
|
-
Generates an instance of `TimeDomainSignal` to test out the features quicky.
|
|
40
|
-
"""
|
|
41
|
-
|
|
42
|
-
T = 0.01 # Time period
|
|
43
|
-
|
|
44
|
-
t = np.arange(0, 10, T)
|
|
45
|
-
y = np.sin(2 * np.pi * 10 * t)
|
|
46
|
-
signal: UniformTimeDomainSignal | AudioSignal = self.signal_cls(y=y, t=t)
|
|
47
|
-
signal.set_units(t_unit="sec")
|
|
48
|
-
signal.set_name("Random")
|
|
49
|
-
signal.set_plot_labels(title=signal.name, y_label="Amplitude", t_label="Time")
|
|
50
|
-
|
|
51
|
-
return signal
|
|
52
|
-
|
|
53
|
-
def generate_random(self):
|
|
54
|
-
"""
|
|
55
|
-
Generates an instance of `TimeDomainSignal` with random initialisation.
|
|
56
|
-
Good for testing purposes.
|
|
57
|
-
"""
|
|
58
|
-
|
|
59
|
-
T = np.random.random()
|
|
60
|
-
|
|
61
|
-
t = np.arange(0, np.random.randint(10, 40), T)
|
|
62
|
-
y = np.random.random(size=t.shape[0])
|
|
63
|
-
signal: UniformTimeDomainSignal | AudioSignal = self.signal_cls(y=y, t=t)
|
|
64
|
-
signal.set_units(t_unit="sec")
|
|
65
|
-
signal.set_name("Random")
|
|
66
|
-
signal.set_plot_labels(title=signal.name, y_label="Amplitude", t_label="Time")
|
|
67
|
-
|
|
68
|
-
return signal
|
|
69
|
-
|
|
70
|
-
@validate_args_type()
|
|
71
|
-
def generate_sinusoid(
|
|
72
|
-
self,
|
|
73
|
-
A: float | int = 1.0,
|
|
74
|
-
f: float | int = 10.0,
|
|
75
|
-
phi: float | int = 0.0,
|
|
76
|
-
duration: float | int = 1.0,
|
|
77
|
-
Ts: float | int = 0.01,
|
|
78
|
-
):
|
|
79
|
-
"""
|
|
80
|
-
Generates a sinusoidal `TimeDomainSignal` with specified frequency, duration, sampling period, and phase.
|
|
81
|
-
"""
|
|
82
|
-
|
|
83
|
-
A, f, phi, duration, Ts = float(A), float(f), float(phi), float(duration), float(Ts)
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
t = np.arange(0, duration, Ts)
|
|
87
|
-
y = A * np.sin(2 * np.pi * f * t + phi)
|
|
88
|
-
|
|
89
|
-
signal = self.signal_cls(y=y, t=t)
|
|
90
|
-
signal.set_name(name=f"Sinusoid: {f}Hz")
|
|
91
|
-
signal.set_plot_labels(
|
|
92
|
-
title=signal.name,
|
|
93
|
-
y_label="Amplitude",
|
|
94
|
-
t_label="Time"
|
|
95
|
-
)
|
|
96
|
-
|
|
97
|
-
return signal
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
@validate_args_type()
|
|
101
|
-
def generate_square(
|
|
102
|
-
self,
|
|
103
|
-
A: float | int = 1.0,
|
|
104
|
-
f: float | int = 10.0,
|
|
105
|
-
phi: float | int = 0.0,
|
|
106
|
-
duration: float | int = 1.0,
|
|
107
|
-
Ts: float | int = 0.01,
|
|
108
|
-
):
|
|
109
|
-
"""
|
|
110
|
-
Generates a square wave
|
|
111
|
-
"""
|
|
112
|
-
|
|
113
|
-
A, f, phi, duration, Ts = float(A), float(f), float(phi), float(duration), float(Ts)
|
|
114
|
-
|
|
115
|
-
t = np.arange(0, duration, Ts)
|
|
116
|
-
y = A * np.sign(np.sin(2 * np.pi * f * t + phi))
|
|
117
|
-
|
|
118
|
-
signal: UniformTimeDomainSignal | AudioSignal = self.signal_cls(y=y, t=t)
|
|
119
|
-
signal.set_units(t_unit="sec")
|
|
120
|
-
signal.set_name(name=f"Square: {f}Hz")
|
|
121
|
-
signal.set_plot_labels(
|
|
122
|
-
title=signal.name,
|
|
123
|
-
y_label="Amplitude",
|
|
124
|
-
t_label="Time"
|
|
125
|
-
)
|
|
126
|
-
|
|
127
|
-
return signal
|
|
128
|
-
|
|
129
|
-
@validate_args_type()
|
|
130
|
-
def generate_sawtooth(
|
|
131
|
-
self,
|
|
132
|
-
A: float | int = 1.0,
|
|
133
|
-
f: float | int = 10.0,
|
|
134
|
-
phi: float | int = 0.0,
|
|
135
|
-
duration: float | int = 1.0,
|
|
136
|
-
Ts: float | int = 0.01,
|
|
137
|
-
):
|
|
138
|
-
"""
|
|
139
|
-
Generates a sawtooth wave.
|
|
140
|
-
"""
|
|
141
|
-
|
|
142
|
-
A, f, phi, duration, Ts = float(A), float(f), float(phi), float(duration), float(Ts)
|
|
143
|
-
|
|
144
|
-
t = np.arange(0, duration, Ts)
|
|
145
|
-
y = A * (2 * (t * f + phi) % 1 - 1)
|
|
146
|
-
|
|
147
|
-
signal: UniformTimeDomainSignal | AudioSignal = self.signal_cls(y=y, t=t)
|
|
148
|
-
signal.set_units(t_unit="sec")
|
|
149
|
-
signal.set_name(name=f"Sawtooth: {f}Hz")
|
|
150
|
-
signal.set_plot_labels(
|
|
151
|
-
title=signal.name,
|
|
152
|
-
y_label="Amplitude",
|
|
153
|
-
t_label="Time"
|
|
154
|
-
)
|
|
155
|
-
|
|
156
|
-
return signal
|
|
157
|
-
|
|
158
|
-
@validate_args_type()
|
|
159
|
-
def generate_triangle(
|
|
160
|
-
self,
|
|
161
|
-
A: float | int = 1.0,
|
|
162
|
-
f: float | int = 10.0,
|
|
163
|
-
phi: float | int = 0.0,
|
|
164
|
-
duration: float | int = 1.0,
|
|
165
|
-
Ts: float | int = 0.01,
|
|
166
|
-
):
|
|
167
|
-
"""
|
|
168
|
-
Generates a triangle wave
|
|
169
|
-
"""
|
|
170
|
-
|
|
171
|
-
A, f, phi, duration, Ts = float(A), float(f), float(phi), float(duration), float(Ts)
|
|
172
|
-
|
|
173
|
-
t = np.arange(0, duration, Ts)
|
|
174
|
-
signal = A * np.abs(2 * (t * f + phi) % 1 - 1)
|
|
175
|
-
|
|
176
|
-
signal: UniformTimeDomainSignal | AudioSignal = self.signal_cls(y=y)
|
|
177
|
-
signal.set_units(t_unit="sec")
|
|
178
|
-
signal.set_name(name=f"Triangle: {f}Hz")
|
|
179
|
-
signal.set_plot_labels(
|
|
180
|
-
title=signal.name,
|
|
181
|
-
y_label="Amplitude",
|
|
182
|
-
t_label="Time"
|
|
183
|
-
)
|
|
184
|
-
|
|
185
|
-
return signal
|
modusa/plugins/plot_1dsignal.py
DELETED
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env python3
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
from modusa.plugins.base import ModusaPlugin
|
|
5
|
-
from modusa.decorators import immutable_property, validate_args_type, plugin_safety_check
|
|
6
|
-
import matplotlib.pyplot as plt
|
|
7
|
-
|
|
8
|
-
class Plot1DSignalPlugin(ModusaPlugin):
|
|
9
|
-
"""
|
|
10
|
-
|
|
11
|
-
"""
|
|
12
|
-
|
|
13
|
-
#--------Meta Information----------
|
|
14
|
-
name = "Plot 1D Signal Plugin"
|
|
15
|
-
description = "A 1D signal plotter plugin with various features."
|
|
16
|
-
author_name = "Ankit Anand"
|
|
17
|
-
author_email = "ankit0.anand0@gmail.com"
|
|
18
|
-
created_at = "2025-07-02"
|
|
19
|
-
#----------------------------------
|
|
20
|
-
|
|
21
|
-
def __init__(self):
|
|
22
|
-
super().__init__()
|
|
23
|
-
|
|
24
|
-
@immutable_property(error_msg="Mutation not allowed.")
|
|
25
|
-
def allowed_input_signal_types(self) -> tuple[type, ...]:
|
|
26
|
-
from modusa.signals import Signal1D
|
|
27
|
-
return (Signal1D, )
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
@immutable_property(error_msg="Mutation not allowed.")
|
|
31
|
-
def allowed_output_signal_types(self) -> tuple[type, ...]:
|
|
32
|
-
return (plt.Figure, type(None)) # None is returned when we want to plot on a given axes, no figure is created in that case
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
@plugin_safety_check()
|
|
36
|
-
@validate_args_type()
|
|
37
|
-
def apply(
|
|
38
|
-
self,
|
|
39
|
-
signal: "Signal1D",
|
|
40
|
-
scale_y: tuple[float, float] | None = None,
|
|
41
|
-
scale_x: tuple[float, float] | None = None,
|
|
42
|
-
ax: plt.Axes | None = None,
|
|
43
|
-
color: str | None = "k",
|
|
44
|
-
marker: str | None = None,
|
|
45
|
-
linestyle: str | None = None,
|
|
46
|
-
stem: bool = False,
|
|
47
|
-
labels: tuple[str, str, str] | None = None,
|
|
48
|
-
legend_loc: str | None = None,
|
|
49
|
-
zoom: tuple[float, float] | None = None,
|
|
50
|
-
highlight: list[tuple[float, float], ...] | None = None,
|
|
51
|
-
show_grid: bool | None = False,
|
|
52
|
-
) -> plt.Figure:
|
|
53
|
-
|
|
54
|
-
# Run the engine here
|
|
55
|
-
from modusa.engines import Plot1DSignalEngine
|
|
56
|
-
|
|
57
|
-
fig: plt.Figure | None = Plot1DSignalEngine().run(y=signal.data, x=signal.x, scale_y=scale_y, scale_x=scale_x, ax=ax, color=color, marker=marker, linestyle=linestyle, stem=stem, labels=labels, legend_loc=legend_loc, zoom=zoom, highlight=highlight)
|
|
58
|
-
|
|
59
|
-
return fig
|
modusa/plugins/plot_2dmatrix.py
DELETED
|
@@ -1,76 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env python3
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
from modusa.plugins.base import ModusaPlugin
|
|
5
|
-
from modusa.decorators import immutable_property, validate_args_type, plugin_safety_check
|
|
6
|
-
import matplotlib.pyplot as plt
|
|
7
|
-
|
|
8
|
-
class Plot2DMatrixPlugin(ModusaPlugin):
|
|
9
|
-
"""
|
|
10
|
-
|
|
11
|
-
"""
|
|
12
|
-
|
|
13
|
-
#--------Meta Information----------
|
|
14
|
-
name = "Plot 2D Matrix Plugin"
|
|
15
|
-
description = "A 2D matrix plotter plugin with various features."
|
|
16
|
-
author_name = "Ankit Anand"
|
|
17
|
-
author_email = "ankit0.anand0@gmail.com"
|
|
18
|
-
created_at = "2025-07-02"
|
|
19
|
-
#----------------------------------
|
|
20
|
-
|
|
21
|
-
def __init__(self):
|
|
22
|
-
super().__init__()
|
|
23
|
-
|
|
24
|
-
@immutable_property(error_msg="Mutation not allowed.")
|
|
25
|
-
def allowed_input_signal_types(self) -> tuple[type, ...]:
|
|
26
|
-
from modusa.signals import Signal2D
|
|
27
|
-
return (Signal2D, )
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
@immutable_property(error_msg="Mutation not allowed.")
|
|
31
|
-
def allowed_output_signal_types(self) -> tuple[type, ...]:
|
|
32
|
-
return (plt.Figure, type(None)) # None is returned when we want to plot on a given axes, no figure is created in that case
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
@plugin_safety_check()
|
|
36
|
-
@validate_args_type()
|
|
37
|
-
def apply(self,
|
|
38
|
-
signal: "Signal2D",
|
|
39
|
-
log_compression_factor: int | float | None = None,
|
|
40
|
-
ax: plt.Axes | None = None,
|
|
41
|
-
labels: tuple[str, str, str, str] | None = None,
|
|
42
|
-
zoom: tuple[float, float, float, float] | None = None, # (r1, r2, c1, c2)
|
|
43
|
-
highlight: list[tuple[float, float, float, float]] | None = None,
|
|
44
|
-
cmap: str = "gray_r",
|
|
45
|
-
origin: str = "upper", # or "lower"
|
|
46
|
-
show_colorbar: bool = True,
|
|
47
|
-
cax: plt.Axes | None = None,
|
|
48
|
-
show_grid: bool = False,
|
|
49
|
-
tick_mode: str = "center", # or "edge"
|
|
50
|
-
n_ticks: tuple[int, int] = (11, 21),
|
|
51
|
-
value_range: tuple[float, float] | None = None,
|
|
52
|
-
|
|
53
|
-
) -> "Signal2D":
|
|
54
|
-
|
|
55
|
-
# Run the engine here
|
|
56
|
-
from modusa.engines import Plot2DMatrixEngine
|
|
57
|
-
|
|
58
|
-
fig: plt.Figure = Plot2DMatrixEngine().run(
|
|
59
|
-
M=signal.M,
|
|
60
|
-
r=signal.r,
|
|
61
|
-
c=signal.c,
|
|
62
|
-
log_compression_factor=log_compression_factor,
|
|
63
|
-
ax=ax,
|
|
64
|
-
labels=signal.labels,
|
|
65
|
-
zoom=zoom,
|
|
66
|
-
highlight=highlight,
|
|
67
|
-
cmap=cmap,
|
|
68
|
-
origin=origin,
|
|
69
|
-
show_colorbar=show_colorbar,
|
|
70
|
-
cax=cax,
|
|
71
|
-
show_grid=show_grid,
|
|
72
|
-
tick_mode=tick_mode,
|
|
73
|
-
n_ticks=n_ticks,
|
|
74
|
-
value_range=value_range)
|
|
75
|
-
|
|
76
|
-
return fig
|
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env python3
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
from modusa.plugins.base import ModusaPlugin
|
|
5
|
-
from modusa.decorators import immutable_property, validate_args_type, plugin_safety_check
|
|
6
|
-
import matplotlib.pyplot as plt
|
|
7
|
-
|
|
8
|
-
class PlotTimeDomainSignalPlugin(ModusaPlugin):
|
|
9
|
-
"""
|
|
10
|
-
|
|
11
|
-
"""
|
|
12
|
-
|
|
13
|
-
#--------Meta Information----------
|
|
14
|
-
name = ""
|
|
15
|
-
description = ""
|
|
16
|
-
author_name = "Ankit Anand"
|
|
17
|
-
author_email = "ankit0.anand0@gmail.com"
|
|
18
|
-
created_at = "2025-07-03"
|
|
19
|
-
#----------------------------------
|
|
20
|
-
|
|
21
|
-
def __init__(self):
|
|
22
|
-
super().__init__()
|
|
23
|
-
|
|
24
|
-
@immutable_property(error_msg="Mutation not allowed.")
|
|
25
|
-
def allowed_input_signal_types(self) -> tuple[type, ...]:
|
|
26
|
-
from modusa.signals import UniformTimeDomainSignal, AudioSignal
|
|
27
|
-
return (UniformTimeDomainSignal, AudioSignal, )
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
@immutable_property(error_msg="Mutation not allowed.")
|
|
31
|
-
def allowed_output_signal_types(self) -> tuple[type, ...]:
|
|
32
|
-
return (plt.Figure, type(None))
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
@plugin_safety_check()
|
|
36
|
-
@validate_args_type()
|
|
37
|
-
def apply(
|
|
38
|
-
self,
|
|
39
|
-
signal: "UniformTimeDomainSignal",
|
|
40
|
-
scale_y: tuple[float, float] | None = None,
|
|
41
|
-
scale_t: tuple[float, float] | None = None,
|
|
42
|
-
ax: plt.Axes | None = None,
|
|
43
|
-
color: str | None = "b",
|
|
44
|
-
marker: str | None = None,
|
|
45
|
-
linestyle: str | None = None,
|
|
46
|
-
stem: bool = False,
|
|
47
|
-
labels: tuple[str, str, str] | None = None,
|
|
48
|
-
legend_loc: str | None = None,
|
|
49
|
-
zoom: tuple[float, float] | None = None,
|
|
50
|
-
highlight: list[tuple[float, float], ...] | None = None,
|
|
51
|
-
show_grid: bool | None = False,
|
|
52
|
-
) -> plt.Figure:
|
|
53
|
-
|
|
54
|
-
# Run the engine here
|
|
55
|
-
from modusa.engines import Plot1DSignalEngine
|
|
56
|
-
|
|
57
|
-
fig: plt.Figure | None = Plot1DSignalEngine().run(y=signal.data, x=signal.t, scale_y=scale_y, scale_x=scale_t, ax=ax, color=color, marker=marker, linestyle=linestyle, stem=stem, labels=labels, legend_loc=legend_loc, zoom=zoom, highlight=highlight)
|
|
58
|
-
|
|
59
|
-
return fig
|