modusa 0.3.92__tar.gz → 0.3.93__tar.gz

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 (94) hide show
  1. {modusa-0.3.92 → modusa-0.3.93}/PKG-INFO +1 -1
  2. {modusa-0.3.92 → modusa-0.3.93}/pyproject.toml +1 -1
  3. {modusa-0.3.92 → modusa-0.3.93}/src/modusa/__init__.py +2 -2
  4. {modusa-0.3.92 → modusa-0.3.93}/src/modusa/tools/__init__.py +1 -1
  5. {modusa-0.3.92 → modusa-0.3.93}/src/modusa/tools/plotter.py +145 -2
  6. {modusa-0.3.92 → modusa-0.3.93}/LICENSE.md +0 -0
  7. {modusa-0.3.92 → modusa-0.3.93}/README.md +0 -0
  8. {modusa-0.3.92 → modusa-0.3.93}/src/modusa/.DS_Store +0 -0
  9. {modusa-0.3.92 → modusa-0.3.93}/src/modusa/config.py +0 -0
  10. {modusa-0.3.92 → modusa-0.3.93}/src/modusa/decorators.py +0 -0
  11. {modusa-0.3.92 → modusa-0.3.93}/src/modusa/devtools/generate_docs_source.py +0 -0
  12. {modusa-0.3.92 → modusa-0.3.93}/src/modusa/devtools/generate_template.py +0 -0
  13. {modusa-0.3.92 → modusa-0.3.93}/src/modusa/devtools/list_authors.py +0 -0
  14. {modusa-0.3.92 → modusa-0.3.93}/src/modusa/devtools/list_plugins.py +0 -0
  15. {modusa-0.3.92 → modusa-0.3.93}/src/modusa/devtools/main.py +0 -0
  16. {modusa-0.3.92 → modusa-0.3.93}/src/modusa/devtools/templates/generator.py +0 -0
  17. {modusa-0.3.92 → modusa-0.3.93}/src/modusa/devtools/templates/io.py +0 -0
  18. {modusa-0.3.92 → modusa-0.3.93}/src/modusa/devtools/templates/model.py +0 -0
  19. {modusa-0.3.92 → modusa-0.3.93}/src/modusa/devtools/templates/plugin.py +0 -0
  20. {modusa-0.3.92 → modusa-0.3.93}/src/modusa/devtools/templates/test.py +0 -0
  21. {modusa-0.3.92 → modusa-0.3.93}/src/modusa/devtools/templates/tool.py +0 -0
  22. {modusa-0.3.92 → modusa-0.3.93}/src/modusa/fonts/NotoSansDevanagari-Regular.ttf +0 -0
  23. {modusa-0.3.92 → modusa-0.3.93}/src/modusa/generators/__init__.py +0 -0
  24. {modusa-0.3.92 → modusa-0.3.93}/src/modusa/generators/audio.py +0 -0
  25. {modusa-0.3.92 → modusa-0.3.93}/src/modusa/generators/audio_waveforms.py +0 -0
  26. {modusa-0.3.92 → modusa-0.3.93}/src/modusa/generators/base.py +0 -0
  27. {modusa-0.3.92 → modusa-0.3.93}/src/modusa/generators/ftds.py +0 -0
  28. {modusa-0.3.92 → modusa-0.3.93}/src/modusa/generators/s1d.py +0 -0
  29. {modusa-0.3.92 → modusa-0.3.93}/src/modusa/generators/s2d.py +0 -0
  30. {modusa-0.3.92 → modusa-0.3.93}/src/modusa/generators/s_ax.py +0 -0
  31. {modusa-0.3.92 → modusa-0.3.93}/src/modusa/generators/t_ax.py +0 -0
  32. {modusa-0.3.92 → modusa-0.3.93}/src/modusa/generators/tds.py +0 -0
  33. {modusa-0.3.92 → modusa-0.3.93}/src/modusa/models/__init__.py +0 -0
  34. {modusa-0.3.92 → modusa-0.3.93}/src/modusa/models/__pycache__/signal1D.cpython-312.pyc.4443461152 +0 -0
  35. {modusa-0.3.92 → modusa-0.3.93}/src/modusa/models/audio.py +0 -0
  36. {modusa-0.3.92 → modusa-0.3.93}/src/modusa/models/base.py +0 -0
  37. {modusa-0.3.92 → modusa-0.3.93}/src/modusa/models/data.py +0 -0
  38. {modusa-0.3.92 → modusa-0.3.93}/src/modusa/models/ftds.py +0 -0
  39. {modusa-0.3.92 → modusa-0.3.93}/src/modusa/models/s1d.py +0 -0
  40. {modusa-0.3.92 → modusa-0.3.93}/src/modusa/models/s2d.py +0 -0
  41. {modusa-0.3.92 → modusa-0.3.93}/src/modusa/models/s_ax.py +0 -0
  42. {modusa-0.3.92 → modusa-0.3.93}/src/modusa/models/t_ax.py +0 -0
  43. {modusa-0.3.92 → modusa-0.3.93}/src/modusa/models/tds.py +0 -0
  44. {modusa-0.3.92 → modusa-0.3.93}/src/modusa/plugins/__init__.py +0 -0
  45. {modusa-0.3.92 → modusa-0.3.93}/src/modusa/plugins/base.py +0 -0
  46. {modusa-0.3.92 → modusa-0.3.93}/src/modusa/tools/_plotter_old.py +0 -0
  47. {modusa-0.3.92 → modusa-0.3.93}/src/modusa/tools/ann_loader.py +0 -0
  48. {modusa-0.3.92 → modusa-0.3.93}/src/modusa/tools/audio_converter.py +0 -0
  49. {modusa-0.3.92 → modusa-0.3.93}/src/modusa/tools/audio_loader.py +0 -0
  50. {modusa-0.3.92 → modusa-0.3.93}/src/modusa/tools/audio_player.py +0 -0
  51. {modusa-0.3.92 → modusa-0.3.93}/src/modusa/tools/audio_recorder.py +0 -0
  52. {modusa-0.3.92 → modusa-0.3.93}/src/modusa/tools/audio_saver.py +0 -0
  53. {modusa-0.3.92 → modusa-0.3.93}/src/modusa/tools/base.py +0 -0
  54. {modusa-0.3.92 → modusa-0.3.93}/src/modusa/tools/math_ops.py +0 -0
  55. {modusa-0.3.92 → modusa-0.3.93}/src/modusa/tools/youtube_downloader.py +0 -0
  56. {modusa-0.3.92 → modusa-0.3.93}/src/modusa/utils/.DS_Store +0 -0
  57. {modusa-0.3.92 → modusa-0.3.93}/src/modusa/utils/__init__.py +0 -0
  58. {modusa-0.3.92 → modusa-0.3.93}/src/modusa/utils/config.py +0 -0
  59. {modusa-0.3.92 → modusa-0.3.93}/src/modusa/utils/excp.py +0 -0
  60. {modusa-0.3.92 → modusa-0.3.93}/src/modusa/utils/logger.py +0 -0
  61. {modusa-0.3.92 → modusa-0.3.93}/src/modusa/utils/np_func_cat.py +0 -0
  62. {modusa-0.3.92 → modusa-0.3.93}/src/modusa/utils/plot.py +0 -0
  63. {modusa-0.3.92 → modusa-0.3.93}/tests/__init__.py +0 -0
  64. {modusa-0.3.92 → modusa-0.3.93}/tests/data/song1.mp3 +0 -0
  65. {modusa-0.3.92 → modusa-0.3.93}/tests/data/song1.wav +0 -0
  66. {modusa-0.3.92 → modusa-0.3.93}/tests/test_generators/audio_waveform.py +0 -0
  67. {modusa-0.3.92 → modusa-0.3.93}/tests/test_generators/test_audio.py +0 -0
  68. {modusa-0.3.92 → modusa-0.3.93}/tests/test_generators/test_ftds.py +0 -0
  69. {modusa-0.3.92 → modusa-0.3.93}/tests/test_generators/test_s1d.py +0 -0
  70. {modusa-0.3.92 → modusa-0.3.93}/tests/test_generators/test_s2d.py +0 -0
  71. {modusa-0.3.92 → modusa-0.3.93}/tests/test_generators/test_s_ax.py +0 -0
  72. {modusa-0.3.92 → modusa-0.3.93}/tests/test_generators/test_signal.py +0 -0
  73. {modusa-0.3.92 → modusa-0.3.93}/tests/test_generators/test_signal_generator.py +0 -0
  74. {modusa-0.3.92 → modusa-0.3.93}/tests/test_generators/test_t_ax.py +0 -0
  75. {modusa-0.3.92 → modusa-0.3.93}/tests/test_generators/test_tds.py +0 -0
  76. {modusa-0.3.92 → modusa-0.3.93}/tests/test_io/audio_player.py +0 -0
  77. {modusa-0.3.92 → modusa-0.3.93}/tests/test_io/plotter.py +0 -0
  78. {modusa-0.3.92 → modusa-0.3.93}/tests/test_models/test_data.py +0 -0
  79. {modusa-0.3.92 → modusa-0.3.93}/tests/test_models/test_t_ax.py +0 -0
  80. {modusa-0.3.92 → modusa-0.3.93}/tests/test_plugins/youtube_audio_loader.py +0 -0
  81. {modusa-0.3.92 → modusa-0.3.93}/tests/test_signals/frequency_domain_signal.py +0 -0
  82. {modusa-0.3.92 → modusa-0.3.93}/tests/test_signals/spectrogram.py +0 -0
  83. {modusa-0.3.92 → modusa-0.3.93}/tests/test_signals/test_axis.py +0 -0
  84. {modusa-0.3.92 → modusa-0.3.93}/tests/test_signals/test_feature_time_domain_signal.py +0 -0
  85. {modusa-0.3.92 → modusa-0.3.93}/tests/test_signals/test_frequency_time_domain_signal.py +0 -0
  86. {modusa-0.3.92 → modusa-0.3.93}/tests/test_signals/test_signal1D.py +0 -0
  87. {modusa-0.3.92 → modusa-0.3.93}/tests/test_signals/test_signal2D.py +0 -0
  88. {modusa-0.3.92 → modusa-0.3.93}/tests/test_signals/test_time_domain_signal.py +0 -0
  89. {modusa-0.3.92 → modusa-0.3.93}/tests/test_signals/test_u_ax.py +0 -0
  90. {modusa-0.3.92 → modusa-0.3.93}/tests/test_signals/test_window_signal.py +0 -0
  91. {modusa-0.3.92 → modusa-0.3.93}/tests/test_signals/time_domain_signal.py +0 -0
  92. {modusa-0.3.92 → modusa-0.3.93}/tests/test_tools/test_audio_converter.py +0 -0
  93. {modusa-0.3.92 → modusa-0.3.93}/tests/test_tools/test_fourier_tranform.py +0 -0
  94. {modusa-0.3.92 → modusa-0.3.93}/tests/test_tools/test_math_ops.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: modusa
