@@ -38,16 +38,35 @@ class MassSpecCalc(PeakPicking, NoiseThresholdCalc):
3838 Calculate the weight average molecular weight
3939 """
4040
41- def percentile_assigned (self , report_error : bool = False , mute_output : bool = False ):
41+ def percentage_assigned (self , report_error : bool = False , mute_output : bool = False ):
4242 """Percentage of peaks which are assigned
4343
44+ Calculates the percentage and relative abundance of assigned peaks in the spectrum.
45+ Includes protection against division by zero with explicit handling of edge cases.
46+
4447 Parameters
4548 -----------
4649 report_error: bool, optional
47- Report the error of the assigned peaks. Default is False.
50+ Report the RMS error of the assigned peaks. Default is False.
4851 mute_output: bool, optional
4952 Override the verbose setting. Default is False.
5053 If True, the function will silence results
54+
55+ Returns
56+ -------
57+ tuple
58+ If report_error is False:
59+ (assigned_count, unassigned_count, total_percent, total_relative_abundance)
60+ If report_error is True:
61+ (assigned_count, unassigned_count, total_percent, total_relative_abundance, rms_error)
62+ where rms_error is None if no assigned peaks exist
63+
64+ Notes
65+ -----
66+ Edge cases are handled with explicit reporting:
67+ - If no peaks detected: returns (0, 0, 0.0, 0.0[, None]) with message
68+ - If no abundance data: returns (i, j, 0.0, 0.0[, None]) with message
69+ - If no assigned peaks but peaks exist: returns with rms_error=None and explanatory message
5170 """
5271 verbose = self .parameters .mass_spectrum .verbose_processing
5372 assign_abun = 0
@@ -67,15 +86,45 @@ def percentile_assigned(self, report_error: bool = False, mute_output: bool = Fa
6786 j += 1
6887 not_assign_abun += mspeak .abundance
6988
70- total_percent = (i / (i + j )) * 100
71- total_relative_abundance = (assign_abun / (not_assign_abun + assign_abun )) * 100
89+ # Protect against division by zero
90+ total_peaks = i + j
91+ total_abundance = assign_abun + not_assign_abun
92+
93+ # Handle edge cases
94+ if total_peaks == 0 :
95+ if verbose and not mute_output :
96+ print ("No peaks detected in spectrum" )
97+ if report_error :
98+ return i , j , 0.0 , 0.0 , None
99+ else :
100+ return i , j , 0.0 , 0.0
101+
102+ if total_abundance == 0 :
103+ if verbose and not mute_output :
104+ print ("No abundance data detected in spectrum" )
105+ if report_error :
106+ return i , j , 0.0 , 0.0 , None
107+ else :
108+ return i , j , 0.0 , 0.0
109+
110+ total_percent = (i / total_peaks * 100 ) if total_peaks > 0 else 0.0
111+ total_relative_abundance = (assign_abun / total_abundance * 100 ) if total_abundance > 0 else 0.0
112+
72113 if report_error :
73- rms_error = sqrt (mean (array (error ) ** 2 ))
114+ rms_error = None
115+ if i > 0 :
116+ rms_error = sqrt (mean (array (error ) ** 2 ))
74117 if verbose and not mute_output :
75- print (
76- "%i assigned peaks and %i unassigned peaks, total = %.2f %%, relative abundance = %.2f %%, RMS error (best candidate) (ppm) = %.3f"
77- % (i , j , total_percent , total_relative_abundance , rms_error )
78- )
118+ if i == 0 :
119+ print (
120+ "No assigned peaks detected - cannot calculate RMS error. %i unassigned peaks, total = %.2f %%, relative abundance = %.2f %%"
121+ % (j , total_percent , total_relative_abundance )
122+ )
123+ else :
124+ print (
125+ "%i assigned peaks and %i unassigned peaks, total = %.2f %%, relative abundance = %.2f %%, RMS error (best candidate) (ppm) = %.3f"
126+ % (i , j , total_percent , total_relative_abundance , rms_error )
127+ )
79128 return i , j , total_percent , total_relative_abundance , rms_error
80129
81130 else :
@@ -91,6 +140,33 @@ def percentile_assigned(self, report_error: bool = False, mute_output: bool = Fa
91140 )
92141 return i , j , total_percent , total_relative_abundance
93142
143+ def percentile_assigned (self , report_error : bool = False , mute_output : bool = False ):
144+ """Deprecated: Use percentage_assigned() instead.
145+
146+ This method is deprecated and will be removed in a future version.
147+ The function returns a percentage, not a percentile, so the name has been corrected.
148+
149+ Parameters
150+ -----------
151+ report_error: bool, optional
152+ Report the error of the assigned peaks. Default is False.
153+ mute_output: bool, optional
154+ Override the verbose setting. Default is False.
155+
156+ Returns
157+ -------
158+ tuple
159+ Refer to percentage_assigned() for return value details.
160+ """
161+ import warnings
162+ warnings .warn (
163+ "percentile_assigned() is deprecated and will be removed in a future version. "
164+ "Use percentage_assigned() instead, as the function returns a percentage, not a percentile." ,
165+ DeprecationWarning ,
166+ stacklevel = 2
167+ )
168+ return self .percentage_assigned (report_error = report_error , mute_output = mute_output )
169+
94170 def resolving_power_calc (self , B : float , T : float ):
95171 """Calculate the theoretical resolving power
96172
0 commit comments