Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[ENH] Combined plot_spectra and plot_spectrum #198

Merged
merged 6 commits into from
Apr 13, 2021
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions doc/api.rst
Original file line number Diff line number Diff line change
Expand Up @@ -247,7 +247,6 @@ Plots for visualizing power spectra.
.. autosummary::
:toctree: generated/

plot_spectrum
plot_spectra

Plots for plotting power spectra with shaded regions.
Expand All @@ -257,7 +256,6 @@ Plots for plotting power spectra with shaded regions.
.. autosummary::
:toctree: generated/

plot_spectrum_shading
plot_spectra_shading

Plot Model Properties & Parameters
Expand Down
10 changes: 5 additions & 5 deletions examples/analyses/plot_mne_example.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
from fooof import FOOOFGroup
from fooof.bands import Bands
from fooof.analysis import get_band_peak_fg
from fooof.plts.spectra import plot_spectrum
from fooof.plts.spectra import plot_spectra

###################################################################################################
# Load & Check MNE Data
Expand Down Expand Up @@ -284,10 +284,10 @@ def check_nans(data, nan_policy='zero'):

# Compare the power spectra between low and high exponent channels
fig, ax = plt.subplots(figsize=(8, 6))
plot_spectrum(fg.freqs, fg.get_fooof(np.argmin(exps)).power_spectrum,
ax=ax, label='Low Exponent')
plot_spectrum(fg.freqs, fg.get_fooof(np.argmax(exps)).power_spectrum,
ax=ax, label='High Exponent')
plot_spectra(fg.freqs, fg.get_fooof(np.argmin(exps)).power_spectrum,
ax=ax, label='Low Exponent')
plot_spectra(fg.freqs, fg.get_fooof(np.argmax(exps)).power_spectrum,
ax=ax, label='High Exponent')

###################################################################################################
# Conclusion
Expand Down
13 changes: 6 additions & 7 deletions examples/plots/plot_power_spectra.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,7 @@
import matplotlib.pyplot as plt

# Import plotting functions
from fooof.plts.spectra import plot_spectrum, plot_spectra
from fooof.plts.spectra import plot_spectrum_shading, plot_spectra_shading
from fooof.plts.spectra import plot_spectra, plot_spectra_shading

# Import simulation utilities for creating test data
from fooof.sim.gen import gen_power_spectrum, gen_group_power_spectra
Expand Down Expand Up @@ -59,7 +58,7 @@
#
# First we will start with the core plotting function that plots an individual power spectrum.
#
# The :func:`~.plot_spectrum` function takes in an array of frequency values and a 1d array of
# The :func:`~.plot_spectra` function takes in an array of frequency values and a 1d array of
# of power values, and plots the corresponding power spectrum.
#
# This function, as all the functions in the plotting module, takes in optional inputs
Expand All @@ -70,7 +69,7 @@
###################################################################################################

# Create a spectrum plot with a single power spectrum
plot_spectrum(freqs, powers1, log_powers=True)
plot_spectra(freqs, powers1, log_powers=True)

###################################################################################################
# Plotting Multiple Power Spectra
Expand All @@ -97,7 +96,7 @@
# In some cases it may be useful to highlight or shade in particular frequency regions,
# for example, when examining power in particular frequency regions.
#
# The :func:`~.plot_spectrum_shading` function takes in a power spectrum and one or more
# The :func:`~.plot_spectra_shading` function takes in a power spectrum and one or more
# shaded regions, and plot the power spectrum with the indicated region shaded.
#
# The same can be done for multiple power spectra with :func:`~.plot_spectra_shading`.
Expand All @@ -110,7 +109,7 @@
###################################################################################################

# Plot a single power spectrum, with a shaded region covering alpha
plot_spectrum_shading(freqs, powers1, [8, 12], log_powers=True)
plot_spectra_shading(freqs, powers1, [8, 12], log_powers=True)

###################################################################################################

