modusa 0.3.46__py3-none-any.whl → 0.3.47__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 +1 -1
- modusa/tools/__init__.py +1 -0
- modusa/tools/plotter.py +397 -4
- {modusa-0.3.46.dist-info → modusa-0.3.47.dist-info}/METADATA +1 -1
- {modusa-0.3.46.dist-info → modusa-0.3.47.dist-info}/RECORD +8 -8
- {modusa-0.3.46.dist-info → modusa-0.3.47.dist-info}/WHEEL +0 -0
- {modusa-0.3.46.dist-info → modusa-0.3.47.dist-info}/entry_points.txt +0 -0
- {modusa-0.3.46.dist-info → modusa-0.3.47.dist-info}/licenses/LICENSE.md +0 -0
    
        modusa/__init__.py
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 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 fig1d, fig2d, plot_dist
         | 
| 4 | 
            +
            from modusa.tools import fig1d, fig2d, plot_dist, fig
         | 
| 5 5 | 
             
            #=====
         | 
| 6 6 |  | 
| 7 7 | 
             
            from modusa.tools import play, convert, record
         | 
    
        modusa/tools/__init__.py
    CHANGED
    
    
    
        modusa/tools/plotter.py
    CHANGED
    
    | @@ -65,9 +65,11 @@ class Figure1D: | |
| 65 65 | 
             
            		- Default: None
         | 
| 66 66 | 
             
            	"""
         | 
| 67 67 |  | 
| 68 | 
            -
            	def __init__(self, n_aux_subplots=0, xlim=None, ylim=None):
         | 
| 68 | 
            +
            	def __init__(self, n_aux_subplots=0, xlim=None, ylim=None, sharex=None):
         | 
| 69 69 | 
             
            		self._n_aux_subplots: int = n_aux_subplots
         | 
| 70 70 | 
             
            		self._active_subplot_idx: int = 1 # Any addition will happen on this subplot (0 is reserved for reference axis)
         | 
| 71 | 
            +
            		if sharex is not None:
         | 
| 72 | 
            +
            			xlim = sharex._xlim
         | 
| 71 73 | 
             
            		self._xlim = xlim # Many add functions depend on this, so we fix it while instantiating the class
         | 
| 72 74 | 
             
            		self._ylim = ylim
         | 
| 73 75 | 
             
            		self._subplots, self._fig = self._generate_subplots() # Will contain all the subplots (list, fig)
         | 
| @@ -109,16 +111,18 @@ class Figure1D: | |
| 109 111 |  | 
| 110 112 | 
             
            		# Add subplots
         | 
| 111 113 | 
             
            		subplots_list = []
         | 
| 114 | 
            +
            		
         | 
| 112 115 | 
             
            		ref_subplot = fig.add_subplot(gs[0, 0])
         | 
| 113 116 | 
             
            		ref_subplot.axis("off")
         | 
| 114 117 | 
             
            		subplots_list.append(ref_subplot)
         | 
| 115 118 |  | 
| 116 119 | 
             
            		for i in range(1, n_subplots):
         | 
| 117 120 | 
             
            			subplots_list.append(fig.add_subplot(gs[i, 0], sharex=ref_subplot))
         | 
| 118 | 
            -
             | 
| 121 | 
            +
            		
         | 
| 119 122 | 
             
            		for i in range(n_subplots - 1):
         | 
| 120 123 | 
             
            			subplots_list[i].tick_params(left=False, bottom=False, labelleft=False, labelbottom=False)
         | 
| 121 124 |  | 
| 125 | 
            +
            		
         | 
| 122 126 | 
             
            		# Set xlim
         | 
| 123 127 | 
             
            		if self._xlim is not None: # xlim should be applied on reference subplot, rest all sharex
         | 
| 124 128 | 
             
            			ref_subplot.set_xlim(self._xlim)
         | 
| @@ -388,9 +392,11 @@ class Figure2D: | |
| 388 392 | 
             
            		- Default: None
         | 
| 389 393 | 
             
            	"""
         | 
| 390 394 |  | 
| 391 | 
            -
            	def __init__(self, n_aux_subplots=0, xlim=None, ylim=None):
         | 
| 395 | 
            +
            	def __init__(self, n_aux_subplots=0, xlim=None, ylim=None, sharex=None):
         | 
| 392 396 | 
             
            		self._n_aux_subplots: int = n_aux_subplots
         | 
| 393 397 | 
             
            		self._active_subplot_idx: int = 1 # Any addition will happen on this subplot (0 is reserved for reference axis)
         | 
| 398 | 
            +
            		if sharex is not None:
         | 
| 399 | 
            +
            			xlim = sharex._xlim
         | 
| 394 400 | 
             
            		self._xlim = xlim # Many add functions depend on this, so we fix it while instantiating the class
         | 
| 395 401 | 
             
            		self._ylim = ylim
         | 