3
- Version: 0.3.92
3
+ Version: 0.3.93
4
4
  Summary: A modular signal analysis python library.
5
5
  Author-Email: Ankit Anand <ankit0.anand0@gmail.com>
6
6
  License: MIT
@@ -16,7 +16,7 @@ dependencies = [
16
16
  ]
17
17
  requires-python = ">=3.10"
18
18
  readme = "README.md"
19
- version = "0.3.92"
19
+ version = "0.3.93"
20
20
 
21
21
  [project.license]
22
22
  text = "MIT"
@@ -1,11 +1,11 @@
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 plot_dist, fig
4
+ from modusa.tools import dist_plot, hill_plot, fig
5
5
  #=====
6
6
 
7
7
  from modusa.tools import play, convert, record, save
8
8
  from modusa.tools import download
9
9
  from modusa.tools import load, load_ann
10
10
 
11
- __version__ = "0.3.92"
11
+ __version__ = "0.3.93"
@@ -9,4 +9,4 @@ from .ann_loader import load_ann
9
9
  from .audio_recorder import record
10
10
 
11
11
  from .plotter import Fig as fig
12
- from .plotter import plot_dist
12
+ from .plotter import dist_plot, hill_plot
@@ -712,10 +712,153 @@ class Fig:
712
712
  fig = self._fig