Expand Down Expand Up @@ -157,6 +156,6 @@
fig, ax = plt.subplots(figsize=[12, 8])
plot_spectra_shading(freqs_al, powers_al, [8, 12],
log_powers=True, alpha=0.6, ax=ax)
plot_spectrum(freqs_al10, powers_al10, log_powers=True,
plot_spectra(freqs_al10, powers_al10, log_powers=True,
color='black', linewidth=3, label='10 Hz Alpha', ax=ax)
plt.title('Comparing Alphas', {'fontsize' : 20, 'fontweight' : 'bold'});
6 changes: 3 additions & 3 deletions examples/sims/plot_simulated_power_spectra.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
from fooof.sim.gen import gen_power_spectrum, gen_group_power_spectra

# Import plotting functions
from fooof.plts.spectra import plot_spectrum, plot_spectra
from fooof.plts.spectra import plot_spectra

###################################################################################################
# Creating Simulated Power Spectra
Expand Down Expand Up @@ -53,7 +53,7 @@
###################################################################################################

# Plot the simulated power spectrum
plot_spectrum(freqs, powers, log_freqs=True, log_powers=False)
plot_spectra(freqs, powers, log_freqs=True, log_powers=False)

###################################################################################################
# Simulating With Different Parameters
Expand Down Expand Up @@ -100,7 +100,7 @@
###################################################################################################

# Plot the new simulated power spectrum
plot_spectrum(freqs, powers, log_powers=True)
plot_spectra(freqs, powers, log_powers=True)

###################################################################################################
# Simulating a Group of Power Spectra
Expand Down
3 changes: 2 additions & 1 deletion fooof/plts/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
"""Plots sub-module for FOOOF."""

from .spectra import plot_spectrum, plot_spectra
from .spectra import plot_spectra
from .spectra import plot_spectra as plot_spectrum
24 changes: 13 additions & 11 deletions fooof/plts/annotate.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,15 @@
from fooof.core.errors import NoModelError
from fooof.core.funcs import gaussian_function
from fooof.core.modutils import safe_import, check_dependency

from fooof.sim.gen import gen_aperiodic
from fooof.analysis.periodic import get_band_peak_fm
from fooof.utils.params import compute_knee_frequency, compute_fwhm

from fooof.plts.spectra import plot_spectra
from fooof.plts.utils import check_ax, savefig
from fooof.plts.spectra import plot_spectrum
from fooof.plts.settings import PLT_FIGSIZES, PLT_COLORS
from fooof.plts.style import style_spectrum_plot
from fooof.analysis.periodic import get_band_peak_fm
from fooof.utils.params import compute_knee_frequency, compute_fwhm

plt = safe_import('.pyplot', 'matplotlib')
mpatches = safe_import('.patches', 'matplotlib')
Expand Down Expand Up @@ -45,12 +47,12 @@ def plot_annotated_peak_search(fm):
# This forces the creation of a new plotting axes per iteration
ax = check_ax(None, PLT_FIGSIZES['spectral'])

plot_spectrum(fm.freqs, flatspec, ax=ax, linewidth=2.5,
label='Flattened Spectrum', color=PLT_COLORS['data'])
plot_spectrum(fm.freqs, [fm.peak_threshold * np.std(flatspec)]*len(fm.freqs), ax=ax,
label='Relative Threshold', color='orange', linewidth=2.5, linestyle='dashed')
plot_spectrum(fm.freqs, [fm.min_peak_height]*len(fm.freqs), ax=ax,
label='Absolute Threshold', color='red', linewidth=2.5, linestyle='dashed')
plot_spectra(fm.freqs, flatspec, ax=ax, linewidth=2.5,
label='Flattened Spectrum', color=PLT_COLORS['data'])
plot_spectra(fm.freqs, [fm.peak_threshold * np.std(flatspec)]*len(fm.freqs), ax=ax,
label='Relative Threshold', color='orange', linewidth=2.5, linestyle='dashed')
plot_spectra(fm.freqs, [fm.min_peak_height]*len(fm.freqs), ax=ax,
label='Absolute Threshold', color='red', linewidth=2.5, linestyle='dashed')

maxi = np.argmax(flatspec)
ax.plot(fm.freqs[maxi], flatspec[maxi], '.',
Expand All @@ -62,8 +64,8 @@ def plot_annotated_peak_search(fm):
if ind < fm.n_peaks_:

gauss = gaussian_function(fm.freqs, *fm.gaussian_params_[ind, :])
plot_spectrum(fm.freqs, gauss, ax=ax, label='Gaussian Fit',
color=PLT_COLORS['periodic'], linestyle=':', linewidth=3.0)
plot_spectra(fm.freqs, gauss, ax=ax, label='Gaussian Fit',
color=PLT_COLORS['periodic'], linestyle=':', linewidth=3.0)

flatspec = flatspec - gauss

Expand Down
4 changes: 2 additions & 2 deletions fooof/plts/error.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import numpy as np

from fooof.core.modutils import safe_import, check_dependency
from fooof.plts.spectra import plot_spectrum
from fooof.plts.spectra import plot_spectra
from fooof.plts.settings import PLT_FIGSIZES
from fooof.plts.style import style_spectrum_plot, style_plot
from fooof.plts.utils import check_ax, savefig
Expand Down Expand Up @@ -40,7 +40,7 @@ def plot_spectral_error(freqs, error, shade=None, log_freqs=False, ax=None, **pl

plt_freqs = np.log10(freqs) if log_freqs else freqs

plot_spectrum(plt_freqs, error, ax=ax, linewidth=3)
plot_spectra(plt_freqs, error, ax=ax, linewidth=3)

if np.any(shade):
ax.fill_between(plt_freqs, error-shade, error+shade, alpha=0.25)
Expand Down
8 changes: 4 additions & 4 deletions fooof/plts/fm.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
from fooof.sim.gen import gen_periodic
from fooof.utils.data import trim_spectrum
from fooof.utils.params import compute_fwhm
from fooof.plts.spectra import plot_spectrum
from fooof.plts.spectra import plot_spectra
from fooof.plts.settings import PLT_FIGSIZES, PLT_COLORS
from fooof.plts.utils import check_ax, check_plot_kwargs, savefig
from fooof.plts.style import style_spectrum_plot, style_plot
Expand Down Expand Up @@ -73,22 +73,22 @@ def plot_fm(fm, plot_peaks=None, plot_aperiodic=True, plt_log=False, add_legend=
data_defaults = {'color' : PLT_COLORS['data'], 'linewidth' : 2.0,
'label' : 'Original Spectrum' if add_legend else None}
data_kwargs = check_plot_kwargs(data_kwargs, data_defaults)
plot_spectrum(fm.freqs, fm.power_spectrum, log_freqs, log_powers, ax=ax, **data_kwargs)
plot_spectra(fm.freqs, fm.power_spectrum, log_freqs, log_powers, ax=ax, **data_kwargs)

# Add the full model fit, and components (if requested)
if fm.has_model:
model_defaults = {'color' : PLT_COLORS['model'], 'linewidth' : 3.0, 'alpha' : 0.5,
'label' : 'Full Model Fit' if add_legend else None}
model_kwargs = check_plot_kwargs(model_kwargs, model_defaults)
plot_spectrum(fm.freqs, fm.fooofed_spectrum_, log_freqs, log_powers, ax=ax, **model_kwargs)
plot_spectra(fm.freqs, fm.fooofed_spectrum_, log_freqs, log_powers, ax=ax, **model_kwargs)

# Plot the aperiodic component of the model fit
if plot_aperiodic:
aperiodic_defaults = {'color' : PLT_COLORS['aperiodic'], 'linewidth' : 3.0,
'alpha' : 0.5, 'linestyle' : 'dashed',
'label' : 'Aperiodic Fit' if add_legend else None}
aperiodic_kwargs = check_plot_kwargs(aperiodic_kwargs, aperiodic_defaults)
plot_spectrum(fm.freqs, fm._ap_fit, log_freqs, log_powers, ax=ax, **aperiodic_kwargs)
plot_spectra(fm.freqs, fm._ap_fit, log_freqs, log_powers, ax=ax, **aperiodic_kwargs)

# Plot the periodic components of the model fit
if plot_peaks:
Expand Down
113 changes: 27 additions & 86 deletions fooof/plts/spectra.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,73 +12,34 @@
from fooof.core.modutils import safe_import, check_dependency
from fooof.plts.settings import PLT_FIGSIZES
from fooof.plts.style import style_spectrum_plot, style_plot
from fooof.plts.utils import check_ax, add_shades, savefig
from fooof.plts.utils import check_ax, add_shades, savefig, check_plot_kwargs

plt = safe_import('.pyplot', 'matplotlib')

###################################################################################################
###################################################################################################

@savefig
@style_plot
@check_dependency(plt, 'matplotlib')
def plot_spectrum(freqs, power_spectrum, log_freqs=False, log_powers=False,
color=None, label=None, ax=None, **plot_kwargs):
"""Plot a power spectrum.

Parameters
----------
freqs : 1d array
Frequency values, to be plotted on the x-axis.
power_spectrum : 1d array
Power values, to be plotted on the y-axis.
log_freqs : bool, optional, default: False
Whether to plot the frequency axis in log spacing.
log_powers : bool, optional, default: False
Whether to plot the power axis in log spacing.
label : str, optional, default: None
Legend label for the spectrum.
color : str, optional, default: None
Line color of the spectrum.
ax : matplotlib.Axes, optional
Figure axis upon which to plot.
**plot_kwargs
Keyword arguments to pass into the ``style_plot``.
"""

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

# Set plot data & labels, logging if requested
plt_freqs = np.log10(freqs) if log_freqs else freqs
plt_powers = np.log10(power_spectrum) if log_powers else power_spectrum

# Create the plot
ax.plot(plt_freqs, plt_powers, linewidth=2.0, color=color, label=label)

style_spectrum_plot(ax, log_freqs, log_powers)


@savefig
@style_plot
@check_dependency(plt, 'matplotlib')
def plot_spectra(freqs, power_spectra, log_freqs=False, log_powers=False,
colors=None, labels=None, ax=None, **plot_kwargs):
"""Plot multiple power spectra on the same plot.
"""Plot one or multiple power spectra.

Parameters
----------
freqs : 2d array or 1d array or list of 1d array
freqs : 1d or 2d array or list of 1d array
Frequency values, to be plotted on the x-axis.
power_spectra : 2d array or list of 1d array
power_spectra : 1d or 2d array or list of 1d array
Power values, to be plotted on the y-axis.
log_freqs : bool, optional, default: False
Whether to plot the frequency axis in log spacing.
log_powers : bool, optional, default: False
Whether to plot the power axis in log spacing.
labels : list of str, optional, default: None
Legend labels for the spectra.
colors : list of str, optional, default: None
Line colors of the spectra.
labels : list of str, optional, default: None
Legend labels for the spectra.
ax : matplotlib.Axes, optional
Figure axes upon which to plot.
**plot_kwargs
Expand All @@ -87,64 +48,44 @@ def plot_spectra(freqs, power_spectra, log_freqs=False, log_powers=False,

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

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

# Make inputs iterable if need to be passed multiple times to plot each spectrum
freqs = repeat(freqs) if isinstance(freqs, np.ndarray) and freqs.ndim == 1 else freqs
plt_powers = np.reshape(power_spectra, (1, -1)) if np.ndim(power_spectra) == 1 else \
power_spectra
plt_freqs = repeat(freqs) if isinstance(freqs, np.ndarray) and freqs.ndim == 1 else freqs

colors = repeat(colors) if not isinstance(colors, list) else cycle(colors)
# Set labels
labels = plot_kwargs.pop('label') if 'label' in plot_kwargs.keys() and labels is None else labels
labels = repeat(labels) if not isinstance(labels, list) else cycle(labels)
colors = repeat(colors) if not isinstance(colors, list) else cycle(colors)

for freq, power_spectrum, color, label in zip(freqs, power_spectra, colors, labels):
plot_spectrum(freq, power_spectrum, log_freqs, log_powers,
color=color, label=label, ax=ax)

style_spectrum_plot(ax, log_freqs, log_powers)


@savefig
@check_dependency(plt, 'matplotlib')
def plot_spectrum_shading(freqs, power_spectrum, shades, shade_colors='r',
add_center=False, ax=None, **plot_kwargs):
"""Plot a power spectrum with a shaded frequency region (or regions).

Parameters
----------
freqs : 1d array
Frequency values, to be plotted on the x-axis.
power_spectrum : 1d array
Power values, to be plotted on the y-axis.
shades : list of [float, float] or list of list of [float, float]
Shaded region(s) to add to plot, defined as [lower_bound, upper_bound].
shade_colors : str or list of string
Color(s) to plot shades.
add_center : bool, optional, default: False
Whether to add a line at the center point of the shaded regions.
ax : matplotlib.Axes, optional
Figure axes upon which to plot.
**plot_kwargs
Keyword arguments to pass into :func:`~.plot_spectrum`.
"""

ax = check_ax(ax, plot_kwargs.pop('figsize', PLT_FIGSIZES['spectral']))
# Plot
for freqs, powers, color, label in zip(plt_freqs, plt_powers, colors, labels):

plot_spectrum(freqs, power_spectrum, ax=ax, **plot_kwargs)
# Set plot data, logging if requested, and collect color, if absent
freqs = np.log10(freqs) if log_freqs else freqs
powers = np.log10(powers) if log_powers else powers
if color:
plot_kwargs['color'] = color

add_shades(ax, shades, shade_colors, add_center, plot_kwargs.get('log_freqs', False))
ax.plot(freqs, powers, label=label, **plot_kwargs)

style_spectrum_plot(ax, plot_kwargs.get('log_freqs', False),
plot_kwargs.get('log_powers', False))
style_spectrum_plot(ax, log_freqs, log_powers)


@savefig
@check_dependency(plt, 'matplotlib')
def plot_spectra_shading(freqs, power_spectra, shades, shade_colors='r',
add_center=False, ax=None, **plot_kwargs):
"""Plot a group of power spectra with a shaded frequency region (or regions).
"""Plot one or multiple power spectra with a shaded frequency region (or regions).

Parameters
----------
freqs : 2d array or 1d array or list of 1d array
freqs : 1d or 2d array or list of 1d array
Frequency values, to be plotted on the x-axis.
power_spectra : 2d array or list of 1d array
power_spectra : 1d or 2d array or list of 1d array
Power values, to be plotted on the y-axis.
shades : list of [float, float] or list of list of [float, float]
Shaded region(s) to add to plot, defined as [lower_bound, upper_bound].
Expand Down
Loading