Example #1
0
File: fm.py Project: parhalje/fooof
def _add_peaks_outline(fm, plt_log, ax, **plot_kwargs):
    """Add an outline of each peak.

    Parameters
    ----------
    fm : FOOOF
        FOOOF object containing results from fitting.
    plt_log : boolean
        Whether to plot the frequency values in log10 spacing.
    ax : matplotlib.Axes
        Figure axes upon which to plot.
    **plot_kwargs
        Keyword arguments to pass into the plot call.
    """

    defaults = {'color': PLT_COLORS['periodic'], 'alpha': 0.7, 'lw': 1.5}
    plot_kwargs = check_plot_kwargs(plot_kwargs, defaults)

    for peak in fm.gaussian_params_:

        # Define the frequency range around each peak to plot - peak bandwidth +/- 3
        peak_range = [peak[0] - peak[2] * 3, peak[0] + peak[2] * 3]

        # Generate a peak reconstruction for each peak, and trim to desired range
        peak_line = fm._ap_fit + gen_periodic(fm.freqs, peak)
        peak_freqs, peak_line = trim_spectrum(fm.freqs, peak_line, peak_range)

        # Plot the peak outline
        peak_freqs = np.log10(peak_freqs) if plt_log else peak_freqs
        ax.plot(peak_freqs, peak_line, **plot_kwargs)
Example #2
0
File: fm.py Project: parhalje/fooof
def _add_peaks_line(fm, plt_log, ax, **plot_kwargs):
    """Add a long line, from the top of the plot, down through the peak, with an arrow at the top.

    Parameters
    ----------
    fm : FOOOF
        FOOOF object containing results from fitting.
    plt_log : boolean
        Whether to plot the frequency values in log10 spacing.
    ax : matplotlib.Axes
        Figure axes upon which to plot.
    **plot_kwargs
        Keyword arguments to pass into the plot call.
    """

    defaults = {
        'color': PLT_COLORS['periodic'],
        'alpha': 0.7,
        'lw': 1.4,
        'ms': 10
    }
    plot_kwargs = check_plot_kwargs(plot_kwargs, defaults)

    ylims = ax.get_ylim()

    for peak in fm.peak_params_:

        freq_point = np.log10(peak[0]) if plt_log else peak[0]
        ax.plot([freq_point, freq_point], ylims, '-', **plot_kwargs)
        ax.plot(freq_point, ylims[1], 'v', **plot_kwargs)
Example #3
0
File: fm.py Project: parhalje/fooof
def _add_peaks_dot(fm, plt_log, ax, **plot_kwargs):
    """Add a short line, from aperiodic to peak, with a dot at the top.

    Parameters
    ----------
    fm : FOOOF
        FOOOF object containing results from fitting.
    plt_log : boolean
        Whether to plot the frequency values in log10 spacing.
    ax : matplotlib.Axes
        Figure axes upon which to plot.
    **plot_kwargs
        Keyword arguments to pass into the plot call.
    """

    defaults = {
        'color': PLT_COLORS['periodic'],
        'alpha': 0.6,
        'lw': 2.5,
        'ms': 6
    }
    plot_kwargs = check_plot_kwargs(plot_kwargs, defaults)

    for peak in fm.peak_params_:

        ap_point = np.interp(peak[0], fm.freqs, fm._ap_fit)
        freq_point = np.log10(peak[0]) if plt_log else peak[0]

        # Add the line from the aperiodic fit up the tip of the peak
        ax.plot([freq_point, freq_point], [ap_point, ap_point + peak[1]],
                **plot_kwargs)

        # Add an extra dot at the tip of the peak
        ax.plot(freq_point, ap_point + peak[1], marker='o', **plot_kwargs)
