Skip to content

Commit 34aedb1

Browse files
committed
Add analysis funcs that operate on FOOOF objects
1 parent 5801f84 commit 34aedb1

File tree

3 files changed

+78
-25
lines changed

3 files changed

+78
-25
lines changed

fooof/analysis.py

Lines changed: 65 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,64 @@
1-
"""Basic analysis functions for FOOOF results."""
1+
"""Analysis functions for FOOOF results."""
22

33
import numpy as np
44

55
###################################################################################################
66
###################################################################################################
77

8-
def get_band_peak_group(peak_params, band_def, n_fits):
9-
"""Extracts peaks within a given band of interest, for a group of FOOOF model fits.
8+
def get_band_peak_fm(fm, band, ret_one=True, attribute='peak_params'):
9+
"""Extract peaks from a band of interest from a FOOOFGroup object.
10+
11+
Parameters
12+
----------
13+
fm : FOOOF
14+
FOOOF object to extract peak data from.
15+
band : tuple of (float, float)
16+
Defines the band of interest, as (lower_frequency_bound, upper_frequency_bound).
17+
ret_one : bool, optional, default: True
18+
Whether to return single peak (if True) or all peaks within the range found (if False).
19+
If True, returns the highest power peak within the search range.
20+
attribute : {'peak_params', 'gaussian_params'}
21+
Which attribute of peak data to extract data from.
22+
23+
Returns
24+
-------
25+
1d or 2d array
26+
Peak data. Each row is a peak, as [CF, Amp, BW]
27+
"""
28+
29+
return get_band_peak(getattr(fm, attribute + '_'), band, ret_one)
30+
31+
32+
def get_band_peaks_fg(fg, band, attribute='peak_params'):
33+
"""Extract peaks from a band of interest from a FOOOF object.
34+
35+
Parameters
36+
----------
37+
fg : FOOOFGroup
38+
FOOOFGroup object to extract peak data from.
39+
band : tuple of (float, float)
40+
Defines the band of interest, as (lower_frequency_bound, upper_frequency_bound).
41+
attribute : {'peak_params', 'gaussian_params'}
42+
Which attribute of peak data to extract data from.
43+
44+
Returns
45+
-------
46+
2d array
47+
Peak data. Each row is a peak, as [CF, Amp, BW].
48+
"""
49+
50+
return get_band_peaks_group(fg.get_all_data(attribute), band, len(fg))
51+
52+
53+
def get_band_peaks_group(peak_params, band, n_fits):
54+
"""Extracts peaks within a given band of interest.
1055
1156
Parameters
1257
----------
1358
peak_params : 2d array
1459
Peak parameters, for a group fit, from FOOOF, with shape of [n_peaks, 4].
15-
band_def : [float, float]
16-
Defines the band of interest, as [lower_frequency_bound, upper_frequency_bound].
60+
band : tuple of (float, float)
61+
Defines the band of interest, as (lower_frequency_bound, upper_frequency_bound).
1762
n_fits : int
1863
The number of model fits in the FOOOFGroup data.
1964
@@ -34,32 +79,32 @@ def get_band_peak_group(peak_params, band_def, n_fits):
3479
3580
>>> peaks = np.empty((0, 3))
3681
>>> for f_res in fg:
37-
>>> peaks = np.vstack((peaks, get_band_peak(f_res.peak_params, band_def, ret_one=False)))
82+
>>> peaks = np.vstack((peaks, get_band_peak(f_res.peak_params, band, ret_one=False)))
3883
3984
"""
4085

4186
band_peaks = np.zeros(shape=[n_fits, 3])
42-
for ind in range(n_fits):
4387

44-
# Extacts an array per FOOOF fit, and extracts band peaks from it
88+
# Extacts an array per FOOOF fit, and extracts band peaks from it
89+
for ind in range(n_fits):
4590
band_peaks[ind, :] = get_band_peak(peak_params[tuple([peak_params[:, -1] == ind])][:, 0:3],
46-
band_def=band_def, ret_one=True)
91+
band=band, ret_one=True)
4792

4893
return band_peaks
4994

5095

51-
def get_band_peak(peak_params, band_def, ret_one=True):
52-
"""Extracts peaks within a given band of interest, for a FOOOF model fit.
96+
def get_band_peak(peak_params, band, ret_one=True):
97+
"""Extracts peaks within a given band of interest.
5398
5499
Parameters
55100
----------
56101
peak_params : 2d array
57102
Peak parameters, from FOOOF, with shape of [n_peaks, 3].
58-
band_def : [float, float]
59-
Defines the band of interest, as [lower_frequency_bound, upper_frequency_bound].
103+
band : tuple of (float, float)
104+
Defines the band of interest, as (lower_frequency_bound, upper_frequency_bound).
60105
ret_one : bool, optional, default: True
61106
Whether to return single peak (if True) or all peaks within the range found (if False).
62-
If True, returns the highest amplitude peak within the search range.
107+
If True, returns the highest power peak within the search range.
63108
64109
Returns
65110
-------
@@ -72,7 +117,7 @@ def get_band_peak(peak_params, band_def, ret_one=True):
72117
return np.array([np.nan, np.nan, np.nan])
73118

74119
# Find indices of peaks in the specified range, and check the number found
75-
peak_inds = (peak_params[:, 0] >= band_def[0]) & (peak_params[:, 0] <= band_def[1])
120+
peak_inds = (peak_params[:, 0] >= band[0]) & (peak_params[:, 0] <= band[1])
76121
n_peaks = sum(peak_inds)
77122

78123
# If there are no peaks within the specified range
@@ -82,12 +127,12 @@ def get_band_peak(peak_params, band_def, ret_one=True):
82127

83128
band_peaks = peak_params[peak_inds, :]
84129

85-
# If results > 1 and ret_one, then we return the highest amplitude peak
130+
# If results > 1 and ret_one, then we return the highest power peak
86131
# Call a sub-function to select highest power peak in band
87132
if n_peaks > 1 and ret_one:
88133
band_peaks = get_highest_amp_peak(band_peaks)
89134

90-
# If results == 1, return peak - [cen, power, bw]
135+
# If results == 1, return single peak
91136
return np.squeeze(band_peaks)
92137

93138

@@ -96,13 +141,13 @@ def get_highest_amp_peak(band_peaks):
96141
97142
Parameters
98143
----------
99-
peak_params : 2d array
144+
band_peaks : 2d array
100145
Peak parameters, from FOOOF, with shape of [n_peaks, 3].
101146
102147
Returns
103148
-------
104-
band_peaks : array
105-
Peak data. Each row is a peak, as [CF, Amp, BW].
149+
1d array
150+
Seleced peak data. Row is a peak, as [CF, Amp, BW].
106151
"""
107152