| 396 402 | 
             
            		self._subplots, self._fig = self._generate_subplots() # Will contain all the subplots (list, fig)
         | 
| @@ -471,6 +477,7 @@ class Figure2D: | |
| 471 477 | 
             
            		ref_subplot = fig.add_subplot(gs[0, 0])
         | 
| 472 478 | 
             
            		ref_subplot.axis("off")
         | 
| 473 479 | 
             
            		subplots_list.append(ref_subplot)
         | 
| 480 | 
            +
             | 
| 474 481 |  | 
| 475 482 | 
             
            		for i in range(1, n_subplots):
         | 
| 476 483 | 
             
            			subplots_list.append(fig.add_subplot(gs[i, 0], sharex=ref_subplot))
         | 
| @@ -900,4 +907,390 @@ def plot_dist(*args, ann=None, xlim=None, ylim=None, ylabel=None, xlabel=None, t | |
| 900 907 |  | 
| 901 908 | 
             
            		fig.subplots_adjust(hspace=0.01, wspace=0.05)
         | 
| 902 909 | 
             
            		plt.close()
         | 
| 903 | 
            -
            		return fig
         | 
| 910 | 
            +
            		return fig
         | 
| 911 | 
            +
            	
         | 
| 912 | 
            +
             | 
| 913 | 
            +
            class Fig:
         | 
| 914 | 
            +
            	"""
         | 
| 915 | 
            +
            	
         | 
| 916 | 
            +
            	"""
         | 
| 917 | 
            +
            	
         | 
| 918 | 
            +
            	def __init__(self, arrangement="asm", title="Untitled", xlabel="Time (sec)", xlim=None):
         | 
| 919 | 
            +
             | 
| 920 | 
            +
            		self._xlim = xlim
         | 
| 921 | 
            +
            		self._curr_row_idx = 1 # Starting from 1 because row 0 is reserved for reference subplot
         | 
| 922 | 
            +
            		self._curr_color_idx = 0 # So that we have different color across all the subplots to avoid legend confusion
         | 
| 923 | 
            +
            		
         | 
| 924 | 
            +
            		# Subplot setup
         | 
| 925 | 
            +
            		self._fig, self._axs = self._generate_subplots(arrangement, title, xlabel) # This will fill in the all the above variables
         | 
| 926 | 
            +
            		
         | 
| 927 | 
            +
            	
         | 
| 928 | 
            +
            	def _get_curr_row(self):
         | 
| 929 | 
            +
            		"""
         | 
| 930 | 
            +
            		Get the active row where you can add
         | 
| 931 | 
            +
            		either annotations or events.
         | 
| 932 | 
            +
            		"""
         | 
| 933 | 
            +
            		curr_row = self._axs[self._curr_row_idx]
         | 
| 934 | 
            +
            		self._curr_row_idx += 1
         | 
| 935 | 
            +
            		
         | 
| 936 | 
            +
            		return curr_row
         | 
| 937 | 
            +
            	
         | 
| 938 | 
            +
            	def _get_new_color(self):
         | 
| 939 | 
            +
            		"""
         | 
| 940 | 
            +
            		Get a new color for different lines.
         | 
| 941 | 
            +
            		"""
         | 
| 942 | 
            +
            		colors = plt.rcParams['axes.prop_cycle'].by_key()['color']
         | 
| 943 | 
            +
            		self._curr_color_idx += 1
         | 
| 944 | 
            +
            		
         | 
| 945 | 
            +
            		return colors[self._curr_color_idx]
         | 
| 946 | 
            +
            	
         | 
| 947 | 
            +
            	def _calculate_extent(self, x, y):
         | 
| 948 | 
            +
            		# Handle spacing safely
         | 
| 949 | 
            +
            		if len(x) > 1:
         | 
| 950 | 
            +
            			dx = x[1] - x[0]
         | 
| 951 | 
            +
            		else:
         | 
| 952 | 
            +
            			dx = 1  # Default spacing for single value
         | 
| 953 | 
            +
            		if len(y) > 1:
         | 
| 954 | 
            +
            			dy = y[1] - y[0]
         | 
| 955 | 
            +
            		else:
         | 
| 956 | 
            +
            			dy = 1  # Default spacing for single value
         | 
| 957 | 
            +
            			
         | 
| 958 | 
            +
            		return [x[0] - dx / 2, x[-1] + dx / 2, y[0] - dy / 2, y[-1] + dy / 2]
         | 
| 959 | 
            +
            	
         | 
| 960 | 
            +
            		
         | 
| 961 | 
            +
            	def _generate_subplots(self, arrangement, title, xlabel):
         | 
| 962 | 
            +
            		"""
         | 
| 963 | 
            +
            		Generate subplots based on the configuration.
         | 
| 964 | 
            +
            		"""
         | 
| 965 | 
            +
            		
         | 
| 966 | 
            +
            		xlim = self._xlim
         | 
| 967 | 
            +
            		
         | 
| 968 | 
            +
            		n_aux_sp = arrangement.count("a")
         | 
| 969 | 
            +
            		n_signal_sp = arrangement.count("s")
         | 
| 970 | 
            +
            		n_matrix_sp = arrangement.count("m")
         | 
| 971 | 
            +
            		n_sp = 1 + n_aux_sp + n_signal_sp + n_matrix_sp # +1 is for the first reference subplot
         | 
| 972 | 
            +
            		
         | 
| 973 | 
            +
            		# Decide heights of different subplots type
         | 
| 974 | 
            +
            		height = {}
         | 
| 975 | 
            +
            		height["r"] = 0.0 # Reference height
         | 
| 976 | 
            +
            		height["a"] = 0.4 # Aux height
         | 
| 977 | 
            +
            		height["s"] = 2.0 # Signal height
         | 
| 978 | 
            +
            		height["m"] = 4.0 # Matrix height
         | 
| 979 | 
            +
            		cbar_width = 0.01
         | 
| 980 | 
            +
            		
         | 
| 981 | 
            +
            		arrangement = "r" + arrangement # "r" is to include the reference
         | 
| 982 | 
            +
            		
         | 
| 983 | 
            +
            		# Calculate height ratios list based on the arrangement
         | 
| 984 | 
            +
            		for char in arrangement:
         | 
| 985 | 
            +
            			height_ratios = [height[char] for char in arrangement]
         | 
| 986 | 
            +
            		
         | 
| 987 | 
            +
            		# Calculate total fig height
         | 
| 988 | 
            +
            		fig_height = height["r"] + (n_aux_sp * height["a"]) + (n_signal_sp * height["s"]) + (n_matrix_sp * height["m"])
         | 
| 989 | 
            +
            		
         | 
| 990 | 
            +
            		# Create figure and axs
         | 
| 991 | 
            +
            		fig, axs = plt.subplots(n_sp, 2, figsize=(16, fig_height), height_ratios=height_ratios, width_ratios=[1, cbar_width])
         | 
| 992 | 
            +
            		
         | 
| 993 | 
            +
            		for i, char in enumerate(arrangement): # For each of the subplots, we modify the layout accordingly
         | 
| 994 | 
            +
            			if char == "r":
         | 
| 995 | 
            +
            				axs[i, 0].axis("off")
         | 
| 996 | 
            +
            				axs[i, 1].axis("off")
         | 
| 997 | 
            +
            			elif char == "a": # Remove ticks and labels from all the aux subplots
         | 
| 998 | 
            +
            				axs[i, 0].tick_params(left=False, bottom=False, labelleft=False, labelbottom=False)
         | 
| 999 | 
            +
            				axs[i, 0].grid(True, linestyle=':', linewidth=0.7, color='gray', alpha=0.7)
         | 
| 1000 | 
            +
            				axs[i, 1].axis("off")
         | 
| 1001 | 
            +
            			elif char == "s":
         | 
| 1002 | 
            +
            				axs[i, 0].tick_params(bottom=False, labelbottom=False)
         | 
| 1003 | 
            +
            				axs[i, 0].grid(True, linestyle=':', linewidth=0.7, color='gray', alpha=0.7)
         | 
| 1004 | 
            +
            				axs[i, 1].axis("off")
         | 
| 1005 | 
            +
            			elif char == "m":
         | 
| 1006 | 
            +
            				axs[i, 0].grid(True, linestyle=':', linewidth=0.7, color='gray', alpha=0.7)
         | 
| 1007 | 
            +
            				axs[i, 0].tick_params(bottom=False, labelbottom=False)
         | 
| 1008 | 
            +
            			
         | 
| 1009 | 
            +
            			axs[i, 0].sharex(axs[0, 0])
         | 
| 1010 | 
            +
            			
         | 
| 1011 | 
            +
            		axs[-1, 0].tick_params(bottom=True, labelbottom=True)
         | 
| 1012 | 
            +
            		
         | 
| 1013 | 
            +
            		# xlim should be applied on reference subplot, rest all subplots will automatically adjust
         | 
| 1014 | 
            +
            		if xlim is not None:
         | 
| 1015 | 
            +
            			axs[0, 0].set_xlim(xlim)
         | 
| 1016 | 
            +
            			
         | 
| 1017 | 
            +
            		# Set title and label
         | 
| 1018 | 
            +
            		if title is not None:
         | 
| 1019 | 
            +
            			axs[0, 0].set_title(title)
         | 
| 1020 | 
            +
            		if xlabel is not None:
         | 
| 1021 | 
            +
            			axs[-1, 0].set_xlabel(xlabel)
         | 
| 1022 | 
            +
            					
         | 
| 1023 | 
            +
            		fig.subplots_adjust(hspace=0.2, wspace=0.05)
         | 
| 1024 | 
            +
             | 
| 1025 | 
            +
            		return fig, axs
         | 
| 1026 | 
            +
            	
         | 
| 1027 | 
            +
            	def add_signal(self, y, x=None, c=None, ls=None, lw=None, m=None, ms=3, label=None, ylabel=None, ylim=None, ax=None):
         | 
| 1028 | 
            +
            		"""
         | 
| 1029 | 
            +
            		Add signal to the figure.
         | 
| 1030 | 
            +
            			
         | 
| 1031 | 
            +
            		Parameters
         | 
| 1032 | 
            +
            		----------
         | 
| 1033 | 
            +
            		y: np.ndarray
         | 
| 1034 | 
            +
            			- Signal y values.
         | 
| 1035 | 
            +
            		x: np.ndarray | None
         | 
| 1036 | 
            +
            			- Signal x values.
         | 
| 1037 | 
            +
            			- Default: None (indices will be used)
         | 
| 1038 | 
            +
            		c: str
         | 
| 1039 | 
            +
            			- Color of the line.
         | 
| 1040 | 
            +
            			- Default: None
         | 
| 1041 | 
            +
            		ls: str
         | 
| 1042 | 
            +
            			- Linestyle
         | 
| 1043 | 
            +
            			- Default: None
         | 
| 1044 | 
            +
            		lw: Number
         | 
| 1045 | 
            +
            			- Linewidth
         | 
| 1046 | 
            +
            			- Default: None
         | 
| 1047 | 
            +
            		m: str
         | 
| 1048 | 
            +
            			- Marker
         | 
| 1049 | 
            +
            			- Default: None
         | 
| 1050 | 
            +
            		ms: number
         | 
| 1051 | 
            +
            			- Markersize
         | 
| 1052 | 
            +
            			- Default: 3
         | 
| 1053 | 
            +
            		label: str
         | 
| 1054 | 
            +
            			- Label for the plot.
         | 
| 1055 | 
            +
            			- Legend will use this.
         | 
| 1056 | 
            +
            			- Default: None
         | 
| 1057 | 
            +
            		ylabel: str
         | 
| 1058 | 
            +
            			- y-label for the plot.
         | 
| 1059 | 
            +
            			- Default: None
         | 
| 1060 | 
            +
            		ylim: tuple
         | 
| 1061 | 
            +
            			- y-lim for the plot.
         | 
| 1062 | 
            +
            			- Default: None
         | 
| 1063 | 
            +
            		ax: int
         | 
| 1064 | 
            +
            			- Which specific axis to plot (1, 2, 3, ...)
         | 
| 1065 | 
            +
            			- None
         | 
| 1066 | 
            +
             | 
| 1067 | 
            +
            		Returns
         | 
| 1068 | 
            +
            		-------
         | 
| 1069 | 
            +
            		None
         | 
| 1070 | 
            +
            		"""
         | 
| 1071 | 
            +
            		
         | 
| 1072 | 
            +
            		curr_row = self._get_curr_row() if ax is None else self._axs[ax]
         | 
| 1073 | 
            +
            		
         | 
| 1074 | 
            +
            		if x is None: x = np.arange(y.size)
         | 
| 1075 | 
            +
            		
         | 
| 1076 | 
            +
            		if c is None: c = self._get_new_color()
         | 
| 1077 | 
            +
             | 
| 1078 | 
            +
            		curr_row[0].plot(x, y, color=c, linestyle=ls, linewidth=lw, marker=m, markersize=ms, label=label)
         | 
| 1079 | 
            +
            		
         | 
| 1080 | 
            +
            		if ylabel is not None: curr_row[0].set_ylabel(ylabel)
         | 
| 1081 | 
            +
            		
         | 
| 1082 | 
            +
            		if ylim is not None: curr_row[0].set_ylim(ylim)
         | 
| 1083 | 
            +
            		
         | 
| 1084 | 
            +
            	def add_matrix(self, M, y=None, x=None, c="gray_r", o="lower", label=None, ylabel=None, ylim=None, cbar=True, ax=None):
         | 
| 1085 | 
            +
            		"""
         | 
| 1086 | 
            +
            		Add matrix to the figure.
         | 
| 1087 | 
            +
            			
         | 
| 1088 | 
            +
            		Parameters
         | 
| 1089 | 
            +
            		----------
         | 
| 1090 | 
            +
            		M: np.ndarray
         | 
| 1091 | 
            +
            			- Matrix (2D) array
         | 
| 1092 | 
            +
            		y: np.ndarray | None
         | 
| 1093 | 
            +
            			- y axis values.
         | 
| 1094 | 
            +
            		x: np.ndarray | None (indices will be used)
         | 
| 1095 | 
            +
            			- x axis values.
         | 
| 1096 | 
            +
            			- Default: None (indices will be used)
         | 
| 1097 | 
            +
            		c: str
         | 
| 1098 | 
            +
            			- cmap for the matrix.
         | 
| 1099 | 
            +
            			- Default: None
         | 
| 1100 | 
            +
            		o: str
         | 
| 1101 | 
            +
            			- origin
         | 
| 1102 | 
            +
            			- Default: "lower"
         | 
| 1103 | 
            +
            		label: str
         | 
| 1104 | 
            +
            			- Label for the plot.
         | 
| 1105 | 
            +
            			- Legend will use this.
         | 
| 1106 | 
            +
            			- Default: "Signal"
         | 
| 1107 | 
            +
            		ylabel: str
         | 
| 1108 | 
            +
            			- y-label for the plot.
         | 
| 1109 | 
            +
            			- Default: None
         | 
| 1110 | 
            +
            		ylim: tuple
         | 
| 1111 | 
            +
            			- y-lim for the plot.
         | 
| 1112 | 
            +
            			- Default: None
         | 
| 1113 | 
            +
            		cbar: bool
         | 
| 1114 | 
            +
            			- Show colorbar
         | 
| 1115 | 
            +
            			- Default: True
         | 
| 1116 | 
            +
            		ax: int
         | 
| 1117 | 
            +
            			- Which specific axis to plot (1, 2, 3, ...)
         | 
| 1118 | 
            +
            			- None
         | 
| 1119 | 
            +
            		
         | 
| 1120 | 
            +
            		Returns
         | 
| 1121 | 
            +
            		-------
         | 
| 1122 | 
            +
            		None
         | 
| 1123 | 
            +
            		"""
         | 
| 1124 | 
            +
            		if x is None: x = np.arange(M.shape[1])
         | 
| 1125 | 
            +
            		if y is None: y = np.arange(M.shape[0])
         | 
| 1126 | 
            +
             | 
| 1127 | 
            +
            		curr_row = self._get_curr_row() if ax is None else self._axs[ax]
         | 
| 1128 | 
            +
            		
         | 
| 1129 | 
            +
            		extent = self._calculate_extent(x, y)
         | 
| 1130 | 
            +
            		im = curr_row[0].imshow(M, aspect="auto", origin=o, cmap=c, extent=extent)
         | 
| 1131 | 
            +
            		
         | 
| 1132 | 
            +
            		if ylabel is not None: curr_row[0].set_ylabel(ylabel)
         | 
| 1133 | 
            +
            		
         | 
| 1134 | 
            +
            		if ylim is not None: curr_row[0].set_ylim(ylim)
         | 
| 1135 | 
            +
            		
         | 
| 1136 | 
            +
            		if cbar is True:
         | 
| 1137 | 
            +
            			cbar = plt.colorbar(im, cax=curr_row[1])
         | 
| 1138 | 
            +
            			if label is not None:
         | 
| 1139 | 
            +
            				cbar.set_label(label, labelpad=5)
         | 
| 1140 | 
            +
            		
         | 
| 1141 | 
            +
            		
         | 
| 1142 | 
            +
            	def add_events(self, events, c=None, ls=None, lw=None, label=None, ax=None):
         | 
| 1143 | 
            +
            		"""
         | 
| 1144 | 
            +
            		Add events to the figure.
         | 
| 1145 | 
            +
            		
         | 
| 1146 | 
            +
            		Parameters
         | 
| 1147 | 
            +
            		----------
         | 
| 1148 | 
            +
            		events: np.ndarray
         | 
| 1149 | 
            +
            			- All the event marker values.
         | 
| 1150 | 
            +
            		c: str
         | 
| 1151 | 
            +
            			- Color of the event marker.
         | 
| 1152 | 
            +
            			- Default: "k"
         | 
| 1153 | 
            +
            		ls: str
         | 
| 1154 | 
            +
            			- Line style.
         | 
| 1155 | 
            +
            			- Default: "-"
         | 
| 1156 | 
            +
            		lw: float
         | 
| 1157 | 
            +
            			- Linewidth.
         | 
| 1158 | 
            +
            			- Default: 1.5
         | 
| 1159 | 
            +
            		label: str
         | 
| 1160 | 
            +
            			- Label for the event type.
         | 
| 1161 | 
            +
            			- This will appear in the legend.
         | 
| 1162 | 
            +
            			- Default: "Event label"
         | 
| 1163 | 
            +
            		ax: int
         | 
| 1164 | 
            +
            			- Which specific axis to plot (1, 2, 3, ...)
         | 
| 1165 | 
            +
            			- None
         | 
| 1166 | 
            +
             | 
| 1167 | 
            +
            		Returns
         | 
| 1168 | 
            +
            		-------
         | 
| 1169 | 
            +
            		None
         | 
| 1170 | 
            +
            		"""
         | 
| 1171 | 
            +
            		
         | 
| 1172 | 
            +
            		curr_row = self._get_curr_row() if ax is None else self._axs[ax]
         | 
| 1173 | 
            +
            			
         | 
| 1174 | 
            +
            		if c is None: c = self._get_new_color()
         | 
| 1175 | 
            +
            			
         | 
| 1176 | 
            +
            		xlim = self._xlim
         | 
| 1177 | 
            +
            		
         | 
| 1178 | 
            +
            		for i, event in enumerate(events):
         | 
| 1179 | 
            +
            			if xlim is not None:
         | 
| 1180 | 
            +
            				if xlim[0] <= event <= xlim[1]:
         | 
| 1181 | 
            +
            					if i == 0: # Label should be set only once for all the events
         | 
| 1182 | 
            +
            						curr_row[0].axvline(x=event, color=c, linestyle=ls, linewidth=lw, label=label)
         | 
| 1183 | 
            +
            					else:
         | 
| 1184 | 
            +
            						curr_row[0].axvline(x=event, color=c, linestyle=ls, linewidth=lw)
         | 
| 1185 | 
            +
            			else:
         | 
| 1186 | 
            +
            				if i == 0: # Label should be set only once for all the events
         | 
| 1187 | 
            +
            					curr_row[0].axvline(x=event, color=c, linestyle=ls, linewidth=lw, label=label)
         | 
| 1188 | 
            +
            				else:
         | 
| 1189 | 
            +
            					curr_row[0].axvline(x=event, color=c, linestyle=ls, linewidth=lw)
         | 
| 1190 | 
            +
            					
         | 
| 1191 | 
            +
            	def add_annotation(self, ann, ax=None):
         | 
| 1192 | 
            +
            		"""
         | 
| 1193 | 
            +
            		Add annotation to the figure.
         | 
| 1194 | 
            +
            		
         | 
| 1195 | 
            +
            		Parameters
         | 
| 1196 | 
            +
            		----------
         | 
| 1197 | 
            +
            		ann : list[tuple[Number, Number, str]] | None
         | 
| 1198 | 
            +
            			- A list of annotation spans. Each tuple should be (start, end, label).
         | 
| 1199 | 
            +
            			- Default: None (no annotations).
         | 
| 1200 | 
            +
            		ax: int
         | 
| 1201 | 
            +
            			- Which specific axis to plot (1, 2, 3, ...)
         | 
| 1202 | 
            +
            			- None
         | 
| 1203 | 
            +
            		Returns
         | 
| 1204 | 
            +
            		-------
         | 
| 1205 | 
            +
            		None
         | 
| 1206 | 
            +
            		"""
         | 
| 1207 | 
            +
            		curr_row = self._get_curr_row() if ax is None else self._axs[ax]
         | 
| 1208 | 
            +
            			
         | 
| 1209 | 
            +
            		xlim = self._xlim
         | 
| 1210 | 
            +
            		
         | 
| 1211 | 
            +
            		for i, (start, end, tag) in enumerate(ann):
         | 
| 1212 | 
            +
            			# We make sure that we only plot annotation that are within the x range of the current view
         | 
| 1213 | 
            +
            			if xlim is not None:
         | 
| 1214 | 
            +
            				if start >= xlim[1] or end <= xlim[0]:
         | 
| 1215 | 
            +
            					continue
         | 
| 1216 | 
            +
            				
         | 
| 1217 | 
            +
            				# Clip boundaries to xlim
         | 
| 1218 | 
            +
            				start = max(start, xlim[0])
         | 
| 1219 | 
            +
            				end = min(end, xlim[1])
         | 
| 1220 | 
            +
            				
         | 
| 1221 | 
            +
            				box_colors = ["gray", "lightgray"] # Alternates color between two
         | 
| 1222 | 
            +
            				box_color = box_colors[i % 2]
         | 
| 1223 | 
            +
            				
         | 
| 1224 | 
            +
            				width = end - start
         | 
| 1225 | 
            +
            				rect = Rectangle((start, 0), width, 1, facecolor=box_color, edgecolor="black", alpha=0.7)
         | 
| 1226 | 
            +
            				curr_row[0].add_patch(rect)
         | 
| 1227 | 
            +
            				
         | 
| 1228 | 
            +
            				text_obj = curr_row[0].text(
         | 
| 1229 | 
            +
            					(start + end) / 2, 0.5, tag,
         | 
| 1230 | 
            +
            					ha='center', va='center',
         | 
| 1231 | 
            +
            					fontsize=10, color="black", fontweight='bold', zorder=10, clip_on=True
         | 
| 1232 | 
            +
            				)
         | 
| 1233 | 
            +
            				
         | 
| 1234 | 
            +
            				text_obj.set_clip_path(rect)
         | 
| 1235 | 
            +
            			else:
         | 
| 1236 | 
            +
            				box_colors = ["gray", "lightgray"] # Alternates color between two
         | 
| 1237 | 
            +
            				box_color = box_colors[i % 2]
         | 
| 1238 | 
            +
            				
         | 
| 1239 | 
            +
            				width = end - start
         | 
| 1240 | 
            +
            				rect = Rectangle((start, 0), width, 1, facecolor=box_color, edgecolor="black", alpha=0.7)
         | 
| 1241 | 
            +
            				curr_row[0].add_patch(rect)
         | 
| 1242 | 
            +
            				
         | 
| 1243 | 
            +
            				text_obj = curr_row[0].text(
         | 
| 1244 | 
            +
            					(start + end) / 2, 0.5, tag,
         | 
| 1245 | 
            +
            					ha='center', va='center',
         | 
| 1246 | 
            +
            					fontsize=10, color="black", fontweight='bold', zorder=10, clip_on=True
         | 
| 1247 | 
            +
            				)
         | 
| 1248 | 
            +
            				
         | 
| 1249 | 
            +
            				text_obj.set_clip_path(rect)
         | 
| 1250 | 
            +
            				
         | 
| 1251 | 
            +
            	def add_legend(self, ypos=1.0):
         | 
| 1252 | 
            +
            		"""
         | 
| 1253 | 
            +
            		Add legend to the figure.
         | 
| 1254 | 
            +
             | 
| 1255 | 
            +
            		Parameters
         | 
| 1256 | 
            +
            		----------
         | 
| 1257 | 
            +
            		ypos: float
         | 
| 1258 | 
            +
            			- y position from the top.
         | 
| 1259 | 
            +
            			- > 1 to push it higher, < 1 to push it lower
         | 
| 1260 | 
            +
            			- Default: 1.3
         | 
| 1261 | 
            +
            		
         | 
| 1262 | 
            +
            		Returns
         | 
| 1263 | 
            +
            		-------
         | 
| 1264 | 
            +
            		None
         | 
| 1265 | 
            +
            		"""
         | 
| 1266 | 
            +
            		axs = self._axs
         | 
| 1267 | 
            +
            		fig = self._fig
         | 
| 1268 | 
            +
            		
         | 
| 1269 | 
            +
            		all_handles, all_labels = [], []
         | 
| 1270 | 
            +
            		
         | 
| 1271 | 
            +
            		for ax in axs:
         | 
| 1272 | 
            +
            			handles, labels = ax[0].get_legend_handles_labels()
         | 
| 1273 | 
            +
            			all_handles.extend(handles)
         | 
| 1274 | 
            +
            			all_labels.extend(labels)
         | 
| 1275 | 
            +
            			
         | 
| 1276 | 
            +
            		# remove duplicates if needed
         | 
| 1277 | 
            +
            		fig.legend(all_handles, all_labels, loc='upper right', bbox_to_anchor=(0.95, ypos), ncol=2, frameon=True, bbox_transform=fig.transFigure)
         | 
| 1278 | 
            +
            		
         | 
| 1279 | 
            +
            	def save(self, path="./figure.png"):
         | 
| 1280 | 
            +
            		"""
         | 
| 1281 | 
            +
            		Save the figure.
         | 
| 1282 | 
            +
             | 
| 1283 | 
            +
            		Parameters
         | 
| 1284 | 
            +
            		----------
         | 
| 1285 | 
            +
            		path: str
         | 
| 1286 | 
            +
            			- Path to the output file.
         | 
| 1287 | 
            +
             | 
| 1288 | 
            +
            		Returns
         | 
| 1289 | 
            +
            		-------
         | 
| 1290 | 
            +
            		None
         | 
| 1291 | 
            +
            		"""
         | 
| 1292 | 
            +
            		fig = self._fig
         | 
| 1293 | 
            +
            		fig.savefig(path, bbox_inches="tight")
         | 
| 1294 | 
            +
            	
         | 
| 1295 | 
            +
            		
         | 
| 1296 | 
            +
            	
         | 
| @@ -1,9 +1,9 @@ | |
| 1 | 
            -
            modusa-0.3. | 
| 2 | 
            -
            modusa-0.3. | 
| 3 | 
            -
            modusa-0.3. | 
| 4 | 
            -
            modusa-0.3. | 
| 1 | 
            +
            modusa-0.3.47.dist-info/METADATA,sha256=Bqakd2bPlWP57HVv-VH91Wf5Jr0ZpkQs5-hFHA2A1tg,1403
         | 
| 2 | 
            +
            modusa-0.3.47.dist-info/WHEEL,sha256=9P2ygRxDrTJz3gsagc0Z96ukrxjr-LFBGOgv3AuKlCA,90
         | 
| 3 | 
            +
            modusa-0.3.47.dist-info/entry_points.txt,sha256=fmKpleVXj6CdaBVL14WoEy6xx7JQCs85jvzwTi3lePM,73
         | 
| 4 | 
            +
            modusa-0.3.47.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= | 
| 6 | 
            +
            modusa/__init__.py,sha256=_Fk3GxsI0GT-uhsZaHgs6p5YcIkqPGb3s78_dzFy1lE,291
         | 
| 7 7 | 
             
            modusa/config.py,sha256=bTqK4t00FZqERVITrxW_q284aDDJAa9aMSfFknfR-oU,280
         | 
| 8 8 | 
             
            modusa/decorators.py,sha256=8zeNX_wE37O6Vp0ysR4-WCZaEL8mq8dyCF_I5DHOzks,5905
         | 
| 9 9 | 
             
            modusa/devtools/generate_docs_source.py,sha256=UDflHsk-Yh9-3YJTVBzKL32y8hcxiRgAlFEBTMiDqwM,3301
         | 
| @@ -41,7 +41,7 @@ modusa/models/t_ax.py,sha256=ZUhvZPUW1TkdZYuUd6Ucm-vsv0JqtZ9yEe3ab67Ma6w,8022 | |
| 41 41 | 
             
            modusa/models/tds.py,sha256=FAGfibjyyE_lkEuQp-vSCuqQnopOjmy_IXqUjRlg9kc,11677
         | 
| 42 42 | 
             
            modusa/plugins/__init__.py,sha256=r1Bf5mnrVKRIwxboutY1iGzDy4EPQhqpk1kSW7iJj_Q,54
         | 
| 43 43 | 
             
            modusa/plugins/base.py,sha256=Bh_1Bja7fOymFsCgwhXDbV6ys3D8muNrPwrfDrG_G_A,2382
         | 
| 44 | 
            -
            modusa/tools/__init__.py,sha256= | 
| 44 | 
            +
            modusa/tools/__init__.py,sha256=s3Yfr4FbfZCXwfyy4uPHDfZ4lqf8XZqgH5KlKUVwQpM,373
         | 
| 45 45 | 
             
            modusa/tools/_plotter_old.py,sha256=KGow7mihA2H1WNq7s5bpivhCgGo2qVIeDaO6iabpsrg,19294
         | 
| 46 46 | 
             
            modusa/tools/ann_loader.py,sha256=RePlwD4qG6gGrD4mOJ3RDR9q_gUscCY90_R9lgFU9lM,780
         | 
| 47 47 | 
             
            modusa/tools/audio_converter.py,sha256=415qBoPm2sBIuBSI7m1XBKm0AbmVmPydIPPr-uO8D3c,1778
         | 
| @@ -50,7 +50,7 @@ modusa/tools/audio_player.py,sha256=GP04TWW4jBwQBjANkfR_cJtEy7cIhvbu8RTwnf9hD6E, | |
| 50 50 | 
             
            modusa/tools/audio_recorder.py,sha256=d2fVt0Sd2tlBdb2WlUs60K4N23zuxM3KUpQqX0ifPi8,2769
         | 
| 51 51 | 
             
            modusa/tools/base.py,sha256=C0ESJ0mIfjjRlAkRbSetNtMoOfS6IrHBjexRp3l_Mh4,1293
         | 
| 52 52 | 
             
            modusa/tools/math_ops.py,sha256=ZZ7U4DgqT7cOeE7_Lzi_Qq-48WYfwR9_osbZwTmE9eg,8690
         | 
| 53 | 
            -
            modusa/tools/plotter.py,sha256= | 
| 53 | 
            +
            modusa/tools/plotter.py,sha256=Yt85kVt5kiWmmExQmupI1RpqTI6NiK0_vsDI22J9u9I,34040
         | 
| 54 54 | 
             
            modusa/tools/youtube_downloader.py,sha256=hB_X8-7nOHXOlxg6vv3wyhBLoAsWyomrULP6_uCQL7s,1698
         | 
| 55 55 | 
             
            modusa/utils/.DS_Store,sha256=nLXMwF7QJNuglLI_Gk74F7vl5Dyus2Wd74Mgowijmdo,6148
         | 
| 56 56 | 
             
            modusa/utils/__init__.py,sha256=1oLL20yLB1GL9IbFiZD8OReDqiCpFr-yetIR6x1cNkI,23
         | 
| @@ -59,4 +59,4 @@ modusa/utils/excp.py,sha256=L9vhaGjKpv9viJYdmC9n5ndmk2GVbUBuFyZyhAQZmWY,906 | |
| 59 59 | 
             
            modusa/utils/logger.py,sha256=K0rsnObeNKCxlNeSnVnJeRhgfmob6riB2uyU7h3dDmA,571
         | 
| 60 60 | 
             
            modusa/utils/np_func_cat.py,sha256=TyIFgRc6bARRMDnZxlVURO5Z0I-GWhxRONYyIv-Vwxs,1007
         | 
| 61 61 | 
             
            modusa/utils/plot.py,sha256=s_vNdxvKfwxEngvJPgrF1PcmxZNnNaaXPViHWjyjJ-c,5335
         | 
| 62 | 
            -
            modusa-0.3. | 
| 62 | 
            +
            modusa-0.3.47.dist-info/RECORD,,
         | 
| 
            File without changes
         | 
| 
            File without changes
         | 
| 
            File without changes
         |