Example #4
0
def _add_peaks_shade(fm, plt_log, ax, **plot_kwargs):
    """Add a shading in of all peaks.

    Parameters
    ----------
    fm : FOOOF
        FOOOF object containing results from fitting.
    plt_log : boolean
        Whether to plot the frequency values in log10 spacing.
    ax : matplotlib.Axes
        Figure axes upon which to plot.
    **plot_kwargs
        Keyword arguments to pass into the plot call.
    """

    kwargs = check_plot_kwargs(plot_kwargs, {
        'color': PLT_COLORS['periodic'],
        'alpha': 0.25
    })

    for peak in fm.gaussian_params_:

        peak_freqs = np.log10(fm.freqs) if plt_log else fm.freqs
        peak_line = fm._ap_fit + gen_periodic(fm.freqs, peak)

        ax.fill_between(peak_freqs, peak_line, fm._ap_fit, **kwargs)
Example #5
0
def plot_peak_params(peaks,
                     freq_range=None,
                     colors=None,
                     labels=None,
                     ax=None,
                     plot_style=style_param_plot,
                     **plot_kwargs):
    """Plot peak parameters as dots representing center frequency, power and bandwidth.

    Parameters
    ----------
    peaks : 2d array or list of 2d array
        Peak data. Each row is a peak, as [CF, PW, BW].
    freq_range : list of [float, float] , optional
        The frequency range to plot the peak parameters across, as [f_min, f_max].
    colors : str or list of str, optional
        Color(s) to plot data.
    labels : list of str, optional
        Label(s) for plotted data, to be added in a legend.
    ax : matplotlib.Axes, optional
        Figure axes upon which to plot.
    plot_style : callable, optional, default: style_param_plot
        A function to call to apply styling & aesthetics to the plot.
    **plot_kwargs
        Keyword arguments to pass into the plot call.
    """

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

    # If there is a list, use recurse function to loop across arrays of data and plot them
    if isinstance(peaks, list):
        recursive_plot(peaks,
                       plot_peak_params,
                       ax,
                       colors=colors,
                       labels=labels,
                       plot_style=plot_style,
                       **plot_kwargs)

    # Otherwise, plot the array of data
    else:

        # Unpack data: CF as x; PW as y; BW as size
        xs, ys = peaks[:, 0], peaks[:, 1]
        sizes = peaks[:, 2] * plot_kwargs.pop('s', 150)

        # Create the plot
        plot_kwargs = check_plot_kwargs(plot_kwargs, {'alpha': 0.7})
        ax.scatter(xs, ys, sizes, c=colors, label=labels, **plot_kwargs)

    # Add axis labels
    ax.set_xlabel('Center Frequency')
    ax.set_ylabel('Power')

    # Set plot limits
    if freq_range:
        ax.set_xlim(freq_range)
    ax.set_ylim([0, ax.get_ylim()[1]])

    check_n_style(plot_style, ax)
Example #6
0
def plot_spectra(freqs,
                 power_spectra,
                 log_freqs=False,
                 log_powers=False,
                 colors=None,
                 labels=None,
                 ax=None,
                 **plot_kwargs):
    """Plot one or multiple power spectra.

    Parameters
    ----------
    freqs : 1d or 2d array or list of 1d array
        Frequency values, to be plotted on the x-axis.
    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.
    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
        Keyword arguments to pass into the ``style_plot``.
    """

    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
    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

    # 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)

    # Plot
    for freqs, powers, color, label in zip(plt_freqs, plt_powers, colors,
                                           labels):

        # 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

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

    style_spectrum_plot(ax, log_freqs, log_powers)
