Skip to content

Commit 93febaf

Browse files
authored
Merge pull request #276 from fooof-tools/plotfull
[ENH] - Update options to plot a broader frequency range
2 parents 8be1ed2 + 2e0987f commit 93febaf

File tree

4 files changed

+67
-16
lines changed

4 files changed

+67
-16
lines changed

fooof/objs/fit.py

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -379,7 +379,7 @@ def add_results(self, fooof_result):
379379

380380

381381
def report(self, freqs=None, power_spectrum=None, freq_range=None,
382-
plt_log=False, **plot_kwargs):
382+
plt_log=False, plot_full_range=False, **plot_kwargs):
383383
"""Run model fit, and display a report, which includes a plot, and printed results.
384384
385385
Parameters
@@ -393,16 +393,26 @@ def report(self, freqs=None, power_spectrum=None, freq_range=None,
393393
If not provided, fits across the entire given range.
394394
plt_log : bool, optional, default: False
395395
Whether or not to plot the frequency axis in log space.
396+
plot_full_range : bool, default: False
397+
If True, plots the full range of the given power spectrum.
398+
Only relevant / effective if `freqs` and `power_spectrum` passed in in this call.
396399
**plot_kwargs
397400
Keyword arguments to pass into the plot method.
401+
Plot options with a name conflict be passed by pre-pending 'plot_'.
402+
e.g. `freqs`, `power_spectrum` and `freq_range`.
398403
399404
Notes
400405
-----
401406
Data is optional, if data has already been added to the object.
402407
"""
403408

404409
self.fit(freqs, power_spectrum, freq_range)
405-
self.plot(plt_log=plt_log, **plot_kwargs)
410+
self.plot(plt_log=plt_log,
411+
freqs=freqs if plot_full_range else plot_kwargs.pop('plot_freqs', None),
412+
power_spectrum=power_spectrum if \
413+
plot_full_range else plot_kwargs.pop('plot_power_spectrum', None),
414+
freq_range=plot_kwargs.pop('plot_freq_range', None),
415+
**plot_kwargs)
406416
self.print_results(concise=False)
407417

408418

@@ -639,12 +649,13 @@ def get_results(self):
639649

640650

