modusa 0.3.22__py3-none-any.whl → 0.3.24__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
@@ -362,4 +362,142 @@ def plot2d(*args, ann=None, events=None, xlim=None, ylim=None, origin="lower", M
362
362
 
363
363
  fig.subplots_adjust(hspace=0.01, wspace=0.05)
364
364
  plt.close()
365
- return fig
365
+ return fig
366
+
367
+ #======== Plot distribution ===========
368
+ def plot_dist(*args, ann=None, xlim=None, ylim=None, ylabel=None, xlabel=None, title=None, legend=None, show_hist=True, npoints=200):
369
+ """
370
+ Plot distribution.
371
+
372
+ .. code-block:: python
373
+
374
+ import modusa as ms
375
+ import numpy as np
376
+ np.random.seed(42)
377
+ data = np.random.normal(loc=1, scale=1, size=1000)
378
+ 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")
379
+
380
+ Parameters
381
+ ----------
382
+ *args: ndarray
383
+ - Data arrays for which distribution needs to be plotted.
384
+ - Arrays will be flattened.
385
+ ann : list[tuple[Number, Number, str] | None
386
+ - A list of annotations to mark specific points. Each tuple should be of the form (start, end, label).
387
+ - Default: None => No annotation.
388
+ events : list[Number] | None
389
+ - A list of x-values where vertical lines (event markers) will be drawn.
390
+ - Default: None
391
+ xlim : tuple[Number, Number] | None
392
+ - Limits for the x-axis as (xmin, xmax).
393
+ - Default: None
394
+ ylim : tuple[Number, Number] | None
395
+ - Limits for the y-axis as (ymin, ymax).
396
+ - Default: None
397
+ xlabel : str | None
398
+ - Label for the x-axis.
399
+ - - Default: None
400
+ ylabel : str | None
401
+ - Label for the y-axis.
402
+ - Default: None
403
+ title : str | None
404
+ - Title of the plot.
405
+ - Default: None
406
+ legend : list[str] | None
407
+ - List of legend labels corresponding to each signal if plotting multiple distributions.
408
+ - Default: None
409
+ show_hist: bool
410
+ - Want to show histogram as well.
411
+ npoints: int
412
+ - Number of points for which gaussian needs to be computed between min and max.
413
+ - Higher value means more points are evaluated with the fitted gaussian, thereby higher resolution.
414
+
415
+ Returns
416
+ -------
417
+ plt.Figure
418
+ - Matplotlib figure.
419
+ """
420
+ from scipy.stats import gaussian_kde
421
+
422
+ if isinstance(legend, str):
423
+ legend = (legend, )
424
+
425
+ if legend is not None:
426
+ if len(legend) < len(args):
427
+ raise ValueError(f"Legend should be provided for each signal.")
428
+
429
+ # Create figure
430
+ fig = plt.figure(figsize=(16, 4))
431
+ gs = gridspec.GridSpec(2, 1, height_ratios=[0.1, 1])
432
+
433
+ colors = plt.get_cmap('tab10').colors
434
+
435
+ dist_ax = fig.add_subplot(gs[1, 0])
436
+ annotation_ax = fig.add_subplot(gs[0, 0], sharex=dist_ax)
437
+
438
+ # Set limits
439
+ if xlim is not None:
440
+ dist_ax.set_xlim(xlim)
441
+
442
+ if ylim is not None:
443
+ dist_ax.set_ylim(ylim)
444
+
445
+ # Add plot
446
+ for i, data in enumerate(args):
447
+ # Fit gaussian to the data
448
+ kde = gaussian_kde(data)
449
+
450
+ # Create points to evaluate KDE
451
+ x_vals = np.linspace(min(data), max(data), npoints)
452
+ y_vals = kde(x_vals)
453
+
454
+ if legend is not None:
455
+ dist_ax.plot(x_vals, y_vals, color=colors[i], label=legend[i])
456
+ if show_hist is True:
457
+ dist_ax.hist(data, bins=30, density=True, alpha=0.3, facecolor=colors[i], edgecolor='black', label=legend[i])
458
+ else:
459
+ dist_ax.plot(x_vals, y_vals, color=colors[i])
460
+ if show_hist is True:
461
+ dist_ax.hist(data, bins=30, density=True, alpha=0.3, facecolor=colors[i], edgecolor='black', label=legeng[i])
462
+
463
+ # Add annotations
464
+ if ann is not None:
465
+ annotation_ax.set_ylim(0, 1)
466
+ for i, (start, end, tag) in enumerate(ann):
467
+ if xlim is not None:
468
+ if end < xlim[0] or start > xlim[1]:
469
+ continue # Skip out-of-view regions
470
+ # Clip boundaries to xlim
471
+ start = max(start, xlim[0])
472
+ end = min(end, xlim[1])
473
+
474
+ color = colors[i % len(colors)]
475
+ width = end - start
476
+ rect = Rectangle((start, 0), width, 1, color=color, alpha=0.7)
477
+ annotation_ax.add_patch(rect)
478
+
479
+ 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)
480
+ text_obj.set_clip_path(rect)
481
+
482
+ # Add legend
483
+ if legend is not None:
484
+ handles, labels = dist_ax.get_legend_handles_labels()
485
+ fig.legend(handles, labels, loc='upper right', bbox_to_anchor=(0.9, 1.1), ncol=len(legend), frameon=True)
486
+
487
+ # Set title, labels
488
+ if title is not None:
489
+ annotation_ax.set_title(title, pad=10, size=11)
490
+ if xlabel is not None:
491
+ dist_ax.set_xlabel(xlabel)
492
+ if ylabel is not None:
493
+ dist_ax.set_ylabel(ylabel)
494
+
495
+ # Remove the boundaries and ticks from annotation axis
496
+ if ann is not None:
497
+ annotation_ax.tick_params(left=False, bottom=False, labelleft=False, labelbottom=False)
498
+ else:
499
+ annotation_ax.axis("off")
500
+
501
+ fig.subplots_adjust(hspace=0.01, wspace=0.05)
502
+ plt.close()
503
+ return fig
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: modusa
3
- Version: 0.3.22
3
+ Version: 0.3.24
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.22.dist-info/METADATA,sha256=uKAnJIVUJhOqOl4eXWXtvytJ7dACKCk3Te-0bctAzCA,1369
2
- modusa-0.3.22.dist-info/WHEEL,sha256=9P2ygRxDrTJz3gsagc0Z96ukrxjr-LFBGOgv3AuKlCA,90
3
- modusa-0.3.22.dist-info/entry_points.txt,sha256=fmKpleVXj6CdaBVL14WoEy6xx7JQCs85jvzwTi3lePM,73
4
- modusa-0.3.22.dist-info/licenses/LICENSE.md,sha256=JTaXAjx5awk76VArKCx5dUW8vmLEWsL_ZlR7-umaHbA,1078
1
+ modusa-0.3.24.dist-info/METADATA,sha256=XroQ__wqEQdtRoR1y22KngZO7gROam3uHT5aEPyAuPM,1369
2
+ modusa-0.3.24.dist-info/WHEEL,sha256=9P2ygRxDrTJz3gsagc0Z96ukrxjr-LFBGOgv3AuKlCA,90
3
+ modusa-0.3.24.dist-info/entry_points.txt,sha256=fmKpleVXj6CdaBVL14WoEy6xx7JQCs85jvzwTi3lePM,73
4
+ modusa-0.3.24.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
@@ -40,13 +40,14 @@ modusa/models/t_ax.py,sha256=ZUhvZPUW1TkdZYuUd6Ucm-vsv0JqtZ9yEe3ab67Ma6w,8022
40
40
  modusa/models/tds.py,sha256=FAGfibjyyE_lkEuQp-vSCuqQnopOjmy_IXqUjRlg9kc,11677