108153
# Catch & return NaN if empty

fooof/tests/test_analysis.py

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,23 @@
77
###################################################################################################
88
###################################################################################################
99

10-
def test_get_band_peak_group():
10+
def test_get_band_peak_fm(tfm):
11+
12+
assert np.all(get_band_peak_fm(tfm, (8, 12)))
13+
14+
def test_get_band_peaks_fg(tfg):
15+
16+
assert np.all(get_band_peaks_fg(tfg, (8, 12)))
17+
18+
def test_get_band_peaks_group():
1119

1220
dat = np.array([[10, 1, 1.8, 0], [13, 1, 2, 2], [14, 2, 4, 2]])
1321

14-
out1 = get_band_peak_group(dat, [8, 12], 3)
22+
out1 = get_band_peaks_group(dat, [8, 12], 3)
1523
assert out1.shape == (3, 3)
1624
assert np.array_equal(out1[0, :], [10, 1, 1.8])
1725

18-
out2 = get_band_peak_group(dat, [12, 16], 3)
26+
out2 = get_band_peaks_group(dat, [12, 16], 3)
1927
assert out2.shape == (3, 3)
2028
assert np.array_equal(out2[2, :], [14, 2, 4])
2129

@@ -50,4 +58,4 @@ def test_empty_inputs():
5058

5159
dat = np.empty(shape=[0, 4])
5260

53-
assert np.all(get_band_peak_group(dat, [8, 12], 0))
61+
assert np.all(get_band_peaks_group(dat, [8, 12], 0))

fooof/tests/test_bands.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,5 +44,5 @@ def test_bands_dunders(tbands):
4444

4545
def test_bands_properties(tbands):
4646

47-
assert tbands.labels == ['theta', 'alpha', 'beta']
47+
assert set(tbands.labels) == set(['theta', 'alpha', 'beta'])
4848
assert tbands.n_bands == 3

0 commit comments

Comments
 (0)