641651
@copy_doc_func_to_method(plot_fm)
642-
def plot(self, plot_peaks=None, plot_aperiodic=True, plt_log=False,
643-
add_legend=True, save_fig=False, file_name=None, file_path=None,
644-
ax=None, data_kwargs=None, model_kwargs=None,
652+
def plot(self, plot_peaks=None, plot_aperiodic=True, freqs=None, power_spectrum=None,
653+
freq_range=None, plt_log=False, add_legend=True, save_fig=False, file_name=None,
654+
file_path=None, ax=None, data_kwargs=None, model_kwargs=None,
645655
aperiodic_kwargs=None, peak_kwargs=None, **plot_kwargs):
646656

647-
plot_fm(self, plot_peaks=plot_peaks, plot_aperiodic=plot_aperiodic, plt_log=plt_log,
657+
plot_fm(self, plot_peaks=plot_peaks, plot_aperiodic=plot_aperiodic, freqs=freqs,
658+
power_spectrum=power_spectrum, freq_range=freq_range, plt_log=plt_log,
648659
add_legend=add_legend, save_fig=save_fig, file_name=file_name,
649660
file_path=file_path, ax=ax, data_kwargs=data_kwargs, model_kwargs=model_kwargs,
650661
aperiodic_kwargs=aperiodic_kwargs, peak_kwargs=peak_kwargs, **plot_kwargs)

fooof/plts/fm.py

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,10 @@
2525
@savefig
2626
@style_plot
2727
@check_dependency(plt, 'matplotlib')
28-
def plot_fm(fm, plot_peaks=None, plot_aperiodic=True, plt_log=False, add_legend=True,
29-
save_fig=False, file_name=None, file_path=None, ax=None, data_kwargs=None,
30-
model_kwargs=None, aperiodic_kwargs=None, peak_kwargs=None, **plot_kwargs):
28+
def plot_fm(fm, plot_peaks=None, plot_aperiodic=True, freqs=None, power_spectrum=None,
29+
freq_range=None, plt_log=False, add_legend=True, save_fig=False, file_name=None,
30+
file_path=None, ax=None, data_kwargs=None, model_kwargs=None, aperiodic_kwargs=None,
31+
peak_kwargs=None, **plot_kwargs):
3132
"""Plot the power spectrum and model fit results from a FOOOF object.
3233
3334
Parameters
@@ -39,6 +40,14 @@ def plot_fm(fm, plot_peaks=None, plot_aperiodic=True, plt_log=False, add_legend=
3940
Can also be a combination of approaches, separated by '-', for example: 'shade-line'.
4041
plot_aperiodic : boolean, optional, default: True
4142
Whether to plot the aperiodic component of the model fit.
43+
freqs : 1d array, optional
44+
Frequency values of the power spectrum to plot, in linear space.
45+
If provided, this overrides the values in the model object.
46+
power_spectrum : 1d array, optional
47+
Power values to plot, in linear space.
48+
If provided, this overrides the values in the model object.
49+
freq_range : list of [float, float], optional
50+
Frequency range to plot, defined in linear space.
4251
plt_log : boolean, optional, default: False
4352
Whether to plot the frequency values in log10 spacing.
4453
add_legend : boolean, optional, default: False
@@ -64,16 +73,22 @@ def plot_fm(fm, plot_peaks=None, plot_aperiodic=True, plt_log=False, add_legend=
6473

6574
ax = check_ax(ax, plot_kwargs.pop('figsize', PLT_FIGSIZES['spectral']))
6675

76+
# Check inputs for what to plot
77+
custom_spectrum = (np.any(freqs) and np.any(power_spectrum))
78+
6779
# Log settings - note that power values in FOOOF objects are already logged
6880
log_freqs = plt_log
6981
log_powers = False
7082

7183
# Plot the data, if available
72-
if fm.has_data:
84+
if fm.has_data or custom_spectrum:
7385
data_defaults = {'color' : PLT_COLORS['data'], 'linewidth' : 2.0,
7486
'label' : 'Original Spectrum' if add_legend else None}
7587
data_kwargs = check_plot_kwargs(data_kwargs, data_defaults)
76-
plot_spectra(fm.freqs, fm.power_spectrum, log_freqs, log_powers, ax=ax, **data_kwargs)
88+
plot_spectra(freqs if custom_spectrum else fm.freqs,
89+
power_spectrum if custom_spectrum else fm.power_spectrum,
90+
log_freqs, log_powers if not custom_spectrum else True,
91+
freq_range, ax=ax, **data_kwargs)
7792

7893
# Add the full model fit, and components (if requested)
7994
if fm.has_model:

fooof/plts/spectra.py

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
@savefig
2525
@style_plot
2626
@check_dependency(plt, 'matplotlib')
27-
def plot_spectra(freqs, power_spectra, log_freqs=False, log_powers=False,
27+
def plot_spectra(freqs, power_spectra, log_freqs=False, log_powers=False, freq_range=None,
2828
colors=None, labels=None, ax=None, **plot_kwargs):
2929
"""Plot one or multiple power spectra.
3030
@@ -38,21 +38,27 @@ def plot_spectra(freqs, power_spectra, log_freqs=False, log_powers=False,
3838
Whether to plot the frequency axis in log spacing.
3939
log_powers : bool, optional, default: False
4040
Whether to plot the power axis in log spacing.
41+
freq_range : list of [float, float], optional
42+
Frequency range to plot, defined in linear space.
4143
colors : list of str, optional, default: None
4244
Line colors of the spectra.
4345
labels : list of str, optional, default: None
4446
Legend labels for the spectra.
4547
ax : matplotlib.Axes, optional
4648
Figure axes upon which to plot.
4749
**plot_kwargs
48-
Keyword arguments to pass into the ``style_plot``.
50+
Additional plot related keyword arguments.
4951
"""
5052

5153
ax = check_ax(ax, plot_kwargs.pop('figsize', PLT_FIGSIZES['spectral']))
5254

5355
# Create the plot
5456
plot_kwargs = check_plot_kwargs(plot_kwargs, {'linewidth' : 2.0})
5557

58+
# Check for frequency range input, and log if x-axis is in log space
59+
if freq_range is not None:
60+
freq_range = np.log10(freq_range) if log_freqs else freq_range
61+
5662
# Make inputs iterable if need to be passed multiple times to plot each spectrum
5763
plt_powers = np.reshape(power_spectra, (1, -1)) if np.ndim(power_spectra) == 1 else \
5864
power_spectra
@@ -63,7 +69,7 @@ def plot_spectra(freqs, power_spectra, log_freqs=False, log_powers=False,
6369
labels = repeat(labels) if not isinstance(labels, list) else cycle(labels)
6470
colors = repeat(colors) if not isinstance(colors, list) else cycle(colors)
6571

66-
# Plot
72+
# Plot power spectra, looping across all spectra to plot
6773
for freqs, powers, color, label in zip(plt_freqs, plt_powers, colors, labels):
6874

6975
# Set plot data, logging if requested, and collect color, if absent
@@ -74,6 +80,8 @@ def plot_spectra(freqs, power_spectra, log_freqs=False, log_powers=False,
7480

7581
ax.plot(freqs, powers, label=label, **plot_kwargs)
7682

83+
ax.set_xlim(freq_range)
84+
7785
style_spectrum_plot(ax, log_freqs, log_powers)
7886

7987

@@ -102,7 +110,8 @@ def plot_spectra_shading(freqs, power_spectra, shades, shade_colors='r',
102110
ax : matplotlib.Axes, optional
103111
Figure axes upon which to plot.
104112
**plot_kwargs
105-
Keyword arguments to pass into :func:`~.plot_spectra`.
113+
Additional plot related keyword arguments.
114+
This can include additional inputs into :func:`~.plot_spectra`.
106115
107116
Notes
108117
-----
@@ -152,7 +161,7 @@ def plot_spectra_yshade(freqs, power_spectra, shade='std', average='mean', scale
152161
ax : matplotlib.Axes, optional
153162
Figure axes upon which to plot.
154163
**plot_kwargs
155-
Keyword arguments to be passed to `plot_spectra` or to the plot call.
164+
Additional plot related keyword arguments.
156165
"""
157166

158167
if (isinstance(shade, str) or isfunction(shade)) and power_spectra.ndim != 2:

fooof/tests/plts/test_fm.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
"""Tests for fooof.plts.fm."""
22

3+
import numpy as np
4+
35
from fooof.tests.tutils import plot_test
46
from fooof.tests.settings import TEST_PLOTS_PATH
57

@@ -17,6 +19,20 @@ def test_plot_fm(tfm, skip_if_no_mpl):
1719
plot_fm(tfm, save_fig=True, file_path=TEST_PLOTS_PATH,
1820
file_name='test_plot_fm.png')
1921

22+
@plot_test
23+
def test_plot_fm_custom(tfm, skip_if_no_mpl):
24+
25+
# Extract broader range of data available in the object
26+
custom_freqs = tfm.freqs
27+
custom_power_spectrum = np.power(10, tfm.power_spectrum)
28+
29+
# Make sure model has been fit - set custom frequency range
30+
tfm.fit(custom_freqs, custom_power_spectrum, freq_range=[5, 35])
31+
32+
plot_fm(tfm, freqs=custom_freqs, power_spectrum=custom_power_spectrum,
33+
freq_range=[1, 55], save_fig=True, file_path=TEST_PLOTS_PATH,
34+
file_name='test_plot_fm_custom.png')
35+
2036
@plot_test
2137
def test_plot_fm_add_peaks(tfm, skip_if_no_mpl):
2238

0 commit comments

Comments
 (0)