Example #7
0
def plot_aperiodic_params(aps,
                          colors=None,
                          labels=None,
                          ax=None,
                          plot_style=style_param_plot,
                          **plot_kwargs):
    """Plot aperiodic parameters as dots representing offset and exponent value.

    Parameters
    ----------
    aps : 2d array or list of 2d array
        Aperiodic parameters. Each row is a parameter set, as [Off, Exp] or [Off, Knee, Exp].
    colors : str or list of str, optional
        Color(s) to plot data.
    labels : list of str, optional
        Label(s) for plotted data, to be added in a legend.
    ax : matplotlib.Axes, optional
        Figure axes upon which to plot.
    plot_style : callable, optional, default: style_param_plot
        A function to call to apply styling & aesthetics to the plot.
    **plot_kwargs
        Keyword arguments to pass into the plot call.
    """

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

    if isinstance(aps, list):
        recursive_plot(aps,
                       plot_aperiodic_params,
                       ax,
                       colors=colors,
                       labels=labels,
                       plot_style=plot_style,
                       **plot_kwargs)

    else:

        # Unpack data: offset as x; exponent as y
        xs, ys = aps[:, 0], aps[:, -1]
        sizes = plot_kwargs.pop('s', 150)

        plot_kwargs = check_plot_kwargs(plot_kwargs, {'alpha': 0.7})
        ax.scatter(xs, ys, sizes, c=colors, label=labels, **plot_kwargs)

    # Add axis labels
    ax.set_xlabel('Offset')
    ax.set_ylabel('Exponent')

    check_n_style(plot_style, ax)
Example #8
0
File: fm.py Project: parhalje/fooof
def _add_peaks_width(fm, plt_log, ax, **plot_kwargs):
    """Add a line across the width of peaks.

    Parameters
    ----------
    fm : FOOOF
        FOOOF object containing results from fitting.
    plt_log : boolean
        Whether to plot the frequency values in log10 spacing.
    ax : matplotlib.Axes
        Figure axes upon which to plot.
    **plot_kwargs
        Keyword arguments to pass into the plot call.

    Notes
    -----
    This line represents the bandwidth (width or gaussian standard deviation) of
    the peak, though what is literally plotted is the full-width half-max.
    """

    defaults = {
        'color': PLT_COLORS['periodic'],
        'alpha': 0.6,
        'lw': 2.5,
        'ms': 6
    }
    plot_kwargs = check_plot_kwargs(plot_kwargs, defaults)

    for peak in fm.gaussian_params_:

        peak_top = fm.power_spectrum[nearest_ind(fm.freqs, peak[0])]
        bw_freqs = [
            peak[0] - 0.5 * compute_fwhm(peak[2]),
            peak[0] + 0.5 * compute_fwhm(peak[2])
        ]

        if plt_log:
            bw_freqs = np.log10(bw_freqs)

        ax.plot(bw_freqs,
                [peak_top - (0.5 * peak[1]), peak_top - (0.5 * peak[1])],
                **plot_kwargs)
Example #9
0
def plot_spectrum(freqs,
                  power_spectrum,
                  log_freqs=False,
                  log_powers=False,
                  ax=None,
                  plot_style=style_spectrum_plot,
                  **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.
    ax : matplotlib.Axes, optional
        Figure axis upon which to plot.
    plot_style : callable, optional, default: style_spectrum_plot
        A function to call to apply styling & aesthetics to the plot.
    **plot_kwargs
        Keyword arguments to be passed to the plot call.
    """

    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
    plot_kwargs = check_plot_kwargs(plot_kwargs, {'linewidth': 2.0})
    ax.plot(plt_freqs, plt_powers, **plot_kwargs)

    check_n_style(plot_style, ax, log_freqs, log_powers)
Example #10
0
def plot_aperiodic_fits(aps,
                        freq_range,
                        control_offset=False,
                        log_freqs=False,
                        colors=None,
                        labels=None,
                        ax=None,
                        plot_style=style_param_plot,
                        **plot_kwargs):
    """Plot reconstructions of model aperiodic fits.

    Parameters
    ----------
    aps : 2d array
        Aperiodic parameters. Each row is a parameter set, as [Off, Exp] or [Off, Knee, Exp].
    freq_range : list of [float, float]
        The frequency range to plot the peak fits across, as [f_min, f_max].
    control_offset : boolean, optonal, default: False
        Whether to control for the offset, by setting it to zero.
    log_freqs : boolean, optonal, default: False
        Whether to plot the x-axis in log space.
    colors : str or list of str, optional
        Color(s) to plot data.
    labels : list of str, optional
        Label(s) for plotted data, to be added in a legend.
    ax : matplotlib.Axes, optional
        Figure axes upon which to plot.
    plot_style : callable, optional, default: style_param_plot
        A function to call to apply styling & aesthetics to the plot.
    **plot_kwargs
        Keyword arguments to pass into the plot call.
    """

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

    if isinstance(aps, list):

        if not colors:
            colors = cycle(plt.rcParams['axes.prop_cycle'].by_key()['color'])

        recursive_plot(aps,
                       plot_function=plot_aperiodic_fits,
                       ax=ax,
                       freq_range=tuple(freq_range),
                       control_offset=control_offset,
                       log_freqs=log_freqs,
                       colors=colors,
                       labels=labels,
                       plot_style=plot_style,
                       **plot_kwargs)
    else:

        freqs = gen_freqs(freq_range, 0.1)
        plt_freqs = np.log10(freqs) if log_freqs else freqs

        colors = colors[0] if isinstance(colors, list) else colors

        avg_vals = np.zeros(shape=[len(freqs)])

        for ap_params in aps:

            if control_offset:

                # Copy the object to not overwrite any data
                ap_params = ap_params.copy()
                ap_params[0] = 0

            # Recreate & plot the aperiodic component from parameters
            ap_vals = gen_aperiodic(freqs, ap_params)

            plot_kwargs = check_plot_kwargs(plot_kwargs, {
                'alpha': 0.35,
                'linewidth': 1.25
            })
            ax.plot(plt_freqs, ap_vals, color=colors, **plot_kwargs)

            # Collect a running average across components
            avg_vals = np.nansum(np.vstack([avg_vals, ap_vals]), axis=0)

        # Plot the average component
        avg = avg_vals / aps.shape[0]
        avg_color = 'black' if not colors else colors
        ax.plot(plt_freqs,
                avg,
                linewidth=plot_kwargs.get('linewidth') * 3,
                color=avg_color,
                label=labels)

    # Add axis labels
    ax.set_xlabel('log(Frequency)' if log_freqs else 'Frequency')
    ax.set_ylabel('log(Power)')

    # Set plot limit
    ax.set_xlim(np.log10(freq_range) if log_freqs else freq_range)

    # Apply plot style
    check_n_style(plot_style, ax)
Example #11
0
File: fm.py Project: parhalje/fooof
def plot_fm(fm,
            plot_peaks=None,
            plot_aperiodic=True,
            plt_log=False,
            add_legend=True,
            save_fig=False,
            file_name=None,
            file_path=None,
            ax=None,
            data_kwargs=None,
            model_kwargs=None,
            aperiodic_kwargs=None,
            peak_kwargs=None,
            **plot_kwargs):
    """Plot the power spectrum and model fit results from a FOOOF object.

    Parameters
    ----------
    fm : FOOOF
        Object containing a power spectrum and (optionally) results from fitting.
    plot_peaks : None or {'shade', 'dot', 'outline', 'line'}, optional
        What kind of approach to take to plot peaks. If None, peaks are not specifically plotted.
        Can also be a combination of approaches, separated by '-', for example: 'shade-line'.
    plot_aperiodic : boolean, optional, default: True
        Whether to plot the aperiodic component of the model fit.
    plt_log : boolean, optional, default: False
        Whether to plot the frequency values in log10 spacing.
    add_legend : boolean, optional, default: False
        Whether to add a legend describing the plot components.
    save_fig : bool, optional, default: False
        Whether to save out a copy of the plot.
    file_name : str, optional
        Name to give the saved out file.
    file_path : str, optional
        Path to directory to save to. If None, saves to current directory.
    ax : matplotlib.Axes, optional
        Figure axes upon which to plot.
    data_kwargs, model_kwargs, aperiodic_kwargs, peak_kwargs : None or dict, optional
        Keyword arguments to pass into the plot call for each plot element.
    **plot_kwargs
        Keyword arguments to pass into the ``style_plot``.

    Notes
    -----
    Since FOOOF objects store power values in log spacing,
    the y-axis (power) is plotted in log spacing by default.
    """

    ax = check_ax(ax, PLT_FIGSIZES['spectral'])

    # Log settings - note that power values in FOOOF objects are already logged
    log_freqs = plt_log
    log_powers = False

    # Plot the data, if available
    if fm.has_data:
        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_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_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_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:
            _add_peaks(fm, plot_peaks, plt_log, ax, peak_kwargs)

    # Apply default style to plot
    style_spectrum_plot(ax, log_freqs, True)
Example #12
0
def plot_peak_fits(peaks,
                   freq_range=None,
                   colors=None,
                   labels=None,
                   ax=None,
                   plot_style=style_param_plot,
                   **plot_kwargs):
    """Plot reconstructions of model peak fits.

    Parameters
    ----------
    peaks : 2d array
        Peak data. Each row is a peak, as [CF, PW, BW].
    freq_range : list of [float, float] , optional
        The frequency range to plot the peak fits across, as [f_min, f_max].
        If not provided, defaults to +/- 4 around given peak center frequencies.
    colors : str or list of str, optional
        Color(s) to plot data.
    labels : list of str, optional
        Label(s) for plotted data, to be added in a legend.
    ax : matplotlib.Axes, optional
        Figure axes upon which to plot.
    plot_style : callable, optional, default: style_param_plot
        A function to call to apply styling & aesthetics to the plot.
    **plot_kwargs
        Keyword arguments to pass into the plot call.
    """

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

    if isinstance(peaks, list):

        if not colors:
            colors = cycle(plt.rcParams['axes.prop_cycle'].by_key()['color'])

        recursive_plot(
            peaks,
            plot_function=plot_peak_fits,
            ax=ax,
            freq_range=tuple(freq_range) if freq_range else freq_range,
            colors=colors,
            labels=labels,
            plot_style=plot_style,
            **plot_kwargs)

    else:

        if not freq_range:

            # Extract all the CF values, excluding any NaNs
            cfs = peaks[~np.isnan(peaks[:, 0]), 0]

            # Define the frequency range as +/- buffer around the data range
            #   This also doesn't let the plot range drop below 0
            f_buffer = 4
            freq_range = [
                cfs.min() - f_buffer if cfs.min() - f_buffer > 0 else 0,
                cfs.max() + f_buffer
            ]

        # Create the frequency axis, which will be the plot x-axis
        freqs = gen_freqs(freq_range, 0.1)

        colors = colors[0] if isinstance(colors, list) else colors

        avg_vals = np.zeros(shape=[len(freqs)])

        for peak_params in peaks:

            # Create & plot the peak model from parameters
            peak_vals = gaussian_function(freqs, *peak_params)
            plot_kwargs = check_plot_kwargs(plot_kwargs, {
                'alpha': 0.35,
                'linewidth': 1.25
            })
            ax.plot(freqs, peak_vals, color=colors, **plot_kwargs)

            # Collect a running average average peaks
            avg_vals = np.nansum(np.vstack([avg_vals, peak_vals]), axis=0)

        # Plot the average across all components
        avg = avg_vals / peaks.shape[0]
        avg_color = 'black' if not colors else colors
        ax.plot(freqs,
                avg,
                color=avg_color,
                linewidth=plot_kwargs.get('linewidth') * 3,
                label=labels)

    # Add axis labels
    ax.set_xlabel('Frequency')
    ax.set_ylabel('log(Power)')

    # Set plot limits
    ax.set_xlim(freq_range)
    ax.set_ylim([0, ax.get_ylim()[1]])

    # Apply plot style
    check_n_style(plot_style, ax)