modusa 0.3.1__py3-none-any.whl → 0.3.4a1__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/__init__.py CHANGED
@@ -1,8 +1,9 @@
1
1
  from modusa.utils import excp, config
2
2
 
3
3
  #=====Giving access to plot functions to plot multiple signals.=====
4
- from modusa.tools import plot1d, plot2d
4
+ from modusa.tools import plot1d, plot2d, plot_dist
5
+ #=====
6
+
5
7
  from modusa.tools import play, convert
6
8
  from modusa.tools import download
7
- from modusa.tools import load
8
- #=====
9
+ from modusa.tools import load, load_ann
@@ -9,17 +9,15 @@ from collections import defaultdict
9
9
  # === Configuration ===
10
10
  BASE_MODULES = [
11
11
  'modusa.tools',
12
- 'modusa.models',
13
- 'modusa.generators',
14
- 'modusa.plugins',
15
- # 'modusa.io'
12
+ # 'modusa.models',
13
+ # 'modusa.generators',
14
+ # 'modusa.plugins',
16
15
  ]
17
16
  OUTPUT_DIRS = [
18
17
  Path('docs/source/tools'),
19
- Path('docs/source/models'),
20
- Path('docs/source/generators'),
21
- Path('docs/source/plugins'),
22
- # Path('docs/source/io')
18
+ # Path('docs/source/models'),
19
+ # Path('docs/source/generators'),
20
+ # Path('docs/source/plugins'),
23
21
  ]
24
22
 
25
23
  # Ensure output directories exist
@@ -89,8 +87,6 @@ def generate_docs_source():
89
87
  write_module_rst_file(module_path, class_list, output_dir)
90
88
 
91
89
  section_name = base_module.split('.')[-1].capitalize()
92
- if section_name == "Io":
93
- section_name = "IO"
94
90
 
95
91
  write_index_rst_file(module_class_map, output_dir, section_name=section_name)
96
92
  print(f"✅ Documentation generated for {base_module} in {output_dir}")
modusa/tools/__init__.py CHANGED
@@ -1,7 +1,8 @@
1
1
  #!/usr/bin/env python3
2
2
 
3
- from .plotter import plot1d, plot2d
3
+ from .plotter import plot1d, plot2d, plot_dist
4
4
  from .audio_player import play
5
5
  from .audio_converter import convert
6
6
  from .youtube_downloader import download
7
- from .audio_loader import load
7
+ from .audio_loader import load
8
+ from .ann_loader import load_ann
@@ -0,0 +1,38 @@
1
+ #!/usr/bin/env python3
2
+
3
+ #---------------------------------
4
+ # Author: Ankit Anand
5
+ # Date: 12/08/25
6
+ # Email: ankit0.anand0@gmail.com
7
+ #---------------------------------
8
+
9
+ from pathlib import Path
10
+
11
+ def load_ann(path):
12
+ """
13
+ Load annotation from audatity label text file.
14
+
15
+ Parameters
16
+ ----------
17
+ path: str
18
+ label text file path.
19
+
20
+ Returns
21
+ -------
22
+ list[tuple, ...]
23
+ - annotation data structure
24
+ - [(start, end, tag), ...]
25
+ """
26
+
27
+ if not isinstance(path, (str, Path)):
28
+ raise ValueError(f"`path` must be one of (str, Path), got {type(path)}")
29
+
30
+ ann = []
31
+ with open(str(path), "r") as f:
32
+ lines = [line.rstrip("\n") for line in f]
33
+ for line in lines:
34
+ start, end, tag = line.split("\t")
35
+ start, end = float(start), float(end)
36
+ ann.append((start, end, tag))
37
+
38
+ return ann
modusa/tools/plotter.py CHANGED
@@ -7,8 +7,27 @@ import matplotlib.gridspec as gridspec
7
7
  from matplotlib.patches import Rectangle
8
8
  from mpl_toolkits.axes_grid1.inset_locator import inset_axes
9
9
 
10
+ # Helper for 2D plot
11
+ def _calculate_extent(x, y):
12
+ # Handle spacing safely
13
+ if len(x) > 1:
14
+ dx = x[1] - x[0]
15
+ else:
16
+ dx = 1 # Default spacing for single value
17
+ if len(y) > 1:
18
+ dy = y[1] - y[0]
19
+ else:
20
+ dy = 1 # Default spacing for single value
21
+
22
+ return [
23
+ x[0] - dx / 2,
24
+ x[-1] + dx / 2,
25
+ y[0] - dy / 2,
26
+ y[-1] + dy / 2
27
+ ]
28
+
10
29
  #======== 1D ===========