41
41
  modusa/plugins/__init__.py,sha256=r1Bf5mnrVKRIwxboutY1iGzDy4EPQhqpk1kSW7iJj_Q,54
42
42
  modusa/plugins/base.py,sha256=Bh_1Bja7fOymFsCgwhXDbV6ys3D8muNrPwrfDrG_G_A,2382
43
- 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
44
45
  modusa/tools/audio_converter.py,sha256=415qBoPm2sBIuBSI7m1XBKm0AbmVmPydIPPr-uO8D3c,1778
45
46
  modusa/tools/audio_loader.py,sha256=DrCzq0pdiQrUDIG-deLJGcu8EaylO5yRtwT4lr8WSf8,2166
46
47
  modusa/tools/audio_player.py,sha256=GP04TWW4jBwQBjANkfR_cJtEy7cIhvbu8RTwnf9hD6E,2817
47
48
  modusa/tools/base.py,sha256=C0ESJ0mIfjjRlAkRbSetNtMoOfS6IrHBjexRp3l_Mh4,1293
48
49
  modusa/tools/math_ops.py,sha256=ZZ7U4DgqT7cOeE7_Lzi_Qq-48WYfwR9_osbZwTmE9eg,8690
49
- modusa/tools/plotter.py,sha256=pmB9l_CTXnxC25fML_6M4jiBV1l645GtpZP4Ewoeo4E,10735
50
+ modusa/tools/plotter.py,sha256=U-Xkm8Br7Ba5C60xBuApd1qf9AScJ1llH_ichQksrxY,15295
50
51
  modusa/tools/youtube_downloader.py,sha256=hB_X8-7nOHXOlxg6vv3wyhBLoAsWyomrULP6_uCQL7s,1698
51
52
  modusa/utils/.DS_Store,sha256=nLXMwF7QJNuglLI_Gk74F7vl5Dyus2Wd74Mgowijmdo,6148
52
53
  modusa/utils/__init__.py,sha256=1oLL20yLB1GL9IbFiZD8OReDqiCpFr-yetIR6x1cNkI,23
@@ -55,4 +56,4 @@ modusa/utils/excp.py,sha256=L9vhaGjKpv9viJYdmC9n5ndmk2GVbUBuFyZyhAQZmWY,906
55
56
  modusa/utils/logger.py,sha256=K0rsnObeNKCxlNeSnVnJeRhgfmob6riB2uyU7h3dDmA,571
56
57
  modusa/utils/np_func_cat.py,sha256=TyIFgRc6bARRMDnZxlVURO5Z0I-GWhxRONYyIv-Vwxs,1007
57
58
  modusa/utils/plot.py,sha256=s_vNdxvKfwxEngvJPgrF1PcmxZNnNaaXPViHWjyjJ-c,5335
58
- modusa-0.3.22.dist-info/RECORD,,
59
+ modusa-0.3.24.dist-info/RECORD,,