713
713
  fig.savefig(path, bbox_inches="tight")
714
714
 
715
+ #======== Distribution ==========
716
+ def hill_plot(*args, labels=None, xlabel=None, ylabel=None, title=None, widths=0.7, bw_method=0.3, jitter_amount=0.1, side='upper', show_stats=True, ax=None):
717
+ """
718
+ A plot to see distribution of different groups
719
+ along with statistical markers.
720
+
721
+ Parameters
722
+ ----------
723
+ *args : array-like
724
+ - Data arrays for each group.
725
+ labels : list of str, optional
726
+ - Labels for each group (y-axis).
727
+ side : str, 'upper' or 'lower'
728
+ Which half of the violin to draw (upper or lower relative to y-axis).
729
+ show_stats : bool, optional
730
+ Whether to show mean and median markers.
731
+ xlabel : str, optional
732
+ Label for x-axis.
733
+ ylabel : str, optional
734
+ Label for y-axis.
735
+ ax : matplotlib axes, optional
736
+ Axes to plot on.
737
+ title : str, optional
738
+ Plot title.
739
+ widths : float, optional
740
+ Width of violins.
741
+ bw_method : float, optional
742
+ Bandwidth method for KDE.
743
+ jitter_amount : float, optional
744
+ Amount of vertical jitter for strip points.
745
+ """
746
+
747
+ created_fig = False
748
+ if ax is None:
749
+ fig, ax = plt.subplots(figsize=(8, len(args) * 1.5))
750
+ created_fig = True
751
+
752
+ n = len(args)
753
+
754
+ # Default labels/colors
755
+ if labels is None:
756
+ labels = [f"Group {i}" for i in range(1, n+1)]
757
+
758
+ colors = plt.cm.tab10.colors
759
+ if len(colors) < n:
760
+ colors = [colors[i % len(colors)] for i in range(n)] # Repeat colors
761
+
762
+ # --- Half-violin ---
763
+ parts = ax.violinplot(args, vert=False, showmeans=False, showmedians=False, widths=widths, bw_method=bw_method)
764
+
765
+ # Remove the default bar lines from violin plot
766
+ for key in ['cbars', 'cmins', 'cmaxes', 'cmedians']:
767
+ if key in parts:
768
+ parts[key].set_visible(False)
769
+
770
+ # Clip violin bodies to show only upper or lower half
771
+ for i, pc in enumerate(parts['bodies']):
772
+ verts = pc.get_paths()[0].vertices
773
+ y_center = i + 1 # Center y-position for this violin
774
+
775
+ if side == 'upper':
776
+ verts[:, 1] = np.maximum(verts[:, 1], y_center)
777
+ else: # 'lower'
778
+ verts[:, 1] = np.minimum(verts[:, 1], y_center)
779
+
780
+ pc.set_facecolor(colors[i])
781
+ pc.set_edgecolor(colors[i])
782
+ pc.set_linewidth(1.5)
783
+ pc.set_alpha(0.3)
784
+
785
+ # --- Strip points with jitter ---
786
+ for i, x in enumerate(args, start=1):
787
+ x = np.array(x)
788
+ jitter = (np.random.rand(len(x)) - 0.5) * jitter_amount
789
+ y_positions = np.full(len(x), i) + jitter
790
+ ax.scatter(x, y_positions, color=colors[i-1], alpha=0.6, s=25, edgecolor="white", linewidth=0.8, zorder=2)
791
+
792
+ # --- Statistical markers on violin distribution curve ---
793
+ if show_stats:
794
+ for i, (pc, x) in enumerate(zip(parts['bodies'], args), start=1):
795
+ x = np.array(x)
796
+ median_val = np.median(x)
797
+ mean_val = np.mean(x)
798
+
799
+ # Get the violin curve vertices
800
+ verts = pc.get_paths()[0].vertices
801
+
802
+ # Find y-position on violin curve for median
803
+ median_mask = np.abs(verts[:, 0] - median_val) < (np.ptp(x) * 0.01)
804
+ if median_mask.any():
805
+ median_y = np.max(verts[median_mask, 1]) if side == 'upper' else np.min(verts[median_mask, 1])
806
+ else:
807
+ median_y = i + widths/2 if side == 'upper' else i - widths/2
808
+
809
+ # Find y-position on violin curve for mean
810
+ mean_mask = np.abs(verts[:, 0] - mean_val) < (np.ptp(x) * 0.01)
811
+ if mean_mask.any():
812
+ mean_y = np.max(verts[mean_mask, 1]) if side == 'upper' else np.min(verts[mean_mask, 1])
813
+ else:
814
+ mean_y = i + widths/2 if side == 'upper' else i - widths/2
815
+
816
+ # Triangle offset from curve
817
+ triangle_offset = 0.05
818
+
819
+ # Mean marker - triangle below curve pointing up
820
+ ax.scatter(mean_val, mean_y - triangle_offset, marker='^', s=30,
821
+ facecolor=colors[i-1], edgecolor='none',
822
+ linewidth=0, zorder=6,
823
+ label='Mean' if i == 1 else '')
824
+
825
+ # Mean value text - below the triangle
826
+ ax.text(mean_val, mean_y - triangle_offset - 0.05, f'mean: {mean_val:.2f}', ha='center', va='top', fontsize=8, fontweight='bold', color=colors[i-1], zorder=7)
827
+
828
+ # Median marker - triangle above curve pointing down
829
+ ax.scatter(median_val, median_y + triangle_offset, marker='v', s=30,
830
+ facecolor=colors[i-1], edgecolor='none',
831
+ linewidth=0, zorder=6,
832
+ label='Median' if i == 1 else '')
833
+
834
+ # Median value text - above the triangle
835
+ ax.text(median_val, median_y + triangle_offset + 0.05, f'median: {median_val:.2f}', ha='center', va='bottom', fontsize=8, fontweight='bold', color=colors[i-1], zorder=7)
836
+
837
+ # --- Labels & formatting ---
838
+ ax.set_yticks(range(1, n + 1))
839
+ ax.set_yticklabels(labels, fontsize=10)
840
+ if side == "lower":
841
+ ax.set_ylim(0.2, n + 0.5)
842
+ else:
843
+ ax.set_ylim(0.5, n + 0.5)
844
+
845
+ # Style improvements
846
+ ax.spines['top'].set_visible(False)
847
+ ax.spines['right'].set_visible(False)
848
+ ax.grid(axis='x', alpha=0.3, linestyle='--', linewidth=0.5)
849
+
850
+ if xlabel:
851
+ ax.set_xlabel(xlabel, fontsize=11, fontweight='bold')
852
+ if ylabel:
853
+ ax.set_ylabel(ylabel, fontsize=11, fontweight='bold')
854
+ if title:
855
+ ax.set_title(title, fontsize=13, fontweight='bold', pad=15)
856
+
857
+ plt.tight_layout()
858
+ return fig
715
859
 
716
860
 
717
- #======== Plot distribution ===========
718
- 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):
861
+ def dist_plot(*args, ann=None, xlim=None, ylim=None, ylabel=None, xlabel=None, title=None, legend=None, show_hist=True, npoints=200, bins=30):
719
862
  """
720
863
  Plot distribution.
721
864
 
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes