def plot_spectral_error(freqs, error, shade=None, log_freqs=False, ax=None, **plot_kwargs): """Plot frequency by frequency error values. Parameters ---------- freqs : 1d array Frequency values, to be plotted on the x-axis. error : 1d array Calculated error values or mean error values across frequencies, to plot on the y-axis. shade : 1d array, optional Values to shade in around the plotted error. This could be, for example, the standard deviation of the errors. log_freqs : bool, optional, default: False Whether to plot the frequency axis in log spacing. 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'])) plt_freqs = np.log10(freqs) if log_freqs else freqs 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) ymin, ymax = ax.get_ylim() if ymin < 0: ax.set_ylim([0, ymax]) ax.set_xlim(plt_freqs.min(), plt_freqs.max()) style_spectrum_plot(ax, log_freqs, True) ax.set_ylabel('Absolute Error')
# Aperiodic params: define values for each spectrum, with length equal to n_spectra aperiodic_params = [[0.5, 1], [1, 1.5]] # Periodic parameters: define a single definition, to be applied to all spectra periodic_params = [10, 0.4, 1] ################################################################################################### # Simulate a group of power spectra freqs, powers = gen_group_power_spectra(n_spectra, freq_range, aperiodic_params, periodic_params, nlv) ################################################################################################### # Plot the power spectra that were just generated plot_spectra(freqs, powers, log_freqs=True, log_powers=True) ################################################################################################### # Tracking Simulation Parameters # ------------------------------ # # When you start simulating multiple power spectra across different parameters, # you may want to keep track of these parameters, so that you can compare any measure # taken on these power spectra to ground truth values. # # When simulating power spectra, you also have the option of returning SimParams objects # that keep track of the simulation parameters. # ###################################################################################################
# Imports from fooof.synth.gen import gen_power_spectrum from fooof.synth.transform import rotate_spectrum from fooof.plts.spectra import plot_spectra ################################################################################################### # Generate a synthetic power spectrum fs, ps = gen_power_spectrum([3, 40], [1, 1], [10, 0.5, 1]) ################################################################################################### # rotate_spectrum # --------------- # # The :func:`rotate_spectrum` function takes in a power spectrum, and rotates the # power spectrum a specified amount, around a specified frequency point, changing # the aperiodic exponent of the spectrum. # ################################################################################################### # Rotate the power spectrum nps = rotate_spectrum(fs, ps, 0.25, 20) ################################################################################################### # Plot the two power spectra plot_spectra(fs, [ps, nps], log_freqs=True, log_powers=True)
# --------------------------------- # # First we will start with the core plotting function that plots an individual power spectrum. # # 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 # `log_freqs` and `log_powers` that control whether the frequency and power axes # are plotted in log space. # ################################################################################################### # Create a spectrum plot with a single power spectrum plot_spectra(freqs, powers1, log_powers=True) ################################################################################################### # Plotting Multiple Power Spectra # ------------------------------- # # The :func:`~.plot_spectra` function takes in one or more frequency arrays and one or more # array of associated power values and plots multiple power spectra. # # Note that the inputs for either can be either 2d arrays, or lists of 1d arrays. You can also # pass in additional optional inputs including `labels`, to specify labels to use in a plot # legend, and `colors` to specify which colors to plot each spectrum in. # ###################################################################################################
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)
# Step 1: Initial Aperiodic Fit # ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ # # We start by taking an initial aperiodic fit. This goal of this fit is to get an initial # fit that is good enough to get started with the fitting process. # ################################################################################################### # Do an initial aperiodic fit - a robust fit, that excludes outliers # This recreates an initial fit that isn't ultimately stored in the FOOOF object init_ap_fit = gen_aperiodic(fm.freqs, fm._robust_ap_fit(fm.freqs, fm.power_spectrum)) # Plot the initial aperiodic fit _, ax = plt.subplots(figsize=(12, 10)) plot_spectra(fm.freqs, fm.power_spectrum, plt_log, label='Original Power Spectrum', color='black', ax=ax) plot_spectra(fm.freqs, init_ap_fit, plt_log, label='Initial Aperiodic Fit', color='blue', alpha=0.5, linestyle='dashed', ax=ax) ################################################################################################### # Step 2: Flatten the Spectrum # ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ # # The initial fit is then used to create a flattened spectrum. # # The initial aperiodic fit is subtracted out from the original data, leaving a flattened # version of the data which no longer contains the aperiodic component. # ###################################################################################################
# ------------------------------- # # The :func:`~.plot_spectra` function takes in one or more frequency arrays and one or more # array of associated power values and plots multiple power spectra. # # Note that the inputs for either can be either 2d arrays, or lists of 1d arrays. You can also # pass in additional optional inputs including `labels`, to specify labels to use in a plot # legend, and `colors` to specify which colors to plot each spectrum in. # ################################################################################################### # Plot multiple spectra on the same plot, in log-log space, specifying some labels labels = ['PSD-1', 'PSD-2'] plot_spectra(freqs, [powers1, powers2], log_freqs=True, log_powers=True, labels=labels) ################################################################################################### # Plots With Shaded Regions # ------------------------- # # 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 # 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`. # # These functions take in an input designating one or more shade regions, each specified
# Create a sampler to choose from two options for aperiodic parameters ap_opts = param_sampler([[1, 1.25], [1, 1]]) # Create sampler to choose from two options for periodic parameters, and specify probabilities gauss_opts = param_sampler([[10, 0.5, 1], [[10, 0.5, 1], [20, 0.25, 2]]], [0.75, 0.25]) ################################################################################################### # Generate some power spectra, using the param samplers fs, ps, syn_params = gen_group_power_spectra(10, [3, 40], ap_opts, gauss_opts) ################################################################################################### # Plot some of the spectra that were generated plot_spectra(fs, ps[0:4, :], log_powers=True) ################################################################################################### # param_iter # ~~~~~~~~~~ # # The :func:`param_iter` function can be used to create iterators that can 'step' across # a range of parameter values to be simulated. # # The :class:`Stepper` object needs to be used in conjuction with :func:`param_iter`, # as it specifies the values to be iterated across. # ################################################################################################### # Set the aperiodic parameters to be stable
# # Plotted below is an example power spectrum, plotted in semi-log space (log10 power values # and linear frequencies). This is our data, that we will be trying to model. # # In the plot, we see a power spectrum in which there is decreasing power across increasing # frequencies. In some frequency regions, there is a 'peak' of power, over and above the general # trend across frequencies. These properties - a pattern of decreasing power across frequencies, # with overlying peaks - are considered to be hallmarks of neural field data. # ################################################################################################### # Plot one of the example power spectra plot_spectra(freqs1, powers1, log_powers=True, color='black', label='Original Spectrum') ################################################################################################### # Conceptual Overview # ------------------- # # The goal of this module is to fit models to parameterize neural power spectra. # # One reason to do so is the idea that there are multiple distinct 'components' within # neural field data. The model is therefore designed to measure these different # 'components' of the data. # # By components, we mean that we are going to conceptualize neural field data as consisting # of a combination of periodic (oscillatory) and aperiodic activity. Restated, we could say
def plot_annotated_peak_search(fm): """Plot a series of plots illustrating the peak search from a flattened spectrum. Parameters ---------- fm : FOOOF FOOOF object, with model fit, data and settings available. """ # Recalculate the initial aperiodic fit and flattened spectrum that # is the same as the one that is used in the peak fitting procedure flatspec = fm.power_spectrum - \ gen_aperiodic(fm.freqs, fm._robust_ap_fit(fm.freqs, fm.power_spectrum)) # Calculate ylims of the plot that are scaled to the range of the data ylims = [ min(flatspec) - 0.1 * np.abs(min(flatspec)), max(flatspec) + 0.1 * max(flatspec) ] # Loop through the iterative search for each peak for ind in range(fm.n_peaks_ + 1): # This forces the creation of a new plotting axes per iteration ax = check_ax(None, PLT_FIGSIZES['spectral']) 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], '.', color=PLT_COLORS['periodic'], alpha=0.75, markersize=30) ax.set_ylim(ylims) ax.set_title('Iteration #' + str(ind + 1), fontsize=16) if ind < fm.n_peaks_: gauss = gaussian_function(fm.freqs, *fm.gaussian_params_[ind, :]) plot_spectra(fm.freqs, gauss, ax=ax, label='Gaussian Fit', color=PLT_COLORS['periodic'], linestyle=':', linewidth=3.0) flatspec = flatspec - gauss style_spectrum_plot(ax, False, True)
# changing the aperiodic exponent of the spectrum. # ################################################################################################### # Rotation settings delta_exp = 0.25 # How much to change the exponent by f_rotation = 20 # The frequency at which to rotate the spectrum # Rotate the power spectrum r_powers = rotate_spectrum(freqs, powers, delta_exp, f_rotation) ################################################################################################### # Plot the two power spectra, with the rotation applied plot_spectra(freqs, [powers, r_powers], log_freqs=True, log_powers=True) ################################################################################################### # # Next, we can fit power spectrum models to check if our change in exponent worked as expected. # ################################################################################################### # Initialize FOOOF objects fm1 = FOOOF(verbose=False) fm2 = FOOOF(verbose=False) # Fit power spectrum models to the original, and rotated, spectrum fm1.fit(freqs, powers) fm2.fit(freqs, r_powers)
# # To visualize how much the exponent values vary, we can again plot some example power # spectra, in this case extracting those with the highest and lower exponent values. # ################################################################################################### # Compare the power spectra between low and high exponent channels fig, ax = plt.subplots(figsize=(8, 6)) spectra = [ fg.get_fooof(np.argmin(exps)).power_spectrum, fg.get_fooof(np.argmax(exps)).power_spectrum ] plot_spectra(fg.freqs, spectra, ax=ax, labels=['Low Exponent', 'High Exponent']) ################################################################################################### # Conclusion # ---------- # # In this example, we have seen how to apply power spectrum models to data that is # managed and processed with MNE. # ################################################################################################### #