11
- def plot1d(*args, ann=None, events=None, xlim=None, ylim=None, xlabel=None, ylabel=None, title=None, legend=None):
30
+ def plot1d(*args, ann=None, events=None, xlim=None, ylim=None, xlabel=None, ylabel=None, title=None, legend=None, show_grid=False, show_stem=False):
12
31
  """
13
32
  Plots a 1D signal using matplotlib.
14
33
 
@@ -53,16 +72,23 @@ def plot1d(*args, ann=None, events=None, xlim=None, ylim=None, xlabel=None, ylab
53
72
  legend : list[str] | None
54
73
  - List of legend labels corresponding to each signal if plotting multiple lines.
55
74
  - Default: None
75
+ show_grid: bool
76
+ - If you want to show the grid.
77
+ - Default: False
78
+ show_stem: bool:
79
+ - If you want stem plot.
80
+ - Default: False
56
81
 
57
82
  Returns
58
83
  -------
59
84
  plt.Figure
60
85
  Matplolib figure.
61
86
  """
62
-
87
+
63
88
  for arg in args:
64
89
  if len(arg) not in [1, 2]: # 1 if it just provides values, 2 if it provided axis as well
65
90
  raise ValueError(f"1D signal needs to have max 2 arrays (y, x) or simply (y, )")
91
+
66
92
  if isinstance(legend, str): legend = (legend, )
67
93
 
68
94
  if legend is not None:
@@ -89,35 +115,73 @@ def plot1d(*args, ann=None, events=None, xlim=None, ylim=None, xlabel=None, ylab
89
115
  for i, signal in enumerate(args):
90
116
  if len(signal) == 1:
91
117
  y = signal[0]
118
+ x = np.arange(y.size)
92
119
  if legend is not None:
93
- signal_ax.plot(y, label=legend[i])
120
+ if show_stem is True:
121
+ markerline, stemlines, baseline = signal_ax.stem(x, y, label=legend[i])
122
+ markerline.set_color(colors[i])
123
+ stemlines.set_color(colors[i])
124
+ baseline.set_color("k")
125
+ else:
126
+ signal_ax.plot(x, y, color=colors[i], label=legend[i])
94
127
  else:
95
- signal_ax.plot(y)
128
+ if show_stem is True:
129
+ markerline, stemlines, baseline = signal_ax.stem(x, y)
130
+ markerline.set_color(colors[i])
131
+ stemlines.set_color(colors[i])
132
+ baseline.set_color("k")
133
+ else:
134
+ signal_ax.plot(x, y, color=colors[i])
135
+
96
136
  elif len(signal) == 2:
97
137
  y, x = signal[0], signal[1]
98
138
  if legend is not None:
99
- signal_ax.plot(x, y, label=legend[i])
139
+ if show_stem is True:
140
+ markerline, stemlines, baseline = signal_ax.stem(x, y, label=legend[i])
141
+ markerline.set_color(colors[i])
142
+ stemlines.set_color(colors[i])
143
+ baseline.set_color("k")
144
+ else:
145
+ signal_ax.plot(x, y, color=colors[i], label=legend[i])
100
146
  else:
101
- signal_ax.plot(x, y)
147
+ if show_stem is True:
148
+ markerline, stemlines, baseline = signal_ax.stem(x, y)
149
+ markerline.set_color(colors[i])
150
+ stemlines.set_color(colors[i])
151
+ baseline.set_color("k")
152
+ else:
153
+ signal_ax.plot(x, y, color=colors[i])
102
154
 
103
155
  # Add annotations
104
156
  if ann is not None:
105
- annotation_ax.set_ylim(0, 1)
157
+ annotation_ax.set_ylim(0, 1) # For consistent layout
158
+ # Determine visible x-range
159
+ x_view_min = xlim[0] if xlim is not None else np.min(x)
160
+ x_view_max = xlim[1] if xlim is not None else np.max(x)
161
+
106
162
  for i, (start, end, tag) in enumerate(ann):
107
- if xlim is not None:
108
- if end < xlim[0] or start > xlim[1]:
109
- continue # Skip out-of-view regions
110
- # Clip boundaries to xlim
111
- start = max(start, xlim[0])
112
- end = min(end, xlim[1])
163
+ # We make sure that we only plot annotation that are within the x range of the current view
164
+ if start >= x_view_max or end <= x_view_min:
165
+ continue
166
+
167
+ # Clip boundaries to xlim
168
+ start = max(start, x_view_min)
169
+ end = min(end, x_view_max)
113
170
 
114
171
  color = colors[i % len(colors)]
115
172
  width = end - start
116
173
  rect = Rectangle((start, 0), width, 1, color=color, alpha=0.7)
117
174
  annotation_ax.add_patch(rect)
118
- annotation_ax.text((start + end) / 2, 0.5, tag,
119
- ha='center', va='center',
120
- fontsize=10, color='white', fontweight='bold', zorder=10)
175
+
176
+ text_obj = annotation_ax.text(
177
+ (start + end) / 2, 0.5, tag,
178
+ ha='center', va='center',
179
+ fontsize=10, color='white', fontweight='bold', zorder=10, clip_on=True
180
+ )
181
+
182
+ text_obj.set_clip_path(rect)
183
+
184
+
121
185
  # Add vlines
122
186
  if events is not None:
123
187
  for xpos in events:
@@ -130,7 +194,7 @@ def plot1d(*args, ann=None, events=None, xlim=None, ylim=None, xlabel=None, ylab
130
194
  # Add legend
131
195
  if legend is not None:
132
196
  handles, labels = signal_ax.get_legend_handles_labels()
133
- fig.legend(handles, labels, loc='upper right', bbox_to_anchor=(0.9, 1.2), ncol=len(legend), frameon=False)
197
+ fig.legend(handles, labels, loc='upper right', bbox_to_anchor=(0.9, 1.2), ncol=len(legend), frameon=True)
134
198
 
135
199
  # Set title, labels
136
200
  if title is not None:
@@ -139,8 +203,12 @@ def plot1d(*args, ann=None, events=None, xlim=None, ylim=None, xlabel=None, ylab
139
203
  signal_ax.set_xlabel(xlabel)
140
204
  if ylabel is not None:
141
205
  signal_ax.set_ylabel(ylabel)
206
+
207
+ # Add grid to the plot
208
+ if show_grid is True:
209
+ signal_ax.grid(True, linestyle=':', linewidth=0.7, color='gray', alpha=0.7)
142
210
 
143
- # Decorating annotation axis thicker
211
+ # Remove the boundaries and ticks from an axis
144
212
  if ann is not None:
145
213
  annotation_ax.tick_params(left=False, bottom=False, labelleft=False, labelbottom=False)
146
214
  else:
@@ -152,7 +220,7 @@ def plot1d(*args, ann=None, events=None, xlim=None, ylim=None, xlabel=None, ylab
152
220
  return fig
153
221
 
154
222
  #======== 2D ===========
155
- def plot2d(*args, ann=None, events=None, xlim=None, ylim=None, origin="lower", Mlabel=None, xlabel=None, ylabel=None, title=None, legend=None, lm=False):
223
+ def plot2d(*args, ann=None, events=None, xlim=None, ylim=None, origin="lower", Mlabel=None, xlabel=None, ylabel=None, title=None, legend=None, lm=False, show_grid=False):
156
224
  """
157
225
  Plots a 2D matrix (e.g., spectrogram or heatmap) with optional annotations and events.
158
226
 
@@ -206,6 +274,9 @@ def plot2d(*args, ann=None, events=None, xlim=None, ylim=None, origin="lower", M
206
274
  - Adds a circular marker for the line.
207
275
  - Default: False
208
276
  - Useful to show the data points.
277
+ show_grid: bool
278
+ - If you want to show the grid.
279
+ - Default: False
209
280
 
210
281
  Returns
211
282
  -------
@@ -246,6 +317,8 @@ def plot2d(*args, ann=None, events=None, xlim=None, ylim=None, origin="lower", M
246
317
  if data.ndim == 1: # 1D
247
318
  if len(signal) == 1: # It means that the axis was not passed
248
319
  x = np.arange(data.shape[0])
320
+ else:
321
+ x = signal[1]
249
322
 
250
323
  if lm is False:
251
324
  if legend is not None:
@@ -267,36 +340,42 @@ def plot2d(*args, ann=None, events=None, xlim=None, ylim=None, origin="lower", M
267
340
  if len(signal) == 1: # It means that the axes were not passed
268
341
  y = np.arange(M.shape[0])
269
342
  x = np.arange(M.shape[1])
270
- dx = x[1] - x[0]
271
- dy = y[1] - y[0]
272
- extent=[x[0] - dx/2, x[-1] + dx/2, y[0] - dy/2, y[-1] + dy/2]
343
+ extent = _calculate_extent(x, y)
273
344
  im = signal_ax.imshow(M, aspect="auto", origin=origin, cmap="gray_r", extent=extent)
274
345
 
275
346
  elif len(signal) == 3: # It means that the axes were passed
276
347
  M, y, x = signal[0], signal[1], signal[2]
277
- dx = x[1] - x[0]
278
- dy = y[1] - y[0]
279
- extent=[x[0] - dx/2, x[-1] + dx/2, y[0] - dy/2, y[-1] + dy/2]
348
+ extent = _calculate_extent(x, y)
280
349
  im = signal_ax.imshow(M, aspect="auto", origin=origin, cmap="gray_r", extent=extent)
281
350
 
282
351
  # Add annotations
283
352
  if ann is not None:
284
- annotation_ax.set_ylim(0, 1)
353
+ annotation_ax.set_ylim(0, 1) # For consistent layout
354
+ # Determine visible x-range
355
+ x_view_min = xlim[0] if xlim is not None else np.min(x)
356
+ x_view_max = xlim[1] if xlim is not None else np.max(x)
357
+
285
358
  for i, (start, end, tag) in enumerate(ann):
286
- if xlim is not None:
287
- if end < xlim[0] or start > xlim[1]:
288
- continue # Skip out-of-view regions
289
- # Clip boundaries to xlim
290
- start = max(start, xlim[0])
291
- end = min(end, xlim[1])
359
+ # We make sure that we only plot annotation that are within the x range of the current view
360
+ if start >= x_view_max or end <= x_view_min:
361
+ continue
362
+
363
+ # Clip boundaries to xlim
364
+ start = max(start, x_view_min)
365
+ end = min(end, x_view_max)
292
366
 
293
367
  color = colors[i % len(colors)]
294
368
  width = end - start
295
369
  rect = Rectangle((start, 0), width, 1, color=color, alpha=0.7)
296
370
  annotation_ax.add_patch(rect)
297
- annotation_ax.text((start + end) / 2, 0.5, tag,
298
- ha='center', va='center',
299
- fontsize=10, color='white', fontweight='bold', zorder=10)
371
+ text_obj = annotation_ax.text(
372
+ (start + end) / 2, 0.5, tag,
373
+ ha='center', va='center',
374
+ fontsize=10, color='white', fontweight='bold', zorder=10, clip_on=True
375
+ )
376
+
377
+ text_obj.set_clip_path(rect)
378
+
300
379
  # Add vlines
301
380
  if events is not None:
302
381
  for xpos in events:
@@ -338,7 +417,10 @@ def plot2d(*args, ann=None, events=None, xlim=None, ylim=None, origin="lower", M
338
417
  signal_ax.set_xlabel(xlabel)
339
418
  if ylabel is not None:
340
419
  signal_ax.set_ylabel(ylabel)
341
-
420
+
421
+ # Add grid to the plot
422
+ if show_grid is True:
423
+ signal_ax.grid(True, linestyle=':', linewidth=0.7, color='gray', alpha=0.7)
342
424
 
343
425
  # Making annotation axis spines thicker
344
426
  if ann is not None:
@@ -348,4 +430,149 @@ def plot2d(*args, ann=None, events=None, xlim=None, ylim=None, origin="lower", M
348
430
 
349
431
  fig.subplots_adjust(hspace=0.01, wspace=0.05)
350
432
  plt.close()
351
- return fig
433
+ return fig
434
+
435
+ #======== Plot distribution ===========
436
+ def plot_dist(*args, ann=None, xlim=None, ylim=None, ylabel=None, xlabel=None, title=None, legend=None, show_hist=True, npoints=200, bins=30):
437
+ """
438
+ Plot distribution.
439
+
440
+ .. code-block:: python
441
+
442
+ import modusa as ms
443
+ import numpy as np
444
+ np.random.seed(42)
445
+ data = np.random.normal(loc=1, scale=1, size=1000)
446
+ ms.plot_dist(data, data+5, data-10, ann=[(0, 1, "A")], legend=("D1", "D2", "D3"), ylim=(0, 1), xlabel="X", ylabel="Counts", title="Distribution")
447
+
448
+ Parameters
449
+ ----------
450
+ *args: ndarray
451
+ - Data arrays for which distribution needs to be plotted.
452
+ - Arrays will be flattened.
453
+ ann : list[tuple[Number, Number, str] | None
454
+ - A list of annotations to mark specific points. Each tuple should be of the form (start, end, label).
455
+ - Default: None => No annotation.
456
+ events : list[Number] | None
457
+ - A list of x-values where vertical lines (event markers) will be drawn.
458
+ - Default: None
459
+ xlim : tuple[Number, Number] | None
460
+ - Limits for the x-axis as (xmin, xmax).
461
+ - Default: None
462
+ ylim : tuple[Number, Number] | None
463
+ - Limits for the y-axis as (ymin, ymax).
464
+ - Default: None
465
+ xlabel : str | None
466
+ - Label for the x-axis.
467
+ - - Default: None
468
+ ylabel : str | None
469
+ - Label for the y-axis.
470
+ - Default: None
471
+ title : str | None
472
+ - Title of the plot.
473
+ - Default: None
474
+ legend : list[str] | None
475
+ - List of legend labels corresponding to each signal if plotting multiple distributions.
476
+ - Default: None
477
+ show_hist: bool
478
+ - Want to show histogram as well.
479
+ npoints: int
480
+ - Number of points for which gaussian needs to be computed between min and max.
481
+ - Higher value means more points are evaluated with the fitted gaussian, thereby higher resolution.
482
+ bins: int
483
+ - The number of bins for histogram.
484
+ - This is used only to plot the histogram.
485
+
486
+ Returns
487
+ -------
488
+ plt.Figure
489
+ - Matplotlib figure.
490
+ """
491
+ from scipy.stats import gaussian_kde
492
+
493
+ if isinstance(legend, str):
494
+ legend = (legend, )
495
+
496
+ if legend is not None:
497
+ if len(legend) < len(args):
498
+ raise ValueError(f"Legend should be provided for each signal.")
499
+
500
+ # Create figure
501
+ fig = plt.figure(figsize=(16, 4))
502
+ gs = gridspec.GridSpec(2, 1, height_ratios=[0.1, 1])
503
+
504
+ colors = plt.get_cmap('tab10').colors
505
+
506
+ dist_ax = fig.add_subplot(gs[1, 0])
507
+ annotation_ax = fig.add_subplot(gs[0, 0], sharex=dist_ax)
508
+
509
+ # Set limits
510
+ if xlim is not None:
511
+ dist_ax.set_xlim(xlim)
512
+
513
+ if ylim is not None:
514
+ dist_ax.set_ylim(ylim)
515
+
516
+ # Add plot
517
+ for i, data in enumerate(args):
518
+ # Fit gaussian to the data
519
+ kde = gaussian_kde(data)
520
+
521
+ # Create points to evaluate KDE
522
+ x = np.linspace(np.min(data), np.max(data), npoints)
523
+ y = kde(x)
524
+
525
+ if legend is not None:
526
+ dist_ax.plot(x, y, color=colors[i], label=legend[i])
527
+ if show_hist is True:
528
+ dist_ax.hist(data, bins=bins, density=True, alpha=0.3, facecolor=colors[i], edgecolor='black', label=legend[i])
529
+ else:
530
+ dist_ax.plot(x, y, color=colors[i])
531
+ if show_hist is True:
532
+ dist_ax.hist(data, bins=bins, density=True, alpha=0.3, facecolor=colors[i], edgecolor='black')
533
+
534
+ # Add annotations
535
+ if ann is not None:
536
+ annotation_ax.set_ylim(0, 1) # For consistent layout
537
+ # Determine visible x-range
538
+ x_view_min = xlim[0] if xlim is not None else np.min(x)
539
+ x_view_max = xlim[1] if xlim is not None else np.max(x)
540
+ for i, (start, end, tag) in enumerate(ann):
541
+ # We make sure that we only plot annotation that are within the x range of the current view
542
+ if start >= x_view_max or end <= x_view_min:
543
+ continue
544
+
545
+ # Clip boundaries to xlim
546
+ start = max(start, x_view_min)
547
+ end = min(end, x_view_max)
548
+
549
+ color = colors[i % len(colors)]
550
+ width = end - start
551
+ rect = Rectangle((start, 0), width, 1, color=color, alpha=0.7)
552
+ annotation_ax.add_patch(rect)
553
+
554
+ text_obj = annotation_ax.text((start + end) / 2, 0.5, tag, ha='center', va='center', fontsize=10, color='white', fontweight='bold', zorder=10, clip_on=True)
555
+ text_obj.set_clip_path(rect)
556
+
557
+ # Add legend
558
+ if legend is not None:
559
+ handles, labels = dist_ax.get_legend_handles_labels()
560
+ fig.legend(handles, labels, loc='upper right', bbox_to_anchor=(0.9, 1.1), ncol=len(legend), frameon=True)
561
+
562
+ # Set title, labels
563
+ if title is not None:
564
+ annotation_ax.set_title(title, pad=10, size=11)
565
+ if xlabel is not None:
566
+ dist_ax.set_xlabel(xlabel)
567
+ if ylabel is not None:
568
+ dist_ax.set_ylabel(ylabel)
569
+
570
+ # Remove the boundaries and ticks from annotation axis
571
+ if ann is not None:
572
+ annotation_ax.tick_params(left=False, bottom=False, labelleft=False, labelbottom=False)
573
+ else:
574
+ annotation_ax.axis("off")
575
+
576
+ fig.subplots_adjust(hspace=0.01, wspace=0.05)
577
+ plt.close()
578
+ return fig
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: modusa
3
- Version: 0.3.1
3
+ Version: 0.3.4a1
4
4
  Summary: A modular signal analysis python library.
5
5
  Author-Email: Ankit Anand <ankit0.anand0@gmail.com>
6
6
  License: MIT
@@ -1,12 +1,12 @@
1
- modusa-0.3.1.dist-info/METADATA,sha256=cErfyykQ9YH87Zjs2TjmBM1iV_jIMHUF4BAU97q09lU,1368
2
- modusa-0.3.1.dist-info/WHEEL,sha256=9P2ygRxDrTJz3gsagc0Z96ukrxjr-LFBGOgv3AuKlCA,90
3
- modusa-0.3.1.dist-info/entry_points.txt,sha256=fmKpleVXj6CdaBVL14WoEy6xx7JQCs85jvzwTi3lePM,73
4
- modusa-0.3.1.dist-info/licenses/LICENSE.md,sha256=JTaXAjx5awk76VArKCx5dUW8vmLEWsL_ZlR7-umaHbA,1078
1
+ modusa-0.3.4a1.dist-info/METADATA,sha256=bt8qXMgqrL5e9qyRv_kJ2CXzCUDH0oqvIOvTEU5hvVs,1370
2
+ modusa-0.3.4a1.dist-info/WHEEL,sha256=9P2ygRxDrTJz3gsagc0Z96ukrxjr-LFBGOgv3AuKlCA,90
3
+ modusa-0.3.4a1.dist-info/entry_points.txt,sha256=fmKpleVXj6CdaBVL14WoEy6xx7JQCs85jvzwTi3lePM,73
4
+ modusa-0.3.4a1.dist-info/licenses/LICENSE.md,sha256=JTaXAjx5awk76VArKCx5dUW8vmLEWsL_ZlR7-umaHbA,1078
5
5
  modusa/.DS_Store,sha256=_gm6qJREwfMi8dE7n5S89_RG46u5t3xHyD-smNhtNoM,6148
6
- modusa/__init__.py,sha256=AALG_17vibpDZbo0MymvGoQroaLp3uVm_onZaESONQA,257
6
+ modusa/__init__.py,sha256=uq6kORFFAODiCMGmOLWO0shE8-dVFWf5gmV8wxekmnk,280
7
7
  modusa/config.py,sha256=bTqK4t00FZqERVITrxW_q284aDDJAa9aMSfFknfR-oU,280
8
8
  modusa/decorators.py,sha256=8zeNX_wE37O6Vp0ysR4-WCZaEL8mq8dyCF_I5DHOzks,5905
9
- modusa/devtools/generate_docs_source.py,sha256=qqxr3UgTeM4iotarQGRN_q2QXwAzGH7ha9bVjs8D4GQ,3409
9
+ modusa/devtools/generate_docs_source.py,sha256=UDflHsk-Yh9-3YJTVBzKL32y8hcxiRgAlFEBTMiDqwM,3301
10
10
  modusa/devtools/generate_template.py,sha256=0sT_5-SjMLXyvePRDaIxr1RCz_9v6zFH9OoJqpuD2zI,5204
11
11
  modusa/devtools/list_authors.py,sha256=FWBQKOLznVthvMYMASrx2Gw5lqKHEOccQpBisDZ53Dw,24
12
12
  modusa/devtools/list_plugins.py,sha256=g-R5hoaCzHfClY_Sfa788IQ9CAKzQGTfyqmthXDZQqw,1729
@@ -27,7 +27,6 @@ modusa/generators/s2d.py,sha256=kU67dZj4tdIDSUFJeheXm_JKbyHpZZOGmW5jya6w0wo,6874
27
27
  modusa/generators/s_ax.py,sha256=4CTFp_KwYnl4HDno-ATpTXOfKR9WEVOV45nwuk2OoVk,2221
28
28
  modusa/generators/t_ax.py,sha256=X-XOJuGWw99dPAVsCVzNTfBFr81Vw56aZlGDmcl5q3k,1478
29
29
  modusa/generators/tds.py,sha256=eGvzcjXyWaw5NVzM3D098r3xkoMcX8Ma9YoDUdL30Mo,5960
30
- modusa/main.py,sha256=v9oOhnPcbw8ULfkKRoantEfHw7MqOETJwXC-odx3dnA,25
31
30
  modusa/models/__init__.py,sha256=G8sNOnBnTKqPmC4Z46ximBhc_pfBOF_G6AIfxT8DFzw,271
32
31
  modusa/models/__pycache__/signal1D.cpython-312.pyc.4443461152,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
33
32
  modusa/models/audio.py,sha256=IcNx3h8tb5Jt6KZug_TQKM5iufVk3i7Ug37iKG4gsJ0,2411
@@ -41,14 +40,14 @@ modusa/models/t_ax.py,sha256=ZUhvZPUW1TkdZYuUd6Ucm-vsv0JqtZ9yEe3ab67Ma6w,8022
41
40
  modusa/models/tds.py,sha256=FAGfibjyyE_lkEuQp-vSCuqQnopOjmy_IXqUjRlg9kc,11677
42
41
  modusa/plugins/__init__.py,sha256=r1Bf5mnrVKRIwxboutY1iGzDy4EPQhqpk1kSW7iJj_Q,54
43
42
  modusa/plugins/base.py,sha256=Bh_1Bja7fOymFsCgwhXDbV6ys3D8muNrPwrfDrG_G_A,2382
44
- modusa/tmp.py,sha256=zPwgFVk5Oh6Rp6GUCbWJdkmwo6vYvhSqI35QVhW5xQM,3180
45
- modusa/tools/__init__.py,sha256=jOFL7PJ1IztN6F7aMdrVKNMTid2yUmoSlSST-WFf0Cc,199
43
+ modusa/tools/__init__.py,sha256=ixqujVIJwU5TNX2j64lVajGtZlXTspcxN-30X54GgcM,243
44
+ modusa/tools/ann_loader.py,sha256=RePlwD4qG6gGrD4mOJ3RDR9q_gUscCY90_R9lgFU9lM,780
46
45
  modusa/tools/audio_converter.py,sha256=415qBoPm2sBIuBSI7m1XBKm0AbmVmPydIPPr-uO8D3c,1778
47
46
  modusa/tools/audio_loader.py,sha256=DrCzq0pdiQrUDIG-deLJGcu8EaylO5yRtwT4lr8WSf8,2166
48
47
  modusa/tools/audio_player.py,sha256=GP04TWW4jBwQBjANkfR_cJtEy7cIhvbu8RTwnf9hD6E,2817
49
48
  modusa/tools/base.py,sha256=C0ESJ0mIfjjRlAkRbSetNtMoOfS6IrHBjexRp3l_Mh4,1293
50
49
  modusa/tools/math_ops.py,sha256=ZZ7U4DgqT7cOeE7_Lzi_Qq-48WYfwR9_osbZwTmE9eg,8690
51
- modusa/tools/plotter.py,sha256=HaiIyP0Ll-Rk8Nw54g-R-AY9aAZxSAtnviYFnfuln_w,10552
50
+ modusa/tools/plotter.py,sha256=KQ94DhZj5ZJr7OhlUslRmtJ938S5ZCDsY0iXrY5QIyc,17656
52
51
  modusa/tools/youtube_downloader.py,sha256=hB_X8-7nOHXOlxg6vv3wyhBLoAsWyomrULP6_uCQL7s,1698
53
52
  modusa/utils/.DS_Store,sha256=nLXMwF7QJNuglLI_Gk74F7vl5Dyus2Wd74Mgowijmdo,6148
54
53
  modusa/utils/__init__.py,sha256=1oLL20yLB1GL9IbFiZD8OReDqiCpFr-yetIR6x1cNkI,23
@@ -57,4 +56,4 @@ modusa/utils/excp.py,sha256=L9vhaGjKpv9viJYdmC9n5ndmk2GVbUBuFyZyhAQZmWY,906
57
56
  modusa/utils/logger.py,sha256=K0rsnObeNKCxlNeSnVnJeRhgfmob6riB2uyU7h3dDmA,571
58
57
  modusa/utils/np_func_cat.py,sha256=TyIFgRc6bARRMDnZxlVURO5Z0I-GWhxRONYyIv-Vwxs,1007
59
58
  modusa/utils/plot.py,sha256=s_vNdxvKfwxEngvJPgrF1PcmxZNnNaaXPViHWjyjJ-c,5335
60
- modusa-0.3.1.dist-info/RECORD,,
59
+ modusa-0.3.4a1.dist-info/RECORD,,
modusa/main.py DELETED
@@ -1,3 +0,0 @@
1
- #!/usr/bin/env python3
2
-
3
-
modusa/tmp.py DELETED
@@ -1,98 +0,0 @@
1
- #def autocorr(self) -> Self:
2
- # """
3
- #
4
- # """
5
- # raise NotImplementedError
6
- # r = np.correlate(self.data, self.data, mode="full")
7
- # r = r[self.data.shape[0] - 1:]
8
- # r_signal = self.__class__(data=r, sr=self.sr, t0=self.t0, title=self.title + " [Autocorr]")
9
- # return r_signal
10
-
11
- # #----------------------------
12
- # # To different signals
13
- # #----------------------------
14
- # def to_audio_signal(self) -> "AudioSignal":
15
- # """
16
- # Moves TimeDomainSignal to AudioSignal
17
- # """
18
- # raise NotImplementedError
19
- # from modusa.signals.audio_signal import AudioSignal
20
- #
21
- # return AudioSignal(data=self.data, sr=self.sr, t0=self.t0, title=self.title)
22
- #
23
- # def to_spectrogram(
24
- # self,
25
- # n_fft: int = 2048,
26
- # hop_length: int = 512,
27
- # win_length: int | None = None,
28
- # window: str = "hann"
29
- # ) -> "Spectrogram":
30
- # """
31
- # Compute the Short-Time Fourier Transform (STFT) and return a Spectrogram object.
32
- #
33
- # Parameters
34
- # ----------
35
- # n_fft : int
36
- # FFT size.
37
- # win_length : int or None
38
- # Window length. Defaults to `n_fft` if None.
39
- # hop_length : int
40
- # Hop length between frames.
41
- # window : str
42
- # Type of window function to use (e.g., 'hann', 'hamming').
43
- #
44
- # Returns
45
- # -------
46
- # Spectrogram
47
- # Spectrogram object containing S (complex STFT), t (time bins), and f (frequency bins).
48
- # """
49
- # raise NotImplementedError
50
- # import warnings
51
- # warnings.filterwarnings("ignore", category=UserWarning, module="librosa.core.intervals")
52
- #
53
- # from modusa.signals.feature_time_domain_signal import FeatureTimeDomainSignal
54
- # import librosa
55
- #
56
- # S = librosa.stft(self.data, n_fft=n_fft, win_length=win_length, hop_length=hop_length, window=window)
57
- # f = librosa.fft_frequencies(sr=self.sr, n_fft=n_fft)
58
- # t = librosa.frames_to_time(np.arange(S.shape[1]), sr=self.sr, hop_length=hop_length)
59
- # frame_rate = self.sr / hop_length
60
- # spec = FeatureTimeDomainSignal(data=S, feature=f, feature_label="Freq (Hz)", frame_rate=frame_rate, t0=self.t0, time_label="Time (sec)", title=self.title)
61
- # if self.title != self._name: # Means title of the audio was reset so we pass that info to spec
62
- # spec = spec.set_meta_info(title=self.title)
63
- #
64
- # return spec
65
- # #=====================================
66
-
67
- #=====================================
68
-
69
- #--------------------------
70
- # Other signal ops
71
- #--------------------------
72
-
73
- # def interpolate(self, to: TimeDomainSignal, kind: str = "linear", fill_value: str | float = "extrapolate") -> TimeDomainSignal:
74
- # """
75
- # Interpolate the current signal to match the time axis of `to`.
76
- #
77
- # Parameters:
78
- # to (TimeDomainSignal): The signal whose time axis will be used.
79
- # kind (str): Interpolation method ('linear', 'nearest', etc.)
80
- # fill_value (str or float): Value used to fill out-of-bounds.
81
- #
82
- # Returns:
83
- # TimeDomainSignal: A new signal with values interpolated at `to.t`.
84
- # """
85
- # assert self.y.ndim == 1, "Only 1D signals supported for interpolation"
86
- #
87
- # interpolator = interp1d(
88
- # self.t,
89
- # self.y,
90
- # kind=kind,
91
- # fill_value=fill_value,
92
- # bounds_error=False,
93
- # assume_sorted=True
94
- # )
95
- #
96
- # y_interp = interpolator(to.y)
97
-
98
- # return self.__class__(y=y_interp, sr=to.sr, t0=to.t0, title=f"{self.title} → interpolated")