diff --git a/_downloads/0088e77b22ed06a6b547464299227fa7/plot_peak_params.py b/_downloads/0088e77b22ed06a6b547464299227fa7/plot_peak_params.py new file mode 100644 index 00000000..5498e0bb --- /dev/null +++ b/_downloads/0088e77b22ed06a6b547464299227fa7/plot_peak_params.py @@ -0,0 +1,102 @@ +""" +Periodic Parameters +=================== + +Exploring properties and topics related to peak parameters. +""" + +################################################################################################### + +from fooof import FOOOF, FOOOFGroup +from fooof.plts.spectra import plot_spectra +from fooof.plts.periodic import plot_peak_params +from fooof.sim.utils import set_random_seed +from fooof.sim.params import Stepper, param_iter +from fooof.sim import gen_power_spectrum, gen_group_power_spectra +from fooof.plts.annotate import plot_annotated_model +from fooof.utils.params import compute_time_constant, compute_knee_frequency + +################################################################################################### +# Gaussian Peak Model +# ------------------- +# +# By default, the spectral parameterization model fits Gaussians to any detected peaks. +# +# These Gaussians are defined by a mean, height, and standard deviation, which we in turn +# interpret as the center frequency (CF), power (PW), and bandwidth (BW) of the putative +# oscillation. +# +# In this example, we will further explore these peak parameters and some topics and +# limitations related to their use and interpretations. +# + +################################################################################################### + +# Simulate an example power spectrum +freqs, powers = gen_power_spectrum([3, 40], [0, 1], [10, 0.3, 1.], freq_res=0.25) + +################################################################################################### + +# Initialize model object and fit power spectrum +fm = FOOOF(min_peak_height=0.1) +fm.fit(freqs, powers) + +################################################################################################### + +# Plot annotated model labelling the peaks +plot_annotated_model(fm, annotate_peaks=True, annotate_aperiodic=False, plt_log=True) + +################################################################################################### +# +# In the above we can see an example of the fit peak parameters +# + +################################################################################################### +# Overlapping Peaks +# ----------------- +# +# Let's now consider some features of fitting Gaussian peaks, and how this relates to +# the neural data under study. In particular, Gaussian's are symmetric and while they do +# seem to approximate the peaks we observe in emprical data quite well, not all peaks +# in empirical power spectra are quite symmetric. +# +# To deal with this, the model sometimes fits overlapping peaks, whereby two or more peaks +# are used by the model to capture the shape of what otherwise looks like a single peak. +# +# We can explore this in a simplified simulation. +# + +################################################################################################### + +# Set the random seed +set_random_seed(10) + +################################################################################################### + +# Simulate an example power spectrum created with an asymmetric peak +freqs, powers = gen_power_spectrum([3, 40], [0, 1], [[10, 0.3, 1.], [11.25, 0.175, 0.5]], freq_res=0.25) + +################################################################################################### + +# Initialize model object and fit power spectrum +fm = FOOOF(min_peak_height=0.1) +fm.report(freqs, powers) + +################################################################################################### +# +# As we can see in the above model solution, in the data, it looks like there is a single +# oscillatory peak, and yet the model has captured this peak with two Gaussians. +# +# This example serves to demonstrate two key points. First, not all Gaussians fit in the model +# necessary reflect separate peaks, as some may overlap. Second, when peaks overlap, +# the parameters of each individually may accurately capture a peak in the data, as the +# overall shape of the peak may be captured as the interaction across multiple Gaussians +# (this is most common / notable for the bandwidth measure, whereby the width of the peak is +# best described as the combined width of the two adjacent peaks). +# +# Note that, by construction, this simulated example was created by simulating two overlapping +# peaks, and so in that sense the model is actually correct in it's solution. In empirical +# data, we do not know if a power spectrum that looks like this does reflect two underlying +# oscillatory processes, or perhaps a single oscillatory process that happens to be asymmetric +# in the frequency domain. +# diff --git a/_downloads/b666d863e975e54d4ee3fe75472e8988/auto_examples_python.zip b/_downloads/07fcc19ba03226cd3d83d4e40ec44385/auto_examples_python.zip similarity index 58% rename from _downloads/b666d863e975e54d4ee3fe75472e8988/auto_examples_python.zip rename to _downloads/07fcc19ba03226cd3d83d4e40ec44385/auto_examples_python.zip index f766a2e1..56c62721 100644 Binary files a/_downloads/b666d863e975e54d4ee3fe75472e8988/auto_examples_python.zip and b/_downloads/07fcc19ba03226cd3d83d4e40ec44385/auto_examples_python.zip differ diff --git a/_downloads/0c0a4641cfbd81a824468178d7a987b7/plot_simulated_power_spectra.py b/_downloads/0c0a4641cfbd81a824468178d7a987b7/plot_simulated_power_spectra.py index ac915f21..f955ed8c 100644 --- a/_downloads/0c0a4641cfbd81a824468178d7a987b7/plot_simulated_power_spectra.py +++ b/_downloads/0c0a4641cfbd81a824468178d7a987b7/plot_simulated_power_spectra.py @@ -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 @@ -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 @@ -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 diff --git a/_downloads/150024fcd7d38e98042735387d6f4e6d/plot_model_components.ipynb b/_downloads/150024fcd7d38e98042735387d6f4e6d/plot_model_components.ipynb index 122bb8af..42d945c3 100644 --- a/_downloads/150024fcd7d38e98042735387d6f4e6d/plot_model_components.ipynb +++ b/_downloads/150024fcd7d38e98042735387d6f4e6d/plot_model_components.ipynb @@ -1,21 +1,10 @@ { "cells": [ - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "collapsed": false - }, - "outputs": [], - "source": [ - "%matplotlib inline" - ] - }, { "cell_type": "markdown", "metadata": {}, "source": [ - "\nPlot Model Components\n=====================\n\nPlotting power spectrum model parameters and components.\n" + "\n# Plot Model Components\n\nPlotting power spectrum model parameters and components.\n" ] }, { @@ -33,7 +22,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Experiment Set Up & Simulate Data\n---------------------------------\n\nIn this example, we will explore the plotting functions available to visualize\nmodel parameters and components from fitting power spectrum models.\n\nTo do so, we will consider a hypothetical experiment in which we are compare power\nspectrum models between two groups of participants, and so we want to visualize differences\nbetween the groups. For simplicity, we will consider that we have one 'grand average'\npower spectrum per subject, which we can compare and visualize.\n\n\n" + "## Experiment Set Up & Simulate Data\n\nIn this example, we will explore the plotting functions available to visualize\nmodel parameters and components from fitting power spectrum models.\n\nTo do so, we will consider a hypothetical experiment in which we are compare power\nspectrum models between two groups of participants, and so we want to visualize differences\nbetween the groups. For simplicity, we will consider that we have one 'grand average'\npower spectrum per subject, which we can compare and visualize.\n\n\n" ] }, { @@ -73,7 +62,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Fit Power Spectrum Models\n~~~~~~~~~~~~~~~~~~~~~~~~~\n\nNow that we have our simulated data, we can fit our power spectrum models, using FOOOFGroup.\n\n\n" + "### Fit Power Spectrum Models\n\nNow that we have our simulated data, we can fit our power spectrum models, using FOOOFGroup.\n\n\n" ] }, { @@ -102,14 +91,14 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Plotting Parameters & Components\n--------------------------------\n\nIn the following, we will explore two visualization options:\n\n- plotting parameter values\n- plotting component reconstructions\n\nEach of these approaches can be done for either aperiodic or periodic parameters.\n\nAll of the plots that we will use in this example can be used to visualize either\none or multiple groups of data. As we will see, you can pass in a single group of\nparameters or components to visualize them, or pass in a list of group results to\nvisualize and compare between groups.\n\nYou can also pass in optional inputs `labels` and `colors` to all the following\nfunctions to add plot labels, and to set the colors used for each group.\n\n\n" + "## Plotting Parameters & Components\n\nIn the following, we will explore two visualization options:\n\n- plotting parameter values\n- plotting component reconstructions\n\nEach of these approaches can be done for either aperiodic or periodic parameters.\n\nAll of the plots that we will use in this example can be used to visualize either\none or multiple groups of data. As we will see, you can pass in a single group of\nparameters or components to visualize them, or pass in a list of group results to\nvisualize and compare between groups.\n\nYou can also pass in optional inputs `labels` and `colors` to all the following\nfunctions to add plot labels, and to set the colors used for each group.\n\n\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "Periodic Components\n-------------------\n\nFirst, let's have a look at the periodic components.\n\nTo do so, we will use the :obj:`~.Bands` object to store our frequency\nband definitions, which we can then use to sub-select peaks within bands of interest.\n\nWe can then plot visualizations of the peak parameters, and the reconstructed fits.\n\n\n" + "## Periodic Components\n\nFirst, let's have a look at the periodic components.\n\nTo do so, we will use the :obj:`~.Bands` object to store our frequency\nband definitions, which we can then use to sub-select peaks within bands of interest.\n\nWe can then plot visualizations of the peak parameters, and the reconstructed fits.\n\n\n" ] }, { @@ -138,7 +127,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Plotting Peak Parameters\n~~~~~~~~~~~~~~~~~~~~~~~~\n\nThe :func:`~.plot_peak_params` function takes in peak parameters,\nand visualizes them, as:\n\n- Center Frequency on the x-axis\n- Power on the y-axis\n- Bandwidth as the size of the circle\n\n\n" + "### Plotting Peak Parameters\n\nThe :func:`~.plot_peak_params` function takes in peak parameters,\nand visualizes them, as:\n\n- Center Frequency on the x-axis\n- Power on the y-axis\n- Bandwidth as the size of the circle\n\n\n" ] }, { @@ -167,7 +156,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Plotting Peak Fits\n~~~~~~~~~~~~~~~~~~\n\nThe :func:`~.plot_peak_fits` function takes in peak parameters,\nand reconstructs peak fits.\n\n\n" + "### Plotting Peak Fits\n\nThe :func:`~.plot_peak_fits` function takes in peak parameters,\nand reconstructs peak fits.\n\n\n" ] }, { @@ -196,7 +185,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Aperiodic Components\n--------------------\n\nNext, let's have a look at the aperiodic components.\n\n\n" + "## Aperiodic Components\n\nNext, let's have a look at the aperiodic components.\n\n\n" ] }, { @@ -214,7 +203,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Plotting Aperiodic Parameters\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nThe :func:`~.plot_aperiodic_params` function takes in\naperiodic parameters, and visualizes them, as:\n\n- Offset on the x-axis\n- Exponent on the y-axis\n\n\n" + "### Plotting Aperiodic Parameters\n\nThe :func:`~.plot_aperiodic_params` function takes in\naperiodic parameters, and visualizes them, as:\n\n- Offset on the x-axis\n- Exponent on the y-axis\n\n\n" ] }, { @@ -243,7 +232,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Plotting Aperiodic Fits\n~~~~~~~~~~~~~~~~~~~~~~~\n\nThe :func:`~.plot_aperiodic_fits` function takes in\naperiodic parameters, and reconstructs aperiodic fits.\n\nHere again we can plot visualizations of the peak parameters, and the reconstructed fits.\n\n\n" + "### Plotting Aperiodic Fits\n\nThe :func:`~.plot_aperiodic_fits` function takes in\naperiodic parameters, and reconstructs aperiodic fits.\n\nHere again we can plot visualizations of the peak parameters, and the reconstructed fits.\n\n\n" ] }, { @@ -279,7 +268,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Conclusions\n-----------\n\nIn this example, we explored plotting model parameters and components within and between\ngroups of parameterized neural power spectra.\n\nIf you check the simulation parameters used for the two groups, you can see that\nwe set these groups to vary in their alpha center frequency and in the exponent value.\nQualitatively, we can see those differences in the plots above, and this (in real data)\nwould suggest there may be interesting differences between these groups. Follow up\nanalyses in such a case could investigate whether there are statistically significant\ndifferences between these groups.\n\n\n" + "## Conclusions\n\nIn this example, we explored plotting model parameters and components within and between\ngroups of parameterized neural power spectra.\n\nIf you check the simulation parameters used for the two groups, you can see that\nwe set these groups to vary in their alpha center frequency and in the exponent value.\nQualitatively, we can see those differences in the plots above, and this (in real data)\nwould suggest there may be interesting differences between these groups. Follow up\nanalyses in such a case could investigate whether there are statistically significant\ndifferences between these groups.\n\n\n" ] } ], @@ -299,7 +288,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.8.5" + "version": "3.8.3" } }, "nbformat": 4, diff --git a/_downloads/1995e37fd6109822fdf41b03edf386b2/plot_03-FOOOFAlgorithm.ipynb b/_downloads/1995e37fd6109822fdf41b03edf386b2/plot_03-FOOOFAlgorithm.ipynb index b38ecbc9..3382b589 100644 --- a/_downloads/1995e37fd6109822fdf41b03edf386b2/plot_03-FOOOFAlgorithm.ipynb +++ b/_downloads/1995e37fd6109822fdf41b03edf386b2/plot_03-FOOOFAlgorithm.ipynb @@ -1,28 +1,17 @@ { "cells": [ - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "collapsed": false - }, - "outputs": [], - "source": [ - "%matplotlib inline" - ] - }, { "cell_type": "markdown", "metadata": {}, "source": [ - "\n03: Fitting Algorithm\n=====================\n\nA step-by-step overview of the algorithm for parameterizing neural power spectra.\n" + "\n# 03: Fitting Algorithm\n\nA step-by-step overview of the algorithm for parameterizing neural power spectra.\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "Algorithmic Description\n-----------------------\n\nIn this tutorial we will step through how the power spectrum model is fit.\n\nNote that this notebook is for demonstrative purposes, and does not represent\nrecommended usage of how to fit power spectrum models.\n\nBroadly, the steps in the algorithm are:\n\n- 1) An initial fit of the aperiodic component is computed from the power spectrum\n- 2) This aperiodic fit is subtracted from the power spectrum, creating a flattened spectrum\n- 3) An iterative process identifies peaks in this flattened spectrum\n- 4) A full peak fit is re-fit from all of the identified peak candidates\n- 5) The peak fit is subtracted from the original power spectrum,\n creating a peak-removed power spectrum\n- 6) A final fit of the aperiodic component is taken of the peak-removed power spectrum\n- 7) The full model is reconstructed from the combination of the aperiodic and peak fits,\n and goodness of fit metrics are calculated.\n\n\n" + "## Algorithmic Description\n\nIn this tutorial we will step through how the power spectrum model is fit.\n\nNote that this notebook is for demonstrative purposes, and does not represent\nrecommended usage of how to fit power spectrum models.\n\nBroadly, the steps in the algorithm are:\n\n- 1) An initial fit of the aperiodic component is computed from the power spectrum\n- 2) This aperiodic fit is subtracted from the power spectrum, creating a flattened spectrum\n- 3) An iterative process identifies peaks in this flattened spectrum\n- 4) A full peak fit is re-fit from all of the identified peak candidates\n- 5) The peak fit is subtracted from the original power spectrum,\n creating a peak-removed power spectrum\n- 6) A final fit of the aperiodic component is taken of the peak-removed power spectrum\n- 7) The full model is reconstructed from the combination of the aperiodic and peak fits,\n and goodness of fit metrics are calculated.\n\n\n" ] }, { @@ -33,7 +22,7 @@ }, "outputs": [], "source": [ - "# General imports\nimport matplotlib.pyplot as plt\n\n# Import the FOOOF object\nfrom fooof import FOOOF\n\n# Import some internal functions\n# These are used here to demonstrate the algorithm\n# You do not need to import these functions for standard usage of the module\nfrom fooof.sim.gen import gen_aperiodic\nfrom fooof.plts.spectra import plot_spectrum\nfrom fooof.plts.annotate import plot_annotated_peak_search\n\n# Import a utility to download and load example data\nfrom fooof.utils.download import load_fooof_data" + "# General imports\nimport matplotlib.pyplot as plt\n\n# Import the FOOOF object\nfrom fooof import FOOOF\n\n# Import some internal functions\n# These are used here to demonstrate the algorithm\n# You do not need to import these functions for standard usage of the module\nfrom fooof.sim.gen import gen_aperiodic\nfrom fooof.plts.spectra import plot_spectra\nfrom fooof.plts.annotate import plot_annotated_peak_search\n\n# Import a utility to download and load example data\nfrom fooof.utils.download import load_fooof_data" ] }, { @@ -120,7 +109,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Step 1: Initial Aperiodic Fit\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\nWe start by taking an initial aperiodic fit. This goal of this fit is to get an initial\nfit that is good enough to get started with the fitting process.\n\n\n" + "### Step 1: Initial Aperiodic Fit\n\nWe start by taking an initial aperiodic fit. This goal of this fit is to get an initial\nfit that is good enough to get started with the fitting process.\n\n\n" ] }, { @@ -131,14 +120,14 @@ }, "outputs": [], "source": [ - "# Do an initial aperiodic fit - a robust fit, that excludes outliers\n# This recreates an initial fit that isn't ultimately stored in the FOOOF object\ninit_ap_fit = gen_aperiodic(fm.freqs, fm._robust_ap_fit(fm.freqs, fm.power_spectrum))\n\n# Plot the initial aperiodic fit\n_, ax = plt.subplots(figsize=(12, 10))\nplot_spectrum(fm.freqs, fm.power_spectrum, plt_log,\n label='Original Power Spectrum', color='black', ax=ax)\nplot_spectrum(fm.freqs, init_ap_fit, plt_log, label='Initial Aperiodic Fit',\n color='blue', alpha=0.5, linestyle='dashed', ax=ax)" + "# Do an initial aperiodic fit - a robust fit, that excludes outliers\n# This recreates an initial fit that isn't ultimately stored in the FOOOF object\ninit_ap_fit = gen_aperiodic(fm.freqs, fm._robust_ap_fit(fm.freqs, fm.power_spectrum))\n\n# Plot the initial aperiodic fit\n_, ax = plt.subplots(figsize=(12, 10))\nplot_spectra(fm.freqs, fm.power_spectrum, plt_log,\n label='Original Power Spectrum', color='black', ax=ax)\nplot_spectra(fm.freqs, init_ap_fit, plt_log, label='Initial Aperiodic Fit',\n color='blue', alpha=0.5, linestyle='dashed', ax=ax)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "Step 2: Flatten the Spectrum\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\nThe initial fit is then used to create a flattened spectrum.\n\nThe initial aperiodic fit is subtracted out from the original data, leaving a flattened\nversion of the data which no longer contains the aperiodic component.\n\n\n" + "### Step 2: Flatten the Spectrum\n\nThe initial fit is then used to create a flattened spectrum.\n\nThe initial aperiodic fit is subtracted out from the original data, leaving a flattened\nversion of the data which no longer contains the aperiodic component.\n\n\n" ] }, { @@ -149,14 +138,14 @@ }, "outputs": [], "source": [ - "# Recompute the flattened spectrum using the initial aperiodic fit\ninit_flat_spec = fm.power_spectrum - init_ap_fit\n\n# Plot the flattened the power spectrum\nplot_spectrum(fm.freqs, init_flat_spec, plt_log,\n label='Flattened Spectrum', color='black')" + "# Recompute the flattened spectrum using the initial aperiodic fit\ninit_flat_spec = fm.power_spectrum - init_ap_fit\n\n# Plot the flattened the power spectrum\nplot_spectra(fm.freqs, init_flat_spec, plt_log,\n label='Flattened Spectrum', color='black')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "Step 3: Detect Peaks\n^^^^^^^^^^^^^^^^^^^^\n\nThe flattened spectrum is then used to detect peaks. We can better isolate\npeaks in the data, as the aperiodic activity has been removed.\n\nThe fitting algorithm uses an iterative procedure to find peaks in the flattened spectrum.\n\nFor each iteration:\n\n- The maximum point of the flattened spectrum is found\n\n - If this point fails to pass the relative or absolute height threshold,\n the procedure halts\n- A Gaussian is fit around this maximum point\n- This 'guess' Gaussian is then subtracted from the flatted spectrum\n- The procedure continues to a new iteration with the new version of the flattened spectrum,\n unless `max_n_peaks` has been reached\n\n\n" + "### Step 3: Detect Peaks\n\nThe flattened spectrum is then used to detect peaks. We can better isolate\npeaks in the data, as the aperiodic activity has been removed.\n\nThe fitting algorithm uses an iterative procedure to find peaks in the flattened spectrum.\n\nFor each iteration:\n\n- The maximum point of the flattened spectrum is found\n\n - If this point fails to pass the relative or absolute height threshold,\n the procedure halts\n- A Gaussian is fit around this maximum point\n- This 'guess' Gaussian is then subtracted from the flatted spectrum\n- The procedure continues to a new iteration with the new version of the flattened spectrum,\n unless `max_n_peaks` has been reached\n\n\n" ] }, { @@ -174,7 +163,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Step 4: Create Full Peak Fit\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\nOnce the iterative procedure has halted and the peaks have been identified in the\nflattened spectrum, the set of identified 'guess' peaks, are then re-fit, all together.\nThis creates the full peak fit of the data.\n\n\n" + "### Step 4: Create Full Peak Fit\n\nOnce the iterative procedure has halted and the peaks have been identified in the\nflattened spectrum, the set of identified 'guess' peaks, are then re-fit, all together.\nThis creates the full peak fit of the data.\n\n\n" ] }, { @@ -185,14 +174,14 @@ }, "outputs": [], "source": [ - "# Plot the peak fit: created by re-fitting all of the candidate peaks together\nplot_spectrum(fm.freqs, fm._peak_fit, plt_log, color='green', label='Final Periodic Fit')" + "# Plot the peak fit: created by re-fitting all of the candidate peaks together\nplot_spectra(fm.freqs, fm._peak_fit, plt_log, color='green', label='Final Periodic Fit')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "Step 5: Create a Peak-Removed Spectrum\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\nNow that the peak component of the fit is completed and available, this fit is then\nused in order to try and isolate a better aperiodic fit.\n\nTo do so, the peak fit is removed from the original power spectrum,\nleaving an 'aperiodic-only' spectrum for re-fitting.\n\n\n" + "### Step 5: Create a Peak-Removed Spectrum\n\nNow that the peak component of the fit is completed and available, this fit is then\nused in order to try and isolate a better aperiodic fit.\n\nTo do so, the peak fit is removed from the original power spectrum,\nleaving an 'aperiodic-only' spectrum for re-fitting.\n\n\n" ] }, { @@ -203,14 +192,14 @@ }, "outputs": [], "source": [ - "# Plot the peak removed power spectrum, created by removing peak fit from original spectrum\nplot_spectrum(fm.freqs, fm._spectrum_peak_rm, plt_log,\n label='Peak Removed Spectrum', color='black')" + "# Plot the peak removed power spectrum, created by removing peak fit from original spectrum\nplot_spectra(fm.freqs, fm._spectrum_peak_rm, plt_log,\n label='Peak Removed Spectrum', color='black')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "Step 6: Re-fit the Aperiodic Component\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\nThe initial aperiodic component fit we made was a robust fit approach that was\nused to get the fitting process started.\n\nWith the peak-removed spectrum, we can now re-fit the aperiodic component, to\nre-estimate a better fit, without the peaks getting in the way.\n\n\n" + "### Step 6: Re-fit the Aperiodic Component\n\nThe initial aperiodic component fit we made was a robust fit approach that was\nused to get the fitting process started.\n\nWith the peak-removed spectrum, we can now re-fit the aperiodic component, to\nre-estimate a better fit, without the peaks getting in the way.\n\n\n" ] }, { @@ -221,14 +210,14 @@ }, "outputs": [], "source": [ - "# Plot the final aperiodic fit, calculated on the peak removed power spectrum\n_, ax = plt.subplots(figsize=(12, 10))\nplot_spectrum(fm.freqs, fm._spectrum_peak_rm, plt_log,\n label='Peak Removed Spectrum', color='black', ax=ax)\nplot_spectrum(fm.freqs, fm._ap_fit, plt_log, label='Final Aperiodic Fit',\n color='blue', alpha=0.5, linestyle='dashed', ax=ax)" + "# Plot the final aperiodic fit, calculated on the peak removed power spectrum\n_, ax = plt.subplots(figsize=(12, 10))\nplot_spectra(fm.freqs, fm._spectrum_peak_rm, plt_log,\n label='Peak Removed Spectrum', color='black', ax=ax)\nplot_spectra(fm.freqs, fm._ap_fit, plt_log, label='Final Aperiodic Fit',\n color='blue', alpha=0.5, linestyle='dashed', ax=ax)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "Step 7: Combine the Full Model Fit\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\nNow that we have the final aperiodic fit, we can combine the aperiodic components\nto create the full model fit.\n\nWith this full model fit, we can also calculate the goodness of fit metrics,\nincluding the error of the fit and the R-squared of the fit, by comparing the\nfull model fit to the original data.\n\n\n" + "### Step 7: Combine the Full Model Fit\n\nNow that we have the final aperiodic fit, we can combine the aperiodic components\nto create the full model fit.\n\nWith this full model fit, we can also calculate the goodness of fit metrics,\nincluding the error of the fit and the R-squared of the fit, by comparing the\nfull model fit to the original data.\n\n\n" ] }, { @@ -239,7 +228,7 @@ }, "outputs": [], "source": [ - "# Plot full model, created by combining the peak and aperiodic fits\nplot_spectrum(fm.freqs, fm.fooofed_spectrum_, plt_log,\n label='Full Model', color='red')" + "# Plot full model, created by combining the peak and aperiodic fits\nplot_spectra(fm.freqs, fm.fooofed_spectrum_, plt_log,\n label='Full Model', color='red')" ] }, { @@ -282,14 +271,14 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Addendum: Data & Model Component Attributes\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\nAs you may have noticed through this tutorial, the :class:`~fooof.FOOOF` object keeps\ntrack of some versions of the original data as well as individual model components fits,\nas well as the final model fit, the ultimate outcome of the fitting procedure.\n\nThese attributes in the FOOOF object are kept at the end of the fitting procedure.\nThough they are primarily computed for internal use (hence being considered 'private'\nattributes, with the leading underscore), they are accessible and potentially\nuseful for some analyses, and so are briefly described here.\n\nStored model components:\n\n- Aperiodic Component: ``_ap_fit``\n\n - This is the aperiodic-only fit of the data.\n - It is computed by generating a reconstruction of the measured aperiodic parameters\n\n- Periodic Component: ``_peak_fit``\n\n - This is the periodic-only (or peak) fit of the data.\n - It is computed by generating a reconstruction of the measured periodic (peak) parameters\n\nStored data attributes:\n\n- Flattened Spectrum: ``_spectrum_flat``\n\n - The original data, with the aperiodic component removed\n - This is computed as ``power_spectrum`` - ``_ap_fit``\n\n- Peak Removed Spectrum: ``_spectrum_peak_rm``\n\n - The original data, with the periodic component (peaks) removed\n - This is computed as ``power_spectrum`` - ``_peak_fit``\n\n\n" + "### Addendum: Data & Model Component Attributes\n\nAs you may have noticed through this tutorial, the :class:`~fooof.FOOOF` object keeps\ntrack of some versions of the original data as well as individual model components fits,\nas well as the final model fit, the ultimate outcome of the fitting procedure.\n\nThese attributes in the FOOOF object are kept at the end of the fitting procedure.\nThough they are primarily computed for internal use (hence being considered 'private'\nattributes, with the leading underscore), they are accessible and potentially\nuseful for some analyses, and so are briefly described here.\n\nStored model components:\n\n- Aperiodic Component: ``_ap_fit``\n\n - This is the aperiodic-only fit of the data.\n - It is computed by generating a reconstruction of the measured aperiodic parameters\n\n- Periodic Component: ``_peak_fit``\n\n - This is the periodic-only (or peak) fit of the data.\n - It is computed by generating a reconstruction of the measured periodic (peak) parameters\n\nStored data attributes:\n\n- Flattened Spectrum: ``_spectrum_flat``\n\n - The original data, with the aperiodic component removed\n - This is computed as ``power_spectrum`` - ``_ap_fit``\n\n- Peak Removed Spectrum: ``_spectrum_peak_rm``\n\n - The original data, with the periodic component (peaks) removed\n - This is computed as ``power_spectrum`` - ``_peak_fit``\n\n\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "Conclusion\n----------\n\nIn this tutorial we have stepped through the parameterization algorithm for fitting\npower spectrum models.\n\nNext, we will continue to explore the FOOOF object by properly introducing and more\nfully describing the settings for the algorithm.\n\n\n" + "## Conclusion\n\nIn this tutorial we have stepped through the parameterization algorithm for fitting\npower spectrum models.\n\nNext, we will continue to explore the FOOOF object by properly introducing and more\nfully describing the settings for the algorithm.\n\n\n" ] } ], @@ -309,7 +298,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.8.5" + "version": "3.8.3" } }, "nbformat": 4, diff --git a/_downloads/208ddf4708879eabf6a6f4aae1ab846a/plot_mne_example.py b/_downloads/208ddf4708879eabf6a6f4aae1ab846a/plot_mne_example.py index 19a058a1..deef1f7a 100644 --- a/_downloads/208ddf4708879eabf6a6f4aae1ab846a/plot_mne_example.py +++ b/_downloads/208ddf4708879eabf6a6f4aae1ab846a/plot_mne_example.py @@ -5,7 +5,7 @@ Parameterizing neural power spectra with MNE, doing a topographical analysis. This tutorial requires that you have `MNE `_ -installed. +installed. This tutorial needs mne >= 1.2. If you don't already have MNE, you can follow instructions to get it `here `_. @@ -23,16 +23,13 @@ # Import MNE, as well as the MNE sample dataset import mne -from mne import io from mne.datasets import sample -from mne.viz import plot_topomap -from mne.time_frequency import psd_welch # FOOOF imports 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 @@ -52,8 +49,7 @@ ################################################################################################### # Get the data path for the MNE example data -raw_fname = sample.data_path() + '/MEG/sample/sample_audvis_filt-0-40_raw.fif' -event_fname = sample.data_path() + '/MEG/sample/sample_audvis_filt-0-40_raw-eve.fif' +raw_fname = sample.data_path() / 'MEG' / 'sample' / 'sample_audvis_filt-0-40_raw.fif' # Load the example MNE data raw = mne.io.read_raw_fif(raw_fname, preload=True, verbose=False) @@ -61,7 +57,7 @@ ################################################################################################### # Select EEG channels from the dataset -raw = raw.pick_types(meg=False, eeg=True, eog=False, exclude='bads') +raw = raw.pick(['eeg'], exclude='bads') ################################################################################################### @@ -110,15 +106,16 @@ def check_nans(data, nan_policy='zero'): # frequency representations - meaning we have to calculate power spectra. # # To do so, we will leverage the time frequency tools available with MNE, -# in the `time_frequency` module. In particular, we can use the ``psd_welch`` -# function, that takes in MNE data objects and calculates and returns power spectra. +# in the `time_frequency` module. In particular, we can use the ``compute_psd`` +# method, that takes in MNE data objects and calculates and returns power spectra. # ################################################################################################### -# Calculate power spectra across the the continuous data -spectra, freqs = psd_welch(raw, fmin=1, fmax=40, tmin=0, tmax=250, - n_overlap=150, n_fft=300) +# Calculate power spectra across the continuous data +psd = raw.compute_psd(method="welch", fmin=1, fmax=40, tmin=0, tmax=250, + n_overlap=150, n_fft=300) +spectra, freqs = psd.get_data(return_freqs=True) ################################################################################################### # Fitting Power Spectrum Models @@ -193,7 +190,7 @@ def check_nans(data, nan_policy='zero'): ################################################################################################### # Plot the topography of alpha power -plot_topomap(alpha_pw, raw.info, cmap=cm.viridis, contours=0); +mne.viz.plot_topomap(alpha_pw, raw.info, cmap=cm.viridis, contours=0, size=4) ################################################################################################### # @@ -214,8 +211,7 @@ def check_nans(data, nan_policy='zero'): band_power = check_nans(get_band_peak_fg(fg, band_def)[:, 1]) # Create a topomap for the current oscillation band - mne.viz.plot_topomap(band_power, raw.info, cmap=cm.viridis, contours=0, - axes=axes[ind], show=False); + mne.viz.plot_topomap(band_power, raw.info, cmap=cm.viridis, contours=0, axes=axes[ind]) # Set the plot title axes[ind].set_title(label + ' power', {'fontsize' : 20}) @@ -268,7 +264,7 @@ def check_nans(data, nan_policy='zero'): ################################################################################################### # Plot the topography of aperiodic exponents -plot_topomap(exps, raw.info, cmap=cm.viridis, contours=0) +mne.viz.plot_topomap(exps, raw.info, cmap=cm.viridis, contours=0, size=4) ################################################################################################### # @@ -284,10 +280,11 @@ 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') + +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 @@ -296,6 +293,3 @@ def check_nans(data, nan_policy='zero'): # In this example, we have seen how to apply power spectrum models to data that is # managed and processed with MNE. # - -################################################################################################### -# diff --git a/_downloads/22eca51ea62d18a21f9995a7bdfe8c49/plot_mne_example.ipynb b/_downloads/22eca51ea62d18a21f9995a7bdfe8c49/plot_mne_example.ipynb index f7f5e85a..bb1cb336 100644 --- a/_downloads/22eca51ea62d18a21f9995a7bdfe8c49/plot_mne_example.ipynb +++ b/_downloads/22eca51ea62d18a21f9995a7bdfe8c49/plot_mne_example.ipynb @@ -1,21 +1,10 @@ { "cells": [ - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "collapsed": false - }, - "outputs": [], - "source": [ - "%matplotlib inline" - ] - }, { "cell_type": "markdown", "metadata": {}, "source": [ - "\nTopographical Analyses with MNE\n===============================\n\nParameterizing neural power spectra with MNE, doing a topographical analysis.\n\nThis tutorial requires that you have `MNE `_\ninstalled.\n\nIf you don't already have MNE, you can follow instructions to get it\n`here `_.\n\nFor this example, we will explore how to parameterize power spectra using data loaded\nand managed with MNE, and how to plot topographies of resulting model parameters.\n" + "\n# Topographical Analyses with MNE\n\nParameterizing neural power spectra with MNE, doing a topographical analysis.\n\nThis tutorial requires that you have [MNE](https://mne-tools.github.io/)\ninstalled. This tutorial needs mne >= 1.2.\n\nIf you don't already have MNE, you can follow instructions to get it\n[here](https://mne-tools.github.io/stable/getting_started.html).\n\nFor this example, we will explore how to parameterize power spectra using data loaded\nand managed with MNE, and how to plot topographies of resulting model parameters.\n" ] }, { @@ -26,14 +15,14 @@ }, "outputs": [], "source": [ - "# General imports\nimport numpy as np\nimport matplotlib.pyplot as plt\nfrom matplotlib import cm, colors, colorbar\n\n# Import MNE, as well as the MNE sample dataset\nimport mne\nfrom mne import io\nfrom mne.datasets import sample\nfrom mne.viz import plot_topomap\nfrom mne.time_frequency import psd_welch\n\n# FOOOF imports\nfrom fooof import FOOOFGroup\nfrom fooof.bands import Bands\nfrom fooof.analysis import get_band_peak_fg\nfrom fooof.plts.spectra import plot_spectrum" + "# General imports\nimport numpy as np\nimport matplotlib.pyplot as plt\nfrom matplotlib import cm, colors, colorbar\n\n# Import MNE, as well as the MNE sample dataset\nimport mne\nfrom mne.datasets import sample\n\n# FOOOF imports\nfrom fooof import FOOOFGroup\nfrom fooof.bands import Bands\nfrom fooof.analysis import get_band_peak_fg\nfrom fooof.plts.spectra import plot_spectra" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "Load & Check MNE Data\n---------------------\n\nWe will use the\n`MNE sample dataset `_\nwhich is a combined MEG/EEG recording with an audiovisual task.\n\nFirst we will load the dataset from MNE, have a quick look at the data,\nand extract the EEG data that we will use for this example.\n\nNote that if you are running this locally, the following cell will download\nthe example dataset, if you do not already have it.\n\n\n" + "## Load & Check MNE Data\n\nWe will use the\n[MNE sample dataset](https://mne.tools/stable/overview/datasets_index.html?#sample)\nwhich is a combined MEG/EEG recording with an audiovisual task.\n\nFirst we will load the dataset from MNE, have a quick look at the data,\nand extract the EEG data that we will use for this example.\n\nNote that if you are running this locally, the following cell will download\nthe example dataset, if you do not already have it.\n\n\n" ] }, { @@ -44,7 +33,7 @@ }, "outputs": [], "source": [ - "# Get the data path for the MNE example data\nraw_fname = sample.data_path() + '/MEG/sample/sample_audvis_filt-0-40_raw.fif'\nevent_fname = sample.data_path() + '/MEG/sample/sample_audvis_filt-0-40_raw-eve.fif'\n\n# Load the example MNE data\nraw = mne.io.read_raw_fif(raw_fname, preload=True, verbose=False)" + "# Get the data path for the MNE example data\nraw_fname = sample.data_path() / 'MEG' / 'sample' / 'sample_audvis_filt-0-40_raw.fif'\n\n# Load the example MNE data\nraw = mne.io.read_raw_fif(raw_fname, preload=True, verbose=False)" ] }, { @@ -55,7 +44,7 @@ }, "outputs": [], "source": [ - "# Select EEG channels from the dataset\nraw = raw.pick_types(meg=False, eeg=True, eog=False, exclude='bads')" + "# Select EEG channels from the dataset\nraw = raw.pick(['eeg'], exclude='bads')" ] }, { @@ -73,7 +62,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Dealing with NaN Values\n-----------------------\n\nOne thing to keep in mind when parameterizing power spectra, and extracting bands of\ninterest, is that there is no guarantee that the model will detect peaks in any given range.\n\nWe consider this a pro, since power spectrum model is able to adjudicate whether there is\nevidence of oscillatory power within a given band, but it does also mean that sometimes\nresults for a given band can be NaN, which doesn't always work very well with further\nanalyses that we may want to do.\n\nTo be able to deal with nan-values, we will define a helper function to\ncheck for NaN values and apply a specified policy for how to deal with them.\n\n\n" + "## Dealing with NaN Values\n\nOne thing to keep in mind when parameterizing power spectra, and extracting bands of\ninterest, is that there is no guarantee that the model will detect peaks in any given range.\n\nWe consider this a pro, since power spectrum model is able to adjudicate whether there is\nevidence of oscillatory power within a given band, but it does also mean that sometimes\nresults for a given band can be NaN, which doesn't always work very well with further\nanalyses that we may want to do.\n\nTo be able to deal with nan-values, we will define a helper function to\ncheck for NaN values and apply a specified policy for how to deal with them.\n\n\n" ] }, { @@ -91,7 +80,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Calculating Power Spectra\n-------------------------\n\nTo fit power spectrum models, we need to convert the time-series data we have loaded in\nfrequency representations - meaning we have to calculate power spectra.\n\nTo do so, we will leverage the time frequency tools available with MNE,\nin the `time_frequency` module. In particular, we can use the ``psd_welch``\nfunction, that takes in MNE data objects and calculates and returns power spectra.\n\n\n" + "## Calculating Power Spectra\n\nTo fit power spectrum models, we need to convert the time-series data we have loaded in\nfrequency representations - meaning we have to calculate power spectra.\n\nTo do so, we will leverage the time frequency tools available with MNE,\nin the `time_frequency` module. In particular, we can use the ``compute_psd``\nmethod, that takes in MNE data objects and calculates and returns power spectra.\n\n\n" ] }, { @@ -102,14 +91,14 @@ }, "outputs": [], "source": [ - "# Calculate power spectra across the the continuous data\nspectra, freqs = psd_welch(raw, fmin=1, fmax=40, tmin=0, tmax=250,\n n_overlap=150, n_fft=300)" + "# Calculate power spectra across the continuous data\npsd = raw.compute_psd(method=\"welch\", fmin=1, fmax=40, tmin=0, tmax=250,\n n_overlap=150, n_fft=300)\nspectra, freqs = psd.get_data(return_freqs=True)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "Fitting Power Spectrum Models\n-----------------------------\n\nNow that we have power spectra, we can fit some power spectrum models.\n\nSince we have multiple power spectra, we will use the :class:`~fooof.FOOOFGroup` object.\n\n\n" + "## Fitting Power Spectrum Models\n\nNow that we have power spectra, we can fit some power spectrum models.\n\nSince we have multiple power spectra, we will use the :class:`~fooof.FOOOFGroup` object.\n\n\n" ] }, { @@ -149,14 +138,14 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Plotting Topographies\n---------------------\n\nNow that we have our power spectrum models calculated across all channels,\nlet's start by plotting topographies of some of the resulting model parameters.\n\nTo do so, we can leverage the fact that both MNE and FOOOF objects preserve data order.\nSo, when we calculated power spectra, our output spectra kept the channel order\nthat is described in the MNE data object, and so did our :class:`~fooof.FOOOFGroup`\nobject.\n\nThat means that to plot our topography, we can use the MNE ``plot_topomap``\nfunction, passing in extracted data for power spectrum parameters per channel, and\nusing the MNE object to define the corresponding channel locations.\n\n\n" + "## Plotting Topographies\n\nNow that we have our power spectrum models calculated across all channels,\nlet's start by plotting topographies of some of the resulting model parameters.\n\nTo do so, we can leverage the fact that both MNE and FOOOF objects preserve data order.\nSo, when we calculated power spectra, our output spectra kept the channel order\nthat is described in the MNE data object, and so did our :class:`~fooof.FOOOFGroup`\nobject.\n\nThat means that to plot our topography, we can use the MNE ``plot_topomap``\nfunction, passing in extracted data for power spectrum parameters per channel, and\nusing the MNE object to define the corresponding channel locations.\n\n\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "Plotting Periodic Topographies\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nLets start start by plotting some periodic model parameters.\n\nTo do so, we will use to :obj:`~.Bands` object to manage some band\ndefinitions, and some analysis utilities to extracts peaks from bands of interest.\n\n\n" + "### Plotting Periodic Topographies\n\nLets start start by plotting some periodic model parameters.\n\nTo do so, we will use to :obj:`~.Bands` object to manage some band\ndefinitions, and some analysis utilities to extracts peaks from bands of interest.\n\n\n" ] }, { @@ -189,7 +178,7 @@ }, "outputs": [], "source": [ - "# Plot the topography of alpha power\nplot_topomap(alpha_pw, raw.info, cmap=cm.viridis, contours=0);" + "# Plot the topography of alpha power\nmne.viz.plot_topomap(alpha_pw, raw.info, cmap=cm.viridis, contours=0, size=4)" ] }, { @@ -207,7 +196,7 @@ }, "outputs": [], "source": [ - "# Plot the topographies across different frequency bands\nfig, axes = plt.subplots(1, 3, figsize=(15, 5))\nfor ind, (label, band_def) in enumerate(bands):\n\n # Get the power values across channels for the current band\n band_power = check_nans(get_band_peak_fg(fg, band_def)[:, 1])\n\n # Create a topomap for the current oscillation band\n mne.viz.plot_topomap(band_power, raw.info, cmap=cm.viridis, contours=0,\n axes=axes[ind], show=False);\n\n # Set the plot title\n axes[ind].set_title(label + ' power', {'fontsize' : 20})" + "# Plot the topographies across different frequency bands\nfig, axes = plt.subplots(1, 3, figsize=(15, 5))\nfor ind, (label, band_def) in enumerate(bands):\n\n # Get the power values across channels for the current band\n band_power = check_nans(get_band_peak_fg(fg, band_def)[:, 1])\n\n # Create a topomap for the current oscillation band\n mne.viz.plot_topomap(band_power, raw.info, cmap=cm.viridis, contours=0, axes=axes[ind])\n\n # Set the plot title\n axes[ind].set_title(label + ' power', {'fontsize' : 20})" ] }, { @@ -239,7 +228,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Plotting Aperiodic Topographies\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nNext up, let's plot the topography of the aperiodic exponent.\n\nTo do so, we can simply extract the aperiodic parameters from our power spectrum models,\nand plot them.\n\n\n" + "### Plotting Aperiodic Topographies\n\nNext up, let's plot the topography of the aperiodic exponent.\n\nTo do so, we can simply extract the aperiodic parameters from our power spectrum models,\nand plot them.\n\n\n" ] }, { @@ -261,7 +250,7 @@ }, "outputs": [], "source": [ - "# Plot the topography of aperiodic exponents\nplot_topomap(exps, raw.info, cmap=cm.viridis, contours=0)" + "# Plot the topography of aperiodic exponents\nmne.viz.plot_topomap(exps, raw.info, cmap=cm.viridis, contours=0, size=4)" ] }, { @@ -279,14 +268,14 @@ }, "outputs": [], "source": [ - "# Compare the power spectra between low and high exponent channels\nfig, ax = plt.subplots(figsize=(8, 6))\nplot_spectrum(fg.freqs, fg.get_fooof(np.argmin(exps)).power_spectrum,\n ax=ax, label='Low Exponent')\nplot_spectrum(fg.freqs, fg.get_fooof(np.argmax(exps)).power_spectrum,\n ax=ax, label='High Exponent')" + "# Compare the power spectra between low and high exponent channels\nfig, ax = plt.subplots(figsize=(8, 6))\n\nspectra = [fg.get_fooof(np.argmin(exps)).power_spectrum,\n fg.get_fooof(np.argmax(exps)).power_spectrum]\n\nplot_spectra(fg.freqs, spectra, ax=ax, labels=['Low Exponent', 'High Exponent'])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "Conclusion\n----------\n\nIn this example, we have seen how to apply power spectrum models to data that is\nmanaged and processed with MNE.\n\n\n" + "## Conclusion\n\nIn this example, we have seen how to apply power spectrum models to data that is\nmanaged and processed with MNE.\n\n\n" ] } ], @@ -306,7 +295,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.8.5" + "version": "3.8.3" } }, "nbformat": 4, diff --git a/_downloads/2576ce0dd0bb489e5f373a7ada2925ea/plot_aperiodic_params.py b/_downloads/2576ce0dd0bb489e5f373a7ada2925ea/plot_aperiodic_params.py new file mode 100644 index 00000000..96f018e4 --- /dev/null +++ b/_downloads/2576ce0dd0bb489e5f373a7ada2925ea/plot_aperiodic_params.py @@ -0,0 +1,177 @@ +""" +Aperiodic Parameters +==================== + +Exploring properties and topics related to aperiodic parameters. +""" + +################################################################################################### + +from scipy.stats import spearmanr + +from fooof import FOOOF, FOOOFGroup +from fooof.plts.spectra import plot_spectra +from fooof.plts.annotate import plot_annotated_model +from fooof.plts.aperiodic import plot_aperiodic_params +from fooof.sim.params import Stepper, param_iter +from fooof.sim import gen_power_spectrum, gen_group_power_spectra +from fooof.utils.params import compute_time_constant, compute_knee_frequency + +################################################################################################### +# 'Fixed' Model +# ------------- +# +# First, we will explore the 'fixed' model, which fits an offset and exponent value +# to characterize the 1/f-like aperiodic component of the data. +# + +################################################################################################### + +# Simulate an example power spectrum +freqs, powers = gen_power_spectrum([1, 50], [0, 1], [10, 0.25, 2], freq_res=0.25) + +################################################################################################### + +# Initialize model object and fit power spectrum +fm = FOOOF(min_peak_height=0.1) +fm.fit(freqs, powers) + +################################################################################################### + +# Check the aperiodic parameters +fm.aperiodic_params_ + +################################################################################################### + +# Plot annotated model of aperiodic parameters +plot_annotated_model(fm, annotate_peaks=False, annotate_aperiodic=True, plt_log=True) + +################################################################################################### +# Comparing Offset & Exponent +# --------------------------- +# +# A common analysis of model fit parameters includes examining and comparing changes +# in the offset and/or exponent values of a set of models, which we will now explore. +# +# To do so, we will start by simulating a set of power spectra with different exponent values. +# + +################################################################################################### + +# Define simulation parameters, stepping across different exponent values +exp_steps = Stepper(0, 2, 0.25) +ap_params = param_iter([1, exp_steps]) + +################################################################################################### + +# Simulate a group of power spectra +freqs, powers = gen_group_power_spectra(\ + len(exp_steps), [3, 40], ap_params, [10, 0.25, 1], freq_res=0.25, f_rotation=10) + +################################################################################################### + +# Plot the set of example power spectra +plot_spectra(freqs, powers, log_powers=True) + +################################################################################################### + +# Initialize a group mode object and parameterize the power spectra +fg = FOOOFGroup() +fg.fit(freqs, powers) + +################################################################################################### + +# Extract the aperiodic values of the model fits +ap_values = fg.get_params('aperiodic') + +################################################################################################### + +# Plot the aperiodic parameters +plot_aperiodic_params(fg.get_params('aperiodic')) + +################################################################################################### + +# Compute the correlation between the offset and exponent +spearmanr(ap_values[0, :], ap_values[1, :]) + +################################################################################################### +# +# What we see above matches the common finding that that the offset and exponent are +# often highly correlated! This is because if you imagine a change in exponent as +# the spectrum 'rotating' around some frequency value, then (almost) any change in exponent +# has a corresponding change in offset value! If you note in the above, we actually specified +# a rotation point around which the exponent changes. +# +# This can also be seen in this animation showing this effect across different rotation points: +# +# .. image:: https://raw.githubusercontent.com/fooof-tools/Visualizers/main/gifs/specrot.gif +# +# Notably this means that while the offset and exponent can change independently (there can be +# offset changes over and above exponent changes), the baseline expectation is that these +# two parameters are highly correlated and likely reflect the same change in the data! +# + +################################################################################################### +# Knee Model +# ---------- +# +# Next, let's explore the knee model, which parameterizes the aperiodic component with +# an offset, knee, and exponent value. +# + +################################################################################################### + +# Generate a power spectrum with a knee +freqs2, powers2 = gen_power_spectrum([1, 50], [0, 15, 1], [8, 0.125, 0.75], freq_res=0.25) + +################################################################################################### + +# Initialize model object and fit power spectrum +fm = FOOOF(min_peak_height=0.05, aperiodic_mode='knee') +fm.fit(freqs2, powers2) + +################################################################################################### + +# Plot annotated knee model +plot_annotated_model(fm, annotate_peaks=False, annotate_aperiodic=True, plt_log=True) + +################################################################################################### + +# Check the measured aperiodic parameters +fm.aperiodic_params_ + +################################################################################################### +# Knee Frequency +# ~~~~~~~~~~~~~~ +# +# You might notice that the knee *parameter* is not an obvious value. Notably, this parameter +# value as extracted from the model is something of an abstract quantify based on the +# formalization of the underlying fit function. A more intuitive measure that we may +# be interested in is the 'knee frequency', which is an estimate of the frequency value +# at which the knee occurs. +# +# The :func:`~.compute_knee_frequency` function can be used to compute the knee frequency. +# + +################################################################################################### + +# Compute the knee frequency from aperiodic parameters +knee_frequency = compute_knee_frequency(*fm.aperiodic_params_[1:]) +print('Knee frequency: ', knee_frequency) + +################################################################################################### +# Time Constant +# ~~~~~~~~~~~~~ +# +# Another interesting property of the knee parameter is that it has a direct relationship +# to the auto-correlation function, and from there to the empirical time constant of the data. +# +# The :func:`~.compute_time_constant` function can be used to compute the knee-derived +# time constant. +# + +################################################################################################### + +# Compute the characteristic time constant of a knee value +time_constant = compute_time_constant(fm.get_params('aperiodic', 'knee')) +print('Knee derived time constant: ', time_constant) diff --git a/_downloads/28df5779df9b7bb1ab24dde234f2e071/plot_07-TroubleShooting.ipynb b/_downloads/28df5779df9b7bb1ab24dde234f2e071/plot_07-TroubleShooting.ipynb index a9d1c040..0bd22bc1 100644 --- a/_downloads/28df5779df9b7bb1ab24dde234f2e071/plot_07-TroubleShooting.ipynb +++ b/_downloads/28df5779df9b7bb1ab24dde234f2e071/plot_07-TroubleShooting.ipynb @@ -1,21 +1,10 @@ { "cells": [ - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "collapsed": false - }, - "outputs": [], - "source": [ - "%matplotlib inline" - ] - }, { "cell_type": "markdown", "metadata": {}, "source": [ - "\n07: Tuning & Troubleshooting\n============================\n\nTips & tricks for choosing algorithm settings, tuning fits, and troubleshooting.\n" + "\n# 07: Tuning & Troubleshooting\n\nTips & tricks for choosing algorithm settings, tuning fits, and troubleshooting.\n" ] }, { @@ -33,35 +22,35 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Algorithm Settings\n------------------\n\nWith default settings, the power spectrum model is relatively minimally constrained. It\ndefaults as such since there are not universal settings that work across all different\nrecording modalities. Appropriate settings also vary with power spectrum quality (noise,\nor effectively, the smoothness of the power spectrum), and frequency ranges.\n\nFor any given dataset, you will likely have to tune some of the algorithm settings\nfor optimal performance.\n\nTo do so, we suggest using a combination of the following considerations:\n\n- A priori constraints, given your data, such as the number of peaks you expect to extract\n- Qualitative analysis, guided by examining the the plotted model fit results,\n as compared to input data\n- Quantitative analysis, considering the model goodness of fit metrics\n (however, see note at the bottom regarding interpreting these metrics)\n\nChoosing settings to tune model fitting is an imperfect art, and should be done carefully,\nas assumptions built into the settings chosen will impact the model results. Model\nfitting is generally not overly sensitive to small changes in the settings, so as long\nas broadly appropriate settings are chosen, small perturbations to these chosen settings\nshould not have a large impact on the fitting.\n\nWe do recommend that model settings should not be changed between power spectra\n(across channels, trials, or subjects), if they are to be meaningfully compared.\nWe therefore recommend first testing fitting the model across some representative\nspectra, in order to select settings, which you then keep constant for the full analysis.\n\n\n" + "## Algorithm Settings\n\nWith default settings, the power spectrum model is relatively minimally constrained. It\ndefaults as such since there are not universal settings that work across all different\nrecording modalities. Appropriate settings also vary with power spectrum quality (noise,\nor effectively, the smoothness of the power spectrum), and frequency ranges.\n\nFor any given dataset, you will likely have to tune some of the algorithm settings\nfor optimal performance.\n\nTo do so, we suggest using a combination of the following considerations:\n\n- A priori constraints, given your data, such as the number of peaks you expect to extract\n- Qualitative analysis, guided by examining the the plotted model fit results,\n as compared to input data\n- Quantitative analysis, considering the model goodness of fit metrics\n (however, see note at the bottom regarding interpreting these metrics)\n\nChoosing settings to tune model fitting is an imperfect art, and should be done carefully,\nas assumptions built into the settings chosen will impact the model results. Model\nfitting is generally not overly sensitive to small changes in the settings, so as long\nas broadly appropriate settings are chosen, small perturbations to these chosen settings\nshould not have a large impact on the fitting.\n\nWe do recommend that model settings should not be changed between power spectra\n(across channels, trials, or subjects), if they are to be meaningfully compared.\nWe therefore recommend first testing fitting the model across some representative\nspectra, in order to select settings, which you then keep constant for the full analysis.\n\n\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "Tuning the Algorithm\n--------------------\n\nWith default settings, the model fit is fairly liberal at fitting peaks, and so\nmost commonly this will lead to overfitting, being overzealous at fitting small\nnoisy bumps as peaks.\n\nIn some cases, you may also find you need to relax some settings, to get better fits.\n\nYou also need to make sure you pick an appropriate aperiodic fitting procedure,\nand that your data meets the assumptions of the approach you choose (see the tutorial\non aperiodic fitting).\n\nThe remainder of this notebook goes through some examples of choosing settings\nfor different datasets.\n\n\n" + "## Tuning the Algorithm\n\nWith default settings, the model fit is fairly liberal at fitting peaks, and so\nmost commonly this will lead to overfitting, being overzealous at fitting small\nnoisy bumps as peaks.\n\nIn some cases, you may also find you need to relax some settings, to get better fits.\n\nYou also need to make sure you pick an appropriate aperiodic fitting procedure,\nand that your data meets the assumptions of the approach you choose (see the tutorial\non aperiodic fitting).\n\nThe remainder of this notebook goes through some examples of choosing settings\nfor different datasets.\n\n\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "Interpreting Model Fit Quality Measures\n---------------------------------------\n\nAfter model fitting, some goodness of fit metrics are calculated to assist with assessing\nthe quality of the model fits. It calculates both the model fit error, as the mean absolute\nerror (MAE) between the full model fit (``fooofed_spectrum_``) and the original power spectrum,\nas well as the R-squared correspondence between the original spectrum and the full model.\n\nThese scores can be used to assess how the model is performing. However interpreting these\nmeasures requires a bit of nuance. Model fitting is NOT optimized to minimize fit error /\nmaximize r-squared at all costs. To do so typically results in fitting a large number of peaks,\nin a way that overfits noise, and only artificially reduces error / maximizes r-squared.\n\nThe power spectrum model is therefore tuned to try and measure the aperiodic component\nand peaks in a parsimonious manner, and, fit the `right` model (meaning the right aperiodic\ncomponent and the right number of peaks) rather than the model with the lowest error.\n\nGiven this, while high error / low r-squared may indicate a poor model fit, very low\nerror / high r-squared may also indicate a power spectrum that is overfit, in particular\nin which the peak parameters from the model may reflect overfitting by fitting too many peaks.\n\nWe therefore recommend that, for a given dataset, initial explorations should involve\nchecking both cases in which model fit error is particularly large, as well as when it\nis particularly low. These explorations can be used to pick settings that are suitable\nfor running across a group. There are not universal settings that optimize this, and so\nit is left up to the user to choose settings appropriately to not under- or over-fit\nfor a given modality / dataset / application.\n\n\n" + "## Interpreting Model Fit Quality Measures\n\nAfter model fitting, some goodness of fit metrics are calculated to assist with assessing\nthe quality of the model fits. It calculates both the model fit error, as the mean absolute\nerror (MAE) between the full model fit (``fooofed_spectrum_``) and the original power spectrum,\nas well as the R-squared correspondence between the original spectrum and the full model.\n\nThese scores can be used to assess how the model is performing. However interpreting these\nmeasures requires a bit of nuance. Model fitting is NOT optimized to minimize fit error /\nmaximize r-squared at all costs. To do so typically results in fitting a large number of peaks,\nin a way that overfits noise, and only artificially reduces error / maximizes r-squared.\n\nThe power spectrum model is therefore tuned to try and measure the aperiodic component\nand peaks in a parsimonious manner, and, fit the `right` model (meaning the right aperiodic\ncomponent and the right number of peaks) rather than the model with the lowest error.\n\nGiven this, while high error / low r-squared may indicate a poor model fit, very low\nerror / high r-squared may also indicate a power spectrum that is overfit, in particular\nin which the peak parameters from the model may reflect overfitting by fitting too many peaks.\n\nWe therefore recommend that, for a given dataset, initial explorations should involve\nchecking both cases in which model fit error is particularly large, as well as when it\nis particularly low. These explorations can be used to pick settings that are suitable\nfor running across a group. There are not universal settings that optimize this, and so\nit is left up to the user to choose settings appropriately to not under- or over-fit\nfor a given modality / dataset / application.\n\n\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "Reducing Overfitting\n--------------------\n\nIf the model appears to be overfitting (for example, fitting too many peaks to small bumps), try:\n\n- Setting a lower-bound bandwidth-limit, to exclude fitting very narrow peaks, that may be noise\n- Setting a maximum number of peaks that the algorithm may fit: `max_n_peaks`\n\n - If set, the algorithm will fit (up to) the `max_n_peaks` highest power peaks.\n- Setting a minimum absolute peak height: `min_peak_height`\n\n\n" + "## Reducing Overfitting\n\nIf the model appears to be overfitting (for example, fitting too many peaks to small bumps), try:\n\n- Setting a lower-bound bandwidth-limit, to exclude fitting very narrow peaks, that may be noise\n- Setting a maximum number of peaks that the algorithm may fit: `max_n_peaks`\n\n - If set, the algorithm will fit (up to) the `max_n_peaks` highest power peaks.\n- Setting a minimum absolute peak height: `min_peak_height`\n\n\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "Simulating Power Spectra\n------------------------\n\nFor this example, we will use simulated data. The FOOOF module includes utilities\nfor creating simulated power-spectra. To do so, we can use the :func:`~.gen_power_spectrum`\nfunction to simulate individual power spectra, following the power spectrum model.\n\nFirst, we will start by generating a noisy simulated power spectrum\n\n\n" + "## Simulating Power Spectra\n\nFor this example, we will use simulated data. The FOOOF module includes utilities\nfor creating simulated power-spectra. To do so, we can use the :func:`~.gen_power_spectrum`\nfunction to simulate individual power spectra, following the power spectrum model.\n\nFirst, we will start by generating a noisy simulated power spectrum\n\n\n" ] }, { @@ -126,14 +115,14 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Power Spectra with No Peaks\n~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nA known case in which the model can overfit is in power spectra in which no peaks are\npresent. In this case, the standard deviation can be very low, and so the relative\npeak height check (``min_peak_threshold``) is very liberal at keeping gaussian fits.\n\nIf you expect, or know, you have power spectra without peaks in your data,\nwe recommend using the ``min_peak_height`` setting. Otherwise, the model is unlikely to\nappropriately fit power spectra as having no peaks, since it uses only a relative\nthreshold if ``min_peak_height`` is set to zero (which is the default value).\nSetting ``min_peak_height`` requires checking the scale of your power spectra,\nallowing you to define an absolute threshold for extracting peaks.\n\n\n" + "### Power Spectra with No Peaks\n\nA known case in which the model can overfit is in power spectra in which no peaks are\npresent. In this case, the standard deviation can be very low, and so the relative\npeak height check (``min_peak_threshold``) is very liberal at keeping gaussian fits.\n\nIf you expect, or know, you have power spectra without peaks in your data,\nwe recommend using the ``min_peak_height`` setting. Otherwise, the model is unlikely to\nappropriately fit power spectra as having no peaks, since it uses only a relative\nthreshold if ``min_peak_height`` is set to zero (which is the default value).\nSetting ``min_peak_height`` requires checking the scale of your power spectra,\nallowing you to define an absolute threshold for extracting peaks.\n\n\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "Reducing Underfitting\n---------------------\n\nIf you are finding that the model is underfitting:\n\n- First check and perhaps loosen any restrictions from ``max_n_peaks`` and ``min_peak_height``\n- Try updating ``peak_threshold`` to a lower value\n- Bad fits may stem from issues with aperiodic component fitting\n\n - Double check that you are using the appropriate aperiodic mode\n\nNext we will simulate a much smoother power spectrum, and update settings accordingly.\n\n\n" + "## Reducing Underfitting\n\nIf you are finding that the model is underfitting:\n\n- First check and perhaps loosen any restrictions from ``max_n_peaks`` and ``min_peak_height``\n- Try updating ``peak_threshold`` to a lower value\n- Bad fits may stem from issues with aperiodic component fitting\n\n - Double check that you are using the appropriate aperiodic mode\n\nNext we will simulate a much smoother power spectrum, and update settings accordingly.\n\n\n" ] }, { @@ -173,14 +162,14 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Checking Fits Across a Group\n----------------------------\n\nSo far we have explored troubleshooting individual model fits. When starting\na new analysis, or working with a new dataset, we do recommend starting by\ntrying some individual fits like this.\n\nIf and when you move to using :class:`~fooof.FOOOFGroup` to fit groups of power spectra,\nthere are some slightly different ways to investigate groups of fits,\nwhich we'll step through now, using some simulated data.\n\n\n" + "## Checking Fits Across a Group\n\nSo far we have explored troubleshooting individual model fits. When starting\na new analysis, or working with a new dataset, we do recommend starting by\ntrying some individual fits like this.\n\nIf and when you move to using :class:`~fooof.FOOOFGroup` to fit groups of power spectra,\nthere are some slightly different ways to investigate groups of fits,\nwhich we'll step through now, using some simulated data.\n\n\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "Simulating a Group of Power Spectra\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nWe will continue using simulated data, this time simulating a group of power spectra.\n\nTo simulate a group of power spectra, we will use the :func:`~.gen_group_power_spectra`\nin combination with called :func:`~.param_sampler` that is used to sample across\npossible parameters.\n\nFor more and descriptions and example of how the simulations work, check out the\n`examples `_ section.\n\n\n" + "### Simulating a Group of Power Spectra\n\nWe will continue using simulated data, this time simulating a group of power spectra.\n\nTo simulate a group of power spectra, we will use the :func:`~.gen_group_power_spectra`\nin combination with called :func:`~.param_sampler` that is used to sample across\npossible parameters.\n\nFor more and descriptions and example of how the simulations work, check out the\n[examples](https://fooof-tools.github.io/fooof/auto_examples/index.html) section.\n\n\n" ] }, { @@ -296,7 +285,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Reporting Bad Fits\n------------------\n\nIf, after working through these suggestions, you are still getting bad fits, and/or\nare just not sure what is going on, please get in touch! We will hopefully be able to\nmake further recommendations, and this also serves as a way for us to investigate when\nand why model fitting fails, so that we can continue to make it better.\n\nYou can report issues on Github `here `.\n\nThere is also a helper method to print out instructions for reporting\nbad fits / bugs back to us, as demonstrated below.\n\n\n" + "## Reporting Bad Fits\n\nIf, after working through these suggestions, you are still getting bad fits, and/or\nare just not sure what is going on, please get in touch! We will hopefully be able to\nmake further recommendations, and this also serves as a way for us to investigate when\nand why model fitting fails, so that we can continue to make it better.\n\nYou can report issues on Github `here `.\n\nThere is also a helper method to print out instructions for reporting\nbad fits / bugs back to us, as demonstrated below.\n\n\n" ] }, { @@ -314,7 +303,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Conclusion\n----------\n\nWe have now stepped through the full work-flow of fitting power spectrum models, using\nFOOOF objects, picking settings, and troubleshooting model fits. In the next\nand final tutorial, we will introduce how to start analyzing FOOOF results.\n\n\n" + "## Conclusion\n\nWe have now stepped through the full work-flow of fitting power spectrum models, using\nFOOOF objects, picking settings, and troubleshooting model fits. In the next\nand final tutorial, we will introduce how to start analyzing FOOOF results.\n\n\n" ] } ], @@ -334,7 +323,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.8.5" + "version": "3.8.3" } }, "nbformat": 4, diff --git a/_downloads/3568949e3564dd4fdfa28ee35e994753/plot_IfYouFilterTheyWillCome.ipynb b/_downloads/3568949e3564dd4fdfa28ee35e994753/plot_IfYouFilterTheyWillCome.ipynb index 933f9008..19051d4d 100644 --- a/_downloads/3568949e3564dd4fdfa28ee35e994753/plot_IfYouFilterTheyWillCome.ipynb +++ b/_downloads/3568949e3564dd4fdfa28ee35e994753/plot_IfYouFilterTheyWillCome.ipynb @@ -1,28 +1,17 @@ { "cells": [ - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "collapsed": false - }, - "outputs": [], - "source": [ - "%matplotlib inline" - ] - }, { "cell_type": "markdown", "metadata": {}, "source": [ - "\nFinding 'Oscillations' With Filters\n===================================\n\nExamining the results of filtering aperiodic signals.\n" + "\n# Finding 'Oscillations' With Filters\n\nExamining the results of filtering aperiodic signals.\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "Filtering Signals\n-----------------\n\nA common component of many analyses of neural time series is to apply filters,\ntypically to try to extract information from frequency bands of interest.\n\nHowever, one thing to keep in mind is that signals with aperiodic activity\nwill always contain power at all frequencies. One of the corollaries of thinking\nof neural signals as containing aperiodic activity, is that there is always power\nwithin any arbitrarily defined frequency range. This power does not necessarily\nentail any periodic activity, but it can look like periodic activity when applying\ntransforms such as narrow-band filters.\n\nIn this notebook we will simulate purely aperiodic signals, and apply filters to\nthem, to explore these ideas.\n\n\n" + "## Filtering Signals\n\nA common component of many analyses of neural time series is to apply filters,\ntypically to try to extract information from frequency bands of interest.\n\nHowever, one thing to keep in mind is that signals with aperiodic activity\nwill always contain power at all frequencies. One of the corollaries of thinking\nof neural signals as containing aperiodic activity, is that there is always power\nwithin any arbitrarily defined frequency range. This power does not necessarily\nentail any periodic activity, but it can look like periodic activity when applying\ntransforms such as narrow-band filters.\n\nIn this notebook we will simulate purely aperiodic signals, and apply filters to\nthem, to explore these ideas.\n\n\n" ] }, { @@ -51,7 +40,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Simulating Data\n~~~~~~~~~~~~~~~\n\nWe will use simulated data for this example, to create some example aperiodic signals,\nthat we can then apply filters to. First, let's simulate some data.\n\n\n" + "### Simulating Data\n\nWe will use simulated data for this example, to create some example aperiodic signals,\nthat we can then apply filters to. First, let's simulate some data.\n\n\n" ] }, { @@ -91,7 +80,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Filtering Aperiodic Signals\n~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nNow that we have a simulated signal, let's filter it into each of our frequency bands.\n\nTo do so, we will loop across our band definitions, and plot the filtered version\nof the signal.\n\n\n" + "### Filtering Aperiodic Signals\n\nNow that we have a simulated signal, let's filter it into each of our frequency bands.\n\nTo do so, we will loop across our band definitions, and plot the filtered version\nof the signal.\n\n\n" ] }, { @@ -116,7 +105,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Observing Changes in Filtered Signals\n-------------------------------------\n\nNext, let's consider what it looks like if you filter a signal that contains\nchanges in the aperiodic activity.\n\nFor this example, we will simulate a signal, with an abrupt change in the aperiodic activity.\n\nWe will then filter this signal into narrow-band frequency ranges, to observe how\nchanges in aperiodic activity appear in filtered data.\n\n\n" + "## Observing Changes in Filtered Signals\n\nNext, let's consider what it looks like if you filter a signal that contains\nchanges in the aperiodic activity.\n\nFor this example, we will simulate a signal, with an abrupt change in the aperiodic activity.\n\nWe will then filter this signal into narrow-band frequency ranges, to observe how\nchanges in aperiodic activity appear in filtered data.\n\n\n" ] }, { @@ -188,7 +177,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Conclusions\n-----------\n\nHere we have seen that filtering signals to narrow band signals can return results\nthat reflect periodic activity and dynamics. We therefore suggest that\nnarrow band filtered signals should not be presumed to necessarily reflect periodic\nactivity. In order to ascertain whether narrow band frequency regions reflect\nperiodic and/or aperiodic activity and which aspects are changing in the data,\nadditional analyses, such as parameterizing neural power spectra, are recommended.\n\n\n" + "## Conclusions\n\nHere we have seen that filtering signals to narrow band signals can return results\nthat reflect periodic activity and dynamics. We therefore suggest that\nnarrow band filtered signals should not be presumed to necessarily reflect periodic\nactivity. In order to ascertain whether narrow band frequency regions reflect\nperiodic and/or aperiodic activity and which aspects are changing in the data,\nadditional analyses, such as parameterizing neural power spectra, are recommended.\n\n\n" ] } ], @@ -208,7 +197,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.8.5" + "version": "3.8.3" } }, "nbformat": 4, diff --git a/_downloads/3976940bb1b6dd60ba5a1510d70fd6aa/plot_BandRatios.ipynb b/_downloads/3976940bb1b6dd60ba5a1510d70fd6aa/plot_BandRatios.ipynb index 2651a9ee..672058a3 100644 --- a/_downloads/3976940bb1b6dd60ba5a1510d70fd6aa/plot_BandRatios.ipynb +++ b/_downloads/3976940bb1b6dd60ba5a1510d70fd6aa/plot_BandRatios.ipynb @@ -1,35 +1,24 @@ { "cells": [ - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "collapsed": false - }, - "outputs": [], - "source": [ - "%matplotlib inline" - ] - }, { "cell_type": "markdown", "metadata": {}, "source": [ - "\nBand Ratio Measures\n===================\n\nExploring how band ratio measures relate to periodic & aperiodic activity.\n" + "\n# Band Ratio Measures\n\nExploring how band ratio measures relate to periodic & aperiodic activity.\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "Introduction\n------------\n\nBand ratios measures are a relatively common measure, proposed to measure oscillatory,\nor periodic, activity.\n\nThey are typically calculated as:\n\n\\begin{align}BR = \\frac{avg(low band power)}{avg(high band power)}\\end{align}\n\nIn this notebook we will explore this measure in the context of conceptualizing\nneural power spectra as a combination of aperiodic and periodic activity.\n\n\n" + "## Introduction\n\nBand ratios measures are a relatively common measure, proposed to measure oscillatory,\nor periodic, activity.\n\nThey are typically calculated as:\n\n\\begin{align}BR = \\frac{avg(low band power)}{avg(high band power)}\\end{align}\n\nIn this notebook we will explore this measure in the context of conceptualizing\nneural power spectra as a combination of aperiodic and periodic activity.\n\n\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "Band Ratios Project\n~~~~~~~~~~~~~~~~~~~\n\nThis example offers a relatively quick demonstration of how band ratios measures\nrelate to periodic and aperiodic activity.\n\nWe have completed a full project investigating methodological properties of band\nratio measures, which is available\n`here `_.\n\n\n" + "### Band Ratios Project\n\nThis example offers a relatively quick demonstration of how band ratios measures\nrelate to periodic and aperiodic activity.\n\nWe have completed a full project investigating methodological properties of band\nratio measures, which is available\n[here](https://github.com/voytekresearch/BandRatios).\n\n\n" ] }, { @@ -40,7 +29,7 @@ }, "outputs": [], "source": [ - "# Import numpy and matplotlib\nimport numpy as np\nimport matplotlib.pyplot as plt\n\n# Import simulation, utility, and plotting tools\nfrom fooof.bands import Bands\nfrom fooof.utils import trim_spectrum\nfrom fooof.sim.gen import gen_power_spectrum\nfrom fooof.sim.utils import set_random_seed\nfrom fooof.plts.spectra import plot_spectrum_shading, plot_spectra_shading" + "# Import numpy and matplotlib\nimport numpy as np\nimport matplotlib.pyplot as plt\n\n# Import simulation, utility, and plotting tools\nfrom fooof.bands import Bands\nfrom fooof.utils import trim_spectrum\nfrom fooof.sim.gen import gen_power_spectrum\nfrom fooof.sim.utils import set_random_seed\nfrom fooof.plts.spectra import plot_spectra_shading" ] }, { @@ -58,7 +47,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Simulating Data\n~~~~~~~~~~~~~~~\n\nFor this example, we will use simulated data. Let's start by simulating a\na baseline power spectrum.\n\n\n" + "### Simulating Data\n\nFor this example, we will use simulated data. Let's start by simulating a\na baseline power spectrum.\n\n\n" ] }, { @@ -87,7 +76,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Calculating Band Ratios\n~~~~~~~~~~~~~~~~~~~~~~~\n\nBand ratio measures are a ratio of power between defined frequency bands.\n\nWe can now define a function we can use to calculate band ratio measures, and\napply it to our baseline power spectrum.\n\nFor this example, we will be using the theta / beta ratio, which is the\nmost commonly applied band ratio measure.\n\nNote that it doesn't matter exactly which ratio measure or which frequency band\ndefinitions we use, as the general properties demonstrated here generalize\nto different bands and ranges.\n\n\n" + "### Calculating Band Ratios\n\nBand ratio measures are a ratio of power between defined frequency bands.\n\nWe can now define a function we can use to calculate band ratio measures, and\napply it to our baseline power spectrum.\n\nFor this example, we will be using the theta / beta ratio, which is the\nmost commonly applied band ratio measure.\n\nNote that it doesn't matter exactly which ratio measure or which frequency band\ndefinitions we use, as the general properties demonstrated here generalize\nto different bands and ranges.\n\n\n" ] }, { @@ -109,7 +98,7 @@ }, "outputs": [], "source": [ - "# Plot the power spectrum, shading the frequency bands used for the ratio\nplot_spectrum_shading(freqs, powers, [bands.theta, bands.beta],\n color='black', shade_colors=shade_color,\n log_powers=True, linewidth=3.5)" + "# Plot the power spectrum, shading the frequency bands used for the ratio\nplot_spectra_shading(freqs, powers, [bands.theta, bands.beta],\n color='black', shade_colors=shade_color,\n log_powers=True, linewidth=3.5)" ] }, { @@ -127,7 +116,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Periodic Impacts on Band Ratio Measures\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nTypical investigations involving band ratios compare differences in band ratio measures\nwithin and between subjects. The typical interpretation of band ratio measures is that\nthey relate to the relative power between two bands.\n\nNext, lets simulate data that varies across different periodic parameters of the data, and\nsee how this changes our measured theta / beta ratio, as compared to our baseline\npower spectrum.\n\n\n" + "### Periodic Impacts on Band Ratio Measures\n\nTypical investigations involving band ratios compare differences in band ratio measures\nwithin and between subjects. The typical interpretation of band ratio measures is that\nthey relate to the relative power between two bands.\n\nNext, lets simulate data that varies across different periodic parameters of the data, and\nsee how this changes our measured theta / beta ratio, as compared to our baseline\npower spectrum.\n\n\n" ] }, { @@ -185,7 +174,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Aperiodic Impacts on Band Ratio Measures\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nNext, we can also examine if changes in aperiodic properties of the data can also\nimpact band ratio measures. We will explore changes in the aperiodic exponent, with\nand without overlying peaks.\n\nTo do so, we will use the same approach to simulating, comparing, and plotting\ndata as above (though note that the code to do so has been condensed in the\nnext section).\n\n\n" + "### Aperiodic Impacts on Band Ratio Measures\n\nNext, we can also examine if changes in aperiodic properties of the data can also\nimpact band ratio measures. We will explore changes in the aperiodic exponent, with\nand without overlying peaks.\n\nTo do so, we will use the same approach to simulating, comparing, and plotting\ndata as above (though note that the code to do so has been condensed in the\nnext section).\n\n\n" ] }, { @@ -221,7 +210,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Conclusion\n----------\n\nBand ratio measures are supposed to reflect the relative power of rhythmic neural activity.\n\nHowever, here we can see that band ratio measures are actually under-determined\nin that many different changes of both periodic and aperiodic parameters can affect\nband ratio measurements - including aperiodic changes when there is no periodic activity.\n\nFor this reason, we conclude that band-ratio measures, by themselves, are\nan insufficient measure of neural activity. We propose that approaches such as\nparameterizing power spectra are more specific for adjudicating what is changing\nin neural data.\n\nFor more investigation into band ratios, their methodological issues, applications to real\ndata, and a comparison to parameterizing power spectra, see the full project\n`here `_,\n\n\n" + "## Conclusion\n\nBand ratio measures are supposed to reflect the relative power of rhythmic neural activity.\n\nHowever, here we can see that band ratio measures are actually under-determined\nin that many different changes of both periodic and aperiodic parameters can affect\nband ratio measurements - including aperiodic changes when there is no periodic activity.\n\nFor this reason, we conclude that band-ratio measures, by themselves, are\nan insufficient measure of neural activity. We propose that approaches such as\nparameterizing power spectra are more specific for adjudicating what is changing\nin neural data.\n\nFor more investigation into band ratios, their methodological issues, applications to real\ndata, and a comparison to parameterizing power spectra, see the full project\n[here](https://github.com/voytekresearch/BandRatios),\n\n\n" ] } ], @@ -241,7 +230,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.8.5" + "version": "3.8.3" } }, "nbformat": 4, diff --git a/_downloads/3ec8e163e0123eaaf98ad9c1f5feb139/plot_02-FOOOF.ipynb b/_downloads/3ec8e163e0123eaaf98ad9c1f5feb139/plot_02-FOOOF.ipynb index 94c02fab..96ea07e6 100644 --- a/_downloads/3ec8e163e0123eaaf98ad9c1f5feb139/plot_02-FOOOF.ipynb +++ b/_downloads/3ec8e163e0123eaaf98ad9c1f5feb139/plot_02-FOOOF.ipynb @@ -1,21 +1,10 @@ { "cells": [ - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "collapsed": false - }, - "outputs": [], - "source": [ - "%matplotlib inline" - ] - }, { "cell_type": "markdown", "metadata": {}, "source": [ - "\n02: Fitting Power Spectrum Models\n=================================\n\nIntroduction to the module, beginning with the FOOOF object.\n" + "\n# 02: Fitting Power Spectrum Models\n\nIntroduction to the module, beginning with the FOOOF object.\n" ] }, { @@ -44,21 +33,21 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "FOOOF Object\n------------\n\nAt the core of the module is the :class:`~fooof.FOOOF` object, which holds relevant data\nand settings as attributes, and contains methods to run the algorithm to parameterize\nneural power spectra.\n\nThe organization and use of the model object is similar to scikit-learn:\n\n- A model object is initialized, with relevant settings\n- The model is used to fit the data\n- Results can be extracted from the object\n\n\n" + "## FOOOF Object\n\nAt the core of the module is the :class:`~fooof.FOOOF` object, which holds relevant data\nand settings as attributes, and contains methods to run the algorithm to parameterize\nneural power spectra.\n\nThe organization and use of the model object is similar to scikit-learn:\n\n- A model object is initialized, with relevant settings\n- The model is used to fit the data\n- Results can be extracted from the object\n\n\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "Calculating Power Spectra\n~~~~~~~~~~~~~~~~~~~~~~~~~\n\nThe :class:`~fooof.FOOOF` object fits models to power spectra. The module itself does not\ncompute power spectra. Computing power spectra needs to be done prior to using\nthe FOOOF module.\n\nThe model is broadly agnostic to exactly how power spectra are computed. Common\nmethods, such as Welch's method, can be used to compute the spectrum.\n\nIf you need a module in Python that has functionality for computing power spectra, try\n`NeuroDSP `_.\n\nNote that FOOOF objects require frequency and power values passed in as inputs to\nbe in linear spacing. Passing in non-linear spaced data (such logged values) may\nproduce erroneous results.\n\n\n" + "### Calculating Power Spectra\n\nThe :class:`~fooof.FOOOF` object fits models to power spectra. The module itself does not\ncompute power spectra. Computing power spectra needs to be done prior to using\nthe FOOOF module.\n\nThe model is broadly agnostic to exactly how power spectra are computed. Common\nmethods, such as Welch's method, can be used to compute the spectrum.\n\nIf you need a module in Python that has functionality for computing power spectra, try\n[NeuroDSP](https://neurodsp-tools.github.io/neurodsp/).\n\nNote that FOOOF objects require frequency and power values passed in as inputs to\nbe in linear spacing. Passing in non-linear spaced data (such logged values) may\nproduce erroneous results.\n\n\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "Fitting an Example Power Spectrum\n---------------------------------\n\nThe following example demonstrates fitting a power spectrum model to a single power spectrum.\n\n\n" + "## Fitting an Example Power Spectrum\n\nThe following example demonstrates fitting a power spectrum model to a single power spectrum.\n\n\n" ] }, { @@ -76,7 +65,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Fitting Models with 'Report'\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nThe above method 'report', is a convenience method that calls a series of methods:\n\n- :meth:`~fooof.FOOOF.fit`: fits the power spectrum model\n- :meth:`~fooof.FOOOF.print_results`: prints out the results\n- :meth:`~fooof.FOOOF.plot`: plots the data and model fit\n\nEach of these methods can also be called individually.\n\n\n" + "### Fitting Models with 'Report'\n\nThe above method 'report', is a convenience method that calls a series of methods:\n\n- :meth:`~fooof.FOOOF.fit`: fits the power spectrum model\n- :meth:`~fooof.FOOOF.print_results`: prints out the results\n- :meth:`~fooof.FOOOF.plot`: plots the data and model fit\n\nEach of these methods can also be called individually.\n\n\n" ] }, { @@ -94,7 +83,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Model Parameters\n~~~~~~~~~~~~~~~~\n\nOnce the power spectrum model has been calculated, the model fit parameters are stored\nas object attributes that can be accessed after fitting.\n\nFollowing scikit-learn conventions, attributes that are fit as a result of\nthe model have a trailing underscore, for example:\n\n- ``aperiodic_params_``\n- ``peak_params_``\n- ``error_``\n- ``r2_``\n- ``n_peaks_``\n\n\n" + "### Model Parameters\n\nOnce the power spectrum model has been calculated, the model fit parameters are stored\nas object attributes that can be accessed after fitting.\n\nFollowing scikit-learn conventions, attributes that are fit as a result of\nthe model have a trailing underscore, for example:\n\n- ``aperiodic_params_``\n- ``peak_params_``\n- ``error_``\n- ``r2_``\n- ``n_peaks_``\n\n\n" ] }, { @@ -119,7 +108,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Selecting Parameters\n~~~~~~~~~~~~~~~~~~~~\n\nYou can also select parameters using the :meth:`~fooof.FOOOF.get_params`\nmethod, which can be used to specify which parameters you want to extract.\n\n\n" + "### Selecting Parameters\n\nYou can also select parameters using the :meth:`~fooof.FOOOF.get_params`\nmethod, which can be used to specify which parameters you want to extract.\n\n\n" ] }, { @@ -144,7 +133,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Notes on Interpreting Peak Parameters\n-------------------------------------\n\nPeak parameters are labeled as:\n\n- CF: center frequency of the extracted peak\n- PW: power of the peak, over and above the aperiodic component\n- BW: bandwidth of the extracted peak\n\nNote that the peak parameters that are returned are not exactly the same as the\nparameters of the Gaussians used internally to fit the peaks.\n\nSpecifically:\n\n- CF is the exact same as mean parameter of the Gaussian\n- PW is the height of the model fit above the aperiodic component [1],\n which is not necessarily the same as the Gaussian height\n- BW is 2 * the standard deviation of the Gaussian [2]\n\n[1] Since the Gaussians are fit together, if any Gaussians overlap,\nthan the actual height of the fit at a given point can only be assessed\nwhen considering all Gaussians. To be better able to interpret heights\nfor individual peaks, we re-define the peak height as above, and label it\nas 'power', as the units of the input data are expected to be units of power.\n\n[2] Gaussian standard deviation is '1 sided', where as the returned BW is '2 sided'.\n\n\n" + "## Notes on Interpreting Peak Parameters\n\nPeak parameters are labeled as:\n\n- CF: center frequency of the extracted peak\n- PW: power of the peak, over and above the aperiodic component\n- BW: bandwidth of the extracted peak\n\nNote that the peak parameters that are returned are not exactly the same as the\nparameters of the Gaussians used internally to fit the peaks.\n\nSpecifically:\n\n- CF is the exact same as mean parameter of the Gaussian\n- PW is the height of the model fit above the aperiodic component [1],\n which is not necessarily the same as the Gaussian height\n- BW is 2 * the standard deviation of the Gaussian [2]\n\n[1] Since the Gaussians are fit together, if any Gaussians overlap,\nthan the actual height of the fit at a given point can only be assessed\nwhen considering all Gaussians. To be better able to interpret heights\nfor individual peaks, we re-define the peak height as above, and label it\nas 'power', as the units of the input data are expected to be units of power.\n\n[2] Gaussian standard deviation is '1 sided', where as the returned BW is '2 sided'.\n\n\n" ] }, { @@ -169,7 +158,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "FOOOFResults\n~~~~~~~~~~~~\n\nThere is also a convenience method to return all model fit results:\n:func:`~fooof.FOOOF.get_results`.\n\nThis method returns all the model fit parameters, including the underlying Gaussian\nparameters, collected together into a FOOOFResults object.\n\nThe FOOOFResults object, which in Python terms is a named tuple, is a standard data\nobject used with FOOOF to organize and collect parameter data.\n\n\n" + "### FOOOFResults\n\nThere is also a convenience method to return all model fit results:\n:func:`~fooof.FOOOF.get_results`.\n\nThis method returns all the model fit parameters, including the underlying Gaussian\nparameters, collected together into a FOOOFResults object.\n\nThe FOOOFResults object, which in Python terms is a named tuple, is a standard data\nobject used with FOOOF to organize and collect parameter data.\n\n\n" ] }, { @@ -198,7 +187,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Conclusion\n----------\n\nIn this tutorial, we have explored the basics of the :class:`~fooof.FOOOF` object,\nfitting power spectrum models, and extracting parameters.\n\nIn the next tutorial, we will explore how this algorithm actually works to fit the model.\n\n\n" + "## Conclusion\n\nIn this tutorial, we have explored the basics of the :class:`~fooof.FOOOF` object,\nfitting power spectrum models, and extracting parameters.\n\nIn the next tutorial, we will explore how this algorithm actually works to fit the model.\n\n\n" ] } ], @@ -218,7 +207,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.8.5" + "version": "3.8.3" } }, "nbformat": 4, diff --git a/_downloads/3f6c1c3c444799e38b8295c41ccb69c4/plot_line_noise.ipynb b/_downloads/3f6c1c3c444799e38b8295c41ccb69c4/plot_line_noise.ipynb new file mode 100644 index 00000000..9bb830cb --- /dev/null +++ b/_downloads/3f6c1c3c444799e38b8295c41ccb69c4/plot_line_noise.ipynb @@ -0,0 +1,242 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n# Dealing with Line Noise\n\nThis example covers strategies for dealing with line noise.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Import the spectral parameterization object and utilities\nfrom fooof import FOOOF\nfrom fooof.plts import plot_spectra\nfrom fooof.utils import trim_spectrum, interpolate_spectrum\n\n# Import simulation functions to create some example data\nfrom fooof.sim.gen import gen_power_spectrum\n\n# Import NeuroDSP functions for simulating & processing time series\nfrom neurodsp.sim import sim_combined\nfrom neurodsp.filt import filter_signal\nfrom neurodsp.spectral import compute_spectrum" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Line Noise Peaks\n\nNeural recordings typically have power line artifacts, at either 50 or 60 Hz, depending on\nwhere the data were collected, which can impact spectral parameterization.\n\nIn this example, we explore some options for dealing with line noise artifacts.\n\n### Interpolating Line Noise Peaks\n\nOne approach is to interpolate away line noise peaks, in the frequency domain. This\napproach simply gets rid of the peaks, interpolating the data to maintain the 1/f\ncharacter of the data, allowing for subsequent fitting.\n\nThe :func:`~fooof.utils.interpolate_spectrum` function allows for doing simple\ninterpolation. Given a narrow frequency region, this function interpolates the spectrum,\nsuch that the 'peak' of the line noise is removed.\n\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Generate an example power spectrum, with line noise\nfreqs1, powers1 = gen_power_spectrum([3, 75], [1, 1],\n [[10, 0.75, 2], [60, 1, 0.5]])\n\n# Visualize the generated power spectrum\nplot_spectra(freqs1, powers1, log_powers=True)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "In the plot above, we have an example spectrum, with some power line noise.\n\nTo prepare this data for fitting, we can interpolate away the line noise region.\n\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Interpolate away the line noise region\ninterp_range = [58, 62]\nfreqs_int1, powers_int1 = interpolate_spectrum(freqs1, powers1, interp_range)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Plot the spectra for the power spectra before and after interpolation\nplot_spectra(freqs1, [powers1, powers_int1], log_powers=True,\n labels=['Original Spectrum', 'Interpolated Spectrum'])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "As we can see in the above, the interpolation removed the peak from the data.\n\nWe can now go ahead and parameterize the spectrum.\n\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Initialize a power spectrum model\nfm1 = FOOOF(verbose=False)\nfm1.report(freqs_int1, powers_int1)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Multiple Interpolation Regions\n\nLine noise artifacts often also display harmonics, such that when analyzing broader\nfrequency ranges, there may be multiple peaks that need to be interpolated.\n\nThis can be done by passing in multiple interpolation regions to\n:func:`~fooof.utils.interpolate_spectrum`, which we will do in the next example.\n\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Generate an example power spectrum, with line noise & harmonics\nfreqs2, powers2 = gen_power_spectrum([1, 150], [1, 500, 1.5],\n [[10, 0.5, 2], [60, 0.75, 0.5], [120, 0.5, 0.5]])\n\n# Interpolate away the line noise region & harmonics\ninterp_ranges = [[58, 62], [118, 122]]\nfreqs_int2, powers_int2 = interpolate_spectrum(freqs2, powers2, interp_ranges)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Plot the power spectrum before and after interpolation\nplot_spectra(freqs2, [powers2, powers_int2], log_powers=True,\n labels=['Original Spectrum', 'Interpolated Spectrum'])" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Parameterize the interpolated power spectrum\nfm2 = FOOOF(aperiodic_mode='knee', verbose=False)\nfm2.report(freqs2, powers_int2)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Fitting Line Noise as Peaks\n\nIn some cases, you may also be able to simply allow the parameterization to peaks to the\nline noise and harmonics. By simply fitting the line noise as peaks, the model can deal\nwith the peaks in order to accurately fit the aperiodic component.\n\nThese peaks are of course not to be analyzed, but once the model has been fit, you can\nsimply ignore them. There should generally be no issue with fitting and having them in\nthe model, and allowing the model to account for these peaks typically helps the model\nbetter fit the rest of the data.\n\nBelow we can see that the model does indeed work when fitting data with line noise peaks.\n\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Fit power spectrum models to original spectra\nfm1.report(freqs1, powers1)\nfm2.report(freqs2, powers2)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### The Problem with Bandstop Filtering\n\nA common approach for getting rid of line noise activity is to use bandstop filtering to\nremove activity at the line noise frequencies. Such a filter effectively set the power\nof these frequencies to be approximately zero.\n\nUnfortunately, this doesn't work very well with spectral parameterization, since the\nparameterization algorithm tries to fit each power value as either part of the aperiodic\ncomponent, or as an overlying peak. Frequencies that have filtered out are neither, and\nthe model has trouble, as it and has no concept of power values below the aperiodic component.\n\nIn practice, this means that the \"missing\" power will impact the fit, and pull down the\naperiodic component. One way to think of this is that the power spectrum model can deal with,\nand even expects, 'positive outliers' above the aperiodic (these are considered 'peaks'), but\nnot 'negative outliers', or values below the aperiodic, as there is no expectation of this\nhappening in the model.\n\nIn the following example, we can see how bandstop filtering negatively impacts fitting.\nBecause of this, for the purposes of spectral parameterization, bandstop filters are not\nrecommended as a way to remove line noise.\n\nNote that if one has already applied a bandstop filter, then you can still\napply the interpolation from above.\n\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# General settings for the simulation\nn_seconds = 30\nfs = 1000\n\n# Define the settings for the simulated signal\ncomponents = {'sim_powerlaw' : {'exponent' : -1.5},\n 'sim_oscillation' : [{'freq' : 10}, {'freq' : 60}]}\ncomp_vars = [0.5, 1, 1]\n\n# Simulate a time series\nsig = sim_combined(n_seconds, fs, components, comp_vars)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Bandstop filter the signal to remove line noise frequencies\nsig_filt = filter_signal(sig, fs, 'bandstop', (57, 63),\n n_seconds=2, remove_edges=False)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Compute a power spectrum of the simulated signal\nfreqs, powers_pre = trim_spectrum(*compute_spectrum(sig, fs), [3, 75])\nfreqs, powers_post = trim_spectrum(*compute_spectrum(sig_filt, fs), [3, 75])" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Plot the spectrum of the data, pre and post bandstop filtering\nplot_spectra(freqs, [powers_pre, powers_post], log_powers=True,\n labels=['Pre-Filter', 'Post-Filter'])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "In the above, we can see that the the bandstop filter removes power in the filtered range,\nleaving a \"dip\" in the power spectrum. This dip causes issues with subsequent fitting.\n\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Initialize and fit a power spectrum model\nfm = FOOOF()\nfm.report(freqs, powers_post)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "In order to try and capture the data points in the \"dip\", the power spectrum model\ngets 'pulled' down, leading to an inaccurate fit of the aperiodic component. This is\nwhy fitting frequency regions that included frequency regions that have been filtered\nout is not recommended.\n\n\n" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.8.3" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} \ No newline at end of file diff --git a/_downloads/465ac0a8386b0d63e3782a905f87cd0c/plot_data_components.py b/_downloads/465ac0a8386b0d63e3782a905f87cd0c/plot_data_components.py new file mode 100644 index 00000000..ba0e72c4 --- /dev/null +++ b/_downloads/465ac0a8386b0d63e3782a905f87cd0c/plot_data_components.py @@ -0,0 +1,213 @@ +""" +Exploring Data Components +========================= + +This example explores the different data components, exploring the isolated aperiodic +and periodic components as they are extracted from the data. +""" + +################################################################################################### + +# sphinx_gallery_thumbnail_number = 3 + +# Import FOOOF model objects +from fooof import FOOOF, FOOOFGroup + +# Import function to plot power spectra +from fooof.plts.spectra import plot_spectra + +# Import simulation functions to create some example data +from fooof.sim import gen_power_spectrum, gen_group_power_spectra + +################################################################################################### + +# Simulate example power spectrum +freqs, powers = gen_power_spectrum([1, 50], [0, 10, 1], [10, 0.25, 2], freq_res=0.25) + +# Initialize model object and fit power spectrum +fm = FOOOF() +fm.fit(freqs, powers) + +################################################################################################### +# Data & Model Components +# ----------------------- +# +# The model fit process includes procedures for isolating aperiodic and periodic components in +# the data, fitting each of these components separately, and then combining the model components +# as the final fit (see the Tutorials for further details on these procedures). +# +# In doing this process, the model fit procedure computes and stores isolated data components, +# which are available in the model. +# + +################################################################################################### +# Full Data & Model Components +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# Before diving into the isolated data components, let's check 'full' components, including +# the data (`power_spectrum`) and full model fit of a model object (`fooofed_spectrum`). +# + +################################################################################################### + +# Plot the original power spectrum data from the object +plot_spectra(fm.freqs, fm.power_spectrum, color='black') + +################################################################################################### + +# Plot the power spectrum model from the object +plot_spectra(fm.freqs, fm.fooofed_spectrum_, color='red') + +################################################################################################### +# Isolated Components +# ------------------- +# +# As well as the 'full' data & model components above, the model fitting procedure includes +# steps that result in isolated periodic and aperiodic components, in both the +# data and model. These isolated components are stored internally in the model. +# +# To access these components, we can use the following `getter` methods: +# +# - :meth:`~fooof.FOOOF.get_data`: allows for accessing data components +# - :meth:`~fooof.FOOOF.get_model`: allows for accessing model components +# + +################################################################################################### +# Aperiodic Component +# ~~~~~~~~~~~~~~~~~~~ +# +# To fit the aperiodic component, the model fit procedure includes a peak removal process. +# +# The resulting 'peak-removed' data component is stored in the model object, as well as the +# isolated aperiodic component model fit. +# + +################################################################################################### + +# Plot the peak removed spectrum data component +plot_spectra(fm.freqs, fm.get_data('aperiodic'), color='black') + +################################################################################################### + +# Plot the peak removed spectrum, with the model aperiodic fit +plot_spectra(fm.freqs, [fm.get_data('aperiodic'), fm.get_model('aperiodic')], + colors=['black', 'blue'], linestyle=['-', '--']) + +################################################################################################### +# Periodic Component +# ~~~~~~~~~~~~~~~~~~ +# +# To fit the periodic component, the model fit procedure removes the fit peaks from the power +# spectrum. +# +# The resulting 'flattened' data component is stored in the model object, as well as the +# isolated periodic component model fit. +# + +################################################################################################### + +# Plot the flattened spectrum data component +plot_spectra(fm.freqs, fm.get_data('peak'), color='black') + +################################################################################################### + +# Plot the flattened spectrum data with the model peak fit +plot_spectra(fm.freqs, [fm.get_data('peak'), fm.get_model('peak')], + colors=['black', 'green'], linestyle=['-', '--']) + +################################################################################################### +# Full Model Fit +# ~~~~~~~~~~~~~~ +# +# The full model fit, which we explored earlier, is calculated as the combination of the +# aperiodic and peak fit, which we can check by plotting these combined components. +# + +################################################################################################### + +# Plot the full model fit, as the combination of the aperiodic and peak model components +plot_spectra(fm.freqs, [fm.get_model('aperiodic') + fm.get_model('peak')], color='red') + +################################################################################################### +# Linear vs Log Spacing +# --------------------- +# +# The above shows data components as they are available on the model object, and used in +# the fitting process - notable, in log10 spacing. +# +# Some analyses may aim to use these isolated components to compute certain measures of +# interest on the data. However, when doing so, one may often want the linear power +# representations of these components. +# +# Both the `get_data` and `get_model` methods accept a 'space' argument, whereby the user +# can specify whether the return the components in log10 or linear spacing. + + + +################################################################################################### +# Aperiodic Components in Linear Space +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# First we can examine the aperiodic data & model components, in linear space. +# + +################################################################################################### + +# Plot the peak removed spectrum, with the model aperiodic fit +plot_spectra(fm.freqs, [fm.get_data('aperiodic', 'linear'), fm.get_model('aperiodic', 'linear')], + colors=['black', 'blue'], linestyle=['-', '--']) + +################################################################################################### +# Peak Component in Linear Space +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# Next, we can examine the peak data & model components, in linear space. +# + +################################################################################################### + +# Plot the flattened spectrum data with the model peak fit +plot_spectra(fm.freqs, [fm.get_data('peak', 'linear'), fm.get_model('peak', 'linear')], + colors=['black', 'green'], linestyle=['-', '--']) + +################################################################################################### +# Linear Space Additive Model +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# Note that specifying 'linear' does not simply unlog the data components to return them +# in linear space, but instead defines the space of the additive data definition such that +# `power_spectrum = aperiodic_component + peak_component` (for data and/or model). +# +# We can see this by plotting the linear space data (or model) with the corresponding +# aperiodic and periodic components summed together. Note that if you simply unlog +# the components and sum them, they does not add up to reflecting the full data / model. +# + +################################################################################################### + +# Plot the linear data, showing the combination of peak + aperiodic matches the full data +plot_spectra(fm.freqs, + [fm.get_data('full', 'linear'), + fm.get_data('aperiodic', 'linear') + fm.get_data('peak', 'linear')], + linestyle=['-', 'dashed'], colors=['black', 'red'], alpha=[0.3, 0.75]) + +################################################################################################### + +# Plot the linear model, showing the combination of peak + aperiodic matches the full model +plot_spectra(fm.freqs, + [fm.get_model('full', 'linear'), + fm.get_model('aperiodic', 'linear') + fm.get_model('peak', 'linear')], + linestyle=['-', 'dashed'], colors=['black', 'red'], alpha=[0.3, 0.75]) + +################################################################################################### +# Notes on Analyzing Data & Model Components +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# The functionality here allows for accessing the model components in log space (as used by +# the model for fitting), as well as recomputing in linear space. +# +# If you are aiming to analyze these components, it is important to consider which version of +# the data you should analyze for the question at hand, as there are key differences to the +# different representations. Users who wish to do so post-hoc analyses of these data and model +# components should consider the benefits and limitations the different representations. +# diff --git a/_downloads/497d4dce8b3da6f065bfbc52f5bce2f8/plot_fit_fooof_3d.ipynb b/_downloads/497d4dce8b3da6f065bfbc52f5bce2f8/plot_fit_fooof_3d.ipynb index 8e81dce1..10f65955 100644 --- a/_downloads/497d4dce8b3da6f065bfbc52f5bce2f8/plot_fit_fooof_3d.ipynb +++ b/_downloads/497d4dce8b3da6f065bfbc52f5bce2f8/plot_fit_fooof_3d.ipynb @@ -1,35 +1,24 @@ { "cells": [ - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "collapsed": false - }, - "outputs": [], - "source": [ - "%matplotlib inline" - ] - }, { "cell_type": "markdown", "metadata": {}, "source": [ - "\nFitting Power Spectrum Models Across 3D Arrays\n==============================================\n\nFitting power spectrum models across 3D arrays of power spectra.\n" + "\n# Fitting Power Spectrum Models Across 3D Arrays\n\nFitting power spectrum models across 3D arrays of power spectra.\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "Running Across 3D\n-----------------\n\nMost of the materials so far have explored using the :class:`~fooof.FOOOF` object to fit\nindividual power spectra, and the :class:`~fooof.FOOOFGroup` object for fitting groups of\npower spectra, where a group of spectra is organized as a 2D array of power spectra.\n\nIn this example, we'll go one step further, and step through how to analyze data\norganized into 3D arrays.\n\n\n" + "## Running Across 3D\n\nMost of the materials so far have explored using the :class:`~fooof.FOOOF` object to fit\nindividual power spectra, and the :class:`~fooof.FOOOFGroup` object for fitting groups of\npower spectra, where a group of spectra is organized as a 2D array of power spectra.\n\nIn this example, we'll go one step further, and step through how to analyze data\norganized into 3D arrays.\n\n\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "Organizing Data into 3D Objects\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nElectrophysiological data typically has multiple dimensions including, for example,\nthe number of subjects, the number of channels and/or recording regions, the number\nof conditions, and/or the number of trials.\n\nThis often means that we organize our data into multi-dimensional arrays.\n\nSo, for example, a 3D array of power spectra could reflect:\n\n- power spectra across task conditions, as [n_conditions, n_channels, n_freqs]\n- power spectra across data epochs within subjects, as [n_epochs, n_channels, n_freqs]\n- power spectra across a group of subjects, as [n_subjects, n_channels, n_freqs]\n- power spectra across regions, as [n_regions, n_channels, n_freqs]\n\nIf you do have data that is or can be organized into 3D arrays, here we will\nexplore how to fit, manage, and organize this data.\n\nA reminder that no matter how the data is organized, it's always the exact same model\nthat is fit, that is the one defined in the FOOOF object. All other objects or organizations\nuse this same code to do the fitting. For example, the FOOOFGroup object inherits from the\nFOOOF, and calls the same underlying fit function.\n\nAs we'll see, we can fit 3D arrays of spectra by distributing FOOOFGroup objects\nacross the data, which also uses the same underlying code.\n\n\n" + "### Organizing Data into 3D Objects\n\nElectrophysiological data typically has multiple dimensions including, for example,\nthe number of subjects, the number of channels and/or recording regions, the number\nof conditions, and/or the number of trials.\n\nThis often means that we organize our data into multi-dimensional arrays.\n\nSo, for example, a 3D array of power spectra could reflect:\n\n- power spectra across task conditions, as [n_conditions, n_channels, n_freqs]\n- power spectra across data epochs within subjects, as [n_epochs, n_channels, n_freqs]\n- power spectra across a group of subjects, as [n_subjects, n_channels, n_freqs]\n- power spectra across regions, as [n_regions, n_channels, n_freqs]\n\nIf you do have data that is or can be organized into 3D arrays, here we will\nexplore how to fit, manage, and organize this data.\n\nA reminder that no matter how the data is organized, it's always the exact same model\nthat is fit, that is the one defined in the FOOOF object. All other objects or organizations\nuse this same code to do the fitting. For example, the FOOOFGroup object inherits from the\nFOOOF, and calls the same underlying fit function.\n\nAs we'll see, we can fit 3D arrays of spectra by distributing FOOOFGroup objects\nacross the data, which also uses the same underlying code.\n\n\n" ] }, { @@ -47,7 +36,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Example Set-Up\n--------------\n\nFor this example, lets imagine we have set up an experiment in which we have recorded\ndata across several different 'conditions', from multiple 'channels'.\n\nWhen managing our time series, we might organize this data as something like:\n[n_conditions, n_channels, n_times]\n\nAfter calculating power spectra, this would become a 3D array of:\n[n_conditions, n_channels, n_freqs]\n\nFor this example, we will use simulated data to explore this example case.\n\nFirst, we'll set up the simulations to create some data.\n\n\n" + "## Example Set-Up\n\nFor this example, lets imagine we have set up an experiment in which we have recorded\ndata across several different 'conditions', from multiple 'channels'.\n\nWhen managing our time series, we might organize this data as something like:\n[n_conditions, n_channels, n_times]\n\nAfter calculating power spectra, this would become a 3D array of:\n[n_conditions, n_channels, n_freqs]\n\nFor this example, we will use simulated data to explore this example case.\n\nFirst, we'll set up the simulations to create some data.\n\n\n" ] }, { @@ -87,14 +76,14 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Fitting Multiple Power Spectra\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nThe goal, for fitting all these power spectra, is to apply our power spectrum model\nefficiently across all power spectra, while keeping our data and results organized\nin a way that we keep track of which model results reflect which data.\n\nThe strategy we will take to do so is by systematically applying FOOOF objects across\nthe data.\n\nFor working with 3D arrays of power spectra, we have the :func:`~.fit_fooof_3d`\nfunction which takes in data and a pre-initialized model object, and uses it to fit\npower spectrum models across all the data, while maintaining the organization of\nthe input data.\n\n\n" + "### Fitting Multiple Power Spectra\n\nThe goal, for fitting all these power spectra, is to apply our power spectrum model\nefficiently across all power spectra, while keeping our data and results organized\nin a way that we keep track of which model results reflect which data.\n\nThe strategy we will take to do so is by systematically applying FOOOF objects across\nthe data.\n\nFor working with 3D arrays of power spectra, we have the :func:`~.fit_fooof_3d`\nfunction which takes in data and a pre-initialized model object, and uses it to fit\npower spectrum models across all the data, while maintaining the organization of\nthe input data.\n\n\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "fit_fooof_3d\n~~~~~~~~~~~~\n\nMore specifically, :func:`~.fit_fooof_3d` takes in:\n\n- a FOOOFGroup object, pre-initialized with the desired settings\n- an array of frequency values and a 3D array of power spectra\n\nInternally, this function uses the :class:`~fooof.FOOOFGroup` object to\nfit models across the power spectra.\n\nThis function then returns a list of :class:`~fooof.FOOOFGroup` objects, which\ncollectively store all the model fit results.\n\n\n" + "### fit_fooof_3d\n\nMore specifically, :func:`~.fit_fooof_3d` takes in:\n\n- a FOOOFGroup object, pre-initialized with the desired settings\n- an array of frequency values and a 3D array of power spectra\n\nInternally, this function uses the :class:`~fooof.FOOOFGroup` object to\nfit models across the power spectra.\n\nThis function then returns a list of :class:`~fooof.FOOOFGroup` objects, which\ncollectively store all the model fit results.\n\n\n" ] }, { @@ -152,7 +141,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Analyzing FOOOF Objects\n~~~~~~~~~~~~~~~~~~~~~~~\n\nOnce you have fit the power spectrum models, you want to analyze the results in some way!\n\nSince you have a collection of :class:`~fooof.FOOOF` objects, you can analyze these the same\nway as you would look into any other FOOOF objects. You can check out the other examples\nand tutorials for more information on how to do this.\n\nA general strategy for analyzing model fit results as they get returned from\n:func:`~.fit_fooof_3d` is to loop across all the objects in the\nreturned list, and then within the loop you can collect and/or analyze and/or plot\nany data of interest.\n\nFor a simple example analysis here, we can investigate if there appears to be a\ndifference in aperiodic exponent between different conditions.\n\n\n" + "### Analyzing FOOOF Objects\n\nOnce you have fit the power spectrum models, you want to analyze the results in some way!\n\nSince you have a collection of :class:`~fooof.FOOOF` objects, you can analyze these the same\nway as you would look into any other FOOOF objects. You can check out the other examples\nand tutorials for more information on how to do this.\n\nA general strategy for analyzing model fit results as they get returned from\n:func:`~.fit_fooof_3d` is to loop across all the objects in the\nreturned list, and then within the loop you can collect and/or analyze and/or plot\nany data of interest.\n\nFor a simple example analysis here, we can investigate if there appears to be a\ndifference in aperiodic exponent between different conditions.\n\n\n" ] }, { @@ -170,7 +159,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Managing FOOOF Objects\n~~~~~~~~~~~~~~~~~~~~~~\n\nWhen running analyses like this, you may start to have many :class:`~fooof.FOOOF` objects.\n\nFor example, you may want to save them out, reload them as needed, and analyze\nresults from each :class:`~fooof.FOOOF` or :class:`~fooof.FOOOFGroup` object.\nYou may also manipulate the objects by, for example, combining model results\nacross objects to check overall model fit properties.\n\nHere, we will continue with a quick example of saving, loading and then combining\nFOOOF objects. Note that a broader exploration of managing different FOOOF objects\nand these object utility functions is available in other examples.\n\n\n" + "### Managing FOOOF Objects\n\nWhen running analyses like this, you may start to have many :class:`~fooof.FOOOF` objects.\n\nFor example, you may want to save them out, reload them as needed, and analyze\nresults from each :class:`~fooof.FOOOF` or :class:`~fooof.FOOOFGroup` object.\nYou may also manipulate the objects by, for example, combining model results\nacross objects to check overall model fit properties.\n\nHere, we will continue with a quick example of saving, loading and then combining\nFOOOF objects. Note that a broader exploration of managing different FOOOF objects\nand these object utility functions is available in other examples.\n\n\n" ] }, { @@ -223,7 +212,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.8.5" + "version": "3.8.3" } }, "nbformat": 4, diff --git a/_downloads/4c23cdca0dc3598148c67ed23a512c59/plot_power_spectra.py b/_downloads/4c23cdca0dc3598148c67ed23a512c59/plot_power_spectra.py index f994c16e..abc8945b 100644 --- a/_downloads/4c23cdca0dc3598148c67ed23a512c59/plot_power_spectra.py +++ b/_downloads/4c23cdca0dc3598148c67ed23a512c59/plot_power_spectra.py @@ -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 @@ -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 @@ -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 @@ -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`. @@ -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) ################################################################################################### @@ -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, - color='black', linewidth=3, label='10 Hz Alpha', ax=ax) +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'}); diff --git a/_downloads/4e94c842ccdf42fd38a1b8dda5e2d2fb/plot_failed_fits.ipynb b/_downloads/4e94c842ccdf42fd38a1b8dda5e2d2fb/plot_failed_fits.ipynb index c17e2d16..43b61402 100644 --- a/_downloads/4e94c842ccdf42fd38a1b8dda5e2d2fb/plot_failed_fits.ipynb +++ b/_downloads/4e94c842ccdf42fd38a1b8dda5e2d2fb/plot_failed_fits.ipynb @@ -1,21 +1,10 @@ { "cells": [ - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "collapsed": false - }, - "outputs": [], - "source": [ - "%matplotlib inline" - ] - }, { "cell_type": "markdown", "metadata": {}, "source": [ - "\nFailed Model Fits\n=================\n\nExample of model fit failures and how to debug them.\n" + "\n# Failed Model Fits\n\nExample of model fit failures and how to debug them.\n" ] }, { @@ -33,7 +22,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Model Fit Failures\n------------------\n\nThe power spectrum model is not guaranteed to fit - sometimes the fit procedure can fail.\n\nModel fit failures are rare, and they typically only happen on spectra that are\nparticular noisy, and/or are some kind of outlier for which the fitting procedure\nfails to find a good model solution.\n\nIn general, model fit failures should lead to a clean exit, meaning that\na failed model fit does not lead to a code error. The failed fit will be encoded in\nthe results as a null model, and the code can continue onwards.\n\nIn this example, we will look through what it looks like when model fits fail.\n\n\n" + "## Model Fit Failures\n\nThe power spectrum model is not guaranteed to fit - sometimes the fit procedure can fail.\n\nModel fit failures are rare, and they typically only happen on spectra that are\nparticular noisy, and/or are some kind of outlier for which the fitting procedure\nfails to find a good model solution.\n\nIn general, model fit failures should lead to a clean exit, meaning that\na failed model fit does not lead to a code error. The failed fit will be encoded in\nthe results as a null model, and the code can continue onwards.\n\nIn this example, we will look through what it looks like when model fits fail.\n\n\n" ] }, { @@ -91,7 +80,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Inducing Model Fit Failures\n~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nSo far, we have no model failures (as is typical).\n\nFor this example, to induce some model fits, we will use a trick to change the number of\niterations the model uses to fit parameters (`_maxfev`), making it much more likely to fail.\n\nNote that in normal usage, you would likely never want to change the value of `_maxfev`,\nand this here is a 'hack' of the code in order to induce reproducible failure modes\nin simulated data.\n\n\n" + "### Inducing Model Fit Failures\n\nSo far, we have no model failures (as is typical).\n\nFor this example, to induce some model fits, we will use a trick to change the number of\niterations the model uses to fit parameters (`_maxfev`), making it much more likely to fail.\n\nNote that in normal usage, you would likely never want to change the value of `_maxfev`,\nand this here is a 'hack' of the code in order to induce reproducible failure modes\nin simulated data.\n\n\n" ] }, { @@ -138,7 +127,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Debug Mode\n----------\n\nThere are multiple possible reasons why a model fit failure can occur, or at least\nmultiple possible steps in the algorithm at which the fit failure can occur.\n\nIf you have a small number of fit failures, you can likely just exclude them.\n\nHowever, if you have multiple fit failures, and/or you want to investigate why the\nmodel is failing, you can use the debug mode to get a bit more information about\nwhere the model is failing.\n\nThe debug mode will stop the FOOOF object catching and continuing any model\nfit errors, allowing you to see where the error is happening, and get more\ninformation about where it is failing.\n\nNote that here we will run the fitting in a try / except to catch the error and\nprint it out, without the error actually being raised (for website purposes).\nIf you just want to see the error, you can run the fit call without the try/except.\n\n\n" + "## Debug Mode\n\nThere are multiple possible reasons why a model fit failure can occur, or at least\nmultiple possible steps in the algorithm at which the fit failure can occur.\n\nIf you have a small number of fit failures, you can likely just exclude them.\n\nHowever, if you have multiple fit failures, and/or you want to investigate why the\nmodel is failing, you can use the debug mode to get a bit more information about\nwhere the model is failing.\n\nThe debug mode will stop the FOOOF object catching and continuing any model\nfit errors, allowing you to see where the error is happening, and get more\ninformation about where it is failing.\n\nNote that here we will run the fitting in a try / except to catch the error and\nprint it out, without the error actually being raised (for website purposes).\nIf you just want to see the error, you can run the fit call without the try/except.\n\n\n" ] }, { @@ -167,7 +156,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Debugging Model Fit Errors\n~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nThis debug mode should indicate in which step the model is failing, which might indicate\nwhat aspects of the data to look into, and/or which settings to try and tweak.\n\nAlso, all known model fit failures should be caught by the object, and not raise an\nerror (when not in debug mode). If you are finding examples in which the model is failing\nto fit, and raising an error (outside of debug mode), then this might be an unanticipated\nissue with the model fit.\n\nIf you are unsure about why or how the model is failing to fit, consider\nopening an `issue `_ on the project\nrepository, and we will try to look into what seems to be happening.\n\n\n" + "### Debugging Model Fit Errors\n\nThis debug mode should indicate in which step the model is failing, which might indicate\nwhat aspects of the data to look into, and/or which settings to try and tweak.\n\nAlso, all known model fit failures should be caught by the object, and not raise an\nerror (when not in debug mode). If you are finding examples in which the model is failing\nto fit, and raising an error (outside of debug mode), then this might be an unanticipated\nissue with the model fit.\n\nIf you are unsure about why or how the model is failing to fit, consider\nopening an [issue](https://github.com/fooof-tools/fooof/issues) on the project\nrepository, and we will try to look into what seems to be happening.\n\n\n" ] } ], @@ -187,7 +176,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.8.5" + "version": "3.8.3" } }, "nbformat": 4, diff --git a/_downloads/51b8f06909b098e687b8fc657c46fc0a/plot_data_components.ipynb b/_downloads/51b8f06909b098e687b8fc657c46fc0a/plot_data_components.ipynb new file mode 100644 index 00000000..1bf523f3 --- /dev/null +++ b/_downloads/51b8f06909b098e687b8fc657c46fc0a/plot_data_components.ipynb @@ -0,0 +1,252 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n# Exploring Data Components\n\nThis example explores the different data components, exploring the isolated aperiodic\nand periodic components as they are extracted from the data.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Import FOOOF model objects\nfrom fooof import FOOOF, FOOOFGroup\n\n# Import function to plot power spectra\nfrom fooof.plts.spectra import plot_spectra\n\n# Import simulation functions to create some example data\nfrom fooof.sim import gen_power_spectrum, gen_group_power_spectra" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Simulate example power spectrum\nfreqs, powers = gen_power_spectrum([1, 50], [0, 10, 1], [10, 0.25, 2], freq_res=0.25)\n\n# Initialize model object and fit power spectrum\nfm = FOOOF()\nfm.fit(freqs, powers)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Data & Model Components\n\nThe model fit process includes procedures for isolating aperiodic and periodic components in\nthe data, fitting each of these components separately, and then combining the model components\nas the final fit (see the Tutorials for further details on these procedures).\n\nIn doing this process, the model fit procedure computes and stores isolated data components,\nwhich are available in the model.\n\n\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Full Data & Model Components\n\nBefore diving into the isolated data components, let's check 'full' components, including\nthe data (`power_spectrum`) and full model fit of a model object (`fooofed_spectrum`).\n\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Plot the original power spectrum data from the object\nplot_spectra(fm.freqs, fm.power_spectrum, color='black')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Plot the power spectrum model from the object\nplot_spectra(fm.freqs, fm.fooofed_spectrum_, color='red')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Isolated Components\n\nAs well as the 'full' data & model components above, the model fitting procedure includes\nsteps that result in isolated periodic and aperiodic components, in both the\ndata and model. These isolated components are stored internally in the model.\n\nTo access these components, we can use the following `getter` methods:\n\n- :meth:`~fooof.FOOOF.get_data`: allows for accessing data components\n- :meth:`~fooof.FOOOF.get_model`: allows for accessing model components\n\n\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Aperiodic Component\n\nTo fit the aperiodic component, the model fit procedure includes a peak removal process.\n\nThe resulting 'peak-removed' data component is stored in the model object, as well as the\nisolated aperiodic component model fit.\n\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Plot the peak removed spectrum data component\nplot_spectra(fm.freqs, fm.get_data('aperiodic'), color='black')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Plot the peak removed spectrum, with the model aperiodic fit\nplot_spectra(fm.freqs, [fm.get_data('aperiodic'), fm.get_model('aperiodic')],\n colors=['black', 'blue'], linestyle=['-', '--'])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Periodic Component\n\nTo fit the periodic component, the model fit procedure removes the fit peaks from the power\nspectrum.\n\nThe resulting 'flattened' data component is stored in the model object, as well as the\nisolated periodic component model fit.\n\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Plot the flattened spectrum data component\nplot_spectra(fm.freqs, fm.get_data('peak'), color='black')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Plot the flattened spectrum data with the model peak fit\nplot_spectra(fm.freqs, [fm.get_data('peak'), fm.get_model('peak')],\n colors=['black', 'green'], linestyle=['-', '--'])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Full Model Fit\n\nThe full model fit, which we explored earlier, is calculated as the combination of the\naperiodic and peak fit, which we can check by plotting these combined components.\n\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Plot the full model fit, as the combination of the aperiodic and peak model components\nplot_spectra(fm.freqs, [fm.get_model('aperiodic') + fm.get_model('peak')], color='red')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Linear vs Log Spacing\n\nThe above shows data components as they are available on the model object, and used in\nthe fitting process - notable, in log10 spacing.\n\nSome analyses may aim to use these isolated components to compute certain measures of\ninterest on the data. However, when doing so, one may often want the linear power\nrepresentations of these components.\n\nBoth the `get_data` and `get_model` methods accept a 'space' argument, whereby the user\ncan specify whether the return the components in log10 or linear spacing.\n\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Aperiodic Components in Linear Space\n\nFirst we can examine the aperiodic data & model components, in linear space.\n\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Plot the peak removed spectrum, with the model aperiodic fit\nplot_spectra(fm.freqs, [fm.get_data('aperiodic', 'linear'), fm.get_model('aperiodic', 'linear')],\n colors=['black', 'blue'], linestyle=['-', '--'])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Peak Component in Linear Space\n\nNext, we can examine the peak data & model components, in linear space.\n\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Plot the flattened spectrum data with the model peak fit\nplot_spectra(fm.freqs, [fm.get_data('peak', 'linear'), fm.get_model('peak', 'linear')],\n colors=['black', 'green'], linestyle=['-', '--'])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Linear Space Additive Model\n\nNote that specifying 'linear' does not simply unlog the data components to return them\nin linear space, but instead defines the space of the additive data definition such that\n`power_spectrum = aperiodic_component + peak_component` (for data and/or model).\n\nWe can see this by plotting the linear space data (or model) with the corresponding\naperiodic and periodic components summed together. Note that if you simply unlog\nthe components and sum them, they does not add up to reflecting the full data / model.\n\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Plot the linear data, showing the combination of peak + aperiodic matches the full data\nplot_spectra(fm.freqs,\n [fm.get_data('full', 'linear'),\n fm.get_data('aperiodic', 'linear') + fm.get_data('peak', 'linear')],\n linestyle=['-', 'dashed'], colors=['black', 'red'], alpha=[0.3, 0.75])" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Plot the linear model, showing the combination of peak + aperiodic matches the full model\nplot_spectra(fm.freqs,\n [fm.get_model('full', 'linear'),\n fm.get_model('aperiodic', 'linear') + fm.get_model('peak', 'linear')],\n linestyle=['-', 'dashed'], colors=['black', 'red'], alpha=[0.3, 0.75])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Notes on Analyzing Data & Model Components\n\nThe functionality here allows for accessing the model components in log space (as used by\nthe model for fitting), as well as recomputing in linear space.\n\nIf you are aiming to analyze these components, it is important to consider which version of\nthe data you should analyze for the question at hand, as there are key differences to the\ndifferent representations. Users who wish to do so post-hoc analyses of these data and model\ncomponents should consider the benefits and limitations the different representations.\n\n\n" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.8.3" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} \ No newline at end of file diff --git a/_downloads/529310c262bb0f4dcf97fa131605dbae/plot_line_noise.py b/_downloads/529310c262bb0f4dcf97fa131605dbae/plot_line_noise.py new file mode 100644 index 00000000..99ab9e8a --- /dev/null +++ b/_downloads/529310c262bb0f4dcf97fa131605dbae/plot_line_noise.py @@ -0,0 +1,219 @@ +""" +Dealing with Line Noise +======================= + +This example covers strategies for dealing with line noise. +""" + +################################################################################################### + +# sphinx_gallery_thumbnail_number = 2 + +# Import the spectral parameterization object and utilities +from fooof import FOOOF +from fooof.plts import plot_spectra +from fooof.utils import trim_spectrum, interpolate_spectrum + +# Import simulation functions to create some example data +from fooof.sim.gen import gen_power_spectrum + +# Import NeuroDSP functions for simulating & processing time series +from neurodsp.sim import sim_combined +from neurodsp.filt import filter_signal +from neurodsp.spectral import compute_spectrum + +################################################################################################### +# Line Noise Peaks +# ---------------- +# +# Neural recordings typically have power line artifacts, at either 50 or 60 Hz, depending on +# where the data were collected, which can impact spectral parameterization. +# +# In this example, we explore some options for dealing with line noise artifacts. +# +# Interpolating Line Noise Peaks +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# One approach is to interpolate away line noise peaks, in the frequency domain. This +# approach simply gets rid of the peaks, interpolating the data to maintain the 1/f +# character of the data, allowing for subsequent fitting. +# +# The :func:`~fooof.utils.interpolate_spectrum` function allows for doing simple +# interpolation. Given a narrow frequency region, this function interpolates the spectrum, +# such that the 'peak' of the line noise is removed. +# + +################################################################################################### + +# Generate an example power spectrum, with line noise +freqs1, powers1 = gen_power_spectrum([3, 75], [1, 1], + [[10, 0.75, 2], [60, 1, 0.5]]) + +# Visualize the generated power spectrum +plot_spectra(freqs1, powers1, log_powers=True) + +################################################################################################### +# +# In the plot above, we have an example spectrum, with some power line noise. +# +# To prepare this data for fitting, we can interpolate away the line noise region. +# + +################################################################################################### + +# Interpolate away the line noise region +interp_range = [58, 62] +freqs_int1, powers_int1 = interpolate_spectrum(freqs1, powers1, interp_range) + +################################################################################################### + +# Plot the spectra for the power spectra before and after interpolation +plot_spectra(freqs1, [powers1, powers_int1], log_powers=True, + labels=['Original Spectrum', 'Interpolated Spectrum']) + +################################################################################################### +# +# As we can see in the above, the interpolation removed the peak from the data. +# +# We can now go ahead and parameterize the spectrum. +# + +################################################################################################### + +# Initialize a power spectrum model +fm1 = FOOOF(verbose=False) +fm1.report(freqs_int1, powers_int1) + +################################################################################################### +# Multiple Interpolation Regions +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# Line noise artifacts often also display harmonics, such that when analyzing broader +# frequency ranges, there may be multiple peaks that need to be interpolated. +# +# This can be done by passing in multiple interpolation regions to +# :func:`~fooof.utils.interpolate_spectrum`, which we will do in the next example. +# + +################################################################################################### + +# Generate an example power spectrum, with line noise & harmonics +freqs2, powers2 = gen_power_spectrum([1, 150], [1, 500, 1.5], + [[10, 0.5, 2], [60, 0.75, 0.5], [120, 0.5, 0.5]]) + +# Interpolate away the line noise region & harmonics +interp_ranges = [[58, 62], [118, 122]] +freqs_int2, powers_int2 = interpolate_spectrum(freqs2, powers2, interp_ranges) + +################################################################################################### + +# Plot the power spectrum before and after interpolation +plot_spectra(freqs2, [powers2, powers_int2], log_powers=True, + labels=['Original Spectrum', 'Interpolated Spectrum']) + +################################################################################################### + +# Parameterize the interpolated power spectrum +fm2 = FOOOF(aperiodic_mode='knee', verbose=False) +fm2.report(freqs2, powers_int2) + +################################################################################################### +# Fitting Line Noise as Peaks +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# In some cases, you may also be able to simply allow the parameterization to peaks to the +# line noise and harmonics. By simply fitting the line noise as peaks, the model can deal +# with the peaks in order to accurately fit the aperiodic component. +# +# These peaks are of course not to be analyzed, but once the model has been fit, you can +# simply ignore them. There should generally be no issue with fitting and having them in +# the model, and allowing the model to account for these peaks typically helps the model +# better fit the rest of the data. +# +# Below we can see that the model does indeed work when fitting data with line noise peaks. +# + +################################################################################################### + +# Fit power spectrum models to original spectra +fm1.report(freqs1, powers1) +fm2.report(freqs2, powers2) + +################################################################################################### +# The Problem with Bandstop Filtering +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# A common approach for getting rid of line noise activity is to use bandstop filtering to +# remove activity at the line noise frequencies. Such a filter effectively set the power +# of these frequencies to be approximately zero. +# +# Unfortunately, this doesn't work very well with spectral parameterization, since the +# parameterization algorithm tries to fit each power value as either part of the aperiodic +# component, or as an overlying peak. Frequencies that have filtered out are neither, and +# the model has trouble, as it and has no concept of power values below the aperiodic component. +# +# In practice, this means that the "missing" power will impact the fit, and pull down the +# aperiodic component. One way to think of this is that the power spectrum model can deal with, +# and even expects, 'positive outliers' above the aperiodic (these are considered 'peaks'), but +# not 'negative outliers', or values below the aperiodic, as there is no expectation of this +# happening in the model. +# +# In the following example, we can see how bandstop filtering negatively impacts fitting. +# Because of this, for the purposes of spectral parameterization, bandstop filters are not +# recommended as a way to remove line noise. +# +# Note that if one has already applied a bandstop filter, then you can still +# apply the interpolation from above. +# + +################################################################################################### + +# General settings for the simulation +n_seconds = 30 +fs = 1000 + +# Define the settings for the simulated signal +components = {'sim_powerlaw' : {'exponent' : -1.5}, + 'sim_oscillation' : [{'freq' : 10}, {'freq' : 60}]} +comp_vars = [0.5, 1, 1] + +# Simulate a time series +sig = sim_combined(n_seconds, fs, components, comp_vars) + +################################################################################################### + +# Bandstop filter the signal to remove line noise frequencies +sig_filt = filter_signal(sig, fs, 'bandstop', (57, 63), + n_seconds=2, remove_edges=False) + +################################################################################################### + +# Compute a power spectrum of the simulated signal +freqs, powers_pre = trim_spectrum(*compute_spectrum(sig, fs), [3, 75]) +freqs, powers_post = trim_spectrum(*compute_spectrum(sig_filt, fs), [3, 75]) + +################################################################################################### + +# Plot the spectrum of the data, pre and post bandstop filtering +plot_spectra(freqs, [powers_pre, powers_post], log_powers=True, + labels=['Pre-Filter', 'Post-Filter']) + +################################################################################################### +# +# In the above, we can see that the the bandstop filter removes power in the filtered range, +# leaving a "dip" in the power spectrum. This dip causes issues with subsequent fitting. +# + +################################################################################################### + +# Initialize and fit a power spectrum model +fm = FOOOF() +fm.report(freqs, powers_post) + +################################################################################################### +# +# In order to try and capture the data points in the "dip", the power spectrum model +# gets 'pulled' down, leading to an inaccurate fit of the aperiodic component. This is +# why fitting frequency regions that included frequency regions that have been filtered +# out is not recommended. +# diff --git a/_downloads/55d902bedd994ca5f11c063498ec382f/plot_sim_params.ipynb b/_downloads/55d902bedd994ca5f11c063498ec382f/plot_sim_params.ipynb index cce87b10..a0b2f910 100644 --- a/_downloads/55d902bedd994ca5f11c063498ec382f/plot_sim_params.ipynb +++ b/_downloads/55d902bedd994ca5f11c063498ec382f/plot_sim_params.ipynb @@ -1,21 +1,10 @@ { "cells": [ - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "collapsed": false - }, - "outputs": [], - "source": [ - "%matplotlib inline" - ] - }, { "cell_type": "markdown", "metadata": {}, "source": [ - "\nSimulation Parameters\n=====================\n\nManage parameters for creating simulated power spectra.\n" + "\n# Simulation Parameters\n\nManage parameters for creating simulated power spectra.\n" ] }, { @@ -33,7 +22,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Simulation Parameters\n---------------------\n\nOne of the useful things about using simulated data is being able to compare results\nto ground truth values - but in order to do that, one needs to keep track of the\nsimulation parameters themselves.\n\nTo do so, there is the :obj:`~.SimParams` object to manage\nand keep track of simulation parameters.\n\nFor example, when you simulate power spectra, the parameters for each spectrum are stored\nin a :obj:`~.SimParams` object, and then these objects are collected and returned.\n\nSimParams objects are named tuples with the following fields:\n\n- ``aperiodic_params``\n- ``periodic_params``\n- ``nlv``\n\n\n" + "## Simulation Parameters\n\nOne of the useful things about using simulated data is being able to compare results\nto ground truth values - but in order to do that, one needs to keep track of the\nsimulation parameters themselves.\n\nTo do so, there is the :obj:`~.SimParams` object to manage\nand keep track of simulation parameters.\n\nFor example, when you simulate power spectra, the parameters for each spectrum are stored\nin a :obj:`~.SimParams` object, and then these objects are collected and returned.\n\nSimParams objects are named tuples with the following fields:\n\n- ``aperiodic_params``\n- ``periodic_params``\n- ``nlv``\n\n\n" ] }, { @@ -84,14 +73,14 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Managing Parameters\n-------------------\n\nThere are also helper functions for managing and selecting parameters for\nsimulating groups of power spectra.\n\nThese functions include:\n\n- :func:`~.param_sampler` which can be used to sample parameters from possible options\n- :func:`~.param_iter` which can be used to iterate across parameter ranges\n- :func:`~.param_jitter` which can be used to add some 'jitter' to simulation parameters\n\n\n" + "## Managing Parameters\n\nThere are also helper functions for managing and selecting parameters for\nsimulating groups of power spectra.\n\nThese functions include:\n\n- :func:`~.param_sampler` which can be used to sample parameters from possible options\n- :func:`~.param_iter` which can be used to iterate across parameter ranges\n- :func:`~.param_jitter` which can be used to add some 'jitter' to simulation parameters\n\n\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "param_sampler\n~~~~~~~~~~~~~\n\nThe :func:`~.param_sampler` function takes a list of parameter options and\nrandomly selects from the parameters to create each power spectrum. You can also optionally\nspecify the probabilities with which to sample from the options.\n\n\n" + "### param_sampler\n\nThe :func:`~.param_sampler` function takes a list of parameter options and\nrandomly selects from the parameters to create each power spectrum. You can also optionally\nspecify the probabilities with which to sample from the options.\n\n\n" ] }, { @@ -131,7 +120,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "param_iter\n~~~~~~~~~~\n\nThe :func:`~.param_iter` function can be used to create iterators that\ncan 'step' across a range of parameter values to be simulated.\n\nThe :class:`~.Stepper` object needs to be used in conjunction with\n:func:`~.param_iter`, as it specifies the values to be iterated across.\n\n\n" + "### param_iter\n\nThe :func:`~.param_iter` function can be used to create iterators that\ncan 'step' across a range of parameter values to be simulated.\n\nThe :class:`~.Stepper` object needs to be used in conjunction with\n:func:`~.param_iter`, as it specifies the values to be iterated across.\n\n\n" ] }, { @@ -171,7 +160,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "param_jitter\n~~~~~~~~~~~~\n\nThe :func:`~.param_jitter` function can be used to create iterators that\napply some 'jitter' to the defined parameter values.\n\n\n" + "### param_jitter\n\nThe :func:`~.param_jitter` function can be used to create iterators that\napply some 'jitter' to the defined parameter values.\n\n\n" ] }, { @@ -231,7 +220,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.8.5" + "version": "3.8.3" } }, "nbformat": 4, diff --git a/_downloads/5861eb06307a9c0018ffa0c6d2f98db2/plot_simulated_power_spectra.ipynb b/_downloads/5861eb06307a9c0018ffa0c6d2f98db2/plot_simulated_power_spectra.ipynb index 03f99666..5b5ae746 100644 --- a/_downloads/5861eb06307a9c0018ffa0c6d2f98db2/plot_simulated_power_spectra.ipynb +++ b/_downloads/5861eb06307a9c0018ffa0c6d2f98db2/plot_simulated_power_spectra.ipynb @@ -1,21 +1,10 @@ { "cells": [ - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "collapsed": false - }, - "outputs": [], - "source": [ - "%matplotlib inline" - ] - }, { "cell_type": "markdown", "metadata": {}, "source": [ - "\nSimulating Neural Power Spectra\n===============================\n\nCreating simulated power spectra.\n" + "\n# Simulating Neural Power Spectra\n\nCreating simulated power spectra.\n" ] }, { @@ -26,14 +15,14 @@ }, "outputs": [], "source": [ - "# Import functions for creating simulated power spectra\nfrom fooof.sim.gen import gen_power_spectrum, gen_group_power_spectra\n\n# Import plotting functions\nfrom fooof.plts.spectra import plot_spectrum, plot_spectra" + "# Import functions for creating simulated power spectra\nfrom fooof.sim.gen import gen_power_spectrum, gen_group_power_spectra\n\n# Import plotting functions\nfrom fooof.plts.spectra import plot_spectra" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "Creating Simulated Power Spectra\n--------------------------------\n\nThe module also contains utilities to create simulated power spectra. Power spectra\nare simulated using the same model and conception that the model employs, namely that\nneural power spectra can be conceptualized as an aperiodic component, with overlying\nperiodic peaks.\n\nTo simulate power spectra, required parameters are:\n\n- ``freq_range``: the frequency range to simulate across\n- ``aperiodic_params``: parameters that define the aperiodic component\n\n - this component is defined with 2 or 3 parameters, as [offset, (knee), exponent]\n- ``gaussian_params``: parameters that define the periodic component\n\n - each peak is defined with three parameters, as [center frequency, height, width]\n\nThe :func:`~.gen_power_spectrum` function takes these parameters as input to\ncreate and return a simulated power spectrum. Note that the parameters that define the peaks\nare labeled as gaussian parameters, as these parameters define the simulated gaussians\ndirectly, and are not the modified peak parameters that the model outputs.\n\n\n" + "## Creating Simulated Power Spectra\n\nThe module also contains utilities to create simulated power spectra. Power spectra\nare simulated using the same model and conception that the model employs, namely that\nneural power spectra can be conceptualized as an aperiodic component, with overlying\nperiodic peaks.\n\nTo simulate power spectra, required parameters are:\n\n- ``freq_range``: the frequency range to simulate across\n- ``aperiodic_params``: parameters that define the aperiodic component\n\n - this component is defined with 2 or 3 parameters, as [offset, (knee), exponent]\n- ``gaussian_params``: parameters that define the periodic component\n\n - each peak is defined with three parameters, as [center frequency, height, width]\n\nThe :func:`~.gen_power_spectrum` function takes these parameters as input to\ncreate and return a simulated power spectrum. Note that the parameters that define the peaks\nare labeled as gaussian parameters, as these parameters define the simulated gaussians\ndirectly, and are not the modified peak parameters that the model outputs.\n\n\n" ] }, { @@ -66,14 +55,14 @@ }, "outputs": [], "source": [ - "# Plot the simulated power spectrum\nplot_spectrum(freqs, powers, log_freqs=True, log_powers=False)" + "# Plot the simulated power spectrum\nplot_spectra(freqs, powers, log_freqs=True, log_powers=False)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "Simulating With Different Parameters\n------------------------------------\n\nPower spectra can be simulated with any desired parameters in the power spectrum model.\n\nThe aperiodic mode for the simulated power spectrum is inferred from the parameters provided.\nIf two parameters are provided, this is interpreted as [offset, exponent] for simulating\na power spectra with a 'fixed' aperiodic component. If three parameters are provided, as in\nthe example below, this is interpreted as [offset, knee, exponent] for a 'knee' spectrum.\n\nPower spectra can also be simulated with any number of peaks. Peaks can be listed in a flat\nlist with [center frequency, height, bandwidth] listed for as many peaks as you would\nlike to add, or as a list of lists containing the same information.\n\nThe following example shows simulating a different power spectrum with some different\nsetttings, also changing the noise level added to the spectrum, and the frequency\nresolution of the simulated spectrum.\n\n\n" + "## Simulating With Different Parameters\n\nPower spectra can be simulated with any desired parameters in the power spectrum model.\n\nThe aperiodic mode for the simulated power spectrum is inferred from the parameters provided.\nIf two parameters are provided, this is interpreted as [offset, exponent] for simulating\na power spectra with a 'fixed' aperiodic component. If three parameters are provided, as in\nthe example below, this is interpreted as [offset, knee, exponent] for a 'knee' spectrum.\n\nPower spectra can also be simulated with any number of peaks. Peaks can be listed in a flat\nlist with [center frequency, height, bandwidth] listed for as many peaks as you would\nlike to add, or as a list of lists containing the same information.\n\nThe following example shows simulating a different power spectrum with some different\nsetttings, also changing the noise level added to the spectrum, and the frequency\nresolution of the simulated spectrum.\n\n\n" ] }, { @@ -106,14 +95,14 @@ }, "outputs": [], "source": [ - "# Plot the new simulated power spectrum\nplot_spectrum(freqs, powers, log_powers=True)" + "# Plot the new simulated power spectrum\nplot_spectra(freqs, powers, log_powers=True)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "Simulating a Group of Power Spectra\n-----------------------------------\n\nFor simulating multiple power spectra, the :func:`~.gen_group_power_spectra` can be used.\n\nThis function takes the same kind of parameter definitions as\n:func:`~.gen_power_spectrum`, and in addition takes a number specifying\nhow many power spectra to simulate, returning a 2D matrix containing the\ndesired number of spectra.\n\nParameters that are passed into :func:`~.gen_group_power_spectra` can be:\n\n- a single definition, whereby the same value is used for all generated spectra\n- a list of parameters, whereby each successive entry is used for each successive spectrum\n- a function or generator that can be called to return parameters for each spectrum\n\n\n" + "## Simulating a Group of Power Spectra\n\nFor simulating multiple power spectra, the :func:`~.gen_group_power_spectra` can be used.\n\nThis function takes the same kind of parameter definitions as\n:func:`~.gen_power_spectrum`, and in addition takes a number specifying\nhow many power spectra to simulate, returning a 2D matrix containing the\ndesired number of spectra.\n\nParameters that are passed into :func:`~.gen_group_power_spectra` can be:\n\n- a single definition, whereby the same value is used for all generated spectra\n- a list of parameters, whereby each successive entry is used for each successive spectrum\n- a function or generator that can be called to return parameters for each spectrum\n\n\n" ] }, { @@ -153,7 +142,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Tracking Simulation Parameters\n------------------------------\n\nWhen you start simulating multiple power spectra across different parameters,\nyou may want to keep track of these parameters, so that you can compare any measure\ntaken on these power spectra to ground truth values.\n\nWhen simulating power spectra, you also have the option of returning SimParams objects\nthat keep track of the simulation parameters.\n\n\n" + "## Tracking Simulation Parameters\n\nWhen you start simulating multiple power spectra across different parameters,\nyou may want to keep track of these parameters, so that you can compare any measure\ntaken on these power spectra to ground truth values.\n\nWhen simulating power spectra, you also have the option of returning SimParams objects\nthat keep track of the simulation parameters.\n\n\n" ] }, { @@ -202,7 +191,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.8.5" + "version": "3.8.3" } }, "nbformat": 4, diff --git a/_downloads/5c77a4224b4479ec9ae12748b0e58e67/plot_dev_demo.ipynb b/_downloads/5c77a4224b4479ec9ae12748b0e58e67/plot_dev_demo.ipynb new file mode 100644 index 00000000..74d7debe --- /dev/null +++ b/_downloads/5c77a4224b4479ec9ae12748b0e58e67/plot_dev_demo.ipynb @@ -0,0 +1,791 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n# Developmental Data Demo\n\nAn example analysis applied to developmental data, demonstrating best practices.\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Spectral Parameterization for studying neurodevelopment\n\nThis example is adapted from the\n[Developmental Data Demo](https://github.com/fooof-tools/DevelopmentalDemo/).\n\nIf you wish to reference this example or use guidelines from it, please cite the associated\npaper `Spectral parameterization for studying neurodevelopment: how and why` by\nBrendan Ostlund, Thomas Donoghue, Berenice Anaya, Kelley E Gunther, Sarah L Karalunas,\nBradley Voytek, and Koraly E P\u00e9rez-Edgar.\n\nPaper link: https://doi.org/10.1016/j.dcn.2022.101073\n\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Import some useful standard library modules\nfrom pathlib import Path\n\n# Import some general scientific python libraries\nimport numpy as np\nimport pandas as pd\nimport matplotlib.pyplot as plt\n\n# Import the parameterization model objects\nfrom fooof import FOOOF, FOOOFGroup\n\n# Import useful parameterization related utilities and plot functions\nfrom fooof.bands import Bands\nfrom fooof.analysis import get_band_peak_fg\nfrom fooof.utils import trim_spectrum\nfrom fooof.utils.data import subsample_spectra\nfrom fooof.sim.gen import gen_aperiodic\nfrom fooof.data import FOOOFSettings\nfrom fooof.plts.templates import plot_hist\nfrom fooof.plts.spectra import plot_spectra\nfrom fooof.plts.periodic import plot_peak_fits, plot_peak_params\nfrom fooof.plts.aperiodic import plot_aperiodic_params, plot_aperiodic_fits\n\n# Import functions to examine frequency-by-frequency error of model fits\nfrom fooof.analysis.error import compute_pointwise_error_fm, compute_pointwise_error_fg\n\n# Import helper utility to access data\nfrom fooof.utils.download import fetch_fooof_data" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Access Example Data\n\nFirst, we will download the example data for this example.\n\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Set the URL where the data is available\ndata_url = 'https://raw.githubusercontent.com/fooof-tools/DevelopmentalDemo/main/Data/'\n\n# Set the data path to load from\ndata_path = Path('data')\n\n# Collect the example data\nfetch_fooof_data('freqs.csv', data_path, data_url)\nfetch_fooof_data('indv.csv', data_path, data_url)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Fitting an Individual Power Spectrum\n\nFor the first part of this example, we will start by loading and fitting an individual PSD.\n\nTo do so, we start by loading some CSV files, including:\n\n- `freqs.csv`, which contains a vector of frequencies\n- `indvPSD.csv`, which contains the power values for an individual power spectrum\n\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Load data\nfreqs = np.ravel(pd.read_csv(data_path / \"freqs.csv\"))\nspectrum = np.ravel(pd.read_csv(data_path / \"indv.csv\"))[1:101]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now that we have loaded the data, we can parameterize our power spectrum!\n\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Define model settings\npeak_width = [1, 8] # `peak_width_limit` setting\nn_peaks = 6 # `max_n_peaks` setting\npeak_height = 0.10 # `min_peak_height` setting\n\n# Define frequency range\nPSD_range = [3, 40]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Initialize a model object for spectral parameterization, with some settings\nfm = FOOOF(peak_width_limits=peak_width, max_n_peaks=n_peaks,\n min_peak_height=peak_height, verbose=False)\n\n# Fit individual PSD over 3-40 Hz range\nfm.report(freqs, spectrum, PSD_range)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "As a reminder you can save these reports using the `.save_report()` method, for example,\nby running `fm.save_report('INDV_demo', file_path=output_path)`.\n\n\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "All of the model fit information is saved to the model object, which we can then access.\n\nNote that all attributes learned in the model fit process have a trailing underscore.\n\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Access the model fit parameters from the model object\nprint('Aperiodic parameters: \\n', fm.aperiodic_params_, '\\n')\nprint('Peak parameters: \\n', fm.peak_params_, '\\n')\nprint('Goodness of fit:')\nprint('Error - ', fm.error_)\nprint('R^2 - ', fm.r_squared_, '\\n')\nprint('Number of fit peaks: \\n', fm.n_peaks_)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Another way to access model fit parameters is to use the `get_params` method,\nwhich can be used to access model fit attributes.\n\nThis method can be used to extract periodic and aperiodic parameters.\n\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Extract aperiodic and periodic parameter\naps = fm.get_params('aperiodic_params')\npeaks = fm.get_params('peak_params')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Extract goodness of fit information\nerr = fm.get_params('error')\nr2s = fm.get_params('r_squared')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Extract specific parameters\nexp = fm.get_params('aperiodic_params', 'exponent')\ncfs = fm.get_params('peak_params', 'CF')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Print out a custom parameter report\ntemplate = (\"With an error level of {error:1.2f}, specparam fit an exponent \"\n \"of {exponent:1.2f} and peaks of {cfs:s} Hz.\")\nprint(template.format(error=err, exponent=exp,\n cfs=' & '.join(map(str, [round(CF, 2) for CF in cfs]))))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Next, we will plot the flattened power spectrum.\n\nIt may be useful to plot a flattened power spectrum, with the aperiodic fit removed.\n\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Set whether to plot in log-log space\nplt_log = False\n\n# Do an initial aperiodic fit - a robust fit, that excludes outliers\ninit_ap_fit = gen_aperiodic(fm.freqs, fm._robust_ap_fit(fm.freqs, fm.power_spectrum))\n\n# Recompute the flattened spectrum using the initial aperiodic fit\ninit_flat_spec = fm.power_spectrum - init_ap_fit" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Plot the flattened the power spectrum\nplot_spectra(fm.freqs, init_flat_spec, plt_log, label='Flattened spectrum', color='black')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The model object also has I/O utilities for saving and reloading data.\n\nThe `.save` method can be used to save out data from the object,\nspecifying which information to save.\n\nFor example, you can save results with the following:\n- settings: `fm.save('fit_settings', save_settings=True, file_path=output_path)\n- results: `fm.save('fit_results', save_results=True, file_path=output_path)`\n- data: `fm.save('fit_data', save_data=True, file_path=output_path)`\n\nAnother option is to save out data as a .csv rather than the default .json file format.\nYou can do this be exporting the results to a dataframe (see other examples for further\nguidance on this topic).\n\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Convert results to dataframe\ndf = fm.to_df(None)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The above dataframe can be saved out to a csv using the `to_csv` method.\n\n\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Checking model fit quality\n\nIt can be useful to plot frequency-by-frequency error of the model fit,\nto identify where in frequency space the spectrum is (or is not) being fit well.\nWhen fitting individual spectrum, this can be accomplished using the\n`compute_pointwise_error_fm` function.\n\nIn this case, we can see that error fluctuates around 0.05, which is the same as\nthe mean absolute error for the model (MAE). There are points in the spectrum where\nthe model fit is somewhat poor, particularly < 4 Hz, around 6-9 Hz, and around 14 Hz.\nFurther considerations may be necessary for this model fit.\n\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Plot frequency-by-frequency error\ncompute_pointwise_error_fm(fm, plot_errors=True)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Compute the frequency-by-frequency errors\nerrs_fm = compute_pointwise_error_fm(fm, plot_errors=False, return_errors=True)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Note that the average of this error is the same as the global error stored\nprint('Average freq-by-freq error:\\t {:1.3f}'.format(np.mean(errs_fm)))\nprint('FOOOF model fit error: \\t\\t {:1.3f}'.format(fm.error_))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Fitting a Group of Power Spectra\n\nIn the next example, we will fit a group of power spectra.\n\nFirst we need to load the data, including:\n\n- `freqs.csv`, which contains a vector of frequencies\n- `eopPSDs.csv`, which contains the power values for a group of power spectrum, one for each subject\n\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Collect the example data\nfetch_fooof_data('freqs.csv', data_path, data_url)\nfetch_fooof_data('eop.csv', data_path, data_url)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Load csv files containing frequency and power values\nfreqs = np.ravel(pd.read_csv(data_path / \"freqs.csv\"))\nspectra = np.array(pd.read_csv(data_path / \"eop.csv\"))[:, 1:101]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Get the number of subjects\nn_subjs = spectra.shape[0]\nprint('There are {:d} subjects.'.format(n_subjs))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now we can parameterize our group of power spectra!\n\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Initialize a model object for spectral parameterization, with some settings\nfg = FOOOFGroup(peak_width_limits=peak_width, max_n_peaks=n_peaks,\n min_peak_height=peak_height, verbose=False)\n\n# Fit group PSDs over the 3-40 Hz range\nfg.fit(freqs, spectra, PSD_range)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Print out the group results and plots of fit parameters\nfg.print_results()\nfg.plot()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "As before, we can also save this report using the `.save_report` method, for example by\ncalling: `fg.save_report('EOP_demo', file_path=output_path)`.\n\n\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "As with the individual model object, the `get_params` method can be\nused to access model fit attributes.\n\nIn addition, here we will use a `Bands` object and the `get_band_peak_fg`\nfunction to organize fit peaks into canonical band ranges.\n\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Extract aperiodic and full periodic parameters\naps = fg.get_params('aperiodic_params')\nper = fg.get_params('peak_params')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Extract group fit information\nerr = fg.get_params('error')\nr2s = fg.get_params('r_squared')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Check the average number of fit peaks, per model\nprint('Average number of fit peaks: ', np.mean(fg.n_peaks_))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Define canonical frequency bands\nbands = Bands({'theta' : [4, 8],\n 'alpha' : [8, 13],\n 'beta' : [13, 30]})" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Extract band-limited peaks information\nthetas = get_band_peak_fg(fg, bands.theta)\nalphas = get_band_peak_fg(fg, bands.alpha)\nbetas = get_band_peak_fg(fg, bands.beta)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The specparam module also has functions for plotting the fit parameters.\n\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Plot the measured aperiodic parameters\nplot_aperiodic_params(aps)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Plot the parameters for peaks, split up by band\n_, axes = plt.subplots(1, 3, figsize=(14, 7))\nall_bands = [thetas, alphas, betas]\nfor ax, label, peaks in zip(np.ravel(axes), bands.labels, all_bands):\n plot_peak_params(peaks, ax=ax)\n ax.set_title(label + ' peaks', fontsize=24)\nplt.subplots_adjust(hspace=0.4)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We can also plot reconstructions of model components.\n\nIn the following, we plot reconstructed alpha peaks and aperiodic components.\n\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Plot reconstructions of model components\n_, axes = plt.subplots(1, 2, figsize=(14, 6))\nplot_peak_fits(alphas, ax=axes[0])\nplot_aperiodic_fits(aps, fg.freq_range, ax=axes[1])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Tuning the specparam algorithm\n\nThere are no strict guidelines about optimal parameters that will be appropriate\nacross data sets and recording modalities. We suggest applying a data-driven approach\nto tune model fitting for optimal performance, while taking into account your expectations\nabout periodic and aperiodic activity given the data, the question of interest, and prior findings.\n\nOne option is to parameterize a subset of data to evaluate the appropriateness of model\nfit settings prior to fitting each power spectrum in the data set.\nHere, we test parameters on a randomly selected 10% of the data.\nResults are saved out to a **Output** folder for further consideration.\n\nFirst, lets randomly sub-sample 10% of the power spectra that we will use to test model settings.\n\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Set random seed\nnp.random.seed(1)\n\n# Define settings for & subsample a selection of power spectra\nsubsample_frac = 0.10\nspectra_subsample = subsample_spectra(spectra, subsample_frac)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Here, we first define settings for two models to be fit and compared.\n\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Define `peak_width_limit` for each model\nm1_peak_width = [2, 5]\nm2_peak_width = [1, 8]\n\n# Define `max_n_peaks` for each model\nm1_n_peaks = 4\nm2_n_peaks = 6\n\n# Define `min_peak_height` for each model\nm1_peak_height = 0.05\nm2_peak_height = 0.10" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Next, we set frequency ranges for each model.\n\nTo sub-select frequency ranges, we can use the `trim_spectrum` function\nto extract frequency ranges of interest for each model.\n\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Define frequency range for each model\nm1_PSD_range = [2, 20]\nm2_PSD_range = [3, 40]\n\n# Sub-select frequency ranges\nm1_freq, m1_spectra = trim_spectrum(freqs, spectra_subsample, m1_PSD_range)\nm2_freq, m2_spectra = trim_spectrum(freqs, spectra_subsample, m2_PSD_range)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Fit models, with different settings.\n\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Fit model object with model 1 settings\nfg1 = FOOOFGroup(peak_width_limits=m1_peak_width, max_n_peaks=m1_n_peaks,\n min_peak_height=m1_peak_height)\nfg1.fit(m1_freq, m1_spectra)\n\n# Create individual reports for model 1 settings (these could be saved and checked)\nfor ind in range(len(fg1)):\n temp_model = fg1.get_fooof(ind, regenerate=True)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We can do the same with the other set of settings.\n\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Fit model object with model 2 settings\nfg2 = FOOOFGroup(peak_width_limits=m2_peak_width, max_n_peaks=m2_n_peaks,\n min_peak_height=m2_peak_height)\nfg2.fit(m2_freq, m2_spectra)\n\n# Create individual reports for model 2 settings (these could be saved and checked)\nfor ind in range(len(fg2)):\n temp_model = fg2.get_fooof(ind, regenerate=True)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "There are also other ways to manage settings, for example, using the `FOOOFSettings` object.\n\nHere we will redefine group model objects (`FOOOFGroup`),\nagain using different settings for each one.\n\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Define settings for model 1\nsettings1 = FOOOFSettings(peak_width_limits=m1_peak_width, max_n_peaks=m1_n_peaks,\n min_peak_height=m1_peak_height, peak_threshold=2.,\n aperiodic_mode='fixed')\n\n# Define settings for model 2\nsettings2 = FOOOFSettings(peak_width_limits=m2_peak_width, max_n_peaks=m2_n_peaks,\n min_peak_height=m2_peak_height, peak_threshold=2.,\n aperiodic_mode='fixed')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Initialize model objects for spectral parameterization, with some settings\nfg1 = FOOOFGroup(*settings1)\nfg2 = FOOOFGroup(*settings2)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now, let's fit models with group model object\n\nNote that when fitting power spectra, you can can specify a fit range to fit the model to,\nso you don't have to explicitly trim the spectra.\n\nHere we will refit the example data, specifying the fit range, and then save the group reports.\n\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Fit group PSD over the 2-20 Hz and 3-40 Hz ranges, respectively\nfg1.fit(freqs, spectra_subsample, freq_range=m1_PSD_range)\nfg2.fit(freqs, spectra_subsample, freq_range=m2_PSD_range)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "At this point, it may typically be useful to save out reports from the above\ndifferent model fits (using `.save_report`), such that these different setting regimes\ncan be compared.\n\n\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "After selecting initial model fit settings, and fitting power spectra from the full sample,\nit is often worthwhile to check the goodness of model fit parameters. Please note,\nthe model objects below correspond to the model fit at the top of this script.\n\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Plot distributions of goodness of fit parameters\n# This information is presented in the print_reports output as well\nfig, (ax0, ax1) = plt.subplots(1, 2, figsize=(14, 6))\nplot_hist(r2s, label='Variance explained (R^2)', ax=ax0)\nplot_hist(err, label='Mean absolute error (MAE)', ax=ax1)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Find the index of the worst model fit from the group\nworst_fit_ind = np.argmax(fg.get_params('error'))\n\n# Extract this model fit from the group\nfm = fg.get_fooof(worst_fit_ind, regenerate=True)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Check results and visualize the extracted model\nfm.print_results()\nfm.plot()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now, let's check for potential under-fitting.\n\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Extract all fits that are above some error threshold, for further examination.\nunderfit_error_threshold = 0.100\nunderfit_check = []\nfor ind, res in enumerate(fg):\n if res.error > underfit_error_threshold:\n underfit_check.append(fg.get_fooof(ind, regenerate=True))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Loop through the problem fits check the plots\nfor ind, fm in enumerate(underfit_check):\n fm.plot()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Let's also check for potential over-fitting.\n\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Extract all fits that are below some error threshold, for further examination.\noverfit_error_threshold = 0.02\noverfit_check = []\nfor ind, res in enumerate(fg):\n if res.error < overfit_error_threshold:\n overfit_check.append(fg.get_fooof(ind, regenerate=True))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Loop through the problem fits and check the plots\nfor ind, fm in enumerate(overfit_check):\n fm.plot()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The same approach for saving out data is available in the group object,\nusing the `save` method, for example:\n\n- settings: `fg.save('group_settings', save_settings=True, file_path=output_path)`\n- results: `fg.save('group_results', save_results=True, file_path=output_path)`\n\n\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Another option is to export results to a dataframe (from which CSV files can be saved).\n\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Save out aperiodic parameter results\ndf = fg.to_df(2)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Frequency-by-frequency errors\n\nIt can be useful to plot frequency-by-frequency error of the model fit,\nto identify where in frequency space the spectrum is (or is not) being fit well.\nWhen fitting individual spectrum, this can be accomplished using the\n`compute_pointwise_error_fg` function. When plotting the error, the plot line is\nthe mean error per frequency, across fits, and the shading indicates the standard deviation\nof the error, also per frequency.\n\nIn this case, we can see that error fluctuates around 0.03, which is the same as\nthe mean absolute error for this group fit. There are points in the spectrum where\nthe model fit is somewhat poor, particularly < 4 Hz.\nThe code below lets you identify the highest mean error and largest standard deviation\nin error for the group fit. In this case, that occurs at 3 Hz,\nsuggesting potential issues with fit at the lower end of the examined frequency range.\n\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Plot frequency-by-frequency error\ncompute_pointwise_error_fg(fg, plot_errors=True)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Return the errors - this returns a 2D matrix of errors for all fits\nerrs_fg = compute_pointwise_error_fg(fg, plot_errors=False, return_errors=True)\n\n# Check which frequency has the highest error\nf_max_err = fg.freqs[np.argmax(np.mean(errs_fg, 0))]\nprint('Frequency with highest mean error: \\t\\t\\t', f_max_err)\n\n# Check which frequency has the largest standard deviation of error\nf_max_std = fg.freqs[np.argmax(np.std(errs_fg, 0))]\nprint('Frequency with highest standard deviation of error: \\t', f_max_std)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "In some cases, it may be necessary to drop poor (or failed) model fits from the group object.\nThis can be done using the `fg.drop` function, as shown here.\nIn this case, we remove a participant who has a MAE greater than 0.10.\nThe error threshold will vary depending on sample characteristics and data quality.\n\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Drop poor model fits based on MAE\nfg.drop(fg.get_params('error') > 0.10)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Conclusions\n\nFor more on this topic, see the\n[DevelopmentalDemo repository](https://github.com/fooof-tools/DevelopmentalDemo/)\nand/or the\n[associated paper](https://doi.org/10.1016/j.dcn.2022.101073)\nfor further information.\n\n\n" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.8.3" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} \ No newline at end of file diff --git a/_downloads/5ee90e99e6d971d885ad278c3972711e/plot_08-FurtherAnalysis.ipynb b/_downloads/5ee90e99e6d971d885ad278c3972711e/plot_08-FurtherAnalysis.ipynb index f73f408e..6fd51cd6 100644 --- a/_downloads/5ee90e99e6d971d885ad278c3972711e/plot_08-FurtherAnalysis.ipynb +++ b/_downloads/5ee90e99e6d971d885ad278c3972711e/plot_08-FurtherAnalysis.ipynb @@ -1,28 +1,17 @@ { "cells": [ - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "collapsed": false - }, - "outputs": [], - "source": [ - "%matplotlib inline" - ] - }, { "cell_type": "markdown", "metadata": {}, "source": [ - "\n08: Further Analysis\n====================\n\nAnalyze results from fitting power spectrum models.\n" + "\n# 08: Further Analysis\n\nAnalyze results from fitting power spectrum models.\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "Exploring Power Spectrum Model Results\n--------------------------------------\n\nSo far we have explored how to parameterize neural power spectra, whereby we can measure\nparameters of interest from data - in particular measuring aperiodic and periodic activity.\n\nThese measured parameters can then be examined within or between groups of interest,\nand/or fed into further analyses. For example, one could examine if these parameters\npredict behavioural or physiological features of interest. Largely, it is up to you what\nto do after fitting power spectrum models, as it depends on your questions of interest.\n\nHere, we briefly introduce some analysis utilities that are included in the module,\nand explore some simple analyses that can be done with model parameters.\n\nTo start, we will load and fit some example data, as well as simulate a group of\npower spectra to fit with power spectrum models, to use as examples for this tutorial.\n\n\n" + "## Exploring Power Spectrum Model Results\n\nSo far we have explored how to parameterize neural power spectra, whereby we can measure\nparameters of interest from data - in particular measuring aperiodic and periodic activity.\n\nThese measured parameters can then be examined within or between groups of interest,\nand/or fed into further analyses. For example, one could examine if these parameters\npredict behavioural or physiological features of interest. Largely, it is up to you what\nto do after fitting power spectrum models, as it depends on your questions of interest.\n\nHere, we briefly introduce some analysis utilities that are included in the module,\nand explore some simple analyses that can be done with model parameters.\n\nTo start, we will load and fit some example data, as well as simulate a group of\npower spectra to fit with power spectrum models, to use as examples for this tutorial.\n\n\n" ] }, { @@ -40,7 +29,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Load and Fit Example Data\n~~~~~~~~~~~~~~~~~~~~~~~~~\n\nFirst, let's load and fit an example power spectrum.\n\n\n" + "### Load and Fit Example Data\n\nFirst, let's load and fit an example power spectrum.\n\n\n" ] }, { @@ -69,7 +58,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Simulate and Fit Group Data\n~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nWe will also simulate and fit some additional example data.\n\n\n" + "### Simulate and Fit Group Data\n\nWe will also simulate and fit some additional example data.\n\n\n" ] }, { @@ -98,14 +87,14 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Analysis Utilities\n------------------\n\nThe FOOOF module includes some analysis functions.\n\nNote that these utilities are generally relatively simple utilities that assist in\naccessing and investigating the model parameters.\n\nIn depth analysis of power spectrum model results is typically idiosyncratic to the goals of\nthe project, and so we consider that this will typically require custom code. Here, we seek\nto offer the most useful general utilities.\n\nWe will demonstrate some of these utility functions covering some general use cases.\n\n\n" + "## Analysis Utilities\n\nThe FOOOF module includes some analysis functions.\n\nNote that these utilities are generally relatively simple utilities that assist in\naccessing and investigating the model parameters.\n\nIn depth analysis of power spectrum model results is typically idiosyncratic to the goals of\nthe project, and so we consider that this will typically require custom code. Here, we seek\nto offer the most useful general utilities.\n\nWe will demonstrate some of these utility functions covering some general use cases.\n\n\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "Analyzing Periodic Components\n-----------------------------\n\nWe will start by analyzing the periodic components.\n\nThese utilities mostly serve to help organize and extract periodic components,\nfor example extracting peaks that fall within defined frequency bands.\n\nThis also includes the :class:`~.Bands` object, which is a custom, dictionary-like object,\nthat is provided to store frequency band definitions.\n\n\n" + "## Analyzing Periodic Components\n\nWe will start by analyzing the periodic components.\n\nThese utilities mostly serve to help organize and extract periodic components,\nfor example extracting peaks that fall within defined frequency bands.\n\nThis also includes the :class:`~.Bands` object, which is a custom, dictionary-like object,\nthat is provided to store frequency band definitions.\n\n\n" ] }, { @@ -123,7 +112,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Extracting peaks from FOOOF Objects\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nThe :func:`~.get_band_peak_fm` function takes in a\n:class:`~.FOOOF` object and extracts peak(s) from a requested frequency range.\n\nYou can optionally specify:\n\n- whether to return one peak from the specified band, in which case the highest peak is\n returned, or whether to return all peaks from within the band\n- whether to apply a minimum threshold to extract peaks, for example, to extract\n peaks only above some minimum power threshold\n\n\n" + "### Extracting peaks from FOOOF Objects\n\nThe :func:`~.get_band_peak_fm` function takes in a\n:class:`~.FOOOF` object and extracts peak(s) from a requested frequency range.\n\nYou can optionally specify:\n\n- whether to return one peak from the specified band, in which case the highest peak is\n returned, or whether to return all peaks from within the band\n- whether to apply a minimum threshold to extract peaks, for example, to extract\n peaks only above some minimum power threshold\n\n\n" ] }, { @@ -141,7 +130,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Extracting peaks from FOOOFGroup Objects\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nSimilarly, the :func:`~.get_band_peak_fg` function can be used\nto select peaks from specified frequency ranges, from :class:`~fooof.FOOOFGroup` objects.\n\nNote that you can also apply a threshold to extract group peaks but, as discussed below,\nthis approach will always only extract at most one peak per individual model fit from\nthe FOOOFGroup object.\n\n\n" + "### Extracting peaks from FOOOFGroup Objects\n\nSimilarly, the :func:`~.get_band_peak_fg` function can be used\nto select peaks from specified frequency ranges, from :class:`~fooof.FOOOFGroup` objects.\n\nNote that you can also apply a threshold to extract group peaks but, as discussed below,\nthis approach will always only extract at most one peak per individual model fit from\nthe FOOOFGroup object.\n\n\n" ] }, { @@ -177,21 +166,21 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Customizing Peak Extraction\n~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nIf you want to do more customized extraction of peaks, for example, extracting all peaks\nin a frequency band from each model in a FOOOFGroup object, you may need to use the\nunderlying functions that operate on arrays of peak parameters. To explore these functions,\ncheck the listings in the API page.\n\n\n" + "### Customizing Peak Extraction\n\nIf you want to do more customized extraction of peaks, for example, extracting all peaks\nin a frequency band from each model in a FOOOFGroup object, you may need to use the\nunderlying functions that operate on arrays of peak parameters. To explore these functions,\ncheck the listings in the API page.\n\n\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "A Note on Frequency Ranges\n--------------------------\n\nA benefit of fitting power spectrum models is that you do not have to define\na priori frequency ranges from which to extract peaks.\n\nNevertheless, it may still be useful to group extracted peaks into 'bands' of interest,\nwhich is why the aforementioned functions are offered.\n\nSince this frequency-range selection can be done after model fitting, we do recommend\nchecking the model results, for example by checking a histogram of the center frequencies\nextracted across a group, in order to ensure the frequency ranges you choose reflect\nthe characteristics of the data under study.\n\n\n" + "## A Note on Frequency Ranges\n\nA benefit of fitting power spectrum models is that you do not have to define\na priori frequency ranges from which to extract peaks.\n\nNevertheless, it may still be useful to group extracted peaks into 'bands' of interest,\nwhich is why the aforementioned functions are offered.\n\nSince this frequency-range selection can be done after model fitting, we do recommend\nchecking the model results, for example by checking a histogram of the center frequencies\nextracted across a group, in order to ensure the frequency ranges you choose reflect\nthe characteristics of the data under study.\n\n\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "Analyzing the Aperiodic Component\n---------------------------------\n\nTypically, for analyzing the aperiodic component of the data, aperiodic parameters\njust need to be extracted from FOOOF objects and fit into analyses of interest.\n\n\n" + "## Analyzing the Aperiodic Component\n\nTypically, for analyzing the aperiodic component of the data, aperiodic parameters\njust need to be extracted from FOOOF objects and fit into analyses of interest.\n\n\n" ] }, { @@ -220,14 +209,14 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Example Analyses\n----------------\n\nOnce you have extracted parameters of interest, you can analyze them by, for example:\n\n- Characterizing periodic & aperiodic properties,\n and analyzing spatial topographies, across demographics, modalities, and tasks\n- Comparing peaks within and between subjects across different tasks of interest\n- Predicting disease state based on power spectrum model parameters\n- Fitting power spectrum models in a trial-by-trial approach to try and decode task\n properties, and behavioral states\n\nSo far we have only introduced the basic utilities to help with selecting and\nexamining power spectrum model parameters.\n\nTo further explore some of these specific analyses, and explore other\nutilities that may be useful, check out the\n`examples `_\npage.\n\n\n" + "## Example Analyses\n\nOnce you have extracted parameters of interest, you can analyze them by, for example:\n\n- Characterizing periodic & aperiodic properties,\n and analyzing spatial topographies, across demographics, modalities, and tasks\n- Comparing peaks within and between subjects across different tasks of interest\n- Predicting disease state based on power spectrum model parameters\n- Fitting power spectrum models in a trial-by-trial approach to try and decode task\n properties, and behavioral states\n\nSo far we have only introduced the basic utilities to help with selecting and\nexamining power spectrum model parameters.\n\nTo further explore some of these specific analyses, and explore other\nutilities that may be useful, check out the\n[examples](https://fooof-tools.github.io/fooof/auto_examples/index.html)\npage.\n\n\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "Conclusion\n----------\n\nThis is the end of the main tutorial materials!\n\nIf you are having any troubles, please submit an issue on Github\n`here `_.\n\n\n" + "## Conclusion\n\nThis is the end of the main tutorial materials!\n\nIf you are having any troubles, please submit an issue on Github\n[here](https://github.com/fooof-tools/fooof).\n\n\n" ] } ], @@ -247,7 +236,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.8.5" + "version": "3.8.3" } }, "nbformat": 4, diff --git a/_downloads/61f23ee9a2846fc99f182c81be62666c/plot_BandRatios.py b/_downloads/61f23ee9a2846fc99f182c81be62666c/plot_BandRatios.py index 030011dc..113e9347 100644 --- a/_downloads/61f23ee9a2846fc99f182c81be62666c/plot_BandRatios.py +++ b/_downloads/61f23ee9a2846fc99f182c81be62666c/plot_BandRatios.py @@ -44,7 +44,7 @@ from fooof.utils import trim_spectrum from fooof.sim.gen import gen_power_spectrum from fooof.sim.utils import set_random_seed -from fooof.plts.spectra import plot_spectrum_shading, plot_spectra_shading +from fooof.plts.spectra import plot_spectra_shading ################################################################################################### @@ -124,9 +124,9 @@ def calc_band_ratio(freqs, powers, low_band, high_band): ################################################################################################### # Plot the power spectrum, shading the frequency bands used for the ratio -plot_spectrum_shading(freqs, powers, [bands.theta, bands.beta], - color='black', shade_colors=shade_color, - log_powers=True, linewidth=3.5) +plot_spectra_shading(freqs, powers, [bands.theta, bands.beta], + color='black', shade_colors=shade_color, + log_powers=True, linewidth=3.5) ################################################################################################### diff --git a/_downloads/16d9586d4d5bb0e93cc846c336cef657/plot_freq_by_freq_error.py b/_downloads/6e8b93e073824005a7259de349123aeb/plot_freq_by_freq_error.py similarity index 100% rename from _downloads/16d9586d4d5bb0e93cc846c336cef657/plot_freq_by_freq_error.py rename to _downloads/6e8b93e073824005a7259de349123aeb/plot_freq_by_freq_error.py diff --git a/_downloads/6f1e7a639e0699d6164445b55e6c116d/auto_examples_jupyter.zip b/_downloads/6f1e7a639e0699d6164445b55e6c116d/auto_examples_jupyter.zip new file mode 100644 index 00000000..6420c341 Binary files /dev/null and b/_downloads/6f1e7a639e0699d6164445b55e6c116d/auto_examples_jupyter.zip differ diff --git a/_downloads/757ad6996ad8864ea6e92f8318944309/plot_dev_demo.py b/_downloads/757ad6996ad8864ea6e92f8318944309/plot_dev_demo.py new file mode 100644 index 00000000..99749e9d --- /dev/null +++ b/_downloads/757ad6996ad8864ea6e92f8318944309/plot_dev_demo.py @@ -0,0 +1,674 @@ +""" +Developmental Data Demo +======================= + +An example analysis applied to developmental data, demonstrating best practices. +""" + +################################################################################################### +# Spectral Parameterization for studying neurodevelopment +# ------------------------------------------------------- +# +# This example is adapted from the +# `Developmental Data Demo `_. +# +# If you wish to reference this example or use guidelines from it, please cite the associated +# paper `Spectral parameterization for studying neurodevelopment: how and why` by +# Brendan Ostlund, Thomas Donoghue, Berenice Anaya, Kelley E Gunther, Sarah L Karalunas, +# Bradley Voytek, and Koraly E Pérez-Edgar. +# +# Paper link: https://doi.org/10.1016/j.dcn.2022.101073 +# + +################################################################################################### + +# Import some useful standard library modules +from pathlib import Path + +# Import some general scientific python libraries +import numpy as np +import pandas as pd +import matplotlib.pyplot as plt + +# Import the parameterization model objects +from fooof import FOOOF, FOOOFGroup + +# Import useful parameterization related utilities and plot functions +from fooof.bands import Bands +from fooof.analysis import get_band_peak_fg +from fooof.utils import trim_spectrum +from fooof.utils.data import subsample_spectra +from fooof.sim.gen import gen_aperiodic +from fooof.data import FOOOFSettings +from fooof.plts.templates import plot_hist +from fooof.plts.spectra import plot_spectra +from fooof.plts.periodic import plot_peak_fits, plot_peak_params +from fooof.plts.aperiodic import plot_aperiodic_params, plot_aperiodic_fits + +# Import functions to examine frequency-by-frequency error of model fits +from fooof.analysis.error import compute_pointwise_error_fm, compute_pointwise_error_fg + +# Import helper utility to access data +from fooof.utils.download import fetch_fooof_data + +################################################################################################### +# Access Example Data +# ~~~~~~~~~~~~~~~~~~~ +# +# First, we will download the example data for this example. +# + +################################################################################################### + +# Set the URL where the data is available +data_url = 'https://raw.githubusercontent.com/fooof-tools/DevelopmentalDemo/main/Data/' + +# Set the data path to load from +data_path = Path('data') + +# Collect the example data +fetch_fooof_data('freqs.csv', data_path, data_url) +fetch_fooof_data('indv.csv', data_path, data_url) + +################################################################################################### +# Fitting an Individual Power Spectrum +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# For the first part of this example, we will start by loading and fitting an individual PSD. +# +# To do so, we start by loading some CSV files, including: +# +# - `freqs.csv`, which contains a vector of frequencies +# - `indvPSD.csv`, which contains the power values for an individual power spectrum +# + +################################################################################################### + +# Load data +freqs = np.ravel(pd.read_csv(data_path / "freqs.csv")) +spectrum = np.ravel(pd.read_csv(data_path / "indv.csv"))[1:101] + +################################################################################################### +# +# Now that we have loaded the data, we can parameterize our power spectrum! +# + +################################################################################################### + +# Define model settings +peak_width = [1, 8] # `peak_width_limit` setting +n_peaks = 6 # `max_n_peaks` setting +peak_height = 0.10 # `min_peak_height` setting + +# Define frequency range +PSD_range = [3, 40] + +################################################################################################### + +# Initialize a model object for spectral parameterization, with some settings +fm = FOOOF(peak_width_limits=peak_width, max_n_peaks=n_peaks, + min_peak_height=peak_height, verbose=False) + +# Fit individual PSD over 3-40 Hz range +fm.report(freqs, spectrum, PSD_range) + +################################################################################################### +# +# As a reminder you can save these reports using the `.save_report()` method, for example, +# by running `fm.save_report('INDV_demo', file_path=output_path)`. +# + +################################################################################################### +# +# All of the model fit information is saved to the model object, which we can then access. +# +# Note that all attributes learned in the model fit process have a trailing underscore. +# + +################################################################################################### + +# Access the model fit parameters from the model object +print('Aperiodic parameters: \n', fm.aperiodic_params_, '\n') +print('Peak parameters: \n', fm.peak_params_, '\n') +print('Goodness of fit:') +print('Error - ', fm.error_) +print('R^2 - ', fm.r_squared_, '\n') +print('Number of fit peaks: \n', fm.n_peaks_) + +################################################################################################### +# +# Another way to access model fit parameters is to use the `get_params` method, +# which can be used to access model fit attributes. +# +# This method can be used to extract periodic and aperiodic parameters. +# + +################################################################################################### + +# Extract aperiodic and periodic parameter +aps = fm.get_params('aperiodic_params') +peaks = fm.get_params('peak_params') + +################################################################################################### + +# Extract goodness of fit information +err = fm.get_params('error') +r2s = fm.get_params('r_squared') + +################################################################################################### + +# Extract specific parameters +exp = fm.get_params('aperiodic_params', 'exponent') +cfs = fm.get_params('peak_params', 'CF') + +################################################################################################### + +# Print out a custom parameter report +template = ("With an error level of {error:1.2f}, specparam fit an exponent " + "of {exponent:1.2f} and peaks of {cfs:s} Hz.") +print(template.format(error=err, exponent=exp, + cfs=' & '.join(map(str, [round(CF, 2) for CF in cfs])))) + +################################################################################################### +# +# Next, we will plot the flattened power spectrum. +# +# It may be useful to plot a flattened power spectrum, with the aperiodic fit removed. +# + +################################################################################################### + +# Set whether to plot in log-log space +plt_log = False + +# Do an initial aperiodic fit - a robust fit, that excludes outliers +init_ap_fit = gen_aperiodic(fm.freqs, fm._robust_ap_fit(fm.freqs, fm.power_spectrum)) + +# Recompute the flattened spectrum using the initial aperiodic fit +init_flat_spec = fm.power_spectrum - init_ap_fit + +################################################################################################### + +# Plot the flattened the power spectrum +plot_spectra(fm.freqs, init_flat_spec, plt_log, label='Flattened spectrum', color='black') + +################################################################################################### +# +# The model object also has I/O utilities for saving and reloading data. +# +# The `.save` method can be used to save out data from the object, +# specifying which information to save. +# +# For example, you can save results with the following: +# - settings: `fm.save('fit_settings', save_settings=True, file_path=output_path) +# - results: `fm.save('fit_results', save_results=True, file_path=output_path)` +# - data: `fm.save('fit_data', save_data=True, file_path=output_path)` +# +# Another option is to save out data as a .csv rather than the default .json file format. +# You can do this be exporting the results to a dataframe (see other examples for further +# guidance on this topic). +# + +################################################################################################### + +# Convert results to dataframe +df = fm.to_df(None) + +################################################################################################### +# +# The above dataframe can be saved out to a csv using the `to_csv` method. +# + +################################################################################################### +# Checking model fit quality +# ~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# It can be useful to plot frequency-by-frequency error of the model fit, +# to identify where in frequency space the spectrum is (or is not) being fit well. +# When fitting individual spectrum, this can be accomplished using the +# `compute_pointwise_error_fm` function. +# +# In this case, we can see that error fluctuates around 0.05, which is the same as +# the mean absolute error for the model (MAE). There are points in the spectrum where +# the model fit is somewhat poor, particularly < 4 Hz, around 6-9 Hz, and around 14 Hz. +# Further considerations may be necessary for this model fit. +# + +################################################################################################### + +# Plot frequency-by-frequency error +compute_pointwise_error_fm(fm, plot_errors=True) + +################################################################################################### + +# Compute the frequency-by-frequency errors +errs_fm = compute_pointwise_error_fm(fm, plot_errors=False, return_errors=True) + +################################################################################################### + +# Note that the average of this error is the same as the global error stored +print('Average freq-by-freq error:\t {:1.3f}'.format(np.mean(errs_fm))) +print('FOOOF model fit error: \t\t {:1.3f}'.format(fm.error_)) + +################################################################################################### +# Fitting a Group of Power Spectra +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# In the next example, we will fit a group of power spectra. +# +# First we need to load the data, including: +# +# - `freqs.csv`, which contains a vector of frequencies +# - `eopPSDs.csv`, which contains the power values for a group of power spectrum, one for each subject +# + +################################################################################################### + +# Collect the example data +fetch_fooof_data('freqs.csv', data_path, data_url) +fetch_fooof_data('eop.csv', data_path, data_url) + +################################################################################################### + +# Load csv files containing frequency and power values +freqs = np.ravel(pd.read_csv(data_path / "freqs.csv")) +spectra = np.array(pd.read_csv(data_path / "eop.csv"))[:, 1:101] + +################################################################################################### + +# Get the number of subjects +n_subjs = spectra.shape[0] +print('There are {:d} subjects.'.format(n_subjs)) + +################################################################################################### +# +# Now we can parameterize our group of power spectra! +# + +################################################################################################### + +# Initialize a model object for spectral parameterization, with some settings +fg = FOOOFGroup(peak_width_limits=peak_width, max_n_peaks=n_peaks, + min_peak_height=peak_height, verbose=False) + +# Fit group PSDs over the 3-40 Hz range +fg.fit(freqs, spectra, PSD_range) + +################################################################################################### + +# Print out the group results and plots of fit parameters +fg.print_results() +fg.plot() + +################################################################################################### +# +# As before, we can also save this report using the `.save_report` method, for example by +# calling: `fg.save_report('EOP_demo', file_path=output_path)`. +# + +################################################################################################### +# +# As with the individual model object, the `get_params` method can be +# used to access model fit attributes. +# +# In addition, here we will use a `Bands` object and the `get_band_peak_fg` +# function to organize fit peaks into canonical band ranges. +# + +################################################################################################### + +# Extract aperiodic and full periodic parameters +aps = fg.get_params('aperiodic_params') +per = fg.get_params('peak_params') + +################################################################################################### + +# Extract group fit information +err = fg.get_params('error') +r2s = fg.get_params('r_squared') + +################################################################################################### + +# Check the average number of fit peaks, per model +print('Average number of fit peaks: ', np.mean(fg.n_peaks_)) + +################################################################################################### + +# Define canonical frequency bands +bands = Bands({'theta' : [4, 8], + 'alpha' : [8, 13], + 'beta' : [13, 30]}) + +################################################################################################### + +# Extract band-limited peaks information +thetas = get_band_peak_fg(fg, bands.theta) +alphas = get_band_peak_fg(fg, bands.alpha) +betas = get_band_peak_fg(fg, bands.beta) + +################################################################################################### +# +# The specparam module also has functions for plotting the fit parameters. +# + +################################################################################################### + +# Plot the measured aperiodic parameters +plot_aperiodic_params(aps) + +################################################################################################### + +# Plot the parameters for peaks, split up by band +_, axes = plt.subplots(1, 3, figsize=(14, 7)) +all_bands = [thetas, alphas, betas] +for ax, label, peaks in zip(np.ravel(axes), bands.labels, all_bands): + plot_peak_params(peaks, ax=ax) + ax.set_title(label + ' peaks', fontsize=24) +plt.subplots_adjust(hspace=0.4) + +################################################################################################### +# +# We can also plot reconstructions of model components. +# +# In the following, we plot reconstructed alpha peaks and aperiodic components. +# + +################################################################################################### + +# Plot reconstructions of model components +_, axes = plt.subplots(1, 2, figsize=(14, 6)) +plot_peak_fits(alphas, ax=axes[0]) +plot_aperiodic_fits(aps, fg.freq_range, ax=axes[1]) + +################################################################################################### +# Tuning the specparam algorithm +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# There are no strict guidelines about optimal parameters that will be appropriate +# across data sets and recording modalities. We suggest applying a data-driven approach +# to tune model fitting for optimal performance, while taking into account your expectations +# about periodic and aperiodic activity given the data, the question of interest, and prior findings. +# +# One option is to parameterize a subset of data to evaluate the appropriateness of model +# fit settings prior to fitting each power spectrum in the data set. +# Here, we test parameters on a randomly selected 10% of the data. +# Results are saved out to a **Output** folder for further consideration. +# +# First, lets randomly sub-sample 10% of the power spectra that we will use to test model settings. +# + +################################################################################################### + +# Set random seed +np.random.seed(1) + +# Define settings for & subsample a selection of power spectra +subsample_frac = 0.10 +spectra_subsample = subsample_spectra(spectra, subsample_frac) + +################################################################################################### +# +# Here, we first define settings for two models to be fit and compared. +# + +################################################################################################### + +# Define `peak_width_limit` for each model +m1_peak_width = [2, 5] +m2_peak_width = [1, 8] + +# Define `max_n_peaks` for each model +m1_n_peaks = 4 +m2_n_peaks = 6 + +# Define `min_peak_height` for each model +m1_peak_height = 0.05 +m2_peak_height = 0.10 + +################################################################################################### +# +# Next, we set frequency ranges for each model. +# +# To sub-select frequency ranges, we can use the `trim_spectrum` function +# to extract frequency ranges of interest for each model. +# + +################################################################################################### + +# Define frequency range for each model +m1_PSD_range = [2, 20] +m2_PSD_range = [3, 40] + +# Sub-select frequency ranges +m1_freq, m1_spectra = trim_spectrum(freqs, spectra_subsample, m1_PSD_range) +m2_freq, m2_spectra = trim_spectrum(freqs, spectra_subsample, m2_PSD_range) + +################################################################################################### +# +# Fit models, with different settings. +# + +################################################################################################### + +# Fit model object with model 1 settings +fg1 = FOOOFGroup(peak_width_limits=m1_peak_width, max_n_peaks=m1_n_peaks, + min_peak_height=m1_peak_height) +fg1.fit(m1_freq, m1_spectra) + +# Create individual reports for model 1 settings (these could be saved and checked) +for ind in range(len(fg1)): + temp_model = fg1.get_fooof(ind, regenerate=True) + +################################################################################################### +# +# We can do the same with the other set of settings. +# + +################################################################################################### + +# Fit model object with model 2 settings +fg2 = FOOOFGroup(peak_width_limits=m2_peak_width, max_n_peaks=m2_n_peaks, + min_peak_height=m2_peak_height) +fg2.fit(m2_freq, m2_spectra) + +# Create individual reports for model 2 settings (these could be saved and checked) +for ind in range(len(fg2)): + temp_model = fg2.get_fooof(ind, regenerate=True) + +################################################################################################### +# +# There are also other ways to manage settings, for example, using the `FOOOFSettings` object. +# +# Here we will redefine group model objects (`FOOOFGroup`), +# again using different settings for each one. +# + +################################################################################################### + +# Define settings for model 1 +settings1 = FOOOFSettings(peak_width_limits=m1_peak_width, max_n_peaks=m1_n_peaks, + min_peak_height=m1_peak_height, peak_threshold=2., + aperiodic_mode='fixed') + +# Define settings for model 2 +settings2 = FOOOFSettings(peak_width_limits=m2_peak_width, max_n_peaks=m2_n_peaks, + min_peak_height=m2_peak_height, peak_threshold=2., + aperiodic_mode='fixed') + +################################################################################################### + +# Initialize model objects for spectral parameterization, with some settings +fg1 = FOOOFGroup(*settings1) +fg2 = FOOOFGroup(*settings2) + +################################################################################################### +# +# Now, let's fit models with group model object +# +# Note that when fitting power spectra, you can can specify a fit range to fit the model to, +# so you don't have to explicitly trim the spectra. +# +# Here we will refit the example data, specifying the fit range, and then save the group reports. +# + +################################################################################################### + +# Fit group PSD over the 2-20 Hz and 3-40 Hz ranges, respectively +fg1.fit(freqs, spectra_subsample, freq_range=m1_PSD_range) +fg2.fit(freqs, spectra_subsample, freq_range=m2_PSD_range) + +################################################################################################### +# +# At this point, it may typically be useful to save out reports from the above +# different model fits (using `.save_report`), such that these different setting regimes +# can be compared. +# + +################################################################################################### +# +# After selecting initial model fit settings, and fitting power spectra from the full sample, +# it is often worthwhile to check the goodness of model fit parameters. Please note, +# the model objects below correspond to the model fit at the top of this script. +# + +################################################################################################### + +# Plot distributions of goodness of fit parameters +# This information is presented in the print_reports output as well +fig, (ax0, ax1) = plt.subplots(1, 2, figsize=(14, 6)) +plot_hist(r2s, label='Variance explained (R^2)', ax=ax0) +plot_hist(err, label='Mean absolute error (MAE)', ax=ax1) + +################################################################################################### + +# Find the index of the worst model fit from the group +worst_fit_ind = np.argmax(fg.get_params('error')) + +# Extract this model fit from the group +fm = fg.get_fooof(worst_fit_ind, regenerate=True) + +################################################################################################### + +# Check results and visualize the extracted model +fm.print_results() +fm.plot() + +################################################################################################### +# +# Now, let's check for potential under-fitting. +# + +################################################################################################### + +# Extract all fits that are above some error threshold, for further examination. +underfit_error_threshold = 0.100 +underfit_check = [] +for ind, res in enumerate(fg): + if res.error > underfit_error_threshold: + underfit_check.append(fg.get_fooof(ind, regenerate=True)) + +################################################################################################### + +# Loop through the problem fits check the plots +for ind, fm in enumerate(underfit_check): + fm.plot() + +################################################################################################### +# +# Let's also check for potential over-fitting. +# + +################################################################################################### + +# Extract all fits that are below some error threshold, for further examination. +overfit_error_threshold = 0.02 +overfit_check = [] +for ind, res in enumerate(fg): + if res.error < overfit_error_threshold: + overfit_check.append(fg.get_fooof(ind, regenerate=True)) + +################################################################################################### + +# Loop through the problem fits and check the plots +for ind, fm in enumerate(overfit_check): + fm.plot() + +################################################################################################### +# +# The same approach for saving out data is available in the group object, +# using the `save` method, for example: +# +# - settings: `fg.save('group_settings', save_settings=True, file_path=output_path)` +# - results: `fg.save('group_results', save_results=True, file_path=output_path)` +# + +################################################################################################### +# +# Another option is to export results to a dataframe (from which CSV files can be saved). +# + +################################################################################################### + +# Save out aperiodic parameter results +df = fg.to_df(2) + +################################################################################################### +# Frequency-by-frequency errors +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# It can be useful to plot frequency-by-frequency error of the model fit, +# to identify where in frequency space the spectrum is (or is not) being fit well. +# When fitting individual spectrum, this can be accomplished using the +# `compute_pointwise_error_fg` function. When plotting the error, the plot line is +# the mean error per frequency, across fits, and the shading indicates the standard deviation +# of the error, also per frequency. +# +# In this case, we can see that error fluctuates around 0.03, which is the same as +# the mean absolute error for this group fit. There are points in the spectrum where +# the model fit is somewhat poor, particularly < 4 Hz. +# The code below lets you identify the highest mean error and largest standard deviation +# in error for the group fit. In this case, that occurs at 3 Hz, +# suggesting potential issues with fit at the lower end of the examined frequency range. +# + +################################################################################################### + +# Plot frequency-by-frequency error +compute_pointwise_error_fg(fg, plot_errors=True) + +################################################################################################### + +# Return the errors - this returns a 2D matrix of errors for all fits +errs_fg = compute_pointwise_error_fg(fg, plot_errors=False, return_errors=True) + +# Check which frequency has the highest error +f_max_err = fg.freqs[np.argmax(np.mean(errs_fg, 0))] +print('Frequency with highest mean error: \t\t\t', f_max_err) + +# Check which frequency has the largest standard deviation of error +f_max_std = fg.freqs[np.argmax(np.std(errs_fg, 0))] +print('Frequency with highest standard deviation of error: \t', f_max_std) + +################################################################################################### +# +# In some cases, it may be necessary to drop poor (or failed) model fits from the group object. +# This can be done using the `fg.drop` function, as shown here. +# In this case, we remove a participant who has a MAE greater than 0.10. +# The error threshold will vary depending on sample characteristics and data quality. +# + +################################################################################################### + +# Drop poor model fits based on MAE +fg.drop(fg.get_params('error') > 0.10) + +################################################################################################### +# Conclusions +# ~~~~~~~~~~~ +# +# For more on this topic, see the +# `DevelopmentalDemo repository `_ +# and/or the +# `associated paper `_ +# for further information. +# diff --git a/_downloads/eebc708cc845523a84d0cf30424adf0a/auto_motivations_jupyter.zip b/_downloads/7997080f3b093e0efee4971aee8e0aa1/auto_motivations_jupyter.zip similarity index 60% rename from _downloads/eebc708cc845523a84d0cf30424adf0a/auto_motivations_jupyter.zip rename to _downloads/7997080f3b093e0efee4971aee8e0aa1/auto_motivations_jupyter.zip index 2f07c42d..f55f72a7 100644 Binary files a/_downloads/eebc708cc845523a84d0cf30424adf0a/auto_motivations_jupyter.zip and b/_downloads/7997080f3b093e0efee4971aee8e0aa1/auto_motivations_jupyter.zip differ diff --git a/_downloads/7cf9bac5ed0cb61d9ff9e816f3a60dce/plot_09-Reporting.ipynb b/_downloads/7cf9bac5ed0cb61d9ff9e816f3a60dce/plot_09-Reporting.ipynb new file mode 100644 index 00000000..9381bd2e --- /dev/null +++ b/_downloads/7cf9bac5ed0cb61d9ff9e816f3a60dce/plot_09-Reporting.ipynb @@ -0,0 +1,213 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n# 09: Reporting & Referencing\n\nThis section covers how to access reporting info and reference use of the module.\n\nThis page is a hands-on example of the reporting and referencing information on the\n[Reference page](https://fooof-tools.github.io/fooof/reference.html).\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Import FOOOF model objects\nfrom fooof import FOOOF, FOOOFGroup\n\n# Import simulation functions to create some example data\nfrom fooof.sim import gen_power_spectrum, gen_group_power_spectra\n\n# Import utilities to print out information for reporting\nfrom fooof.utils.reports import methods_report_info, methods_report_text" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Checking Module Version\n\nIt's useful and important to keep track of which version of the module you are using,\nand to report this information when referencing use of the tool.\n\nThere are several ways to check the version of the the module that you are using,\nincluding checking what is installed in the Python environment you are using.\n\nFrom within Python, you can also check the version of the module by checking\n`__version__`, as shown below:\n\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Check the version of the module\nfrom fooof import __version__ as fooof_version\nprint('Current fooof version:', fooof_version)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Getting Model Reporting Information\n\nTo assist with reporting information, the module has the following utilities:\n\n- the :func:`~.methods_report_info`, which prints out methods reporting information\n- the :func:`~.methods_report_text`, which prints out a template of methods reporting text\n\nBoth of the these functions take as input a model object, and use the object to\ncollect and return information related to the model fits.\n\nNote that not all information may be returned by the model - these methods only have access\nto the current object. This means it is also important that if you use these functions,\nyou use them with objects that match the settings and data used in the analysis to be reported.\n\nIn the following, we will explore an example of using these functions for an example model fit.\n\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Initialize model object\nfooof_obj = FOOOF()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Print out all the methods information for reporting\nmethods_report_info(fooof_obj)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "You might notice that the above function prints out several different sections,\nsome of which might look familiar.\n\nThe settings information, for example, is the same as printed using the\n# - :meth:`~fooof.FOOOF.print_settings` method.\n\nNext, let's check out the text version of the methods report.\n\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Generate methods text, with methods information inserted\nmethods_report_text(fooof_obj)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Additional Examples\n\nIn the above examples, not all the information was printed, as not all information was\navailable in the example object (for example, it had no data).\n\nIn the next example, let's see how the outputs look for an example object with model fit results.\n\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Simulate an example power spectrum\nfreqs, powers = gen_power_spectrum([1, 50], [0, 10, 1], [10, 0.25, 2], freq_res=0.25)\n\n# Initialize model object\nfm = FOOOF(min_peak_height=0.1, peak_width_limits=[1, 6], aperiodic_mode='knee')\nfm.fit(freqs, powers)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Generate methods text, with methods information inserted\nmethods_report_info(fm)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Generate methods text, with methods information inserted\nmethods_report_text(fm)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The report text is meant as a template / example that could be added to a methods section.\n\nNote that there may be missing information that needs to be filled in (indicated by 'XX's),\nand you can and should consider this a template to be edited as needed.\n\n\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Other Model Objects\n\nNote that the reporting functions work with any model object.\n\nFor example, next we will use them on a :class:`~fooof.FOOOFGroup` object.\n\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Simulate an example group of power spectra\nfreqs, powers = gen_group_power_spectra(10, [1, 75], [0, 1], [10, 0.25, 2])" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Initialize and fit group model object\nfg = FOOOFGroup(max_n_peaks=4, peak_threshold=1.75)\nfg.fit(freqs, powers)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Generate the methods report information\nmethods_report_info(fg)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Generate the methods report text\nmethods_report_text(fg)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "That concludes the example of using the helper utilities for generating methods reports!\n\n\n" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.8.3" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} \ No newline at end of file diff --git a/_downloads/7e099e5ab5f83bfcc6b644a0c2cd6393/plot_fooof_models.ipynb b/_downloads/7e099e5ab5f83bfcc6b644a0c2cd6393/plot_fooof_models.ipynb index f00aed97..b86fd224 100644 --- a/_downloads/7e099e5ab5f83bfcc6b644a0c2cd6393/plot_fooof_models.ipynb +++ b/_downloads/7e099e5ab5f83bfcc6b644a0c2cd6393/plot_fooof_models.ipynb @@ -1,21 +1,10 @@ { "cells": [ - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "collapsed": false - }, - "outputs": [], - "source": [ - "%matplotlib inline" - ] - }, { "cell_type": "markdown", "metadata": {}, "source": [ - "\nPlot Power Spectrum Models\n==========================\n\nPlotting power spectrum models, directly from FOOOF objects.\n\nIn order to the get a qualitative sense of if the model is fitting well, and what\nthe results look like, it can be useful to visualize power spectrum model reconstructions.\n\nThis example dives deeper into plotting model reconstructions, using the\n:meth:`~fooof.FOOOF.plot` method from a :class:`~fooof.FOOOF` object, and explores\noptions for tuning these these visualizations.\n" + "\n# Plot Power Spectrum Models\n\nPlotting power spectrum models, directly from FOOOF objects.\n\nIn order to the get a qualitative sense of if the model is fitting well, and what\nthe results look like, it can be useful to visualize power spectrum model reconstructions.\n\nThis example dives deeper into plotting model reconstructions, using the\n:meth:`~fooof.FOOOF.plot` method from a :class:`~fooof.FOOOF` object, and explores\noptions for tuning these these visualizations.\n" ] }, { @@ -44,7 +33,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Plotting From FOOOF Objects\n~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nThe FOOOF object has a :meth:`~fooof.FOOOF.plot` method that can be used to visualize\ndata and models available in the :class:`~fooof.FOOOF` object.\n\n\n" + "## Plotting From FOOOF Objects\n\nThe FOOOF object has a :meth:`~fooof.FOOOF.plot` method that can be used to visualize\ndata and models available in the :class:`~fooof.FOOOF` object.\n\n\n" ] }, { @@ -98,7 +87,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Plotting Aperiodic Components\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nAs you can see above, the :meth:`~fooof.FOOOF.plot` call by default also plots the\naperiodic component, in a dashed blue line.\n\nYou can toggle whether to display the aperiodic component with the\n``plot_aperiodic`` parameter.\n\n\n" + "## Plotting Aperiodic Components\n\nAs you can see above, the :meth:`~fooof.FOOOF.plot` call by default also plots the\naperiodic component, in a dashed blue line.\n\nYou can toggle whether to display the aperiodic component with the\n``plot_aperiodic`` parameter.\n\n\n" ] }, { @@ -116,7 +105,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Plotting Periodic Components\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nBy default the peaks are only visualized as parts of the full model fit.\n\nHowever, in some cases it can be useful to more explicitly visualize individual peaks,\nincluding where they are and if and how they overlap.\n\nTo do so, you can use the ``plot_peaks`` parameter, passing in a string specifier\nof which approach you wish to use to visualize the peaks.\n\nThere are four options for visualizing peaks:\n\n- 'shade' : shade in peaks\n- 'dot' : add a line through the peak, with a dot at the top\n- 'outline' : outline each peak\n- 'line' : add a vertical line through the whole plot at peak locations\n\n\n" + "## Plotting Periodic Components\n\nBy default the peaks are only visualized as parts of the full model fit.\n\nHowever, in some cases it can be useful to more explicitly visualize individual peaks,\nincluding where they are and if and how they overlap.\n\nTo do so, you can use the ``plot_peaks`` parameter, passing in a string specifier\nof which approach you wish to use to visualize the peaks.\n\nThere are four options for visualizing peaks:\n\n- 'shade' : shade in peaks\n- 'dot' : add a line through the peak, with a dot at the top\n- 'outline' : outline each peak\n- 'line' : add a vertical line through the whole plot at peak locations\n\n\n" ] }, { @@ -181,7 +170,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Other Plotting Options\n~~~~~~~~~~~~~~~~~~~~~~\n\nThere are also some other optional inputs to the :meth:`~fooof.FOOOF.plot` call, including:\n\n- `plt_log` : Optional input for plotting the frequency axis in log10 spacing\n- `add_legend` : Optional input to toggle whether to add a legend\n- `save_fig` : Optional input for whether to save out the figure\n\n - you can control the filename and where to save to with `file_name` and `file_path`\n- `ax` : Optional input to specify a matplotlib axes object to plot to\n\n\n" + "## Other Plotting Options\n\nThere are also some other optional inputs to the :meth:`~fooof.FOOOF.plot` call, including:\n\n- `plt_log` : Optional input for plotting the frequency axis in log10 spacing\n- `add_legend` : Optional input to toggle whether to add a legend\n- `save_fig` : Optional input for whether to save out the figure\n\n - you can control the filename and where to save to with `file_name` and `file_path`\n- `ax` : Optional input to specify a matplotlib axes object to plot to\n\n\n" ] }, { @@ -212,7 +201,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.8.5" + "version": "3.8.3" } }, "nbformat": 4, diff --git a/_downloads/8bfec2e3f0f74ee4d9194f322c31b51e/plot_01-ModelDescription.ipynb b/_downloads/8bfec2e3f0f74ee4d9194f322c31b51e/plot_01-ModelDescription.ipynb index 66730ec0..e7d76abc 100644 --- a/_downloads/8bfec2e3f0f74ee4d9194f322c31b51e/plot_01-ModelDescription.ipynb +++ b/_downloads/8bfec2e3f0f74ee4d9194f322c31b51e/plot_01-ModelDescription.ipynb @@ -1,35 +1,24 @@ { "cells": [ - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "collapsed": false - }, - "outputs": [], - "source": [ - "%matplotlib inline" - ] - }, { "cell_type": "markdown", "metadata": {}, "source": [ - "\n01: Model Description\n=====================\n\nA description of and introduction to the power spectrum model.\n" + "\n# 01: Model Description\n\nA description of and introduction to the power spectrum model.\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "Introduction\n------------\n\nWelcome to the tutorials!\n\nIn this first tutorial, we will introduce an overview and description of power spectrum\nmodel, as well as visualizing some examples.\n\nKeep in mind as you go, that if you want more information that describes, motivates, and\njustifies our modeling approach, you can also check out the associated\n`paper `_,\nand/or the\n`motivations `_\nsection of the site.\n\n\n" + "## Introduction\n\nWelcome to the tutorials!\n\nIn this first tutorial, we will introduce an overview and description of power spectrum\nmodel, as well as visualizing some examples.\n\nKeep in mind as you go, that if you want more information that describes, motivates, and\njustifies our modeling approach, you can also check out the associated\n[paper](https://www.biorxiv.org/content/early/2018/04/11/299859),\nand/or the\n[motivations](https://fooof-tools.github.io/fooof/auto_tutorials/index.html)\nsection of the site.\n\n\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "Example Power Spectra and Models\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nFirst, we will import and run some code to simulate some example power spectra, and\nfit some power spectrum models to them, to use as examples.\n\nFor the purpose of this tutorial, you don't need to know how this code works\nyet, and can skip past reading the code itself.\n\n\n" + "### Example Power Spectra and Models\n\nFirst, we will import and run some code to simulate some example power spectra, and\nfit some power spectrum models to them, to use as examples.\n\nFor the purpose of this tutorial, you don't need to know how this code works\nyet, and can skip past reading the code itself.\n\n\n" ] }, { @@ -40,7 +29,7 @@ }, "outputs": [], "source": [ - "# Import required code for visualizing example models\nfrom fooof import FOOOF\nfrom fooof.sim.gen import gen_power_spectrum\nfrom fooof.sim.utils import set_random_seed\nfrom fooof.plts.spectra import plot_spectrum\nfrom fooof.plts.annotate import plot_annotated_model" + "# Import required code for visualizing example models\nfrom fooof import FOOOF\nfrom fooof.sim.gen import gen_power_spectrum\nfrom fooof.sim.utils import set_random_seed\nfrom fooof.plts.spectra import plot_spectra\nfrom fooof.plts.annotate import plot_annotated_model" ] }, { @@ -80,21 +69,21 @@ }, "outputs": [], "source": [ - "# Plot one of the example power spectra\nplot_spectrum(freqs1, powers1, log_powers=True,\n color='black', label='Original Spectrum')" + "# Plot one of the example power spectra\nplot_spectra(freqs1, powers1, log_powers=True,\n color='black', label='Original Spectrum')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "Conceptual Overview\n-------------------\n\nThe goal of this module is to fit models to parameterize neural power spectra.\n\nOne reason to do so is the idea that there are multiple distinct 'components' within\nneural field data. The model is therefore designed to measure these different\n'components' of the data.\n\nBy components, we mean that we are going to conceptualize neural field data as consisting\nof a combination of periodic (oscillatory) and aperiodic activity. Restated, we could say\nthat neural data contains both periodic and aperiodic components.\n\nThe goal of the model is to measure these components, separately and explicitly,\nfrom frequency representations of neural field data (neural power spectra).\n\n\n" + "## Conceptual Overview\n\nThe goal of this module is to fit models to parameterize neural power spectra.\n\nOne reason to do so is the idea that there are multiple distinct 'components' within\nneural field data. The model is therefore designed to measure these different\n'components' of the data.\n\nBy components, we mean that we are going to conceptualize neural field data as consisting\nof a combination of periodic (oscillatory) and aperiodic activity. Restated, we could say\nthat neural data contains both periodic and aperiodic components.\n\nThe goal of the model is to measure these components, separately and explicitly,\nfrom frequency representations of neural field data (neural power spectra).\n\n\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "Visualizing Power Spectrum Models\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nFirst, let's start by revisiting the example power spectrum, this time also adding the model\nfit to the plot.\n\nIn the plot below, black is the data, same as before, and in red we've added the\nmodel fit of the data. If things are working, this line should be good approximation\nof the data.\n\n\n" + "### Visualizing Power Spectrum Models\n\nFirst, let's start by revisiting the example power spectrum, this time also adding the model\nfit to the plot.\n\nIn the plot below, black is the data, same as before, and in red we've added the\nmodel fit of the data. If things are working, this line should be good approximation\nof the data.\n\n\n" ] }, { @@ -119,14 +108,14 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Mathematical Description of Overall Model\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nTo enact the conceptual idea described above, we will need to formalize the model. To do\nso, throughout the rest of this tutorial, we will lay out the mathematical description of\nhow neural power spectra can be modeled as a combination of periodic and aperiodic activity.\n\nOverall, the goal is to describe a neural power spectrum, described as $NPS$, as\na combination of periodic and aperiodic components. We will describe each of these\ncomponents in their own section.\n\nNote that as we go, we will continue to consider power in log10 spacing. You will\nalso see each component includes $(F)$, where $F$ is the array of\nfrequency values (in linear spacing) for the power spectrum, which just indicates that\neach component is a function of frequency.\n\n\n" + "### Mathematical Description of Overall Model\n\nTo enact the conceptual idea described above, we will need to formalize the model. To do\nso, throughout the rest of this tutorial, we will lay out the mathematical description of\nhow neural power spectra can be modeled as a combination of periodic and aperiodic activity.\n\nOverall, the goal is to describe a neural power spectrum, described as $NPS$, as\na combination of periodic and aperiodic components. We will describe each of these\ncomponents in their own section.\n\nNote that as we go, we will continue to consider power in log10 spacing. You will\nalso see each component includes $(F)$, where $F$ is the array of\nfrequency values (in linear spacing) for the power spectrum, which just indicates that\neach component is a function of frequency.\n\n\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "Periodic Component\n------------------\n\nBy periodic activity, we mean activity that has a characteristic frequency.\nThis includes what are typically referred to as neural oscillations, often described\nin particular frequency bands such as delta, theta, alpha, beta, gamma, etc.\n\nIn the frequency domain, putative oscillations are frequency regions in which\nthere are 'bumps' of power over and above the aperiodic component.\nWe will generally refer to the these as 'peaks' in the neural power spectrum.\n\nTo measure the periodic activity, we would like to describe these peaks, without our\nmeasures of these peaks being influenced by co-occurring aperiodic activity.\nThis is important, since, as we can see in the plots above, the aperiodic and periodic\ncomponents of the data can 'overlap', in frequency space. This means the total power\nat a given frequency may have contributions from both components. To measure periodic power,\nspecifically, we need to measure the power relative to the aperiodic component of the data.\n\nNext, let's explore an annotated version of our power spectrum model.\n\n\n" + "## Periodic Component\n\nBy periodic activity, we mean activity that has a characteristic frequency.\nThis includes what are typically referred to as neural oscillations, often described\nin particular frequency bands such as delta, theta, alpha, beta, gamma, etc.\n\nIn the frequency domain, putative oscillations are frequency regions in which\nthere are 'bumps' of power over and above the aperiodic component.\nWe will generally refer to the these as 'peaks' in the neural power spectrum.\n\nTo measure the periodic activity, we would like to describe these peaks, without our\nmeasures of these peaks being influenced by co-occurring aperiodic activity.\nThis is important, since, as we can see in the plots above, the aperiodic and periodic\ncomponents of the data can 'overlap', in frequency space. This means the total power\nat a given frequency may have contributions from both components. To measure periodic power,\nspecifically, we need to measure the power relative to the aperiodic component of the data.\n\nNext, let's explore an annotated version of our power spectrum model.\n\n\n" ] }, { @@ -151,14 +140,14 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Mathematical Description of the Periodic Component\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nTo fit this periodic activity - the regions of power over above the aperiodic component,\nor 'peaks' - the model uses Gaussians. As we've seen, there can be multiple peaks in the model.\n\nEach Gaussian, $n$, referred to as $G(F)_n$, is of the form:\n\n\\begin{align}G(F)_n = a * exp (\\frac{- (F - c)^2}{2 * w^2})\\end{align}\n\nThis describes each peak in terms of parameters `a`, `c` and `w`, where:\n\n- $a$ is the height of the peak, over and above the aperiodic component\n- $c$ is the center frequency of the peak\n- $w$ is the width of the peak\n- $F$ is the array of frequency values\n\n\n" + "### Mathematical Description of the Periodic Component\n\nTo fit this periodic activity - the regions of power over above the aperiodic component,\nor 'peaks' - the model uses Gaussians. As we've seen, there can be multiple peaks in the model.\n\nEach Gaussian, $n$, referred to as $G(F)_n$, is of the form:\n\n\\begin{align}G(F)_n = a * exp (\\frac{- (F - c)^2}{2 * w^2})\\end{align}\n\nThis describes each peak in terms of parameters `a`, `c` and `w`, where:\n\n- $a$ is the height of the peak, over and above the aperiodic component\n- $c$ is the center frequency of the peak\n- $w$ is the width of the peak\n- $F$ is the array of frequency values\n\n\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "Aperiodic Component\n-------------------\n\nBy 'aperiodic' activity, we mean activity that is not rhythmic, or activity that has\nno characteristic frequency.\n\nIn the power spectrum, we typically see this as 1/f-like activity, whereby (in linear space)\nthe power across frequencies decreases with a $\\frac{1}{F^\\chi}$ relationship.\n\nTo measure the aperiodic activity, we would like to describe the pattern of activity\nacross all frequencies, without our measure being influenced by co-occurring periodic\nactivity (peaks).\n\n\n" + "## Aperiodic Component\n\nBy 'aperiodic' activity, we mean activity that is not rhythmic, or activity that has\nno characteristic frequency.\n\nIn the power spectrum, we typically see this as 1/f-like activity, whereby (in linear space)\nthe power across frequencies decreases with a $\\frac{1}{F^\\chi}$ relationship.\n\nTo measure the aperiodic activity, we would like to describe the pattern of activity\nacross all frequencies, without our measure being influenced by co-occurring periodic\nactivity (peaks).\n\n\n" ] }, { @@ -183,14 +172,14 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Mathematical Description of the Aperiodic Component\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nTo fit the aperiodic component, we will use the function $L$:\n\n\\begin{align}L(F) = b - \\log(k + F^\\chi)\\end{align}\n\nNote that this function is fit on the semi-log power spectrum, meaning linear frequencies\nand $log_{10}$ power values.\n\nIn this formulation, the parameters $b$, $k$, and $\\chi$\ndefine the aperiodic component, as:\n\n- $b$ is the broadband 'offset'\n- $k$ is the 'knee'\n- $\\chi$ is the 'exponent' of the aperiodic fit\n- $F$ is the array of frequency values\n\nNote that fitting the knee parameter is optional. If used, the knee parameter defines a\n'bend' in the aperiodic `1/f` like component of the data. If not used, the 'knee'\nparameter is set to zero.\n\nThis function form is technically described as a Lorentzian function. We use the option\nof adding a knee parameter, since even though neural data is often discussed in terms\nof having `1/f` activity, there is often not a single `1/f` characteristic, especially\nacross broader frequency ranges. Therefore, using this function form allows for modeling\nbends in the power spectrum of the aperiodic component, if and when they occur.\n\nNote that if we were to want the equivalent function in linear power, using $AP$\nto indicate the aperiodic component in linear spacing, it would be:\n\n\\begin{align}AP(F) = 10^b * \\frac{1}{(k + F^\\chi)}\\end{align}\n\n\n" + "### Mathematical Description of the Aperiodic Component\n\nTo fit the aperiodic component, we will use the function $L$:\n\n\\begin{align}L(F) = b - \\log(k + F^\\chi)\\end{align}\n\nNote that this function is fit on the semi-log power spectrum, meaning linear frequencies\nand $log_{10}$ power values.\n\nIn this formulation, the parameters $b$, $k$, and $\\chi$\ndefine the aperiodic component, as:\n\n- $b$ is the broadband 'offset'\n- $k$ is the 'knee'\n- $\\chi$ is the 'exponent' of the aperiodic fit\n- $F$ is the array of frequency values\n\nNote that fitting the knee parameter is optional. If used, the knee parameter defines a\n'bend' in the aperiodic `1/f` like component of the data. If not used, the 'knee'\nparameter is set to zero.\n\nThis function form is technically described as a Lorentzian function. We use the option\nof adding a knee parameter, since even though neural data is often discussed in terms\nof having `1/f` activity, there is often not a single `1/f` characteristic, especially\nacross broader frequency ranges. Therefore, using this function form allows for modeling\nbends in the power spectrum of the aperiodic component, if and when they occur.\n\nNote that if we were to want the equivalent function in linear power, using $AP$\nto indicate the aperiodic component in linear spacing, it would be:\n\n\\begin{align}AP(F) = 10^b * \\frac{1}{(k + F^\\chi)}\\end{align}\n\n\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "A Note on Logging\n~~~~~~~~~~~~~~~~~\n\nSo far, we have been plotting in semi-log, meaning the x-axis (frequency) is in linear\nspacing, and the y-axis (power) is in log10 space. This is common practice, as power values\nare exponentially distributed.\n\nIt can also be useful, for visualization, to plot with both axes on a log scale.\nNote that in this module, plotting in log-log is just a visualization choice, and does\nnot affect how the data is stored and/or how models are fit.\n\nBelow we can see the same spectrum again, with all the annotations on, plotted in log-log.\nThe most notable difference is that the aperiodic component is a straight line in log-log\nspacing. This is a hallmark of `1/f` activity.\n\n\n" + "### A Note on Logging\n\nSo far, we have been plotting in semi-log, meaning the x-axis (frequency) is in linear\nspacing, and the y-axis (power) is in log10 space. This is common practice, as power values\nare exponentially distributed.\n\nIt can also be useful, for visualization, to plot with both axes on a log scale.\nNote that in this module, plotting in log-log is just a visualization choice, and does\nnot affect how the data is stored and/or how models are fit.\n\nBelow we can see the same spectrum again, with all the annotations on, plotted in log-log.\nThe most notable difference is that the aperiodic component is a straight line in log-log\nspacing. This is a hallmark of `1/f` activity.\n\n\n" ] }, { @@ -208,14 +197,14 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Relating Exponents to Power Spectrum Slope\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nAnother way to measure 1/f properties in neural power spectra is to measure the slope\nof the spectrum in log-log spacing, fitting a linear equation as:\n\n\\begin{align}L(log(F)) = aF + b\\end{align}\n\nWhere:\n\n- $a$ is the power spectrum slope\n- $b$ is the offset\n- $F$ is the array of frequency values\n\nIn this formulation, the data is considered in log-log space, meaning the frequency values\nare also in log space. Since 1/f is a straight line in log-log spacing, this approach captures\n1/f activity.\n\nThis is equivalent to the power spectrum model in this module, when fitting with no knee,\nwith a direct relationship between the slope ($a$) and the exponent ($\\chi$):\n\n\\begin{align}\\chi = -a\\end{align}\n\n\n" + "### Relating Exponents to Power Spectrum Slope\n\nAnother way to measure 1/f properties in neural power spectra is to measure the slope\nof the spectrum in log-log spacing, fitting a linear equation as:\n\n\\begin{align}L(log(F)) = aF + b\\end{align}\n\nWhere:\n\n- $a$ is the power spectrum slope\n- $b$ is the offset\n- $F$ is the array of frequency values\n\nIn this formulation, the data is considered in log-log space, meaning the frequency values\nare also in log space. Since 1/f is a straight line in log-log spacing, this approach captures\n1/f activity.\n\nThis is equivalent to the power spectrum model in this module, when fitting with no knee,\nwith a direct relationship between the slope ($a$) and the exponent ($\\chi$):\n\n\\begin{align}\\chi = -a\\end{align}\n\n\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "Fitting Knees\n~~~~~~~~~~~~~\n\nIn the original model we fit and explored, there was no aperiodic 'knee'. Depending on\nthe data, or the frequency range, there may or may not be a knee present in the data\n(more on that later in the tutorial).\n\nIn the next plot, there is another annotated model, from a broader frequency range that also\nincludes a knee. When plotted in log-log, the presence of a knee can be seen as 'bend' or\n'knee' in the aperiodic component.\n\n\n" + "### Fitting Knees\n\nIn the original model we fit and explored, there was no aperiodic 'knee'. Depending on\nthe data, or the frequency range, there may or may not be a knee present in the data\n(more on that later in the tutorial).\n\nIn the next plot, there is another annotated model, from a broader frequency range that also\nincludes a knee. When plotted in log-log, the presence of a knee can be seen as 'bend' or\n'knee' in the aperiodic component.\n\n\n" ] }, { @@ -240,7 +229,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Conclusion\n----------\n\nSo far, we have explored how neural power spectra, $NPS$, across a set of frequencies\n$F$ can be modeled as a combination of an aperiodic component, $L$, and the\nperiodic component, which is comprised of `N` peaks, where each $G_n$ is a Gaussian.\n\nTo summarize, the full model is:\n\n\\begin{align}NPS(F) = L(F) + G(F)_n\\end{align}\n\nwhere:\n\n\\begin{align}L(F) = b - \\log(k + F^\\chi) \\quad \\quad G(F)_n = a * exp (\\frac{- (F - c)^2}{2 * w^2})\\end{align}\n\nThis approach allows us to measure periodic and aperiodic activity from neural\npower spectra, and describe them with model parameters:\n\n- $b$, $k$, and $\\chi$ of the aperiodic component which reflect\n the `offset`, `knee` and `exponent`, respectively\n- $c$, $a$, $w$ for each periodic peak, relating to the\n `center frequency`, `power` and `bandwidth` of putative periodic activity\n\nFor more technical details on the model formulation and fitting process, check out the\n`paper `_.\n\nIn the next tutorial, we will start to use this model.\n\n\n" + "## Conclusion\n\nSo far, we have explored how neural power spectra, $NPS$, across a set of frequencies\n$F$ can be modeled as a combination of an aperiodic component, $L$, and the\nperiodic component, which is comprised of `N` peaks, where each $G_n$ is a Gaussian.\n\nTo summarize, the full model is:\n\n\\begin{align}NPS(F) = L(F) + G(F)_n\\end{align}\n\nwhere:\n\n\\begin{align}L(F) = b - \\log(k + F^\\chi) \\quad \\quad G(F)_n = a * exp (\\frac{- (F - c)^2}{2 * w^2})\\end{align}\n\nThis approach allows us to measure periodic and aperiodic activity from neural\npower spectra, and describe them with model parameters:\n\n- $b$, $k$, and $\\chi$ of the aperiodic component which reflect\n the `offset`, `knee` and `exponent`, respectively\n- $c$, $a$, $w$ for each periodic peak, relating to the\n `center frequency`, `power` and `bandwidth` of putative periodic activity\n\nFor more technical details on the model formulation and fitting process, check out the\n[paper](https://www.biorxiv.org/content/early/2018/04/11/299859).\n\nIn the next tutorial, we will start to use this model.\n\n\n" ] } ], @@ -260,7 +249,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.8.5" + "version": "3.8.3" } }, "nbformat": 4, diff --git a/_downloads/91057e4aeee06f0a0baa05c9f8714658/plot_04-MoreFOOOF.py b/_downloads/91057e4aeee06f0a0baa05c9f8714658/plot_04-MoreFOOOF.py index 3aef8557..8b916fc4 100644 --- a/_downloads/91057e4aeee06f0a0baa05c9f8714658/plot_04-MoreFOOOF.py +++ b/_downloads/91057e4aeee06f0a0baa05c9f8714658/plot_04-MoreFOOOF.py @@ -79,20 +79,20 @@ # iteratively by height (over and above the aperiodic component), and so this approach will # extract (up to) the *n* largest peaks. # -# **peak_threshold (in units of standard deviation)** default: 2.0 +# **peak_threshold (relative threshold - standard deviation of power spectrum)** default: 2.0 # # The threshold, in terms of standard deviation of the aperiodic-removed power # spectrum, above which a data point must pass to be considered a candidate peak. # Once a candidate peak drops below this threshold, the peak search is halted (without # including the most recent candidate). # -# **min_peak_height (units of power - same as the input spectrum)** default: 0 +# **min_peak_height (absolute threshold - units of log power)** default: 0 # # The minimum height, above the aperiodic fit, that a peak must have to be extracted -# in the initial fit stage. Once a candidate peak drops below this threshold, the peak -# search is halted (without including the most recent candidate). Note that because -# this constraint is enforced during peak search, and prior to final peak fit, returned -# peaks are not guaranteed to surpass this value in height. +# in the initial fit stage. This threshold is defined in units of log power. Once a +# candidate peak drops below this threshold, the peak search is halted (without including +# the most recent candidate). Note that because this constraint is enforced during peak search, +# and prior to final peak fit, returned peaks are not guaranteed to surpass this value in height. # # There are two different height-related halting conditions for the peak searching. # By default, the relative (standard-deviation based) threshold is defined, whereas the diff --git a/_downloads/c22235139db46cb22adb1c928806dad0/plot_freq_by_freq_error.ipynb b/_downloads/951d01cde136b55267103faa4582e9b2/plot_freq_by_freq_error.ipynb similarity index 73% rename from _downloads/c22235139db46cb22adb1c928806dad0/plot_freq_by_freq_error.ipynb rename to _downloads/951d01cde136b55267103faa4582e9b2/plot_freq_by_freq_error.ipynb index 08c32ca0..91bbb235 100644 --- a/_downloads/c22235139db46cb22adb1c928806dad0/plot_freq_by_freq_error.ipynb +++ b/_downloads/951d01cde136b55267103faa4582e9b2/plot_freq_by_freq_error.ipynb @@ -1,21 +1,10 @@ { "cells": [ - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "collapsed": false - }, - "outputs": [], - "source": [ - "%matplotlib inline" - ] - }, { "cell_type": "markdown", "metadata": {}, "source": [ - "\nFrequency-by-Frequency Errors\n=============================\n\nCheck the error of power spectrum models across frequencies.\n" + "\n# Frequency-by-Frequency Errors\n\nCheck the error of power spectrum models across frequencies.\n" ] }, { @@ -33,14 +22,14 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Frequency-by-Frequency Error\n----------------------------\n\nWhen fitting power spectrum models, one of the goodness-of-fit measures computed and\nreturned is the total error of th full model fit, compared to the original data.\n\nThough potentially useful for evaluating overall performance, this total error\nmeasure doesn't necessarily help to indicate where, in frequency space, or in what\nways the model might be going wrong.\n\nTo get better insight into the model fitting, here we will explore some utilities\nthat calculate and visualize the frequency-by-frequency error of model fits.\nThis can allow for identifying where in the spectrum is being fit well, or not well.\n\n\n" + "## Frequency-by-Frequency Error\n\nWhen fitting power spectrum models, one of the goodness-of-fit measures computed and\nreturned is the total error of th full model fit, compared to the original data.\n\nThough potentially useful for evaluating overall performance, this total error\nmeasure doesn't necessarily help to indicate where, in frequency space, or in what\nways the model might be going wrong.\n\nTo get better insight into the model fitting, here we will explore some utilities\nthat calculate and visualize the frequency-by-frequency error of model fits.\nThis can allow for identifying where in the spectrum is being fit well, or not well.\n\n\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "Checking the Error of Individual Model Fits\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nFirst we will start by examining frequency-by-frequency error of an individual model fit,\nusing simulated data.\n\nThe function for analyzing error from a FOOOF object is\n:func:`~.compute_pointwise_error_fm`.\nTo start with, we will indicate to this function to plot the frequency-by-frequency\nerror of our model fit.\n\n\n" + "### Checking the Error of Individual Model Fits\n\nFirst we will start by examining frequency-by-frequency error of an individual model fit,\nusing simulated data.\n\nThe function for analyzing error from a FOOOF object is\n:func:`~.compute_pointwise_error_fm`.\nTo start with, we will indicate to this function to plot the frequency-by-frequency\nerror of our model fit.\n\n\n" ] }, { @@ -109,7 +98,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Checking the Error Across Groups of Model Fits\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nNext, lets move on to calculating frequency-by-frequency error across groups of fits,\nagain using some simulated data.\n\nTo analyze error from a FOOOFGroup object, use :func:`~.compute_pointwise_error_fg`.\n\n\n" + "### Checking the Error Across Groups of Model Fits\n\nNext, lets move on to calculating frequency-by-frequency error across groups of fits,\nagain using some simulated data.\n\nTo analyze error from a FOOOFGroup object, use :func:`~.compute_pointwise_error_fg`.\n\n\n" ] }, { @@ -196,7 +185,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Frequency-by-Frequency Errors When There is a Problem\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nSo far we have examined cases in which the models were working well, and the\nfrequency-by-frequency error revealed no big surprises.\n\nAs a final example, let's examine a case in which the model is not working well,\nand see how the errors look. In particular, we will simulate some new power spectra,\nwith a knee parameter, and refit with the same FOOOFGroup object, in 'fixed' aperiodic\nmode, and then analyze the frequency-by-frequency errors, as before. In this scenario,\nwe are fitting data with the wrong model form, and so we expect there to be some issues\nwith the fit, and we can use the frequency-by-frequency error to investigate if and how\nthis is the case.\n\n\n" + "### Frequency-by-Frequency Errors When There is a Problem\n\nSo far we have examined cases in which the models were working well, and the\nfrequency-by-frequency error revealed no big surprises.\n\nAs a final example, let's examine a case in which the model is not working well,\nand see how the errors look. In particular, we will simulate some new power spectra,\nwith a knee parameter, and refit with the same FOOOFGroup object, in 'fixed' aperiodic\nmode, and then analyze the frequency-by-frequency errors, as before. In this scenario,\nwe are fitting data with the wrong model form, and so we expect there to be some issues\nwith the fit, and we can use the frequency-by-frequency error to investigate if and how\nthis is the case.\n\n\n" ] }, { @@ -245,7 +234,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.8.5" + "version": "3.8.3" } }, "nbformat": 4, diff --git a/_downloads/95d526fd1c3dba8ce2b3e75487d81703/plot_data_exporting.py b/_downloads/95d526fd1c3dba8ce2b3e75487d81703/plot_data_exporting.py new file mode 100644 index 00000000..9a3125a2 --- /dev/null +++ b/_downloads/95d526fd1c3dba8ce2b3e75487d81703/plot_data_exporting.py @@ -0,0 +1,174 @@ +""" +Exporting Model Results +======================= + +This example covers utilities for extracting and exporting model fit results. + +Note that the functionality to export to pandas DataFrames was added in version 1.1, +and requires the optional dependency `pandas` to be installed. +""" + +################################################################################################### + +# Import model objects, and Bands object to define bands of interest +from fooof import FOOOF, FOOOFGroup, Bands + +# Import simulation functions to create some example data +from fooof.sim import gen_power_spectrum, gen_group_power_spectra + +################################################################################################### +# Exporting Results +# ----------------- +# +# In this example we will explore available functionality for extracting model fit results, +# specifically the options available for exporting results to pandas objects. +# +# Note that the main use case of exporting models to pandas DataFrames is for +# analysis across models. If you are just trying to access the model fit results from +# a fit model, you may want the :meth:`~fooof.FOOOF.get_results` and/or +# :meth:`~fooof.FOOOF.get_params` methods. +# +# Defining Oscillation Bands +# ~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# A difficulty with exporting and collecting model results across model fits is that the +# models may be different sizes - most notably, they may contain different numbers of peaks. +# +# This means that we need to define some kind of strategy to organize the peak +# parameters across different models. Across these examples, this will include using the +# :class:`~fooof.Bands` object to define oscillations bands of interest. +# + +################################################################################################### + +# Initialize bands object, defining alpha band +bands1 = Bands({'alpha' : [7, 14]}) + +# Initialize model object +fm = FOOOF() + +################################################################################################### + +# Simulate example power spectrum +freqs, powers = gen_power_spectrum([1, 50], [0, 10, 1], [10, 0.25, 2], freq_res=0.25) + +# Fit model to power spectrum +fm.fit(freqs, powers) + +################################################################################################### +# +# The :meth:`~fooof.FOOOF.to_df` method supports exporting model fit results to pandas objects. +# + +################################################################################################### + +# Export results +fm.to_df(None) + +################################################################################################### +# +# In the above, we export the model fit results to a pandas Series. +# +# Note that we explicitly passed in `None` to the `peak_org` argument, meaning we did not define +# a strategy for managing peaks. Because of this, the export did not include any peak parameters. +# +# Next, let's can try exporting again, this time passing in an integer to define the number +# of peaks to extract. +# + +################################################################################################### + +# Export results - extracting 1 peak +fm.to_df(1) + +################################################################################################### +# Using Band Definitions +# ~~~~~~~~~~~~~~~~~~~~~~ +# +# In the above, we extract the results specifying to extract 1 peak. By default, this approach +# will extract the dominant (highest power) peak. +# +# Notably, specifying a set number of peaks to extract does allow for combining across peaks +# (in terms of enforcing the same model size), but may not be the ideal way to examine across +# peaks (since the dominant extract peak may vary across model fits). +# +# Therefore, we may often want to instead define a set of band definitions to organize peaks, +# as can be done by passing a `Bands` object in to the `to_df` method. +# + +################################################################################################### + +# Export results - extracting peaks based on bands object +fm.to_df(bands1) + +################################################################################################### +# +# Note that there are limitations to using the bands definitions - notably that doing so +# necessarily requires extracting at most 1 peak per band. In doing so, the extraction will +# select the dominant peak per band. However, this may not fully reflect the full model fit +# if there are, for example, multiple peaks fit within a band. +# + +################################################################################################### +# Example on Group Object +# ~~~~~~~~~~~~~~~~~~~~~~~ +# +# In the above, we used the model object to show the basic exporting functionalities. +# +# This functionality is more useful when considering multiple model fits together, such +# as can be done using the :meth:`~fooof.FOOOFGroup.to_df` method from the Group object, +# which allows for exporting DataFrames of organized model fit parameters across power spectra. +# +# As with the above, keep in mind that for some cases you may want the +# :meth:`~fooof.FOOOFGroup.get_results` and/or :meth:`~fooof.FOOOFGroup.get_params` methods +# instead of doing a DataFrame export. +# + +################################################################################################### + +# Simulate an example group of power spectra +freqs, powers = gen_group_power_spectra(5, [1, 50], [0, 1], [10, 0.25, 2]) + +# Initialize a group model object and fit power spectra +fg = FOOOFGroup(verbose=False) +fg.fit(freqs, powers) + +################################################################################################### + +# Export results to dataframe, with no peak definition +fg.to_df(None) + +################################################################################################### + +# Export results to dataframe, specifying to export a single peak +fg.to_df(1) + +################################################################################################### + +# Export results to dataframe, using bands definition with defines the alpha band +fg.to_df(bands1) + +################################################################################################### +# +# In the above examples, we showed the same exports on the Group object as we previously +# explored on the single spectrum in the model object. +# +# Note that we can also define new bands objects to change the peak output organization, +# as demonstrated in the following example. +# + +################################################################################################### + +# Define a new bands object, specifying both the alpha and beta band +bands2 = Bands({'alpha' : [7, 14], + 'beta' : [15, 30]}) + +################################################################################################### + +# Export results to dataframe, using bands object with alpha & beta +fg.to_df(bands2) + +################################################################################################### +# +# That covers the pandas export functionality available from the model objects. +# diff --git a/_downloads/cc4e77d21a4555620200446bfe038506/auto_tutorials_jupyter.zip b/_downloads/97a1de59bce682890841bb846e3dd09c/auto_tutorials_jupyter.zip similarity index 51% rename from _downloads/cc4e77d21a4555620200446bfe038506/auto_tutorials_jupyter.zip rename to _downloads/97a1de59bce682890841bb846e3dd09c/auto_tutorials_jupyter.zip index 40d01871..aa3106c4 100644 Binary files a/_downloads/cc4e77d21a4555620200446bfe038506/auto_tutorials_jupyter.zip and b/_downloads/97a1de59bce682890841bb846e3dd09c/auto_tutorials_jupyter.zip differ diff --git a/_downloads/b4b208c1f35ab1e06a6ac5626f448096/plot_04-MoreFOOOF.ipynb b/_downloads/b4b208c1f35ab1e06a6ac5626f448096/plot_04-MoreFOOOF.ipynb index 8b09a002..5aad46e6 100644 --- a/_downloads/b4b208c1f35ab1e06a6ac5626f448096/plot_04-MoreFOOOF.ipynb +++ b/_downloads/b4b208c1f35ab1e06a6ac5626f448096/plot_04-MoreFOOOF.ipynb @@ -1,21 +1,10 @@ { "cells": [ - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "collapsed": false - }, - "outputs": [], - "source": [ - "%matplotlib inline" - ] - }, { "cell_type": "markdown", "metadata": {}, "source": [ - "\n04: Exploring the FOOOF Object\n==============================\n\nFurther exploring the FOOOF object, including algorithm settings and available methods.\n" + "\n# 04: Exploring the FOOOF Object\n\nFurther exploring the FOOOF object, including algorithm settings and available methods.\n" ] }, { @@ -44,28 +33,28 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Description of methods and attributes\n-------------------------------------\n\nThe :class:`~fooof.FOOOF` object contents consist of 4 main components (groups of data / code):\n\n- 1) settings attributes, that control the algorithm fitting\n- 2) data attributes, that contain and describe the data\n- 3) result attributes, that contain the resulting parameters that describe the model fit\n- 4) methods (functions) that perform procedures for fitting models and associated utilities\n\nEach these which are described in more detail below.\n\nThe FOOOF module follows the following Python conventions:\n\n- all user exposed settings, data, and methods are directly accessible through the object\n- 'hidden' (internal) settings and methods have a leading underscore\n\n - you *can* access these if you need to, but one should be cautious doing so\n\n\n" + "## Description of methods and attributes\n\nThe :class:`~fooof.FOOOF` object contents consist of 4 main components (groups of data / code):\n\n- 1) settings attributes, that control the algorithm fitting\n- 2) data attributes, that contain and describe the data\n- 3) result attributes, that contain the resulting parameters that describe the model fit\n- 4) methods (functions) that perform procedures for fitting models and associated utilities\n\nEach these which are described in more detail below.\n\nThe FOOOF module follows the following Python conventions:\n\n- all user exposed settings, data, and methods are directly accessible through the object\n- 'hidden' (internal) settings and methods have a leading underscore\n\n - you *can* access these if you need to, but one should be cautious doing so\n\n\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "1) Settings (attributes)\n^^^^^^^^^^^^^^^^^^^^^^^^\n\nThere are a number of settings that control the fitting algorithm, that\ncan be set by the user when initializing the :class:`~fooof.FOOOF` object.\n\nThere are some internal settings that are not exposed at initialization.\nThese settings are unlikely to need to be accessed by the user, but can be if desired -\nthey are all defined and documented in the code in the object's \\__init\\__ (there are no\nother settings, or 'magic numbers' in any other parts of the code).\n\n\n" + "### 1) Settings (attributes)\n\nThere are a number of settings that control the fitting algorithm, that\ncan be set by the user when initializing the :class:`~fooof.FOOOF` object.\n\nThere are some internal settings that are not exposed at initialization.\nThese settings are unlikely to need to be accessed by the user, but can be if desired -\nthey are all defined and documented in the code in the object's \\__init\\__ (there are no\nother settings, or 'magic numbers' in any other parts of the code).\n\n\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "Controlling Peak Fits\n~~~~~~~~~~~~~~~~~~~~~\n\n**peak_width_limits (Hz)** default: [0.5, 12]\n\nEnforced limits on the minimum and maximum widths of extracted peaks, given as a list of\n[minimum bandwidth, maximum bandwidth]. We recommend that the minimum bandwidth be set to\nbe at last twice the frequency resolution of the power spectrum, so that single points\ncan not be fit as peaks.\n\n\n" + "#### Controlling Peak Fits\n\n**peak_width_limits (Hz)** default: [0.5, 12]\n\nEnforced limits on the minimum and maximum widths of extracted peaks, given as a list of\n[minimum bandwidth, maximum bandwidth]. We recommend that the minimum bandwidth be set to\nbe at last twice the frequency resolution of the power spectrum, so that single points\ncan not be fit as peaks.\n\n\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "Peak Search Stopping Criteria\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nAn iterative procedure searches for candidate peaks in the flattened spectrum. Candidate\npeaks are extracted in order of decreasing height, until some stopping criterion is met,\nwhich is controlled by the following settings:\n\n**max_n_peaks (int)** default: infinite\n\nThe maximum number of peaks that can be extracted from a given power spectrum. The algorithm\nwill halt searching for new peaks when this number is reached. Note that peaks are extracted\niteratively by height (over and above the aperiodic component), and so this approach will\nextract (up to) the *n* largest peaks.\n\n**peak_threshold (in units of standard deviation)** default: 2.0\n\nThe threshold, in terms of standard deviation of the aperiodic-removed power\nspectrum, above which a data point must pass to be considered a candidate peak.\nOnce a candidate peak drops below this threshold, the peak search is halted (without\nincluding the most recent candidate).\n\n**min_peak_height (units of power - same as the input spectrum)** default: 0\n\nThe minimum height, above the aperiodic fit, that a peak must have to be extracted\nin the initial fit stage. Once a candidate peak drops below this threshold, the peak\nsearch is halted (without including the most recent candidate). Note that because\nthis constraint is enforced during peak search, and prior to final peak fit, returned\npeaks are not guaranteed to surpass this value in height.\n\nThere are two different height-related halting conditions for the peak searching.\nBy default, the relative (standard-deviation based) threshold is defined, whereas the\nabsolute threshold is set to zero (this default is because there is no general way to\nset this value without knowing the scale of the data). If both are defined, both are\nused and the peak search will halt when a candidate peak fails to pass either the absolute,\nor relative threshold.\n\nAperiodic Mode\n~~~~~~~~~~~~~~\n\n**aperiodic_mode (string)** default='fixed'\n\nThe fitting approach to use for the aperiodic component.\n\nOptions:\n - 'fixed' : fits without a knee parameter (with the knee parameter 'fixed' at 0)\n - 'knee' : fits the full exponential equation, including the 'knee' parameter\n\nVerbosity\n~~~~~~~~~\n\n**verbose (boolean)** default='True'\n\nWhether to print out status updates and warnings.\n\n\n" + "#### Peak Search Stopping Criteria\n\nAn iterative procedure searches for candidate peaks in the flattened spectrum. Candidate\npeaks are extracted in order of decreasing height, until some stopping criterion is met,\nwhich is controlled by the following settings:\n\n**max_n_peaks (int)** default: infinite\n\nThe maximum number of peaks that can be extracted from a given power spectrum. The algorithm\nwill halt searching for new peaks when this number is reached. Note that peaks are extracted\niteratively by height (over and above the aperiodic component), and so this approach will\nextract (up to) the *n* largest peaks.\n\n**peak_threshold (relative threshold - standard deviation of power spectrum)** default: 2.0\n\nThe threshold, in terms of standard deviation of the aperiodic-removed power\nspectrum, above which a data point must pass to be considered a candidate peak.\nOnce a candidate peak drops below this threshold, the peak search is halted (without\nincluding the most recent candidate).\n\n**min_peak_height (absolute threshold - units of log power)** default: 0\n\nThe minimum height, above the aperiodic fit, that a peak must have to be extracted\nin the initial fit stage. This threshold is defined in units of log power. Once a\ncandidate peak drops below this threshold, the peak search is halted (without including\nthe most recent candidate). Note that because this constraint is enforced during peak search,\nand prior to final peak fit, returned peaks are not guaranteed to surpass this value in height.\n\nThere are two different height-related halting conditions for the peak searching.\nBy default, the relative (standard-deviation based) threshold is defined, whereas the\nabsolute threshold is set to zero (this default is because there is no general way to\nset this value without knowing the scale of the data). If both are defined, both are\nused and the peak search will halt when a candidate peak fails to pass either the absolute,\nor relative threshold.\n\n#### Aperiodic Mode\n\n**aperiodic_mode (string)** default='fixed'\n\nThe fitting approach to use for the aperiodic component.\n\nOptions:\n - 'fixed' : fits without a knee parameter (with the knee parameter 'fixed' at 0)\n - 'knee' : fits the full exponential equation, including the 'knee' parameter\n\n#### Verbosity\n\n**verbose (boolean)** default='True'\n\nWhether to print out status updates and warnings.\n\n\n" ] }, { @@ -83,7 +72,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Changing Settings\n~~~~~~~~~~~~~~~~~\n\nNote that if you wish to change settings, then you should re-initialize\na new :class:`~fooof.FOOOF` object with new settings.\n\nSimply changing the value of the relevant attribute may not appropriately propagate\nthe value, and thus may lead to a failure, either creating an error, or not applying\nthe settings properly during fit and returning erroneous results.\n\nHere we will re-initialize a new FOOOF object, with some new settings.\n\n\n" + "#### Changing Settings\n\nNote that if you wish to change settings, then you should re-initialize\na new :class:`~fooof.FOOOF` object with new settings.\n\nSimply changing the value of the relevant attribute may not appropriately propagate\nthe value, and thus may lead to a failure, either creating an error, or not applying\nthe settings properly during fit and returning erroneous results.\n\nHere we will re-initialize a new FOOOF object, with some new settings.\n\n\n" ] }, { @@ -101,7 +90,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "2) Data (attributes)\n^^^^^^^^^^^^^^^^^^^^\n\nThe :class:`~fooof.FOOOF` object stores the following data attributes:\n\n- ``freqs``: the frequency values of the power spectrum\n- ``power_spectrum``: the power values of the power spectrum\n- ``freq_range``: the frequency range of the data\n- ``freq_res``: the frequency resolution of the data\n\nDuring the fit procedure, interim (hidden) data variables are also created and used.\n\nThere is also an indicator attribute, ``has_data`` which indicates\nif the current object has data loaded.\n\n\n" + "### 2) Data (attributes)\n\nThe :class:`~fooof.FOOOF` object stores the following data attributes:\n\n- ``freqs``: the frequency values of the power spectrum\n- ``power_spectrum``: the power values of the power spectrum\n- ``freq_range``: the frequency range of the data\n- ``freq_res``: the frequency resolution of the data\n\nDuring the fit procedure, interim (hidden) data variables are also created and used.\n\nThere is also an indicator attribute, ``has_data`` which indicates\nif the current object has data loaded.\n\n\n" ] }, { @@ -170,7 +159,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "3) Results (attributes)\n^^^^^^^^^^^^^^^^^^^^^^^\n\nWith our model fit, the results attributes should now hold values.\n\nRecall that by convention, any attributes that contain model results are\nindicated by a trailing underscore.\n\nThe model results stored by the object are:\n\n- ``aperiodic_params_``: a list of aperiodic parameters, stored as [Offset, (Knee), Exponent]\n- ``peak_params_``: all periodic parameters, where each row is a peak, as [CF, PW, BW]\n- ``r_squared_``: the r-squared of the model, as compared to the original data\n- ``error_``: the error of the model, as compared to the original data\n\nOther attributes which store outputs from the model are:\n\n- ``fooofed_spectrum_``: the full model reconstruction\n- ``n_peaks_``: a helper attribute which indicates how many peaks were fit in the model\n\nThe :class:`~fooof.FOOOF` object also has an indicator attribute, ``has_model``\nwhich indicates if the current object has model results available.\n\n\n" + "### 3) Results (attributes)\n\nWith our model fit, the results attributes should now hold values.\n\nRecall that by convention, any attributes that contain model results are\nindicated by a trailing underscore.\n\nThe model results stored by the object are:\n\n- ``aperiodic_params_``: a list of aperiodic parameters, stored as [Offset, (Knee), Exponent]\n- ``peak_params_``: all periodic parameters, where each row is a peak, as [CF, PW, BW]\n- ``r_squared_``: the r-squared of the model, as compared to the original data\n- ``error_``: the error of the model, as compared to the original data\n\nOther attributes which store outputs from the model are:\n\n- ``fooofed_spectrum_``: the full model reconstruction\n- ``n_peaks_``: a helper attribute which indicates how many peaks were fit in the model\n\nThe :class:`~fooof.FOOOF` object also has an indicator attribute, ``has_model``\nwhich indicates if the current object has model results available.\n\n\n" ] }, { @@ -199,7 +188,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "4) Methods\n^^^^^^^^^^\n\nThe :class:`~fooof.FOOOF` object contains a number of methods that are either used\nto fit models and access data, and/or offer extra functionality.\n\nIn addition to the exposed methods, there are some internal private methods,\nwith a leading underscore in their name, that are called in the\nfitting procedure. These methods should not be called directly by the user\nas they may depend on internal state of the object as defined by other methods,\nand so may not do as expected in isolation.\n\n\n" + "### 4) Methods\n\nThe :class:`~fooof.FOOOF` object contains a number of methods that are either used\nto fit models and access data, and/or offer extra functionality.\n\nIn addition to the exposed methods, there are some internal private methods,\nwith a leading underscore in their name, that are called in the\nfitting procedure. These methods should not be called directly by the user\nas they may depend on internal state of the object as defined by other methods,\nand so may not do as expected in isolation.\n\n\n" ] }, { @@ -217,7 +206,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Saving Data & Results\n~~~~~~~~~~~~~~~~~~~~~\n\nThere is also functionality for saving out, and loading back in, data and results.\n\nYou have the option to specify which data to save.\n\n- `results`: model fit results (same as is returned in FOOOFResult)\n- `settings`: all public settings (everything available at initialization)\n- `data`: freqs & power spectrum\n\nSelected items are saved out to JSON files. You can specify a file name to save\nor append to, or pass in a JSON file object.\n\n\n" + "#### Saving Data & Results\n\nThere is also functionality for saving out, and loading back in, data and results.\n\nYou have the option to specify which data to save.\n\n- `results`: model fit results (same as is returned in FOOOFResult)\n- `settings`: all public settings (everything available at initialization)\n- `data`: freqs & power spectrum\n\nSelected items are saved out to JSON files. You can specify a file name to save\nor append to, or pass in a JSON file object.\n\n\n" ] }, { @@ -257,7 +246,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Creating Reports\n~~~~~~~~~~~~~~~~\n\nThere is also functionality to save out a 'report' of a particular model fit.\n\nThis generates and saves a PDF which contains the same output as\n:meth:`~fooof.FOOOF.print_results`,\n:meth:`~fooof.FOOOF.plot`, and\n:meth:`~fooof.FOOOF.print_settings`.\n\n\n" + "#### Creating Reports\n\nThere is also functionality to save out a 'report' of a particular model fit.\n\nThis generates and saves a PDF which contains the same output as\n:meth:`~fooof.FOOOF.print_results`,\n:meth:`~fooof.FOOOF.plot`, and\n:meth:`~fooof.FOOOF.print_settings`.\n\n\n" ] }, { @@ -275,7 +264,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Conclusion\n----------\n\nWe have now fully explored the :class:`~fooof.FOOOF` object, and all it contains.\nNext, we will take a deeper dive into how to choose different modes for fitting\nthe aperiodic component of power spectra.\n\n\n" + "## Conclusion\n\nWe have now fully explored the :class:`~fooof.FOOOF` object, and all it contains.\nNext, we will take a deeper dive into how to choose different modes for fitting\nthe aperiodic component of power spectra.\n\n\n" ] } ], @@ -295,7 +284,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.8.5" + "version": "3.8.3" } }, "nbformat": 4, diff --git a/_downloads/b5b2c9277c4315e5778cb46a8f532c69/plot_DoYouEvenOscillate.ipynb b/_downloads/b5b2c9277c4315e5778cb46a8f532c69/plot_DoYouEvenOscillate.ipynb index b1cc9160..96602fe1 100644 --- a/_downloads/b5b2c9277c4315e5778cb46a8f532c69/plot_DoYouEvenOscillate.ipynb +++ b/_downloads/b5b2c9277c4315e5778cb46a8f532c69/plot_DoYouEvenOscillate.ipynb @@ -1,35 +1,24 @@ { "cells": [ - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "collapsed": false - }, - "outputs": [], - "source": [ - "%matplotlib inline" - ] - }, { "cell_type": "markdown", "metadata": {}, "source": [ - "\nRhythmicity of Time Series\n==========================\n\nExploring the rhythmicity of time series and their frequency representations.\n" + "\n# Rhythmicity of Time Series\n\nExploring the rhythmicity of time series and their frequency representations.\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "Rhythmicity of Time Series\n--------------------------\n\nCentral to the motivation for parameterizing neural power is the claim that power at a\ngiven frequency is not sufficient to claim that there is evidence for rhythmic, or\nperiodic, activity at that frequency.\n\nIn this example, we will explore this idea by examining some example signals in the\ntime domain, and their frequency domain representations. We will use these signals to\nmotivate if and when signals should be interpreted as containing periodic activity.\n\n\n" + "## Rhythmicity of Time Series\n\nCentral to the motivation for parameterizing neural power is the claim that power at a\ngiven frequency is not sufficient to claim that there is evidence for rhythmic, or\nperiodic, activity at that frequency.\n\nIn this example, we will explore this idea by examining some example signals in the\ntime domain, and their frequency domain representations. We will use these signals to\nmotivate if and when signals should be interpreted as containing periodic activity.\n\n\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "The Fourier Theorem\n~~~~~~~~~~~~~~~~~~~\n\nStated informally, the Fourier theorem tells us that any time series can be represented\nas a sum of sinusoids.\n\nThis is a powerful and useful theorem, as it means that we can use tools such as the\nFourier transform and other similar measures, to compute frequency representations\nof any time series data.\n\nHowever, just because a signal can be represented by sinusoids does not mean that any\ngiven signal, or any given aspect of a signal, for which a power spectrum can be computed\nshould be conceptualized as being comprised of rhythmic components.\n\nThe power spectrum is just a possible representation of the original data, not a\ndescriptive claim of the actual components of the data.\n\n\n" + "### The Fourier Theorem\n\nStated informally, the Fourier theorem tells us that any time series can be represented\nas a sum of sinusoids.\n\nThis is a powerful and useful theorem, as it means that we can use tools such as the\nFourier transform and other similar measures, to compute frequency representations\nof any time series data.\n\nHowever, just because a signal can be represented by sinusoids does not mean that any\ngiven signal, or any given aspect of a signal, for which a power spectrum can be computed\nshould be conceptualized as being comprised of rhythmic components.\n\nThe power spectrum is just a possible representation of the original data, not a\ndescriptive claim of the actual components of the data.\n\n\n" ] }, { @@ -58,14 +47,14 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Frequency Representations of Aperiodic Signals\n----------------------------------------------\n\nLet's start with aperiodic signals, and examine how different types of aperiodic\nsignals are represented in the frequency domain.\n\n\n" + "## Frequency Representations of Aperiodic Signals\n\nLet's start with aperiodic signals, and examine how different types of aperiodic\nsignals are represented in the frequency domain.\n\n\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "The Dirac Delta\n~~~~~~~~~~~~~~~\n\nThe Dirac delta is arguably the simplest signal, as it's a signal of all zeros,\nexcept for a single value of 1.\n\n\n" + "### The Dirac Delta\n\nThe Dirac delta is arguably the simplest signal, as it's a signal of all zeros,\nexcept for a single value of 1.\n\n\n" ] }, { @@ -123,21 +112,21 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Section Conclusions\n^^^^^^^^^^^^^^^^^^^\n\nAs we can see above, the power spectrum of the Dirac delta function has\npower across all frequencies.\n\nThis is despite it containing containing a single non-zero value, and thus having\nno rhythmic properties to it in the time domain.\n\nThe Dirac delta example can be taken as a proof of principle that observing power\nat a particular frequency does not necessarily imply that one should consider that\nthere are any rhythmic properties at that frequency in the original time series.\n\nIn this case, and many like it, power across all frequencies is a representation of\ntransient (or aperiodic) activity in the time series. Broadly, when there are transients,\nor aperiodic components, lots of sinusoids have to be added together in order to represent\naperiodic activity out of a basis set of periodic sine waves, and this is why such\nsignals typically look very broadband in the frequency domain.\n\n\n" + "#### Section Conclusions\n\nAs we can see above, the power spectrum of the Dirac delta function has\npower across all frequencies.\n\nThis is despite it containing containing a single non-zero value, and thus having\nno rhythmic properties to it in the time domain.\n\nThe Dirac delta example can be taken as a proof of principle that observing power\nat a particular frequency does not necessarily imply that one should consider that\nthere are any rhythmic properties at that frequency in the original time series.\n\nIn this case, and many like it, power across all frequencies is a representation of\ntransient (or aperiodic) activity in the time series. Broadly, when there are transients,\nor aperiodic components, lots of sinusoids have to be added together in order to represent\naperiodic activity out of a basis set of periodic sine waves, and this is why such\nsignals typically look very broadband in the frequency domain.\n\n\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "Colored Noise Signals\n~~~~~~~~~~~~~~~~~~~~~\n\nLet's now look at 'noise' signals.\n\nIn the signals below, we will simulate colored noise signals, in which samples are\ndrawn randomly from noise distributions, with no rhythmic properties.\n\nAs we will see, in the power spectrum, these signals exhibit power at all frequencies,\nwith specific patterns of powers across frequencies, which is dependent on the 'color'\nof the noise.\n\n\n" + "### Colored Noise Signals\n\nLet's now look at 'noise' signals.\n\nIn the signals below, we will simulate colored noise signals, in which samples are\ndrawn randomly from noise distributions, with no rhythmic properties.\n\nAs we will see, in the power spectrum, these signals exhibit power at all frequencies,\nwith specific patterns of powers across frequencies, which is dependent on the 'color'\nof the noise.\n\n\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "White Noise\n^^^^^^^^^^^\n\nA 'white noise' signal is one that is generated with uncorrelated samples drawn from\na random distribution. Since each element of the signal is sampled randomly,\nthere is no consistent rhythmic structure in the signal.\n\n\n" + "#### White Noise\n\nA 'white noise' signal is one that is generated with uncorrelated samples drawn from\na random distribution. Since each element of the signal is sampled randomly,\nthere is no consistent rhythmic structure in the signal.\n\n\n" ] }, { @@ -202,7 +191,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Pink Noise\n^^^^^^^^^^\n\nOther 'colors' of noise refer to different patterns of power distributions\nin the power spectrum.\n\nFor example, pink noise is a signal where power systematically decreases across\nfrequencies in the power spectrum.\n\n\n" + "#### Pink Noise\n\nOther 'colors' of noise refer to different patterns of power distributions\nin the power spectrum.\n\nFor example, pink noise is a signal where power systematically decreases across\nfrequencies in the power spectrum.\n\n\n" ] }, { @@ -253,21 +242,21 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Section Conclusion\n^^^^^^^^^^^^^^^^^^\n\nThe 'colored noise' signals above are simulated signals with no rhythmic properties,\nin the sense that there are no characteristic frequencies or visible rhythms in the data.\n\nNevertheless, and by definition, in the power spectra of such signals, there is power across\nall frequencies, with some pattern of power across frequencies.\n\nHowever, there are no frequencies at which power is different from expected from an\naperiodic noise signal. These signals are statistically, by definition, aperiodic.\n\n\n" + "#### Section Conclusion\n\nThe 'colored noise' signals above are simulated signals with no rhythmic properties,\nin the sense that there are no characteristic frequencies or visible rhythms in the data.\n\nNevertheless, and by definition, in the power spectra of such signals, there is power across\nall frequencies, with some pattern of power across frequencies.\n\nHowever, there are no frequencies at which power is different from expected from an\naperiodic noise signal. These signals are statistically, by definition, aperiodic.\n\n\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "Frequency Representations of Rhythmic Signals\n---------------------------------------------\n\nNext, lets check what frequency representations look like for time series that do have\nrhythmic activity.\n\n\n" + "## Frequency Representations of Rhythmic Signals\n\nNext, lets check what frequency representations look like for time series that do have\nrhythmic activity.\n\n\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "Sinusoidal Signals\n~~~~~~~~~~~~~~~~~~\n\nThere are many different rhythmic signals we could simulate, in terms of different\nrhythmic shapes, and or temporal properties (such as rhythmic bursts). For this\nexample, we will stick to simulating continuous sinusoidal signals.\n\n\n" + "### Sinusoidal Signals\n\nThere are many different rhythmic signals we could simulate, in terms of different\nrhythmic shapes, and or temporal properties (such as rhythmic bursts). For this\nexample, we will stick to simulating continuous sinusoidal signals.\n\n\n" ] }, { @@ -318,21 +307,21 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Section Conclusion\n^^^^^^^^^^^^^^^^^^\n\nWhen there is rhythmic activity at a particular frequency, this exhibits as a 'peak'\nof power in the frequency domain. This peak indicates high power at a specific frequency,\nwhere as the power values at all other frequencies are effectively zero.\n\n\n" + "#### Section Conclusion\n\nWhen there is rhythmic activity at a particular frequency, this exhibits as a 'peak'\nof power in the frequency domain. This peak indicates high power at a specific frequency,\nwhere as the power values at all other frequencies are effectively zero.\n\n\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "Frequency Representations of Complex Signals\n--------------------------------------------\n\nNow let's consider the case whereby one could have a signal comprised of multiple\ncomponents, for example one or more oscillations combined with an aperiodic component.\n\n\n" + "## Frequency Representations of Complex Signals\n\nNow let's consider the case whereby one could have a signal comprised of multiple\ncomponents, for example one or more oscillations combined with an aperiodic component.\n\n\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "Combined Aperiodic & Periodic Signals\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nTo examine this, we will simulate combined signals, comprising both periodic and aperiodic\ncomponents, and see what the frequency representations look like.\n\n\n" + "### Combined Aperiodic & Periodic Signals\n\nTo examine this, we will simulate combined signals, comprising both periodic and aperiodic\ncomponents, and see what the frequency representations look like.\n\n\n" ] }, { @@ -383,14 +372,14 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Section Conclusion\n^^^^^^^^^^^^^^^^^^\n\nIn the power spectrum above, we can see that combined signals, with aperiodic & periodic\nactivity reflect elements of both components. The periodic power can be seen as a\npeak of power over and above the rest of the spectrum, at the frequency of the simulated\nrhythm. Across all frequencies, we also see the power contributed by the aperiodic component.\n\n\n" + "#### Section Conclusion\n\nIn the power spectrum above, we can see that combined signals, with aperiodic & periodic\nactivity reflect elements of both components. The periodic power can be seen as a\npeak of power over and above the rest of the spectrum, at the frequency of the simulated\nrhythm. Across all frequencies, we also see the power contributed by the aperiodic component.\n\n\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "Conclusion\n----------\n\nIn this example, we have seen that, in the frequency domain:\n\n- transients and aperiodic activity exhibit power across all frequencies\n- oscillations exhibit specific power, or a 'peak', at the frequency of the rhythm\n- combined signals display a combination of these properties, with power\n across all frequencies, and overlying 'peaks' at frequencies with periodic activity\n\nCollectively, we have seen cases that motivate that simply having power at a particularly\nfrequency does not imply any rhythmic component at that frequency. Peaks of frequency specific\npower are associated with rhythmic activity in the time series.\n\nWhat we have covered here are just a starting point for some properties of time\nseries analysis and digital signal processing. For neural data, these properties alone\ndo not tell us how to interpret neural power spectra. However, here we take them as a\nstarting point that motivate why prominent rhythms in the time series can be measured\nas peaks in the power spectrum, but that absent a peak, we should not automatically\ninterpret power at any given frequency as necessarily reflecting rhythmic activity.\n\n\n" + "## Conclusion\n\nIn this example, we have seen that, in the frequency domain:\n\n- transients and aperiodic activity exhibit power across all frequencies\n- oscillations exhibit specific power, or a 'peak', at the frequency of the rhythm\n- combined signals display a combination of these properties, with power\n across all frequencies, and overlying 'peaks' at frequencies with periodic activity\n\nCollectively, we have seen cases that motivate that simply having power at a particularly\nfrequency does not imply any rhythmic component at that frequency. Peaks of frequency specific\npower are associated with rhythmic activity in the time series.\n\nWhat we have covered here are just a starting point for some properties of time\nseries analysis and digital signal processing. For neural data, these properties alone\ndo not tell us how to interpret neural power spectra. However, here we take them as a\nstarting point that motivate why prominent rhythms in the time series can be measured\nas peaks in the power spectrum, but that absent a peak, we should not automatically\ninterpret power at any given frequency as necessarily reflecting rhythmic activity.\n\n\n" ] } ], @@ -410,7 +399,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.8.5" + "version": "3.8.3" } }, "nbformat": 4, diff --git a/_downloads/b6191b178a287c7db5f8ad9da5406ff5/plot_BandByBand.ipynb b/_downloads/b6191b178a287c7db5f8ad9da5406ff5/plot_BandByBand.ipynb index febbb720..1b4f1f8b 100644 --- a/_downloads/b6191b178a287c7db5f8ad9da5406ff5/plot_BandByBand.ipynb +++ b/_downloads/b6191b178a287c7db5f8ad9da5406ff5/plot_BandByBand.ipynb @@ -1,21 +1,10 @@ { "cells": [ - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "collapsed": false - }, - "outputs": [], - "source": [ - "%matplotlib inline" - ] - }, { "cell_type": "markdown", "metadata": {}, "source": [ - "\nBand-by-Band\n============\n\nComparing how 'Band-by-Band' approaches relate to periodic & aperiodic components.\n\nThis example is based on a recent project investigating band-by-band analyses as\noften done in the context of development. The paper for that project is available\n`here `_.\n" + "\n# Band-by-Band\n\nComparing how 'Band-by-Band' approaches relate to periodic & aperiodic components.\n\nThis example is based on a recent project investigating band-by-band analyses as\noften done in the context of development. The paper for that project is available\n[here](https://doi.org/10.1101/839258).\n" ] }, { @@ -33,14 +22,14 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Overview\n--------\n\nA common analysis approach for investigating neural data is to measure and analyze\nchanges across multiple frequency bands.\n\nThis is typically done using predefined bands, such as:\n\n- delta (1-4 Hz)\n- theta (4-8 Hz)\n- alpha (8-13 Hz)\n- beta (13-30 Hz)\n- gamma (30-50 Hz)\n\nWhen analyzed in this way, and comparing within or between subjects, investigations often\nreport a pattern of changes or differences across bands, for example:\n\n- decreased power in lower frequency bands (delta, theta)\n- increased power in higher frequency bands (beta, gamma)\n\nUnder this framework, each defined band reflects a different entity in the data,\nand the interpretation is typically that there are multiple things changing, with\ncorrelated changes in power across multiple distinct bands.\n\nAn alternative hypothesis for what is changing is that this pattern of results could\nbe driven by changes or differences in the aperiodic component of the data. Changes\nin aperiodic activity, when analyzed in a band-by-band manner, can look like correlated\nchanges across multiple bands.\n\nIn this example, we will use simulated data to examine both the different ways of\nanalyzing such data (band-by-band compared to parameterizing neural power spectra),\nand examine what it looks like if data differs in these hypothesized ways.\nTo do so, we will simulate and analyze data with correlated changes in multiple\ndistinct frequency bands, as well as data in which there is a shift in the aperiodic\ncomponent.\n\n\n" + "## Overview\n\nA common analysis approach for investigating neural data is to measure and analyze\nchanges across multiple frequency bands.\n\nThis is typically done using predefined bands, such as:\n\n- delta (1-4 Hz)\n- theta (4-8 Hz)\n- alpha (8-13 Hz)\n- beta (13-30 Hz)\n- gamma (30-50 Hz)\n\nWhen analyzed in this way, and comparing within or between subjects, investigations often\nreport a pattern of changes or differences across bands, for example:\n\n- decreased power in lower frequency bands (delta, theta)\n- increased power in higher frequency bands (beta, gamma)\n\nUnder this framework, each defined band reflects a different entity in the data,\nand the interpretation is typically that there are multiple things changing, with\ncorrelated changes in power across multiple distinct bands.\n\nAn alternative hypothesis for what is changing is that this pattern of results could\nbe driven by changes or differences in the aperiodic component of the data. Changes\nin aperiodic activity, when analyzed in a band-by-band manner, can look like correlated\nchanges across multiple bands.\n\nIn this example, we will use simulated data to examine both the different ways of\nanalyzing such data (band-by-band compared to parameterizing neural power spectra),\nand examine what it looks like if data differs in these hypothesized ways.\nTo do so, we will simulate and analyze data with correlated changes in multiple\ndistinct frequency bands, as well as data in which there is a shift in the aperiodic\ncomponent.\n\n\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "Settings\n~~~~~~~~\n\nFirst, we can define some settings for this notebook and analysis.\n\n\n" + "### Settings\n\nFirst, we can define some settings for this notebook and analysis.\n\n\n" ] }, { @@ -58,7 +47,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Helper Functions\n~~~~~~~~~~~~~~~~\n\nThroughout this notebook we will be computing and analyzing differences between\npower spectra. Here, we will define some helper functions to do so.\n\n\n" + "### Helper Functions\n\nThroughout this notebook we will be computing and analyzing differences between\npower spectra. Here, we will define some helper functions to do so.\n\n\n" ] }, { @@ -76,7 +65,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Band-by-Band\n------------\n\nIn the 'band-by-band' idea of the data, analyses and interpretations focus on analyzing\nactivity across a range of frequency bands, and looking for patterns of changes within\nand between these bands.\n\nTo visualize this, we can simulate hypothesized power spectra for different groups,\nin which we will set the same aperiodic activity, and vary overlying periodic peaks.\n\nIn this example, for clarity, the center frequencies for all peaks are\nsimulated as being the same between groups, though in real data these could also vary.\n\n\n" + "## Band-by-Band\n\nIn the 'band-by-band' idea of the data, analyses and interpretations focus on analyzing\nactivity across a range of frequency bands, and looking for patterns of changes within\nand between these bands.\n\nTo visualize this, we can simulate hypothesized power spectra for different groups,\nin which we will set the same aperiodic activity, and vary overlying periodic peaks.\n\nIn this example, for clarity, the center frequencies for all peaks are\nsimulated as being the same between groups, though in real data these could also vary.\n\n\n" ] }, { @@ -116,7 +105,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Flatten the Spectra\n~~~~~~~~~~~~~~~~~~~\n\nUnder the band-by-band idea, controlling for aperiodic activity and flattening\nthe spectra should show specific differences in each band.\n\nIt should also find no systematic difference in the aperiodic activity between groups.\n\nTo check this, we can fit power spectrum models, and examine which parameters are\nchanging in the data.\n\n\n" + "### Flatten the Spectra\n\nUnder the band-by-band idea, controlling for aperiodic activity and flattening\nthe spectra should show specific differences in each band.\n\nIt should also find no systematic difference in the aperiodic activity between groups.\n\nTo check this, we can fit power spectrum models, and examine which parameters are\nchanging in the data.\n\n\n" ] }, { @@ -145,7 +134,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Compare Spectral Parameters\n~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nNext, let's compare the measured parameters of the data.\n\n\n" + "### Compare Spectral Parameters\n\nNext, let's compare the measured parameters of the data.\n\n\n" ] }, { @@ -181,7 +170,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Periodic & Aperiodic\n--------------------\n\nAn alternative hypothesis is that aperiodic activity may vary between groups.\n\nIn the next simulation, we will simulate each group as having same periodic activity,\nin this case, just an alpha peak, with a difference in the aperiodic activity.\n\n\n" + "## Periodic & Aperiodic\n\nAn alternative hypothesis is that aperiodic activity may vary between groups.\n\nIn the next simulation, we will simulate each group as having same periodic activity,\nin this case, just an alpha peak, with a difference in the aperiodic activity.\n\n\n" ] }, { @@ -210,7 +199,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Flatten the Spectra\n~~~~~~~~~~~~~~~~~~~\n\nIn the scenario in which there are differences in aperiodic activity, flattening\nthe spectra should show no differences in periodic peaks.\n\nWe can again parameterize the spectra to investigate this.\n\n\n" + "### Flatten the Spectra\n\nIn the scenario in which there are differences in aperiodic activity, flattening\nthe spectra should show no differences in periodic peaks.\n\nWe can again parameterize the spectra to investigate this.\n\n\n" ] }, { @@ -239,7 +228,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Compare Spectral Parameters\n~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nLet's again compare the measured parameters of the data.\n\n\n" + "### Compare Spectral Parameters\n\nLet's again compare the measured parameters of the data.\n\n\n" ] }, { @@ -275,7 +264,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Conclusion\n----------\n\nHere we have investigated changes across power spectra, comparing a 'band-by-band'\napproach to the parameterizing neural power spectra notion of 'periodic & aperiodic'\ncomponents.\n\nWhat we can see is that parameterizing neural power spectra is able to determine\nif changes are driven by differences in oscillatory peaks, and/or by changes in the\naperiodic component of the data.\n\nHowever, we also saw that simply doing a band-by-band power analysis can conflate differences\nfrom aperiodic and periodic changes. Specifically, when we change the aperiodic activity\nin a power spectrum, the band-by-band analysis suggests that multiple distinct frequency\nbands are changing, whereas the more parsimonious (and in the simulated case, the true)\nconclusion should be that changes are driven by changes in the aperiodic activity\nthat affects all frequencies. This also means that if a band-by-band analysis finds\ndifferences across bands, this is not enough to know if there are band-specific changes,\nor aperiodic changes, as this analysis approach does not differentiate the two.\n\nWe conclude here that band-by-band analysis, without measuring or controlling for\naperiodic activity, are ill posed to adjudicate which aspects of the data are changing.\nParameterizing neural power spectra allows for disentangling changes in\nperiodic and aperiodic components of the data.\n\nIn this example, with simulated data, we cannot conclude which changes are more likely\nto be occurring in real data. However, in the real data analysis that this example\nis based on, it was found that a great deal of the changes across development are\ndriven by aperiodic changes, and not by band-by-band differences. This finding\ncame from using the parameterization approach, but was not evidence in prior\nwork using only a band-by-band approach.\nYou can find more on that project\n`here `_.\n\n\n" + "## Conclusion\n\nHere we have investigated changes across power spectra, comparing a 'band-by-band'\napproach to the parameterizing neural power spectra notion of 'periodic & aperiodic'\ncomponents.\n\nWhat we can see is that parameterizing neural power spectra is able to determine\nif changes are driven by differences in oscillatory peaks, and/or by changes in the\naperiodic component of the data.\n\nHowever, we also saw that simply doing a band-by-band power analysis can conflate differences\nfrom aperiodic and periodic changes. Specifically, when we change the aperiodic activity\nin a power spectrum, the band-by-band analysis suggests that multiple distinct frequency\nbands are changing, whereas the more parsimonious (and in the simulated case, the true)\nconclusion should be that changes are driven by changes in the aperiodic activity\nthat affects all frequencies. This also means that if a band-by-band analysis finds\ndifferences across bands, this is not enough to know if there are band-specific changes,\nor aperiodic changes, as this analysis approach does not differentiate the two.\n\nWe conclude here that band-by-band analysis, without measuring or controlling for\naperiodic activity, are ill posed to adjudicate which aspects of the data are changing.\nParameterizing neural power spectra allows for disentangling changes in\nperiodic and aperiodic components of the data.\n\nIn this example, with simulated data, we cannot conclude which changes are more likely\nto be occurring in real data. However, in the real data analysis that this example\nis based on, it was found that a great deal of the changes across development are\ndriven by aperiodic changes, and not by band-by-band differences. This finding\ncame from using the parameterization approach, but was not evidence in prior\nwork using only a band-by-band approach.\nYou can find more on that project\n[here](https://doi.org/10.1101/839258).\n\n\n" ] } ], @@ -295,7 +284,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.8.5" + "version": "3.8.3" } }, "nbformat": 4, diff --git a/_downloads/ee710e89e9827206e88677ec3a7784a9/auto_motivations_python.zip b/_downloads/b9e47ac59fc48cae331a1a48b15b4fc0/auto_motivations_python.zip similarity index 87% rename from _downloads/ee710e89e9827206e88677ec3a7784a9/auto_motivations_python.zip rename to _downloads/b9e47ac59fc48cae331a1a48b15b4fc0/auto_motivations_python.zip index 6f2274e6..d2049786 100644 Binary files a/_downloads/ee710e89e9827206e88677ec3a7784a9/auto_motivations_python.zip and b/_downloads/b9e47ac59fc48cae331a1a48b15b4fc0/auto_motivations_python.zip differ diff --git a/_downloads/bdf3a9db3c5ce7191e3dcd22c91d3ebc/auto_examples_jupyter.zip b/_downloads/bdf3a9db3c5ce7191e3dcd22c91d3ebc/auto_examples_jupyter.zip deleted file mode 100644 index c36c69d4..00000000 Binary files a/_downloads/bdf3a9db3c5ce7191e3dcd22c91d3ebc/auto_examples_jupyter.zip and /dev/null differ diff --git a/_downloads/c8102b67a528eed85b861137f14ade9a/plot_data_exporting.ipynb b/_downloads/c8102b67a528eed85b861137f14ade9a/plot_data_exporting.ipynb new file mode 100644 index 00000000..728fda9d --- /dev/null +++ b/_downloads/c8102b67a528eed85b861137f14ade9a/plot_data_exporting.ipynb @@ -0,0 +1,220 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n# Exporting Model Results\n\nThis example covers utilities for extracting and exporting model fit results.\n\nNote that the functionality to export to pandas DataFrames was added in version 1.1,\nand requires the optional dependency `pandas` to be installed.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Import model objects, and Bands object to define bands of interest\nfrom fooof import FOOOF, FOOOFGroup, Bands\n\n# Import simulation functions to create some example data\nfrom fooof.sim import gen_power_spectrum, gen_group_power_spectra" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Exporting Results\n\nIn this example we will explore available functionality for extracting model fit results,\nspecifically the options available for exporting results to pandas objects.\n\nNote that the main use case of exporting models to pandas DataFrames is for\nanalysis across models. If you are just trying to access the model fit results from\na fit model, you may want the :meth:`~fooof.FOOOF.get_results` and/or\n:meth:`~fooof.FOOOF.get_params` methods.\n\n### Defining Oscillation Bands\n\nA difficulty with exporting and collecting model results across model fits is that the\nmodels may be different sizes - most notably, they may contain different numbers of peaks.\n\nThis means that we need to define some kind of strategy to organize the peak\nparameters across different models. Across these examples, this will include using the\n:class:`~fooof.Bands` object to define oscillations bands of interest.\n\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Initialize bands object, defining alpha band\nbands1 = Bands({'alpha' : [7, 14]})\n\n# Initialize model object\nfm = FOOOF()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Simulate example power spectrum\nfreqs, powers = gen_power_spectrum([1, 50], [0, 10, 1], [10, 0.25, 2], freq_res=0.25)\n\n# Fit model to power spectrum\nfm.fit(freqs, powers)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The :meth:`~fooof.FOOOF.to_df` method supports exporting model fit results to pandas objects.\n\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Export results\nfm.to_df(None)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "In the above, we export the model fit results to a pandas Series.\n\nNote that we explicitly passed in `None` to the `peak_org` argument, meaning we did not define\na strategy for managing peaks. Because of this, the export did not include any peak parameters.\n\nNext, let's can try exporting again, this time passing in an integer to define the number\nof peaks to extract.\n\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Export results - extracting 1 peak\nfm.to_df(1)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Using Band Definitions\n\nIn the above, we extract the results specifying to extract 1 peak. By default, this approach\nwill extract the dominant (highest power) peak.\n\nNotably, specifying a set number of peaks to extract does allow for combining across peaks\n(in terms of enforcing the same model size), but may not be the ideal way to examine across\npeaks (since the dominant extract peak may vary across model fits).\n\nTherefore, we may often want to instead define a set of band definitions to organize peaks,\nas can be done by passing a `Bands` object in to the `to_df` method.\n\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Export results - extracting peaks based on bands object\nfm.to_df(bands1)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Note that there are limitations to using the bands definitions - notably that doing so\nnecessarily requires extracting at most 1 peak per band. In doing so, the extraction will\nselect the dominant peak per band. However, this may not fully reflect the full model fit\nif there are, for example, multiple peaks fit within a band.\n\n\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Example on Group Object\n\nIn the above, we used the model object to show the basic exporting functionalities.\n\nThis functionality is more useful when considering multiple model fits together, such\nas can be done using the :meth:`~fooof.FOOOFGroup.to_df` method from the Group object,\nwhich allows for exporting DataFrames of organized model fit parameters across power spectra.\n\nAs with the above, keep in mind that for some cases you may want the\n:meth:`~fooof.FOOOFGroup.get_results` and/or :meth:`~fooof.FOOOFGroup.get_params` methods\ninstead of doing a DataFrame export.\n\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Simulate an example group of power spectra\nfreqs, powers = gen_group_power_spectra(5, [1, 50], [0, 1], [10, 0.25, 2])\n\n# Initialize a group model object and fit power spectra\nfg = FOOOFGroup(verbose=False)\nfg.fit(freqs, powers)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Export results to dataframe, with no peak definition\nfg.to_df(None)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Export results to dataframe, specifying to export a single peak\nfg.to_df(1)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Export results to dataframe, using bands definition with defines the alpha band\nfg.to_df(bands1)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "In the above examples, we showed the same exports on the Group object as we previously\nexplored on the single spectrum in the model object.\n\nNote that we can also define new bands objects to change the peak output organization,\nas demonstrated in the following example.\n\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Define a new bands object, specifying both the alpha and beta band\nbands2 = Bands({'alpha' : [7, 14],\n 'beta' : [15, 30]})" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Export results to dataframe, using bands object with alpha & beta\nfg.to_df(bands2)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "That covers the pandas export functionality available from the model objects.\n\n\n" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.8.3" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} \ No newline at end of file diff --git a/_downloads/d294106d17ffb64a8556c43667a0781c/auto_tutorials_python.zip b/_downloads/cab7a090c4183ca69dc0cd84d3b04413/auto_tutorials_python.zip similarity index 91% rename from _downloads/d294106d17ffb64a8556c43667a0781c/auto_tutorials_python.zip rename to _downloads/cab7a090c4183ca69dc0cd84d3b04413/auto_tutorials_python.zip index d8fe36f3..64fd4ed2 100644 Binary files a/_downloads/d294106d17ffb64a8556c43667a0781c/auto_tutorials_python.zip and b/_downloads/cab7a090c4183ca69dc0cd84d3b04413/auto_tutorials_python.zip differ diff --git a/_downloads/cc804a6d6a719c9e628feb4f056bbd74/plot_01-ModelDescription.py b/_downloads/cc804a6d6a719c9e628feb4f056bbd74/plot_01-ModelDescription.py index 18088d86..36046fab 100644 --- a/_downloads/cc804a6d6a719c9e628feb4f056bbd74/plot_01-ModelDescription.py +++ b/_downloads/cc804a6d6a719c9e628feb4f056bbd74/plot_01-ModelDescription.py @@ -41,7 +41,7 @@ from fooof import FOOOF from fooof.sim.gen import gen_power_spectrum from fooof.sim.utils import set_random_seed -from fooof.plts.spectra import plot_spectrum +from fooof.plts.spectra import plot_spectra from fooof.plts.annotate import plot_annotated_model ################################################################################################### @@ -81,8 +81,8 @@ ################################################################################################### # Plot one of the example power spectra -plot_spectrum(freqs1, powers1, log_powers=True, - color='black', label='Original Spectrum') +plot_spectra(freqs1, powers1, log_powers=True, + color='black', label='Original Spectrum') ################################################################################################### # Conceptual Overview diff --git a/_downloads/cd28e8b309d37589cba9b514ff578f2c/plot_03-FOOOFAlgorithm.py b/_downloads/cd28e8b309d37589cba9b514ff578f2c/plot_03-FOOOFAlgorithm.py index 7a63a038..5ad2a08c 100644 --- a/_downloads/cd28e8b309d37589cba9b514ff578f2c/plot_03-FOOOFAlgorithm.py +++ b/_downloads/cd28e8b309d37589cba9b514ff578f2c/plot_03-FOOOFAlgorithm.py @@ -41,7 +41,7 @@ # These are used here to demonstrate the algorithm # You do not need to import these functions for standard usage of the module from fooof.sim.gen import gen_aperiodic -from fooof.plts.spectra import plot_spectrum +from fooof.plts.spectra import plot_spectra from fooof.plts.annotate import plot_annotated_peak_search # Import a utility to download and load example data @@ -110,10 +110,10 @@ # Plot the initial aperiodic fit _, ax = plt.subplots(figsize=(12, 10)) -plot_spectrum(fm.freqs, fm.power_spectrum, plt_log, - label='Original Power Spectrum', color='black', ax=ax) -plot_spectrum(fm.freqs, init_ap_fit, plt_log, label='Initial Aperiodic Fit', - color='blue', alpha=0.5, linestyle='dashed', ax=ax) +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 @@ -131,8 +131,8 @@ init_flat_spec = fm.power_spectrum - init_ap_fit # Plot the flattened the power spectrum -plot_spectrum(fm.freqs, init_flat_spec, plt_log, - label='Flattened Spectrum', color='black') +plot_spectra(fm.freqs, init_flat_spec, plt_log, + label='Flattened Spectrum', color='black') ################################################################################################### # Step 3: Detect Peaks @@ -172,7 +172,7 @@ ################################################################################################### # Plot the peak fit: created by re-fitting all of the candidate peaks together -plot_spectrum(fm.freqs, fm._peak_fit, plt_log, color='green', label='Final Periodic Fit') +plot_spectra(fm.freqs, fm._peak_fit, plt_log, color='green', label='Final Periodic Fit') ################################################################################################### # Step 5: Create a Peak-Removed Spectrum @@ -188,8 +188,8 @@ ################################################################################################### # Plot the peak removed power spectrum, created by removing peak fit from original spectrum -plot_spectrum(fm.freqs, fm._spectrum_peak_rm, plt_log, - label='Peak Removed Spectrum', color='black') +plot_spectra(fm.freqs, fm._spectrum_peak_rm, plt_log, + label='Peak Removed Spectrum', color='black') ################################################################################################### # Step 6: Re-fit the Aperiodic Component @@ -206,10 +206,10 @@ # Plot the final aperiodic fit, calculated on the peak removed power spectrum _, ax = plt.subplots(figsize=(12, 10)) -plot_spectrum(fm.freqs, fm._spectrum_peak_rm, plt_log, - label='Peak Removed Spectrum', color='black', ax=ax) -plot_spectrum(fm.freqs, fm._ap_fit, plt_log, label='Final Aperiodic Fit', - color='blue', alpha=0.5, linestyle='dashed', ax=ax) +plot_spectra(fm.freqs, fm._spectrum_peak_rm, plt_log, + label='Peak Removed Spectrum', color='black', ax=ax) +plot_spectra(fm.freqs, fm._ap_fit, plt_log, label='Final Aperiodic Fit', + color='blue', alpha=0.5, linestyle='dashed', ax=ax) ################################################################################################### # Step 7: Combine the Full Model Fit @@ -226,8 +226,8 @@ ################################################################################################### # Plot full model, created by combining the peak and aperiodic fits -plot_spectrum(fm.freqs, fm.fooofed_spectrum_, plt_log, - label='Full Model', color='red') +plot_spectra(fm.freqs, fm.fooofed_spectrum_, plt_log, + label='Full Model', color='red') ################################################################################################### # diff --git a/_downloads/d3bfa0d1bce89560d1c94a16a3226fd8/plot_peak_params.ipynb b/_downloads/d3bfa0d1bce89560d1c94a16a3226fd8/plot_peak_params.ipynb new file mode 100644 index 00000000..1f006bc5 --- /dev/null +++ b/_downloads/d3bfa0d1bce89560d1c94a16a3226fd8/plot_peak_params.ipynb @@ -0,0 +1,137 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n# Periodic Parameters\n\nExploring properties and topics related to peak parameters.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "from fooof import FOOOF, FOOOFGroup\nfrom fooof.plts.spectra import plot_spectra\nfrom fooof.plts.periodic import plot_peak_params\nfrom fooof.sim.utils import set_random_seed\nfrom fooof.sim.params import Stepper, param_iter\nfrom fooof.sim import gen_power_spectrum, gen_group_power_spectra\nfrom fooof.plts.annotate import plot_annotated_model\nfrom fooof.utils.params import compute_time_constant, compute_knee_frequency" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Gaussian Peak Model\n\nBy default, the spectral parameterization model fits Gaussians to any detected peaks.\n\nThese Gaussians are defined by a mean, height, and standard deviation, which we in turn\ninterpret as the center frequency (CF), power (PW), and bandwidth (BW) of the putative\noscillation.\n\nIn this example, we will further explore these peak parameters and some topics and\nlimitations related to their use and interpretations.\n\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Simulate an example power spectrum\nfreqs, powers = gen_power_spectrum([3, 40], [0, 1], [10, 0.3, 1.], freq_res=0.25)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Initialize model object and fit power spectrum\nfm = FOOOF(min_peak_height=0.1)\nfm.fit(freqs, powers)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Plot annotated model labelling the peaks\nplot_annotated_model(fm, annotate_peaks=True, annotate_aperiodic=False, plt_log=True)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "In the above we can see an example of the fit peak parameters\n\n\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Overlapping Peaks\n\nLet's now consider some features of fitting Gaussian peaks, and how this relates to\nthe neural data under study. In particular, Gaussian's are symmetric and while they do\nseem to approximate the peaks we observe in emprical data quite well, not all peaks\nin empirical power spectra are quite symmetric.\n\nTo deal with this, the model sometimes fits overlapping peaks, whereby two or more peaks\nare used by the model to capture the shape of what otherwise looks like a single peak.\n\nWe can explore this in a simplified simulation.\n\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Set the random seed\nset_random_seed(10)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Simulate an example power spectrum created with an asymmetric peak\nfreqs, powers = gen_power_spectrum([3, 40], [0, 1], [[10, 0.3, 1.], [11.25, 0.175, 0.5]], freq_res=0.25)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Initialize model object and fit power spectrum\nfm = FOOOF(min_peak_height=0.1)\nfm.report(freqs, powers)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "As we can see in the above model solution, in the data, it looks like there is a single\noscillatory peak, and yet the model has captured this peak with two Gaussians.\n\nThis example serves to demonstrate two key points. First, not all Gaussians fit in the model\nnecessary reflect separate peaks, as some may overlap. Second, when peaks overlap,\nthe parameters of each individually may accurately capture a peak in the data, as the\noverall shape of the peak may be captured as the interaction across multiple Gaussians\n(this is most common / notable for the bandwidth measure, whereby the width of the peak is\nbest described as the combined width of the two adjacent peaks).\n\nNote that, by construction, this simulated example was created by simulating two overlapping\npeaks, and so in that sense the model is actually correct in it's solution. In empirical\ndata, we do not know if a power spectrum that looks like this does reflect two underlying\noscillatory processes, or perhaps a single oscillatory process that happens to be asymmetric\nin the frequency domain.\n\n\n" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.8.3" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} \ No newline at end of file diff --git a/_downloads/d49fe0cacb8bde8dde32384afc5ed2ef/plot_06-FOOOFGroup.ipynb b/_downloads/d49fe0cacb8bde8dde32384afc5ed2ef/plot_06-FOOOFGroup.ipynb index cc9c28b8..716a8498 100644 --- a/_downloads/d49fe0cacb8bde8dde32384afc5ed2ef/plot_06-FOOOFGroup.ipynb +++ b/_downloads/d49fe0cacb8bde8dde32384afc5ed2ef/plot_06-FOOOFGroup.ipynb @@ -1,21 +1,10 @@ { "cells": [ - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "collapsed": false - }, - "outputs": [], - "source": [ - "%matplotlib inline" - ] - }, { "cell_type": "markdown", "metadata": {}, "source": [ - "\n06: FOOOFGroup\n==============\n\nUsing FOOOFGroup to run fit models across multiple power spectra.\n" + "\n# 06: FOOOFGroup\n\nUsing FOOOFGroup to run fit models across multiple power spectra.\n" ] }, { @@ -33,7 +22,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Fitting Multiple Spectra\n------------------------\n\nSo far, we have explored using the :class:`~fooof.FOOOF` object to fit individual power spectra.\n\nHowever, many potential analyses will including many power spectra that need to be fit.\n\nTo support this, here we will introduce the :class:`~fooof.FOOOFGroup` object, which\napplies the model fitting procedure across multiple power spectra.\n\n\n" + "## Fitting Multiple Spectra\n\nSo far, we have explored using the :class:`~fooof.FOOOF` object to fit individual power spectra.\n\nHowever, many potential analyses will including many power spectra that need to be fit.\n\nTo support this, here we will introduce the :class:`~fooof.FOOOFGroup` object, which\napplies the model fitting procedure across multiple power spectra.\n\n\n" ] }, { @@ -69,7 +58,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "FOOOFGroup\n----------\n\nThe :class:`~fooof.FOOOFGroup` object is very similar to the FOOOF object (programmatically,\nit inherits from the FOOOF object), and can be used in the same way.\n\nThe main difference is that instead of running across a single power spectrum, it\noperates across 2D matrices containing multiple power spectra.\n\nNote that by 'group' we mean merely to refer to a group of power-spectra. We\nare not using the term 'group' in terms of necessarily referring to multiple subjects\nor any particular idea of what a 'group' may be. A group of power spectra could\nbe spectra from across channels, or across trials, or across subjects, or\nwhatever organization makes sense for the analysis at hand.\n\nThe main differences with the :class:`~fooof.FOOOFGroup` object, are that it uses a\n`power_spectra` attribute, which stores the matrix of power-spectra to be fit,\nand collects fit results into a `group_results` attribute.\n\nOtherwise, :class:`~fooof.FOOOFGroup` supports all the same functionality,\naccessed in the same way as the :class:`~fooof.FOOOF` object.\n\nInternally, it runs the exact same fitting procedure, per spectrum, as the FOOOF object.\n\n\n" + "## FOOOFGroup\n\nThe :class:`~fooof.FOOOFGroup` object is very similar to the FOOOF object (programmatically,\nit inherits from the FOOOF object), and can be used in the same way.\n\nThe main difference is that instead of running across a single power spectrum, it\noperates across 2D matrices containing multiple power spectra.\n\nNote that by 'group' we mean merely to refer to a group of power-spectra. We\nare not using the term 'group' in terms of necessarily referring to multiple subjects\nor any particular idea of what a 'group' may be. A group of power spectra could\nbe spectra from across channels, or across trials, or across subjects, or\nwhatever organization makes sense for the analysis at hand.\n\nThe main differences with the :class:`~fooof.FOOOFGroup` object, are that it uses a\n`power_spectra` attribute, which stores the matrix of power-spectra to be fit,\nand collects fit results into a `group_results` attribute.\n\nOtherwise, :class:`~fooof.FOOOFGroup` supports all the same functionality,\naccessed in the same way as the :class:`~fooof.FOOOF` object.\n\nInternally, it runs the exact same fitting procedure, per spectrum, as the FOOOF object.\n\n\n" ] }, { @@ -138,7 +127,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "FOOOFGroup Results\n------------------\n\nFOOOFGroup collects fits across power spectra, and stores them in an attribute\ncalled ``group_results``, which is a list of FOOOFResults objects.\n\n\n" + "## FOOOFGroup Results\n\nFOOOFGroup collects fits across power spectra, and stores them in an attribute\ncalled ``group_results``, which is a list of FOOOFResults objects.\n\n\n" ] }, { @@ -156,7 +145,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "get_params\n~~~~~~~~~~\n\nTo collect results from across all model fits, and to select specific parameters\nyou can use the :func:`~fooof.FOOOFGroup.get_params` method.\n\nThis method works the same as in the :class:`~fooof.FOOOF` object, and lets you extract\nspecific results by specifying a field, as a string, and (optionally) a specific column\nto extract.\n\nSince the :class:`~fooof.FOOOFGroup` object collects results from across multiple model fits,\nyou should always use :func:`~fooof.FOOOFGroup.get_params` to access model parameters.\nThe results attributes introduced with the FOOOF object (such as `aperiodic_params_` or\n`peak_params_`) do not store results across the group, as they are defined for individual\nmodel fits (and used internally as such by the FOOOFGroup object).\n\n\n" + "### get_params\n\nTo collect results from across all model fits, and to select specific parameters\nyou can use the :func:`~fooof.FOOOFGroup.get_params` method.\n\nThis method works the same as in the :class:`~fooof.FOOOF` object, and lets you extract\nspecific results by specifying a field, as a string, and (optionally) a specific column\nto extract.\n\nSince the :class:`~fooof.FOOOFGroup` object collects results from across multiple model fits,\nyou should always use :func:`~fooof.FOOOFGroup.get_params` to access model parameters.\nThe results attributes introduced with the FOOOF object (such as `aperiodic_params_` or\n`peak_params_`) do not store results across the group, as they are defined for individual\nmodel fits (and used internally as such by the FOOOFGroup object).\n\n\n" ] }, { @@ -225,7 +214,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Saving & Loading with FOOOFGroup\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nFOOOFGroup also support saving and loading, with the same options for saving out\ndifferent things as defined and described for the FOOOF object.\n\nThe only difference in saving FOOOFGroup, is that it saves out a 'jsonlines' file,\nin which each line is a JSON object, saving the specified data, settings, and results for\na single power spectrum.\n\n\n" + "### Saving & Loading with FOOOFGroup\n\nFOOOFGroup also support saving and loading, with the same options for saving out\ndifferent things as defined and described for the FOOOF object.\n\nThe only difference in saving FOOOFGroup, is that it saves out a 'jsonlines' file,\nin which each line is a JSON object, saving the specified data, settings, and results for\na single power spectrum.\n\n\n" ] }, { @@ -265,7 +254,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Parallel Support\n~~~~~~~~~~~~~~~~\n\nFOOOFGroup also has support for running in parallel, which can speed things up, since\neach power spectrum can be fit independently.\n\nThe fit method includes an optional parameter ``n_jobs``, which if set at 1 (as default),\nwill fit models linearly (one at a time, in order). If you set this parameter to some other\ninteger, fitting will launch 'n_jobs' number of jobs, in parallel. Setting n_jobs to -1 will\nlaunch model fitting in parallel across all available cores.\n\nNote, however, that fitting power spectrum models in parallel does not guarantee a quicker\nruntime overall. The computation time per model fit scales with the frequency range fit over,\nand the 'complexity' of the power spectra, in terms of number of peaks. For relatively small\nnumbers of power spectra (less than ~100), across relatively small frequency ranges\n(say ~3-40Hz), running in parallel may offer no appreciable speed up.\n\n\n" + "### Parallel Support\n\nFOOOFGroup also has support for running in parallel, which can speed things up, since\neach power spectrum can be fit independently.\n\nThe fit method includes an optional parameter ``n_jobs``, which if set at 1 (as default),\nwill fit models linearly (one at a time, in order). If you set this parameter to some other\ninteger, fitting will launch 'n_jobs' number of jobs, in parallel. Setting n_jobs to -1 will\nlaunch model fitting in parallel across all available cores.\n\nNote, however, that fitting power spectrum models in parallel does not guarantee a quicker\nruntime overall. The computation time per model fit scales with the frequency range fit over,\nand the 'complexity' of the power spectra, in terms of number of peaks. For relatively small\nnumbers of power spectra (less than ~100), across relatively small frequency ranges\n(say ~3-40Hz), running in parallel may offer no appreciable speed up.\n\n\n" ] }, { @@ -283,7 +272,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Progress Bar\n~~~~~~~~~~~~\n\nIf you have a large number of spectra to fit with a :class:`~fooof.FOOOFGroup`, and you\nwant to monitor it's progress, you can also use a progress bar to print out fitting progress.\n\nProgress bar options are:\n\n- ``tqdm`` : a progress bar for running in terminals\n- ``tqdm.notebook`` : a progress bar for running in Jupyter notebooks\n\n\n" + "### Progress Bar\n\nIf you have a large number of spectra to fit with a :class:`~fooof.FOOOFGroup`, and you\nwant to monitor it's progress, you can also use a progress bar to print out fitting progress.\n\nProgress bar options are:\n\n- ``tqdm`` : a progress bar for running in terminals\n- ``tqdm.notebook`` : a progress bar for running in Jupyter notebooks\n\n\n" ] }, { @@ -301,7 +290,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Extracting Individual Fits\n~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nWhen fitting power spectrum models for a group of power spectra, results are stored\nin FOOOFResults objects, which store (only) the results of the model fit,\nnot the full model fits themselves.\n\nTo examine individual model fits, :class:`~fooof.FOOOFGroup` can regenerate\n:class:`~fooof.FOOOF` objects for individual power spectra, with the full model available\nfor visualization. To do so, you can use the :meth:`~fooof.FOOOFGroup.get_fooof` method.\n\n\n" + "### Extracting Individual Fits\n\nWhen fitting power spectrum models for a group of power spectra, results are stored\nin FOOOFResults objects, which store (only) the results of the model fit,\nnot the full model fits themselves.\n\nTo examine individual model fits, :class:`~fooof.FOOOFGroup` can regenerate\n:class:`~fooof.FOOOF` objects for individual power spectra, with the full model available\nfor visualization. To do so, you can use the :meth:`~fooof.FOOOFGroup.get_fooof` method.\n\n\n" ] }, { @@ -330,7 +319,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Conclusion\n----------\n\nNow we have explored fitting power spectrum models and running these fits across multiple\npower spectra. Next we dig deeper into how to choose and tune the algorithm settings,\nand how to troubleshoot if any of the fitting seems to go wrong.\n\n\n" + "## Conclusion\n\nNow we have explored fitting power spectrum models and running these fits across multiple\npower spectra. Next we dig deeper into how to choose and tune the algorithm settings,\nand how to troubleshoot if any of the fitting seems to go wrong.\n\n\n" ] } ], @@ -350,7 +339,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.8.5" + "version": "3.8.3" } }, "nbformat": 4, diff --git a/_downloads/db26135e85e3f8b4440c4fc4f5b0ad17/plot_aperiodic_params.ipynb b/_downloads/db26135e85e3f8b4440c4fc4f5b0ad17/plot_aperiodic_params.ipynb new file mode 100644 index 00000000..91808b4d --- /dev/null +++ b/_downloads/db26135e85e3f8b4440c4fc4f5b0ad17/plot_aperiodic_params.ipynb @@ -0,0 +1,272 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n# Aperiodic Parameters\n\nExploring properties and topics related to aperiodic parameters.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "from scipy.stats import spearmanr\n\nfrom fooof import FOOOF, FOOOFGroup\nfrom fooof.plts.spectra import plot_spectra\nfrom fooof.plts.annotate import plot_annotated_model\nfrom fooof.plts.aperiodic import plot_aperiodic_params\nfrom fooof.sim.params import Stepper, param_iter\nfrom fooof.sim import gen_power_spectrum, gen_group_power_spectra\nfrom fooof.utils.params import compute_time_constant, compute_knee_frequency" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 'Fixed' Model\n\nFirst, we will explore the 'fixed' model, which fits an offset and exponent value\nto characterize the 1/f-like aperiodic component of the data.\n\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Simulate an example power spectrum\nfreqs, powers = gen_power_spectrum([1, 50], [0, 1], [10, 0.25, 2], freq_res=0.25)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Initialize model object and fit power spectrum\nfm = FOOOF(min_peak_height=0.1)\nfm.fit(freqs, powers)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Check the aperiodic parameters\nfm.aperiodic_params_" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Plot annotated model of aperiodic parameters\nplot_annotated_model(fm, annotate_peaks=False, annotate_aperiodic=True, plt_log=True)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Comparing Offset & Exponent\n\nA common analysis of model fit parameters includes examining and comparing changes\nin the offset and/or exponent values of a set of models, which we will now explore.\n\nTo do so, we will start by simulating a set of power spectra with different exponent values.\n\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Define simulation parameters, stepping across different exponent values\nexp_steps = Stepper(0, 2, 0.25)\nap_params = param_iter([1, exp_steps])" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Simulate a group of power spectra\nfreqs, powers = gen_group_power_spectra(\\\n len(exp_steps), [3, 40], ap_params, [10, 0.25, 1], freq_res=0.25, f_rotation=10)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Plot the set of example power spectra\nplot_spectra(freqs, powers, log_powers=True)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Initialize a group mode object and parameterize the power spectra\nfg = FOOOFGroup()\nfg.fit(freqs, powers)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Extract the aperiodic values of the model fits\nap_values = fg.get_params('aperiodic')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Plot the aperiodic parameters\nplot_aperiodic_params(fg.get_params('aperiodic'))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Compute the correlation between the offset and exponent\nspearmanr(ap_values[0, :], ap_values[1, :])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "What we see above matches the common finding that that the offset and exponent are\noften highly correlated! This is because if you imagine a change in exponent as\nthe spectrum 'rotating' around some frequency value, then (almost) any change in exponent\nhas a corresponding change in offset value! If you note in the above, we actually specified\na rotation point around which the exponent changes.\n\nThis can also be seen in this animation showing this effect across different rotation points:\n\n\n\nNotably this means that while the offset and exponent can change independently (there can be\noffset changes over and above exponent changes), the baseline expectation is that these\ntwo parameters are highly correlated and likely reflect the same change in the data!\n\n\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Knee Model\n\nNext, let's explore the knee model, which parameterizes the aperiodic component with\nan offset, knee, and exponent value.\n\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Generate a power spectrum with a knee\nfreqs2, powers2 = gen_power_spectrum([1, 50], [0, 15, 1], [8, 0.125, 0.75], freq_res=0.25)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Initialize model object and fit power spectrum\nfm = FOOOF(min_peak_height=0.05, aperiodic_mode='knee')\nfm.fit(freqs2, powers2)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Plot annotated knee model\nplot_annotated_model(fm, annotate_peaks=False, annotate_aperiodic=True, plt_log=True)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Check the measured aperiodic parameters\nfm.aperiodic_params_" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Knee Frequency\n\nYou might notice that the knee *parameter* is not an obvious value. Notably, this parameter\nvalue as extracted from the model is something of an abstract quantify based on the\nformalization of the underlying fit function. A more intuitive measure that we may\nbe interested in is the 'knee frequency', which is an estimate of the frequency value\nat which the knee occurs.\n\nThe :func:`~.compute_knee_frequency` function can be used to compute the knee frequency.\n\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Compute the knee frequency from aperiodic parameters\nknee_frequency = compute_knee_frequency(*fm.aperiodic_params_[1:])\nprint('Knee frequency: ', knee_frequency)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Time Constant\n\nAnother interesting property of the knee parameter is that it has a direct relationship\nto the auto-correlation function, and from there to the empirical time constant of the data.\n\nThe :func:`~.compute_time_constant` function can be used to compute the knee-derived\ntime constant.\n\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Compute the characteristic time constant of a knee value\ntime_constant = compute_time_constant(fm.get_params('aperiodic', 'knee'))\nprint('Knee derived time constant: ', time_constant)" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.8.3" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} \ No newline at end of file diff --git a/_downloads/dc1a2813add9611c09fb37514f162d27/plot_power_spectra.ipynb b/_downloads/dc1a2813add9611c09fb37514f162d27/plot_power_spectra.ipynb index e02e23f7..24729d10 100644 --- a/_downloads/dc1a2813add9611c09fb37514f162d27/plot_power_spectra.ipynb +++ b/_downloads/dc1a2813add9611c09fb37514f162d27/plot_power_spectra.ipynb @@ -1,21 +1,10 @@ { "cells": [ - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "collapsed": false - }, - "outputs": [], - "source": [ - "%matplotlib inline" - ] - }, { "cell_type": "markdown", "metadata": {}, "source": [ - "\nPlot Power Spectra\n==================\n\nVisualizing power spectra.\n" + "\n# Plot Power Spectra\n\nVisualizing power spectra.\n" ] }, { @@ -26,14 +15,14 @@ }, "outputs": [], "source": [ - "# Import matplotlib, which will be used to manage some plots\nimport matplotlib.pyplot as plt\n\n# Import plotting functions\nfrom fooof.plts.spectra import plot_spectrum, plot_spectra\nfrom fooof.plts.spectra import plot_spectrum_shading, plot_spectra_shading\n\n# Import simulation utilities for creating test data\nfrom fooof.sim.gen import gen_power_spectrum, gen_group_power_spectra\nfrom fooof.sim.params import param_iter, Stepper" + "# Import matplotlib, which will be used to manage some plots\nimport matplotlib.pyplot as plt\n\n# Import plotting functions\nfrom fooof.plts.spectra import plot_spectra, plot_spectra_shading\n\n# Import simulation utilities for creating test data\nfrom fooof.sim.gen import gen_power_spectrum, gen_group_power_spectra\nfrom fooof.sim.params import param_iter, Stepper" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "Plotting Power Spectra\n----------------------\n\nThe module also includes a plotting sub-module that includes several plotting\noptions for visualizing power spectra.\n\nThese plot functions overlap with what is accessible directly through the FOOOF objects,\nas the :meth:`~fooof.FOOOF.plot` method. There are extra functions in the module, and\nextra functionality available in the plotting module.\n\nNote that the plots in the module are all built using matplotlib. They all allow for\npassing in extra matplotlib parameters for tuning the plot aesthetics, and can also be\ncustomized using matplotlib code and approaches.\n\n\n" + "## Plotting Power Spectra\n\nThe module also includes a plotting sub-module that includes several plotting\noptions for visualizing power spectra.\n\nThese plot functions overlap with what is accessible directly through the FOOOF objects,\nas the :meth:`~fooof.FOOOF.plot` method. There are extra functions in the module, and\nextra functionality available in the plotting module.\n\nNote that the plots in the module are all built using matplotlib. They all allow for\npassing in extra matplotlib parameters for tuning the plot aesthetics, and can also be\ncustomized using matplotlib code and approaches.\n\n\n" ] }, { @@ -58,7 +47,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Plotting Individual Power Spectra\n---------------------------------\n\nFirst we will start with the core plotting function that plots an individual power spectrum.\n\nThe :func:`~.plot_spectrum` function takes in an array of frequency values and a 1d array of\nof power values, and plots the corresponding power spectrum.\n\nThis function, as all the functions in the plotting module, takes in optional inputs\n`log_freqs` and `log_powers` that control whether the frequency and power axes\nare plotted in log space.\n\n\n" + "## Plotting Individual Power Spectra\n\nFirst we will start with the core plotting function that plots an individual power spectrum.\n\nThe :func:`~.plot_spectra` function takes in an array of frequency values and a 1d array of\nof power values, and plots the corresponding power spectrum.\n\nThis function, as all the functions in the plotting module, takes in optional inputs\n`log_freqs` and `log_powers` that control whether the frequency and power axes\nare plotted in log space.\n\n\n" ] }, { @@ -69,14 +58,14 @@ }, "outputs": [], "source": [ - "# Create a spectrum plot with a single power spectrum\nplot_spectrum(freqs, powers1, log_powers=True)" + "# Create a spectrum plot with a single power spectrum\nplot_spectra(freqs, powers1, log_powers=True)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "Plotting Multiple Power Spectra\n-------------------------------\n\nThe :func:`~.plot_spectra` function takes in one or more frequency arrays and one or more\narray of associated power values and plots multiple power spectra.\n\nNote that the inputs for either can be either 2d arrays, or lists of 1d arrays. You can also\npass in additional optional inputs including `labels`, to specify labels to use in a plot\nlegend, and `colors` to specify which colors to plot each spectrum in.\n\n\n" + "## Plotting Multiple Power Spectra\n\nThe :func:`~.plot_spectra` function takes in one or more frequency arrays and one or more\narray of associated power values and plots multiple power spectra.\n\nNote that the inputs for either can be either 2d arrays, or lists of 1d arrays. You can also\npass in additional optional inputs including `labels`, to specify labels to use in a plot\nlegend, and `colors` to specify which colors to plot each spectrum in.\n\n\n" ] }, { @@ -94,7 +83,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Plots With Shaded Regions\n-------------------------\n\nIn some cases it may be useful to highlight or shade in particular frequency regions,\nfor example, when examining power in particular frequency regions.\n\nThe :func:`~.plot_spectrum_shading` function takes in a power spectrum and one or more\nshaded regions, and plot the power spectrum with the indicated region shaded.\n\nThe same can be done for multiple power spectra with :func:`~.plot_spectra_shading`.\n\nThese functions take in an input designating one or more shade regions, each specified\nas [freq_low, freq_high] of the region to shade. They also take in an optional argument\nof `shade_colors` which can be used to control the color(s) of the shade regions.\n\n\n" + "## Plots With Shaded Regions\n\nIn some cases it may be useful to highlight or shade in particular frequency regions,\nfor example, when examining power in particular frequency regions.\n\nThe :func:`~.plot_spectra_shading` function takes in a power spectrum and one or more\nshaded regions, and plot the power spectrum with the indicated region shaded.\n\nThe same can be done for multiple power spectra with :func:`~.plot_spectra_shading`.\n\nThese functions take in an input designating one or more shade regions, each specified\nas [freq_low, freq_high] of the region to shade. They also take in an optional argument\nof `shade_colors` which can be used to control the color(s) of the shade regions.\n\n\n" ] }, { @@ -105,7 +94,7 @@ }, "outputs": [], "source": [ - "# Plot a single power spectrum, with a shaded region covering alpha\nplot_spectrum_shading(freqs, powers1, [8, 12], log_powers=True)" + "# Plot a single power spectrum, with a shaded region covering alpha\nplot_spectra_shading(freqs, powers1, [8, 12], log_powers=True)" ] }, { @@ -123,7 +112,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Put it all together\n-------------------\n\nFinally, we can put all these plotting tools together.\n\nTo do so, note also that all plot functions also take in an optional `ax` argument\nthat can specify an axes to plot on. This can be used to place plots in multi-axes\nfigures, and/or to add to existing plots.\n\nHere we will also take advantage of being able to pass in parameters for the underlying\nmatplotlib `plot` call to tune the aesthetics of our plot.\n\nAs a final example then, we will simulate different alpha center frequencies (in faded colors)\nas compared to a 'canonical' 10 Hz centered alpha, altogether on a plot with a shaded\nin alpha region.\n\n\n" + "## Put it all together\n\nFinally, we can put all these plotting tools together.\n\nTo do so, note also that all plot functions also take in an optional `ax` argument\nthat can specify an axes to plot on. This can be used to place plots in multi-axes\nfigures, and/or to add to existing plots.\n\nHere we will also take advantage of being able to pass in parameters for the underlying\nmatplotlib `plot` call to tune the aesthetics of our plot.\n\nAs a final example then, we will simulate different alpha center frequencies (in faded colors)\nas compared to a 'canonical' 10 Hz centered alpha, altogether on a plot with a shaded\nin alpha region.\n\n\n" ] }, { @@ -145,7 +134,7 @@ }, "outputs": [], "source": [ - "# Create the plot, plotting onto the same axes object\nfig, ax = plt.subplots(figsize=[12, 8])\nplot_spectra_shading(freqs_al, powers_al, [8, 12],\n log_powers=True, alpha=0.6, ax=ax)\nplot_spectrum(freqs_al10, powers_al10, log_powers=True,\n color='black', linewidth=3, label='10 Hz Alpha', ax=ax)\nplt.title('Comparing Alphas', {'fontsize' : 20, 'fontweight' : 'bold'});" + "# Create the plot, plotting onto the same axes object\nfig, ax = plt.subplots(figsize=[12, 8])\nplot_spectra_shading(freqs_al, powers_al, [8, 12],\n log_powers=True, alpha=0.6, ax=ax)\nplot_spectra(freqs_al10, powers_al10, log_powers=True,\n color='black', linewidth=3, label='10 Hz Alpha', ax=ax)\nplt.title('Comparing Alphas', {'fontsize' : 20, 'fontweight' : 'bold'});" ] } ], @@ -165,7 +154,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.8.5" + "version": "3.8.3" } }, "nbformat": 4, diff --git a/_downloads/e4ef6df4590ca63466dc3b85c671a8f6/plot_PeriodicAperiodicFeatures.ipynb b/_downloads/e4ef6df4590ca63466dc3b85c671a8f6/plot_PeriodicAperiodicFeatures.ipynb index 23377c4f..20510daa 100644 --- a/_downloads/e4ef6df4590ca63466dc3b85c671a8f6/plot_PeriodicAperiodicFeatures.ipynb +++ b/_downloads/e4ef6df4590ca63466dc3b85c671a8f6/plot_PeriodicAperiodicFeatures.ipynb @@ -1,28 +1,17 @@ { "cells": [ - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "collapsed": false - }, - "outputs": [], - "source": [ - "%matplotlib inline" - ] - }, { "cell_type": "markdown", "metadata": {}, "source": [ - "\nConflating Periodic & Aperiodic Changes\n=======================================\n\nDemonstrating how changes in periodic & aperiodic parameters can be conflated.\n\nThis example is a code implementation and quantitatively exact version of Figure 1 from the\n`Parameterizing Neural Power Spectra `_\npaper.\n" + "\n# Conflating Periodic & Aperiodic Changes\n\nDemonstrating how changes in periodic & aperiodic parameters can be conflated.\n\nThis example is a code implementation and quantitatively exact version of Figure 1 from the\n[Parameterizing Neural Power Spectra](https://www.biorxiv.org/content/10.1101/2020.01.11.900977v1)\npaper.\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "Measuring Neural Activity\n-------------------------\n\nIn electrophysiological data analysis, we often wish to measure and interpret changes\nin particular aspects of our data, for example, measuring changes in the power of\na frequency band of interest.\n\nIn this example, we will examine how using predefined frequency ranges to measure\nand then interpret differences from power spectra can lead to misinterpretations\nin the face of complex data in which multiple different aspects of the data can\nchange or vary within and between recordings.\n\nWe conceptualize neural data as complex data that contains multiple 'components', which\nwe categorize as periodic and aperiodic, and note that each of these components can also\nhave multiple parameters, each of which could vary.\n\nTo briefly recap, these components and parameters include:\n\n- aperiodic activity, the 1/f-like aspect of the data, described, at minimum with:\n\n - exponent\n - offset\n- periodic activity, peaks in the power spectrum, each with a:\n\n - center frequency\n - power\n - bandwidth\n\n\n" + "## Measuring Neural Activity\n\nIn electrophysiological data analysis, we often wish to measure and interpret changes\nin particular aspects of our data, for example, measuring changes in the power of\na frequency band of interest.\n\nIn this example, we will examine how using predefined frequency ranges to measure\nand then interpret differences from power spectra can lead to misinterpretations\nin the face of complex data in which multiple different aspects of the data can\nchange or vary within and between recordings.\n\nWe conceptualize neural data as complex data that contains multiple 'components', which\nwe categorize as periodic and aperiodic, and note that each of these components can also\nhave multiple parameters, each of which could vary.\n\nTo briefly recap, these components and parameters include:\n\n- aperiodic activity, the 1/f-like aspect of the data, described, at minimum with:\n\n - exponent\n - offset\n- periodic activity, peaks in the power spectrum, each with a:\n\n - center frequency\n - power\n - bandwidth\n\n\n" ] }, { @@ -51,7 +40,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Simulating Data\n~~~~~~~~~~~~~~~\n\nFor this example, we will use simulated data, and consider the example case of\ninvestigating differences in alpha activity.\n\nWe will start by simulating a baseline power spectrum, with an alpha peak, and\nconcurrent aperiodic activity. We will also simulate several altered versions of\nthis spectrum, each which a change in a specific parameter of the power spectrum.\n\n\n" + "### Simulating Data\n\nFor this example, we will use simulated data, and consider the example case of\ninvestigating differences in alpha activity.\n\nWe will start by simulating a baseline power spectrum, with an alpha peak, and\nconcurrent aperiodic activity. We will also simulate several altered versions of\nthis spectrum, each which a change in a specific parameter of the power spectrum.\n\n\n" ] }, { @@ -102,7 +91,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Plotting Power Spectra\n~~~~~~~~~~~~~~~~~~~~~~\n\nNow that we have our power spectra simulated, let's plot them all together.\n\nIn the visualization below, we can see that we have created four sets of comparisons,\nwhere each has a change in one parameter of the data.\n\nSpecifically, these changes are:\n\n- a change in alpha **power**, part of the periodic component\n- a change in alpha **center frequency**, part of the periodic component\n- a change in the **offset** of the aperiodic component\n- a change in the **exponent** of the aperiodic component\n\n\n" + "### Plotting Power Spectra\n\nNow that we have our power spectra simulated, let's plot them all together.\n\nIn the visualization below, we can see that we have created four sets of comparisons,\nwhere each has a change in one parameter of the data.\n\nSpecifically, these changes are:\n\n- a change in alpha **power**, part of the periodic component\n- a change in alpha **center frequency**, part of the periodic component\n- a change in the **offset** of the aperiodic component\n- a change in the **exponent** of the aperiodic component\n\n\n" ] }, { @@ -120,7 +109,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Comparing Power Spectra\n~~~~~~~~~~~~~~~~~~~~~~~\n\nNow let's compare our different power spectra, in terms of band-specific power measures.\n\nTo do so, we will first define a helper function that calculates the average power in\na band.\n\nThen, for each pair, consisting of the baseline power spectrum and an adapted version\nin which one parameter has been changed, we can measure the change in band specific\nactivity relating to this change.\n\n\n" + "### Comparing Power Spectra\n\nNow let's compare our different power spectra, in terms of band-specific power measures.\n\nTo do so, we will first define a helper function that calculates the average power in\na band.\n\nThen, for each pair, consisting of the baseline power spectrum and an adapted version\nin which one parameter has been changed, we can measure the change in band specific\nactivity relating to this change.\n\n\n" ] }, { @@ -167,7 +156,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Spectra Without any Oscillations\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nSo far we have considered the case in which the goal is to analyze and measure\nalpha power activity, in a scenario in which there actually is alpha activity.\n\nHowever, we can also consider the possible scenario of analyzing alpha power (or, by\nanalogy, any other band), in cases in which there is no band-specific power.\n\nTo do so, we will simulate, plot and measure a new set of data, with the same set up\nas above, but without adding any alpha peaks to the spectra.\n\n\n" + "### Spectra Without any Oscillations\n\nSo far we have considered the case in which the goal is to analyze and measure\nalpha power activity, in a scenario in which there actually is alpha activity.\n\nHowever, we can also consider the possible scenario of analyzing alpha power (or, by\nanalogy, any other band), in cases in which there is no band-specific power.\n\nTo do so, we will simulate, plot and measure a new set of data, with the same set up\nas above, but without adding any alpha peaks to the spectra.\n\n\n" ] }, { @@ -225,7 +214,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Conclusion\n~~~~~~~~~~\n\nIn the simulations above, we have shown that changes in multiple different parameters can\nlead to the same measured difference in band-specific power.\n\nIn any given case in which narrow-band ranges are used, any of these changes, or\na combination of them, could be contributing to the measured changes.\n\nAs an alternative to analyzing narrow-band power, parameterizing power spectra offers\nan approach that can measure which parameters of the data are changing, and in what\nways.\n\n\n" + "### Conclusion\n\nIn the simulations above, we have shown that changes in multiple different parameters can\nlead to the same measured difference in band-specific power.\n\nIn any given case in which narrow-band ranges are used, any of these changes, or\na combination of them, could be contributing to the measured changes.\n\nAs an alternative to analyzing narrow-band power, parameterizing power spectra offers\nan approach that can measure which parameters of the data are changing, and in what\nways.\n\n\n" ] } ], @@ -245,7 +234,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.8.5" + "version": "3.8.3" } }, "nbformat": 4, diff --git a/_downloads/ec180706d849ba370152a1a7a5a30b46/plot_WigglyPeaks.py b/_downloads/ec180706d849ba370152a1a7a5a30b46/plot_WigglyPeaks.py new file mode 100644 index 00000000..2a605c33 --- /dev/null +++ b/_downloads/ec180706d849ba370152a1a7a5a30b46/plot_WigglyPeaks.py @@ -0,0 +1,187 @@ +""" +'Oscillations' as Peaks +======================= + +Exploring the idea of oscillations as peaks of power. +""" + +################################################################################################### + +# Imports from NeuroDSP to simulate & plot time series +from neurodsp.sim import sim_powerlaw, sim_oscillation, sim_combined, set_random_seed +from neurodsp.spectral import compute_spectrum +from neurodsp.plts import plot_time_series, plot_power_spectra +from neurodsp.utils import create_times + +################################################################################################### + +# Define simulation settings +n_seconds = 30 +fs = 1000 + +# Create a times vector +times = create_times(n_seconds, fs) + +################################################################################################### +# Frequency Specific Power +# ------------------------ +# +# Part of the motivation behind spectral parameterization is dissociating aperiodic +# activity, with no characteristic frequency, to periodic power, which is defined as +# having frequency specific power. This leads to the idea of oscillations as 'peaks' +# of power in the power spectrum, which can be detected and measured. +# +# In this exploration, we will use simulated time series to examine how rhythmic signals +# do display as 'peaks' of power in frequency domain representations. We will also +# explore some limitations of this idea. +# + +################################################################################################### + +# Simulate an ongoing sine wave +sine_wave = sim_oscillation(n_seconds, fs, 10) + +# Visualize the sine wave +plot_time_series(times, sine_wave, xlim=[0, 5]) + +################################################################################################### +# +# In the above, we simulated a pure sinusoid, at 10 Hz. +# + +################################################################################################### + +# Compute the power spectrum of the sine wave +freqs, powers = compute_spectrum(sine_wave, fs) + +# Visualize the power spectrum +plot_power_spectra(freqs, powers) + +################################################################################################### +# +# The power spectrum of the sine wave shows a clear peak of power at 10 Hz, reflecting +# the simulated rhythm, with close to zero power at all other frequencies. +# +# This is characteristic of a sine wave, and demonstrates the basic idea of considering +# oscillations as peaks of power in the power spectrum. +# +# Next lets examine a more complicated signal, with multiple components. +# + +################################################################################################### + +# Define components for a combined signal +components = { + 'sim_oscillation' : {'freq' : 10}, + 'sim_powerlaw' : {'exponent' : -1}, +} + +# Simulate a combined signal +sig = sim_combined(n_seconds, fs, components) + +# Visualize the time series +plot_time_series(times, sig, xlim=[0, 5]) + +################################################################################################### +# +# Here we see a simply simulation meant to be closer to neural data, reflecting an oscillatory +# component, as well as an aperiodic component, which contributes power across all frequencies. +# + +################################################################################################### + +# Compute the power spectrum of the sine wave +freqs, powers = compute_spectrum(sig, fs) + +# Visualize the power spectrum +plot_power_spectra(freqs, powers) + +################################################################################################### +# Interim Conclusion +# ~~~~~~~~~~~~~~~~~~ +# +# In the power spectrum of the combined signal, we can still the peak of power at 10 Hz, as +# well as the pattern of power across all frequencies contributed by the aperiodic component. +# +# This basic example serves as the basic motivation for spectral parameterization. In this +# simulated example, we know there are two components, and so a procedure for detecting the +# peaks and measuring the pattern of aperiodic power (as is done in spectral parameterization) +# provides a method to measuring these components in the data. +# + +################################################################################################### +# Harmonic Peaks +# -------------- +# +# The above seeks to demonstrate the basic idea whereby a peak of power _may_ reflect +# an oscillation at that frequency, where as patterns of power across all frequencies +# likely reflect aperiodic activity. +# +# In the this section, we will further explore peaks of power in the frequency domain, +# showing that not every peak necessarily reflect an independent oscillation. +# +# To do so, we will start by simulating a non-sinusoidal oscillation. +# + +################################################################################################### + +# Simulate a sawtooth wave +sawtooth = sim_oscillation(n_seconds, fs, 10, 'sawtooth', width=0.5) + +# Visualize the sine wave +plot_time_series(times, sawtooth, xlim=[0, 5]) + +################################################################################################### +# +# In the above, we can see that there is again an oscillation, although it is not sinusoidal. +# + +################################################################################################### + +# Compute the power spectrum of the sine wave +freqs, powers = compute_spectrum(sawtooth, fs) + +# Visualize the power spectrum +plot_power_spectra(freqs, powers) + +################################################################################################### +# +# Note the 10 Hz peak, as well as the additional peaks in the frequency domain. +# +# Before further discussing this, let's create an example with an aperiodic component. +# + +################################################################################################### + +# Define components for a combined signal +components = { + 'sim_oscillation' : {'freq' : 10, 'cycle' : 'sawtooth', 'width' : 0.25}, + 'sim_powerlaw' : {'exponent' : -1.}, +} + +# Simulate a combined signal +sig = sim_combined(n_seconds, fs, components) + +# Visualize the time series +plot_time_series(times, sig, xlim=[0, 5]) + +################################################################################################### + +# Compute the power spectrum of the sine wave +freqs, powers = compute_spectrum(sig, fs) + +# Visualize the power spectrum +plot_power_spectra(freqs, powers) + +################################################################################################### +# +# In the power spectrum above, we see that there is a peak of power at the fundamental frequency +# of the rhythm (10 Hz), but there are also numerous other peaks. These additional peaks are +# 'harmonics', and that are components of the frequency domain representation that reflect +# the non-sinusoidality of the time domain signal. +# +# This serves as the basic motivation for the claim that although a peak _may_ reflect an +# independent oscillation, this need not be the case, as a given peak could simply be the harmonic +# of an asymmetric oscillation at a different frequency. For this reason, the number of peaks in +# a model can not be interpreted as the number of oscillations in a signal. +# diff --git a/_downloads/eeacea3372c9b352efaf451aa65ffd36/plot_09-Reporting.py b/_downloads/eeacea3372c9b352efaf451aa65ffd36/plot_09-Reporting.py new file mode 100644 index 00000000..8d530da9 --- /dev/null +++ b/_downloads/eeacea3372c9b352efaf451aa65ffd36/plot_09-Reporting.py @@ -0,0 +1,170 @@ +""" +09: Reporting & Referencing +=========================== + +This section covers how to access reporting info and reference use of the module. + +This page is a hands-on example of the reporting and referencing information on the +`Reference page `_. +""" + +################################################################################################### + +# Import FOOOF model objects +from fooof import FOOOF, FOOOFGroup + +# Import simulation functions to create some example data +from fooof.sim import gen_power_spectrum, gen_group_power_spectra + +# Import utilities to print out information for reporting +from fooof.utils.reports import methods_report_info, methods_report_text + +# sphinx_gallery_start_ignore +# Note: this code gets hidden, but serves to create the text plot for the icon +from fooof.core.strings import gen_methods_report_str +from fooof.core.reports import REPORT_FONT +import matplotlib.pyplot as plt +text = gen_methods_report_str(concise=True) +text = text[0:142] + '\n' + text[142:] +_, ax = plt.subplots(figsize=(8, 3)) +ax.text(0.5, 0.5, text, REPORT_FONT, ha='center', va='center') +ax.set_frame_on(False) +_ = ax.set(xticks=[], yticks=[]) +# sphinx_gallery_end_ignore + +################################################################################################### +# Checking Module Version +# ----------------------- +# +# It's useful and important to keep track of which version of the module you are using, +# and to report this information when referencing use of the tool. +# +# There are several ways to check the version of the the module that you are using, +# including checking what is installed in the Python environment you are using. +# +# From within Python, you can also check the version of the module by checking +# `__version__`, as shown below: +# + +################################################################################################### + +# Check the version of the module +from fooof import __version__ as fooof_version +print('Current fooof version:', fooof_version) + +################################################################################################### +# Getting Model Reporting Information +# ----------------------------------- +# +# To assist with reporting information, the module has the following utilities: +# +# - the :func:`~.methods_report_info`, which prints out methods reporting information +# - the :func:`~.methods_report_text`, which prints out a template of methods reporting text +# +# Both of the these functions take as input a model object, and use the object to +# collect and return information related to the model fits. +# +# Note that not all information may be returned by the model - these methods only have access +# to the current object. This means it is also important that if you use these functions, +# you use them with objects that match the settings and data used in the analysis to be reported. +# +# In the following, we will explore an example of using these functions for an example model fit. +# + +################################################################################################### + +# Initialize model object +fooof_obj = FOOOF() + +################################################################################################### + +# Print out all the methods information for reporting +methods_report_info(fooof_obj) + +################################################################################################### +# +# You might notice that the above function prints out several different sections, +# some of which might look familiar. +# +# The settings information, for example, is the same as printed using the +# # - :meth:`~fooof.FOOOF.print_settings` method. +# +# Next, let's check out the text version of the methods report. +# + +################################################################################################### + +# Generate methods text, with methods information inserted +methods_report_text(fooof_obj) + +################################################################################################### +# Additional Examples +# ~~~~~~~~~~~~~~~~~~~ +# +# In the above examples, not all the information was printed, as not all information was +# available in the example object (for example, it had no data). +# +# In the next example, let's see how the outputs look for an example object with model fit results. +# + +################################################################################################### + +# Simulate an example power spectrum +freqs, powers = gen_power_spectrum([1, 50], [0, 10, 1], [10, 0.25, 2], freq_res=0.25) + +# Initialize model object +fm = FOOOF(min_peak_height=0.1, peak_width_limits=[1, 6], aperiodic_mode='knee') +fm.fit(freqs, powers) + +################################################################################################### + +# Generate methods text, with methods information inserted +methods_report_info(fm) + +################################################################################################### + +# Generate methods text, with methods information inserted +methods_report_text(fm) + +################################################################################################### +# +# The report text is meant as a template / example that could be added to a methods section. +# +# Note that there may be missing information that needs to be filled in (indicated by 'XX's), +# and you can and should consider this a template to be edited as needed. +# + +################################################################################################### +# Other Model Objects +# ~~~~~~~~~~~~~~~~~~~ +# +# Note that the reporting functions work with any model object. +# +# For example, next we will use them on a :class:`~fooof.FOOOFGroup` object. +# + +################################################################################################### + +# Simulate an example group of power spectra +freqs, powers = gen_group_power_spectra(10, [1, 75], [0, 1], [10, 0.25, 2]) + +################################################################################################### + +# Initialize and fit group model object +fg = FOOOFGroup(max_n_peaks=4, peak_threshold=1.75) +fg.fit(freqs, powers) + +################################################################################################### + +# Generate the methods report information +methods_report_info(fg) + +################################################################################################### + +# Generate the methods report text +methods_report_text(fg) + +################################################################################################### +# +# That concludes the example of using the helper utilities for generating methods reports! +# diff --git a/_downloads/eff087d272789ceeccb8067625fef590/plot_transforms.ipynb b/_downloads/eff087d272789ceeccb8067625fef590/plot_transforms.ipynb index 354f5f13..c1b8e15d 100644 --- a/_downloads/eff087d272789ceeccb8067625fef590/plot_transforms.ipynb +++ b/_downloads/eff087d272789ceeccb8067625fef590/plot_transforms.ipynb @@ -1,21 +1,10 @@ { "cells": [ - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "collapsed": false - }, - "outputs": [], - "source": [ - "%matplotlib inline" - ] - }, { "cell_type": "markdown", "metadata": {}, "source": [ - "\nTransforming Power Spectra\n==========================\n\nApply transformations to power spectra.\n\nOne of the goals of parameterizing neural power spectra is to be able to understand\nif and how power spectra may be different and/or be changing across time or context.\n\nIn order to explore how power spectra can change, the simulation framework also\nprovides functions and utilities for transforming power spectra. These approaches\ncan be useful to specifically define changes and how spectra relate to each other,\nand track how outcome measures relate to changes in the power spectra.\n" + "\n# Transforming Power Spectra\n\nApply transformations to power spectra.\n\nOne of the goals of parameterizing neural power spectra is to be able to understand\nif and how power spectra may be different and/or be changing across time or context.\n\nIn order to explore how power spectra can change, the simulation framework also\nprovides functions and utilities for transforming power spectra. These approaches\ncan be useful to specifically define changes and how spectra relate to each other,\nand track how outcome measures relate to changes in the power spectra.\n" ] }, { @@ -44,7 +33,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Rotating Power Spectra\n----------------------\n\nThe :func:`~.rotate_spectrum` function takes in a power spectrum, and\nrotates the power spectrum a specified amount, around a specified frequency point,\nchanging the aperiodic exponent of the spectrum.\n\n\n" + "## Rotating Power Spectra\n\nThe :func:`~.rotate_spectrum` function takes in a power spectrum, and\nrotates the power spectrum a specified amount, around a specified frequency point,\nchanging the aperiodic exponent of the spectrum.\n\n\n" ] }, { @@ -91,7 +80,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Rotation Related Offset Changes\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nNote that when you rotate a power spectrum, the offset also necessarily changes.\n\nIf you wish to compute the change in offset that occurs due to a change in exponent,\nyou can use the :func:`~.compute_rotation_offset` function.\n\n\n" + "### Rotation Related Offset Changes\n\nNote that when you rotate a power spectrum, the offset also necessarily changes.\n\nIf you wish to compute the change in offset that occurs due to a change in exponent,\nyou can use the :func:`~.compute_rotation_offset` function.\n\n\n" ] }, { @@ -109,7 +98,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Translating Power Spectra\n-------------------------\n\nAnother transformation you can apply to power spectra is a translation, which changes\nthe offset, effectively moving the whole spectrum up or down.\n\nNote that changing the offset does not change the exponent.\n\n\n" + "## Translating Power Spectra\n\nAnother transformation you can apply to power spectra is a translation, which changes\nthe offset, effectively moving the whole spectrum up or down.\n\nNote that changing the offset does not change the exponent.\n\n\n" ] }, { @@ -138,7 +127,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Transforming while Tracking Simulation Parameters\n-------------------------------------------------\n\nAs we've seen, transforming power spectra changes their definitions, and sometimes\nmore than just the parameter we are manipulating directly.\n\nIf you are transforming simulated spectra, it can be useful to keep track of these changes.\n\nTo do so, there are also the functions :func:`~.rotate_sim_spectrum` and\n:func:`~.translate_sim_spectrum`, which work the same as what we've seen so far,\nwith the addition that they take in a :obj:`~.SimParams` object, and update and\nreturn a new :obj:`~.SimParams` object that tracks the updated simulation parameters.\n\n\n" + "## Transforming while Tracking Simulation Parameters\n\nAs we've seen, transforming power spectra changes their definitions, and sometimes\nmore than just the parameter we are manipulating directly.\n\nIf you are transforming simulated spectra, it can be useful to keep track of these changes.\n\nTo do so, there are also the functions :func:`~.rotate_sim_spectrum` and\n:func:`~.translate_sim_spectrum`, which work the same as what we've seen so far,\nwith the addition that they take in a :obj:`~.SimParams` object, and update and\nreturn a new :obj:`~.SimParams` object that tracks the updated simulation parameters.\n\n\n" ] }, { @@ -167,7 +156,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Relations Between Power Spectra\n-------------------------------\n\nIn some cases, what we care about when transforming power spectra, is the relation\nbetween multiple transformed power spectra.\n\nFor example, if we start with a power spectrum 'A', and compute two transformations\non it, call them 'B' and 'C' at the same or different changes in exponent and/or\nrotation frequencies, what is the relation between 'B' and 'C'?\n\nIn the following examples, we will explore the relations between transformed\npower spectra.\n\n\n" + "## Relations Between Power Spectra\n\nIn some cases, what we care about when transforming power spectra, is the relation\nbetween multiple transformed power spectra.\n\nFor example, if we start with a power spectrum 'A', and compute two transformations\non it, call them 'B' and 'C' at the same or different changes in exponent and/or\nrotation frequencies, what is the relation between 'B' and 'C'?\n\nIn the following examples, we will explore the relations between transformed\npower spectra.\n\n\n" ] }, { @@ -196,7 +185,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Rotate at the Same Rotation Frequencies\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nFirst, let's consider the case in which we rotate a spectrum by the different delta\nexponents, at the same rotation frequency.\n\nIn this case, each rotation creates the same change in offset between 'B' & 'C', and\nso B & C end up with the same offset. The difference in exponent between 'B' and 'C'\nis computable as the different of delta exponents applied to each spectrum.\n\n\n" + "### Rotate at the Same Rotation Frequencies\n\nFirst, let's consider the case in which we rotate a spectrum by the different delta\nexponents, at the same rotation frequency.\n\nIn this case, each rotation creates the same change in offset between 'B' & 'C', and\nso B & C end up with the same offset. The difference in exponent between 'B' and 'C'\nis computable as the different of delta exponents applied to each spectrum.\n\n\n" ] }, { @@ -247,7 +236,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Rotate at Different Rotation Frequencies\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nNext, let's consider the case in which we rotate a spectrum by the same delta exponent,\nbut do so at different rotation frequencies.\n\nThe resulting power spectra will have the same final exponent value, but there will\nbe a difference in offset between them, as each rotation, at different rotation points,\ncreates a different change in offset. The difference in offset between 'B' & 'C' is\ncomputed as the difference of rotation offset changes between them.\n\n\n" + "### Rotate at Different Rotation Frequencies\n\nNext, let's consider the case in which we rotate a spectrum by the same delta exponent,\nbut do so at different rotation frequencies.\n\nThe resulting power spectra will have the same final exponent value, but there will\nbe a difference in offset between them, as each rotation, at different rotation points,\ncreates a different change in offset. The difference in offset between 'B' & 'C' is\ncomputed as the difference of rotation offset changes between them.\n\n\n" ] }, { @@ -298,7 +287,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Rotate Different Amounts at Different Frequencies\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nFinally, let's consider the case in which we rotate a spectrum by different delta exponents,\nand do so at different rotation frequencies.\n\nAs before, the changes in offset cancel out, and the total change in exponent is\nthe difference of the two delta values.\n\nHowever, in this case, the frequency of rotation between 'B' and 'C' is neither of the\noriginal rotation frequencies. To calculate the rotation frequency between 'B' and 'C',\nwe can use the :func:`~.compute_rotation_frequency` function, which calculates the new\nrelationship between 'B' and 'C', using the formula for how spectra are rotated.\n\n\n" + "### Rotate Different Amounts at Different Frequencies\n\nFinally, let's consider the case in which we rotate a spectrum by different delta exponents,\nand do so at different rotation frequencies.\n\nAs before, the changes in offset cancel out, and the total change in exponent is\nthe difference of the two delta values.\n\nHowever, in this case, the frequency of rotation between 'B' and 'C' is neither of the\noriginal rotation frequencies. To calculate the rotation frequency between 'B' and 'C',\nwe can use the :func:`~.compute_rotation_frequency` function, which calculates the new\nrelationship between 'B' and 'C', using the formula for how spectra are rotated.\n\n\n" ] }, { @@ -362,7 +351,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.8.5" + "version": "3.8.3" } }, "nbformat": 4, diff --git a/_downloads/f2e346deeb11403be8ed2a2138a98ecc/plot_05-AperiodicFitting.ipynb b/_downloads/f2e346deeb11403be8ed2a2138a98ecc/plot_05-AperiodicFitting.ipynb index 6ec3929f..300e584a 100644 --- a/_downloads/f2e346deeb11403be8ed2a2138a98ecc/plot_05-AperiodicFitting.ipynb +++ b/_downloads/f2e346deeb11403be8ed2a2138a98ecc/plot_05-AperiodicFitting.ipynb @@ -1,21 +1,10 @@ { "cells": [ - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "collapsed": false - }, - "outputs": [], - "source": [ - "%matplotlib inline" - ] - }, { "cell_type": "markdown", "metadata": {}, "source": [ - "\n05: Aperiodic Component Fitting\n===============================\n\nChoosing and using different modes for fitting the aperiodic component.\n" + "\n# 05: Aperiodic Component Fitting\n\nChoosing and using different modes for fitting the aperiodic component.\n" ] }, { @@ -33,14 +22,14 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Aperiodic Fitting Approaches\n----------------------------\n\nThere are currently two approaches for fitting the aperiodic component:\n\n- Fitting with just an offset and a exponent, equivalent to a linear fit in log-log space\n\n - `aperiodic_mode` = 'fixed'\n- Including a 'knee' parameter, reflecting a fit with a bend, in log-log space\n\n - `aperiodic_mode` = 'knee'\n\nFitting in the 'fixed' mode assumes a single 1/f like characteristic to the aperiodic\ncomponent, meaning it looks linear across all frequencies in log-log space.\n\nThough this assumption is true across *some* frequency ranges in neural data, it generally\ndoes not hold up across broad frequency ranges. If fitting is done in the 'fixed' mode,\nbut the assumption of a single 1/f is violated, then fitting will go wrong.\n\nBroad frequency ranges (typically ranges greater than ~40 Hz range) typically do not\nhave a single 1/f, as assumed by 'fixed' mode, as they typically exhibit a 'bend' in\nthe aperiodic component. This indicates that there is not a single 1/f property across\nall frequencies, but rather a 'bend' in the aperiodic component. For these cases, fitting\nshould be done using an extra parameter to capture this, using the 'knee' mode.\n\n\n" + "## Aperiodic Fitting Approaches\n\nThere are currently two approaches for fitting the aperiodic component:\n\n- Fitting with just an offset and a exponent, equivalent to a linear fit in log-log space\n\n - `aperiodic_mode` = 'fixed'\n- Including a 'knee' parameter, reflecting a fit with a bend, in log-log space\n\n - `aperiodic_mode` = 'knee'\n\nFitting in the 'fixed' mode assumes a single 1/f like characteristic to the aperiodic\ncomponent, meaning it looks linear across all frequencies in log-log space.\n\nThough this assumption is true across *some* frequency ranges in neural data, it generally\ndoes not hold up across broad frequency ranges. If fitting is done in the 'fixed' mode,\nbut the assumption of a single 1/f is violated, then fitting will go wrong.\n\nBroad frequency ranges (typically ranges greater than ~40 Hz range) typically do not\nhave a single 1/f, as assumed by 'fixed' mode, as they typically exhibit a 'bend' in\nthe aperiodic component. This indicates that there is not a single 1/f property across\nall frequencies, but rather a 'bend' in the aperiodic component. For these cases, fitting\nshould be done using an extra parameter to capture this, using the 'knee' mode.\n\n\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "Fitting with an Aperiodic 'Knee'\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nLet's explore fitting power spectrum models across a broader frequency range,\nusing some local field potential data.\n\n\n" + "### Fitting with an Aperiodic 'Knee'\n\nLet's explore fitting power spectrum models across a broader frequency range,\nusing some local field potential data.\n\n\n" ] }, { @@ -80,14 +69,14 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "A note on interpreting the 'knee' parameter\n-------------------------------------------\n\nThe aperiodic fit has the form:\n\n\\begin{align}AP = 10^b * \\ \\frac{1}{(k + F^\\chi)}\\end{align}\n\nThe knee parameter reported above corresponds to `k` in the equation.\n\nThis parameter is dependent on the frequency at which the aperiodic fit\ntransitions from horizontal to negatively sloped.\n\nTo interpret this parameter as a frequency, take the $\\chi$-th root of `k`, i.e.:\n\n\\begin{align}knee \\ frequency = k^{1/\\ \\chi}\\end{align}\n\nInterpreting the fit results when using knee fits is more complex, as the exponent result is\nno longer a simple measure of the aperiodic component as a whole, but instead reflects the\naperiodic component past the 'knee' inflecting point. Because of this, when doing knee fits,\nknee & exponent values should be considered together.\n\n\n" + "## A note on interpreting the 'knee' parameter\n\nThe aperiodic fit has the form:\n\n\\begin{align}AP = 10^b * \\ \\frac{1}{(k + F^\\chi)}\\end{align}\n\nThe knee parameter reported above corresponds to `k` in the equation.\n\nThis parameter is dependent on the frequency at which the aperiodic fit\ntransitions from horizontal to negatively sloped.\n\nTo interpret this parameter as a frequency, take the $\\chi$-th root of `k`, i.e.:\n\n\\begin{align}knee \\ frequency = k^{1/\\ \\chi}\\end{align}\n\nInterpreting the fit results when using knee fits is more complex, as the exponent result is\nno longer a simple measure of the aperiodic component as a whole, but instead reflects the\naperiodic component past the 'knee' inflecting point. Because of this, when doing knee fits,\nknee & exponent values should be considered together.\n\n\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "Example: Aperiodic Fitting Gone Wrong\n-------------------------------------\n\nIn the example above, we jumped directly to fitting with a knee.\n\nHere we will explore what it looks like if we don't use the appropriate mode for fitting\nthe aperiodic component - fitting in 'fixed' mode when we should use 'knee'\n\n\n" + "## Example: Aperiodic Fitting Gone Wrong\n\nIn the example above, we jumped directly to fitting with a knee.\n\nHere we will explore what it looks like if we don't use the appropriate mode for fitting\nthe aperiodic component - fitting in 'fixed' mode when we should use 'knee'\n\n\n" ] }, { @@ -112,14 +101,14 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Choosing an Aperiodic Fitting Procedure\n---------------------------------------\n\nIt is important to choose the appropriate aperiodic fitting approach for your data.\n\nIf there is a clear knee in the power spectrum, fitting in 'fixed' mode will not\nwork well. However fitting with a knee may perform sub-optimally in ambiguous cases\n(where the data may or may not have a knee), or if no knee is present.\n\nGiven this, we recommend:\n\n- Check your data, across the frequency range of interest,\n for what the aperiodic component looks like.\n\n - If it looks roughly linear (in log-log space), fit without a knee.\n\n - This is likely across smaller frequency ranges, such as 3-30.\n - Do not perform no-knee fits across a range in which this does not hold.\n - If there is a clear knee, then use knee fits.\n\n - This is likely across larger fitting ranges such as 1-150 Hz.\n- Be wary of ambiguous ranges, where there may or may not be a knee.\n\n - Trying to fit without a knee, when there is not a single consistent aperiodic component,\n can lead to very bad fits. However, trying to fit with a knee may lead to suboptimal fits\n when no knee is present, and makes interpreting the exponent more difficult.\n\n - We therefore currently recommend picking frequency ranges in which the expected\n aperiodic component process is relatively clear.\n\n\n" + "## Choosing an Aperiodic Fitting Procedure\n\nIt is important to choose the appropriate aperiodic fitting approach for your data.\n\nIf there is a clear knee in the power spectrum, fitting in 'fixed' mode will not\nwork well. However fitting with a knee may perform sub-optimally in ambiguous cases\n(where the data may or may not have a knee), or if no knee is present.\n\nGiven this, we recommend:\n\n- Check your data, across the frequency range of interest,\n for what the aperiodic component looks like.\n\n - If it looks roughly linear (in log-log space), fit without a knee.\n\n - This is likely across smaller frequency ranges, such as 3-30.\n - Do not perform no-knee fits across a range in which this does not hold.\n - If there is a clear knee, then use knee fits.\n\n - This is likely across larger fitting ranges such as 1-150 Hz.\n- Be wary of ambiguous ranges, where there may or may not be a knee.\n\n - Trying to fit without a knee, when there is not a single consistent aperiodic component,\n can lead to very bad fits. However, trying to fit with a knee may lead to suboptimal fits\n when no knee is present, and makes interpreting the exponent more difficult.\n\n - We therefore currently recommend picking frequency ranges in which the expected\n aperiodic component process is relatively clear.\n\n\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "Conclusion\n----------\n\nWe have now explored the :class:`~fooof.FOOOF` object, and different fitting\napproaches for the aperiodic component. Next up, we will be introducing how\nto scale the fitting to apply across multiple power spectra.\n\n\n" + "## Conclusion\n\nWe have now explored the :class:`~fooof.FOOOF` object, and different fitting\napproaches for the aperiodic component. Next up, we will be introducing how\nto scale the fitting to apply across multiple power spectra.\n\n\n" ] } ], @@ -139,7 +128,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.8.5" + "version": "3.8.3" } }, "nbformat": 4, diff --git a/_downloads/fecff9e7a6734e3ad683b96c3c92b484/plot_WigglyPeaks.ipynb b/_downloads/fecff9e7a6734e3ad683b96c3c92b484/plot_WigglyPeaks.ipynb new file mode 100644 index 00000000..5317607a --- /dev/null +++ b/_downloads/fecff9e7a6734e3ad683b96c3c92b484/plot_WigglyPeaks.ipynb @@ -0,0 +1,205 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n# 'Oscillations' as Peaks\n\nExploring the idea of oscillations as peaks of power.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Imports from NeuroDSP to simulate & plot time series\nfrom neurodsp.sim import sim_powerlaw, sim_oscillation, sim_combined, set_random_seed\nfrom neurodsp.spectral import compute_spectrum\nfrom neurodsp.plts import plot_time_series, plot_power_spectra\nfrom neurodsp.utils import create_times" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Define simulation settings\nn_seconds = 30\nfs = 1000\n\n# Create a times vector\ntimes = create_times(n_seconds, fs)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Frequency Specific Power\n\nPart of the motivation behind spectral parameterization is dissociating aperiodic\nactivity, with no characteristic frequency, to periodic power, which is defined as\nhaving frequency specific power. This leads to the idea of oscillations as 'peaks'\nof power in the power spectrum, which can be detected and measured.\n\nIn this exploration, we will use simulated time series to examine how rhythmic signals\ndo display as 'peaks' of power in frequency domain representations. We will also\nexplore some limitations of this idea.\n\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Simulate an ongoing sine wave\nsine_wave = sim_oscillation(n_seconds, fs, 10)\n\n# Visualize the sine wave\nplot_time_series(times, sine_wave, xlim=[0, 5])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "In the above, we simulated a pure sinusoid, at 10 Hz.\n\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Compute the power spectrum of the sine wave\nfreqs, powers = compute_spectrum(sine_wave, fs)\n\n# Visualize the power spectrum\nplot_power_spectra(freqs, powers)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The power spectrum of the sine wave shows a clear peak of power at 10 Hz, reflecting\nthe simulated rhythm, with close to zero power at all other frequencies.\n\nThis is characteristic of a sine wave, and demonstrates the basic idea of considering\noscillations as peaks of power in the power spectrum.\n\nNext lets examine a more complicated signal, with multiple components.\n\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Define components for a combined signal\ncomponents = {\n 'sim_oscillation' : {'freq' : 10},\n 'sim_powerlaw' : {'exponent' : -1},\n}\n\n# Simulate a combined signal\nsig = sim_combined(n_seconds, fs, components)\n\n# Visualize the time series\nplot_time_series(times, sig, xlim=[0, 5])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Here we see a simply simulation meant to be closer to neural data, reflecting an oscillatory\ncomponent, as well as an aperiodic component, which contributes power across all frequencies.\n\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Compute the power spectrum of the sine wave\nfreqs, powers = compute_spectrum(sig, fs)\n\n# Visualize the power spectrum\nplot_power_spectra(freqs, powers)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Interim Conclusion\n\nIn the power spectrum of the combined signal, we can still the peak of power at 10 Hz, as\nwell as the pattern of power across all frequencies contributed by the aperiodic component.\n\nThis basic example serves as the basic motivation for spectral parameterization. In this\nsimulated example, we know there are two components, and so a procedure for detecting the\npeaks and measuring the pattern of aperiodic power (as is done in spectral parameterization)\nprovides a method to measuring these components in the data.\n\n\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Harmonic Peaks\n\nThe above seeks to demonstrate the basic idea whereby a peak of power _may_ reflect\nan oscillation at that frequency, where as patterns of power across all frequencies\nlikely reflect aperiodic activity.\n\nIn the this section, we will further explore peaks of power in the frequency domain,\nshowing that not every peak necessarily reflect an independent oscillation.\n\nTo do so, we will start by simulating a non-sinusoidal oscillation.\n\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Simulate a sawtooth wave\nsawtooth = sim_oscillation(n_seconds, fs, 10, 'sawtooth', width=0.5)\n\n# Visualize the sine wave\nplot_time_series(times, sawtooth, xlim=[0, 5])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "In the above, we can see that there is again an oscillation, although it is not sinusoidal.\n\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Compute the power spectrum of the sine wave\nfreqs, powers = compute_spectrum(sawtooth, fs)\n\n# Visualize the power spectrum\nplot_power_spectra(freqs, powers)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Note the 10 Hz peak, as well as the additional peaks in the frequency domain.\n\nBefore further discussing this, let's create an example with an aperiodic component.\n\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Define components for a combined signal\ncomponents = {\n 'sim_oscillation' : {'freq' : 10, 'cycle' : 'sawtooth', 'width' : 0.25},\n 'sim_powerlaw' : {'exponent' : -1.},\n}\n\n# Simulate a combined signal\nsig = sim_combined(n_seconds, fs, components)\n\n# Visualize the time series\nplot_time_series(times, sig, xlim=[0, 5])" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Compute the power spectrum of the sine wave\nfreqs, powers = compute_spectrum(sig, fs)\n\n# Visualize the power spectrum\nplot_power_spectra(freqs, powers)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "In the power spectrum above, we see that there is a peak of power at the fundamental frequency\nof the rhythm (10 Hz), but there are also numerous other peaks. These additional peaks are\n'harmonics', and that are components of the frequency domain representation that reflect\nthe non-sinusoidality of the time domain signal.\n\nThis serves as the basic motivation for the claim that although a peak _may_ reflect an\nindependent oscillation, this need not be the case, as a given peak could simply be the harmonic\nof an asymmetric oscillation at a different frequency. For this reason, the number of peaks in\na model can not be interpreted as the number of oscillations in a signal.\n\n\n" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.8.3" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} \ No newline at end of file diff --git a/_downloads/ffd69fba210c78a742499c454560f80f/plot_manipulating_fooofs.ipynb b/_downloads/ffd69fba210c78a742499c454560f80f/plot_manipulating_fooofs.ipynb index da728f2a..1002c3e9 100644 --- a/_downloads/ffd69fba210c78a742499c454560f80f/plot_manipulating_fooofs.ipynb +++ b/_downloads/ffd69fba210c78a742499c454560f80f/plot_manipulating_fooofs.ipynb @@ -1,21 +1,10 @@ { "cells": [ - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "collapsed": false - }, - "outputs": [], - "source": [ - "%matplotlib inline" - ] - }, { "cell_type": "markdown", "metadata": {}, "source": [ - "\nManipulating FOOOF Objects\n==========================\n\nExamples with combining, sub-selecting, dropping, and averaging power spectrum models.\n" + "\n# Manipulating FOOOF Objects\n\nExamples with combining, sub-selecting, dropping, and averaging power spectrum models.\n" ] }, { @@ -69,7 +58,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Combining FOOOF Objects\n-----------------------\n\nSometimes, when working with models in :class:`~fooof.FOOOF` or :class:`~fooof.FOOOFGroup`\nobjects, you may want to combine them together, to check some group properties.\n\nThe :func:`~.combine_fooofs` function takes a list of FOOOF and/or\nFOOOFGroup objects, and combines all available fits together into a FOOOFGroup object.\n\nLet's now combine our individual model fits into a FOOOFGroup object.\n\n\n" + "## Combining FOOOF Objects\n\nSometimes, when working with models in :class:`~fooof.FOOOF` or :class:`~fooof.FOOOFGroup`\nobjects, you may want to combine them together, to check some group properties.\n\nThe :func:`~.combine_fooofs` function takes a list of FOOOF and/or\nFOOOFGroup objects, and combines all available fits together into a FOOOFGroup object.\n\nLet's now combine our individual model fits into a FOOOFGroup object.\n\n\n" ] }, { @@ -87,7 +76,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Note on Manipulating FOOOF Objects\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nNote that these functions that manipulate FOOOF objects typically do more than just\ncopy results data - they also check and manage settings and meta-data of objects.\n\nFor example, combining FOOOF objects returns a new FOOOFGroup object with the same settings.\n\nWe can see this by using the :func:`~.compare_info` function to compare\nthe settings between FOOOF objects.\n\nYou can also use this function if you wish to compare FOOOF objects to ensure that\nyou are comparing model results that were fit with equivalent settings.\n\n\n" + "### Note on Manipulating FOOOF Objects\n\nNote that these functions that manipulate FOOOF objects typically do more than just\ncopy results data - they also check and manage settings and meta-data of objects.\n\nFor example, combining FOOOF objects returns a new FOOOFGroup object with the same settings.\n\nWe can see this by using the :func:`~.compare_info` function to compare\nthe settings between FOOOF objects.\n\nYou can also use this function if you wish to compare FOOOF objects to ensure that\nyou are comparing model results that were fit with equivalent settings.\n\n\n" ] }, { @@ -105,7 +94,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Sub-Select from FOOOFGroup\n--------------------------\n\nWhen you have a :class:`~fooof.FOOOFGroup` object, you may also want to sub-select\na group of models.\n\nExample use cases for this could be:\n\n- you want to sub-select models that meet some kind of goodness-of-fit criterion\n- you want to examine a subset of model reflect, for example, particular channels or trials\n\nTo do so, we can use the :func:`~fooof.FOOOFGroup.get_group` method of the FOOOFGroup object.\nThis method takes in an input specifying which indices to sub-select, and returns a\nnew FOOOFGroup object, containing only the requested model fits.\n\nNote that if you want to sub-select a single FOOOF model you can\nuse the :meth:`~fooof.FOOOFGroup.get_fooof` method.\n\n\n" + "## Sub-Select from FOOOFGroup\n\nWhen you have a :class:`~fooof.FOOOFGroup` object, you may also want to sub-select\na group of models.\n\nExample use cases for this could be:\n\n- you want to sub-select models that meet some kind of goodness-of-fit criterion\n- you want to examine a subset of model reflect, for example, particular channels or trials\n\nTo do so, we can use the :func:`~fooof.FOOOFGroup.get_group` method of the FOOOFGroup object.\nThis method takes in an input specifying which indices to sub-select, and returns a\nnew FOOOFGroup object, containing only the requested model fits.\n\nNote that if you want to sub-select a single FOOOF model you can\nuse the :meth:`~fooof.FOOOFGroup.get_fooof` method.\n\n\n" ] }, { @@ -130,7 +119,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Dropping Fits from FOOOFGroup\n-----------------------------\n\nAnother option is to 'drop' model fits from a FOOOFGroup object. You can do this with\nthe :meth:`~fooof.FOOOFGroup.drop` method from a :class:`~fooof.FOOOFGroup` object.\n\nThis can be used, for example, for a quality control step. If you have checked through\nthe object, and noticed some outlier model fits, you may want to exclude them from\nfuture analyses.\n\nIn this case, we'll use an example in which we drop any model fits that\nhave particularly high error.\n\n\n" + "## Dropping Fits from FOOOFGroup\n\nAnother option is to 'drop' model fits from a FOOOFGroup object. You can do this with\nthe :meth:`~fooof.FOOOFGroup.drop` method from a :class:`~fooof.FOOOFGroup` object.\n\nThis can be used, for example, for a quality control step. If you have checked through\nthe object, and noticed some outlier model fits, you may want to exclude them from\nfuture analyses.\n\nIn this case, we'll use an example in which we drop any model fits that\nhave particularly high error.\n\n\n" ] }, { @@ -148,7 +137,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Note on Dropped or Failed Fits\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nWhen models are dropped from :class:`~fooof.FOOOFGroup` objects, they are set as null models.\nThey are therefore cleared of results, but not literally dropped, which\nis done to preserve the ordering of the FOOOFGroup, so that the `n-th` model\ndoesn't change if some models are dropped.\n\nNote that there may in some cases be Null models in a FOOOFGroup without\nexplicitly dropping them, if any models failed during the fitting process.\n\n\n" + "### Note on Dropped or Failed Fits\n\nWhen models are dropped from :class:`~fooof.FOOOFGroup` objects, they are set as null models.\nThey are therefore cleared of results, but not literally dropped, which\nis done to preserve the ordering of the FOOOFGroup, so that the `n-th` model\ndoesn't change if some models are dropped.\n\nNote that there may in some cases be Null models in a FOOOFGroup without\nexplicitly dropping them, if any models failed during the fitting process.\n\n\n" ] }, { @@ -177,14 +166,14 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Note on Selecting From FOOOF Objects\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nBoth the :meth:`~fooof.FOOOFGroup.get_group` and :meth:`~fooof.FOOOFGroup.drop` methods\ntake an input of the indices of FOOOF model to select or drop.\n\nIn both cases, the input can be defined in multiple ways, including directly indicating\nthe indices as a list of integers, or boolean masks.\n\n\n" + "### Note on Selecting From FOOOF Objects\n\nBoth the :meth:`~fooof.FOOOFGroup.get_group` and :meth:`~fooof.FOOOFGroup.drop` methods\ntake an input of the indices of FOOOF model to select or drop.\n\nIn both cases, the input can be defined in multiple ways, including directly indicating\nthe indices as a list of integers, or boolean masks.\n\n\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "Averaging Across Model Fits\n---------------------------\n\nFinally, let's average across the models in our FOOOFGroup object, to examine\nthe average model of the data.\n\nNote that in order to be able to average across individual models, we need to define\na set of frequency bands to average peaks across. Otherwise, there is no clear way\nto average across all the peaks across all models.\n\n\n" + "## Averaging Across Model Fits\n\nFinally, let's average across the models in our FOOOFGroup object, to examine\nthe average model of the data.\n\nNote that in order to be able to average across individual models, we need to define\na set of frequency bands to average peaks across. Otherwise, there is no clear way\nto average across all the peaks across all models.\n\n\n" ] }, { @@ -215,7 +204,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.8.5" + "version": "3.8.3" } }, "nbformat": 4, diff --git a/_images/sphx_glr_plot_01-ModelDescription_001.png b/_images/sphx_glr_plot_01-ModelDescription_001.png index f735045b..86033151 100644 Binary files a/_images/sphx_glr_plot_01-ModelDescription_001.png and b/_images/sphx_glr_plot_01-ModelDescription_001.png differ diff --git a/_images/sphx_glr_plot_01-ModelDescription_002.png b/_images/sphx_glr_plot_01-ModelDescription_002.png index ba67ae15..3add5b77 100644 Binary files a/_images/sphx_glr_plot_01-ModelDescription_002.png and b/_images/sphx_glr_plot_01-ModelDescription_002.png differ diff --git a/_images/sphx_glr_plot_01-ModelDescription_003.png b/_images/sphx_glr_plot_01-ModelDescription_003.png index 6d4917dc..702a4333 100644 Binary files a/_images/sphx_glr_plot_01-ModelDescription_003.png and b/_images/sphx_glr_plot_01-ModelDescription_003.png differ diff --git a/_images/sphx_glr_plot_01-ModelDescription_004.png b/_images/sphx_glr_plot_01-ModelDescription_004.png index e3276451..d5deef12 100644 Binary files a/_images/sphx_glr_plot_01-ModelDescription_004.png and b/_images/sphx_glr_plot_01-ModelDescription_004.png differ diff --git a/_images/sphx_glr_plot_01-ModelDescription_005.png b/_images/sphx_glr_plot_01-ModelDescription_005.png index d273e4a2..360c292c 100644 Binary files a/_images/sphx_glr_plot_01-ModelDescription_005.png and b/_images/sphx_glr_plot_01-ModelDescription_005.png differ diff --git a/_images/sphx_glr_plot_01-ModelDescription_006.png b/_images/sphx_glr_plot_01-ModelDescription_006.png index f301e7fa..cec9790d 100644 Binary files a/_images/sphx_glr_plot_01-ModelDescription_006.png and b/_images/sphx_glr_plot_01-ModelDescription_006.png differ diff --git a/_images/sphx_glr_plot_01-ModelDescription_thumb.png b/_images/sphx_glr_plot_01-ModelDescription_thumb.png index a76102e9..c65e2213 100644 Binary files a/_images/sphx_glr_plot_01-ModelDescription_thumb.png and b/_images/sphx_glr_plot_01-ModelDescription_thumb.png differ diff --git a/_images/sphx_glr_plot_02-FOOOF_001.png b/_images/sphx_glr_plot_02-FOOOF_001.png index 6687f8fe..d12112b8 100644 Binary files a/_images/sphx_glr_plot_02-FOOOF_001.png and b/_images/sphx_glr_plot_02-FOOOF_001.png differ diff --git a/_images/sphx_glr_plot_02-FOOOF_thumb.png b/_images/sphx_glr_plot_02-FOOOF_thumb.png index 5c74e5c2..cdbce50c 100644 Binary files a/_images/sphx_glr_plot_02-FOOOF_thumb.png and b/_images/sphx_glr_plot_02-FOOOF_thumb.png differ diff --git a/_images/sphx_glr_plot_03-FOOOFAlgorithm_001.png b/_images/sphx_glr_plot_03-FOOOFAlgorithm_001.png index 8bade06b..f32e12e9 100644 Binary files a/_images/sphx_glr_plot_03-FOOOFAlgorithm_001.png and b/_images/sphx_glr_plot_03-FOOOFAlgorithm_001.png differ diff --git a/_images/sphx_glr_plot_03-FOOOFAlgorithm_002.png b/_images/sphx_glr_plot_03-FOOOFAlgorithm_002.png index 086e3420..8a1836c7 100644 Binary files a/_images/sphx_glr_plot_03-FOOOFAlgorithm_002.png and b/_images/sphx_glr_plot_03-FOOOFAlgorithm_002.png differ diff --git a/_images/sphx_glr_plot_03-FOOOFAlgorithm_003.png b/_images/sphx_glr_plot_03-FOOOFAlgorithm_003.png index 5f2acabb..b8027cb3 100644 Binary files a/_images/sphx_glr_plot_03-FOOOFAlgorithm_003.png and b/_images/sphx_glr_plot_03-FOOOFAlgorithm_003.png differ diff --git a/_images/sphx_glr_plot_03-FOOOFAlgorithm_004.png b/_images/sphx_glr_plot_03-FOOOFAlgorithm_004.png index 3b6d8094..99779468 100644 Binary files a/_images/sphx_glr_plot_03-FOOOFAlgorithm_004.png and b/_images/sphx_glr_plot_03-FOOOFAlgorithm_004.png differ diff --git a/_images/sphx_glr_plot_03-FOOOFAlgorithm_005.png b/_images/sphx_glr_plot_03-FOOOFAlgorithm_005.png index d24b24e2..fda26b7b 100644 Binary files a/_images/sphx_glr_plot_03-FOOOFAlgorithm_005.png and b/_images/sphx_glr_plot_03-FOOOFAlgorithm_005.png differ diff --git a/_images/sphx_glr_plot_03-FOOOFAlgorithm_006.png b/_images/sphx_glr_plot_03-FOOOFAlgorithm_006.png index bfcbd074..3ea292d7 100644 Binary files a/_images/sphx_glr_plot_03-FOOOFAlgorithm_006.png and b/_images/sphx_glr_plot_03-FOOOFAlgorithm_006.png differ diff --git a/_images/sphx_glr_plot_03-FOOOFAlgorithm_007.png b/_images/sphx_glr_plot_03-FOOOFAlgorithm_007.png index 217e7e3a..e11fb859 100644 Binary files a/_images/sphx_glr_plot_03-FOOOFAlgorithm_007.png and b/_images/sphx_glr_plot_03-FOOOFAlgorithm_007.png differ diff --git a/_images/sphx_glr_plot_03-FOOOFAlgorithm_008.png b/_images/sphx_glr_plot_03-FOOOFAlgorithm_008.png index 190013c6..1c4eeea4 100644 Binary files a/_images/sphx_glr_plot_03-FOOOFAlgorithm_008.png and b/_images/sphx_glr_plot_03-FOOOFAlgorithm_008.png differ diff --git a/_images/sphx_glr_plot_03-FOOOFAlgorithm_009.png b/_images/sphx_glr_plot_03-FOOOFAlgorithm_009.png index 3cb06b49..256d0f41 100644 Binary files a/_images/sphx_glr_plot_03-FOOOFAlgorithm_009.png and b/_images/sphx_glr_plot_03-FOOOFAlgorithm_009.png differ diff --git a/_images/sphx_glr_plot_03-FOOOFAlgorithm_010.png b/_images/sphx_glr_plot_03-FOOOFAlgorithm_010.png index 2ad04c13..b4e9a6d3 100644 Binary files a/_images/sphx_glr_plot_03-FOOOFAlgorithm_010.png and b/_images/sphx_glr_plot_03-FOOOFAlgorithm_010.png differ diff --git a/_images/sphx_glr_plot_03-FOOOFAlgorithm_011.png b/_images/sphx_glr_plot_03-FOOOFAlgorithm_011.png index d7563fbe..df67c4f3 100644 Binary files a/_images/sphx_glr_plot_03-FOOOFAlgorithm_011.png and b/_images/sphx_glr_plot_03-FOOOFAlgorithm_011.png differ diff --git a/_images/sphx_glr_plot_03-FOOOFAlgorithm_thumb.png b/_images/sphx_glr_plot_03-FOOOFAlgorithm_thumb.png index 6d585c2f..66e1a7c9 100644 Binary files a/_images/sphx_glr_plot_03-FOOOFAlgorithm_thumb.png and b/_images/sphx_glr_plot_03-FOOOFAlgorithm_thumb.png differ diff --git a/_images/sphx_glr_plot_04-MoreFOOOF_001.png b/_images/sphx_glr_plot_04-MoreFOOOF_001.png index 61e60fcb..b0a73cf8 100644 Binary files a/_images/sphx_glr_plot_04-MoreFOOOF_001.png and b/_images/sphx_glr_plot_04-MoreFOOOF_001.png differ diff --git a/_images/sphx_glr_plot_04-MoreFOOOF_thumb.png b/_images/sphx_glr_plot_04-MoreFOOOF_thumb.png index 24ed0555..562a74b6 100644 Binary files a/_images/sphx_glr_plot_04-MoreFOOOF_thumb.png and b/_images/sphx_glr_plot_04-MoreFOOOF_thumb.png differ diff --git a/_images/sphx_glr_plot_05-AperiodicFitting_001.png b/_images/sphx_glr_plot_05-AperiodicFitting_001.png index 98e77575..80dcb7c8 100644 Binary files a/_images/sphx_glr_plot_05-AperiodicFitting_001.png and b/_images/sphx_glr_plot_05-AperiodicFitting_001.png differ diff --git a/_images/sphx_glr_plot_05-AperiodicFitting_002.png b/_images/sphx_glr_plot_05-AperiodicFitting_002.png index db4e9337..f323554a 100644 Binary files a/_images/sphx_glr_plot_05-AperiodicFitting_002.png and b/_images/sphx_glr_plot_05-AperiodicFitting_002.png differ diff --git a/_images/sphx_glr_plot_05-AperiodicFitting_thumb.png b/_images/sphx_glr_plot_05-AperiodicFitting_thumb.png index fc0ac3d9..8524520c 100644 Binary files a/_images/sphx_glr_plot_05-AperiodicFitting_thumb.png and b/_images/sphx_glr_plot_05-AperiodicFitting_thumb.png differ diff --git a/_images/sphx_glr_plot_06-FOOOFGroup_001.png b/_images/sphx_glr_plot_06-FOOOFGroup_001.png index d384acd2..874bceb5 100644 Binary files a/_images/sphx_glr_plot_06-FOOOFGroup_001.png and b/_images/sphx_glr_plot_06-FOOOFGroup_001.png differ diff --git a/_images/sphx_glr_plot_06-FOOOFGroup_002.png b/_images/sphx_glr_plot_06-FOOOFGroup_002.png index 0244cb98..67c7b5e5 100644 Binary files a/_images/sphx_glr_plot_06-FOOOFGroup_002.png and b/_images/sphx_glr_plot_06-FOOOFGroup_002.png differ diff --git a/_images/sphx_glr_plot_06-FOOOFGroup_thumb.png b/_images/sphx_glr_plot_06-FOOOFGroup_thumb.png index 20e9de66..e5b7aa02 100644 Binary files a/_images/sphx_glr_plot_06-FOOOFGroup_thumb.png and b/_images/sphx_glr_plot_06-FOOOFGroup_thumb.png differ diff --git a/_images/sphx_glr_plot_07-TroubleShooting_001.png b/_images/sphx_glr_plot_07-TroubleShooting_001.png index e8db11bf..763fce0b 100644 Binary files a/_images/sphx_glr_plot_07-TroubleShooting_001.png and b/_images/sphx_glr_plot_07-TroubleShooting_001.png differ diff --git a/_images/sphx_glr_plot_07-TroubleShooting_002.png b/_images/sphx_glr_plot_07-TroubleShooting_002.png index 492f009a..147e11cf 100644 Binary files a/_images/sphx_glr_plot_07-TroubleShooting_002.png and b/_images/sphx_glr_plot_07-TroubleShooting_002.png differ diff --git a/_images/sphx_glr_plot_07-TroubleShooting_003.png b/_images/sphx_glr_plot_07-TroubleShooting_003.png index c13255ee..acc18598 100644 Binary files a/_images/sphx_glr_plot_07-TroubleShooting_003.png and b/_images/sphx_glr_plot_07-TroubleShooting_003.png differ diff --git a/_images/sphx_glr_plot_07-TroubleShooting_004.png b/_images/sphx_glr_plot_07-TroubleShooting_004.png index 3b9eb522..2132a632 100644 Binary files a/_images/sphx_glr_plot_07-TroubleShooting_004.png and b/_images/sphx_glr_plot_07-TroubleShooting_004.png differ diff --git a/_images/sphx_glr_plot_07-TroubleShooting_005.png b/_images/sphx_glr_plot_07-TroubleShooting_005.png index cb152150..31abcdd1 100644 Binary files a/_images/sphx_glr_plot_07-TroubleShooting_005.png and b/_images/sphx_glr_plot_07-TroubleShooting_005.png differ diff --git a/_images/sphx_glr_plot_07-TroubleShooting_006.png b/_images/sphx_glr_plot_07-TroubleShooting_006.png index cb152150..31abcdd1 100644 Binary files a/_images/sphx_glr_plot_07-TroubleShooting_006.png and b/_images/sphx_glr_plot_07-TroubleShooting_006.png differ diff --git a/_images/sphx_glr_plot_07-TroubleShooting_007.png b/_images/sphx_glr_plot_07-TroubleShooting_007.png index 38382ddd..f98c061a 100644 Binary files a/_images/sphx_glr_plot_07-TroubleShooting_007.png and b/_images/sphx_glr_plot_07-TroubleShooting_007.png differ diff --git a/_images/sphx_glr_plot_07-TroubleShooting_thumb.png b/_images/sphx_glr_plot_07-TroubleShooting_thumb.png index 9770a1e0..f632aec6 100644 Binary files a/_images/sphx_glr_plot_07-TroubleShooting_thumb.png and b/_images/sphx_glr_plot_07-TroubleShooting_thumb.png differ diff --git a/_images/sphx_glr_plot_08-FurtherAnalysis_001.png b/_images/sphx_glr_plot_08-FurtherAnalysis_001.png index 30c31ce0..683a0ca1 100644 Binary files a/_images/sphx_glr_plot_08-FurtherAnalysis_001.png and b/_images/sphx_glr_plot_08-FurtherAnalysis_001.png differ diff --git a/_images/sphx_glr_plot_08-FurtherAnalysis_thumb.png b/_images/sphx_glr_plot_08-FurtherAnalysis_thumb.png index 1f0ca803..ab969660 100644 Binary files a/_images/sphx_glr_plot_08-FurtherAnalysis_thumb.png and b/_images/sphx_glr_plot_08-FurtherAnalysis_thumb.png differ diff --git a/_images/sphx_glr_plot_09-Reporting_001.png b/_images/sphx_glr_plot_09-Reporting_001.png new file mode 100644 index 00000000..a3f866fd Binary files /dev/null and b/_images/sphx_glr_plot_09-Reporting_001.png differ diff --git a/_images/sphx_glr_plot_09-Reporting_thumb.png b/_images/sphx_glr_plot_09-Reporting_thumb.png new file mode 100644 index 00000000..a99336d5 Binary files /dev/null and b/_images/sphx_glr_plot_09-Reporting_thumb.png differ diff --git a/_images/sphx_glr_plot_BandByBand_001.png b/_images/sphx_glr_plot_BandByBand_001.png index f1554dfa..2763029d 100644 Binary files a/_images/sphx_glr_plot_BandByBand_001.png and b/_images/sphx_glr_plot_BandByBand_001.png differ diff --git a/_images/sphx_glr_plot_BandByBand_002.png b/_images/sphx_glr_plot_BandByBand_002.png index d2a58302..705321eb 100644 Binary files a/_images/sphx_glr_plot_BandByBand_002.png and b/_images/sphx_glr_plot_BandByBand_002.png differ diff --git a/_images/sphx_glr_plot_BandByBand_003.png b/_images/sphx_glr_plot_BandByBand_003.png index 8c9baad7..329c0bcf 100644 Binary files a/_images/sphx_glr_plot_BandByBand_003.png and b/_images/sphx_glr_plot_BandByBand_003.png differ diff --git a/_images/sphx_glr_plot_BandByBand_004.png b/_images/sphx_glr_plot_BandByBand_004.png index dcece703..60522123 100644 Binary files a/_images/sphx_glr_plot_BandByBand_004.png and b/_images/sphx_glr_plot_BandByBand_004.png differ diff --git a/_images/sphx_glr_plot_BandByBand_thumb.png b/_images/sphx_glr_plot_BandByBand_thumb.png index 3bd412ba..861b4bd9 100644 Binary files a/_images/sphx_glr_plot_BandByBand_thumb.png and b/_images/sphx_glr_plot_BandByBand_thumb.png differ diff --git a/_images/sphx_glr_plot_BandRatios_001.png b/_images/sphx_glr_plot_BandRatios_001.png index 22e08979..2b4aeb46 100644 Binary files a/_images/sphx_glr_plot_BandRatios_001.png and b/_images/sphx_glr_plot_BandRatios_001.png differ diff --git a/_images/sphx_glr_plot_BandRatios_002.png b/_images/sphx_glr_plot_BandRatios_002.png index 845d5199..186efe2f 100644 Binary files a/_images/sphx_glr_plot_BandRatios_002.png and b/_images/sphx_glr_plot_BandRatios_002.png differ diff --git a/_images/sphx_glr_plot_BandRatios_003.png b/_images/sphx_glr_plot_BandRatios_003.png index 7c8fdf27..9c68c715 100644 Binary files a/_images/sphx_glr_plot_BandRatios_003.png and b/_images/sphx_glr_plot_BandRatios_003.png differ diff --git a/_images/sphx_glr_plot_BandRatios_thumb.png b/_images/sphx_glr_plot_BandRatios_thumb.png index adb47419..918b9d4a 100644 Binary files a/_images/sphx_glr_plot_BandRatios_thumb.png and b/_images/sphx_glr_plot_BandRatios_thumb.png differ diff --git a/_images/sphx_glr_plot_DoYouEvenOscillate_001.png b/_images/sphx_glr_plot_DoYouEvenOscillate_001.png index bc39af61..37f4c161 100644 Binary files a/_images/sphx_glr_plot_DoYouEvenOscillate_001.png and b/_images/sphx_glr_plot_DoYouEvenOscillate_001.png differ diff --git a/_images/sphx_glr_plot_DoYouEvenOscillate_002.png b/_images/sphx_glr_plot_DoYouEvenOscillate_002.png index 40823729..05b4d3db 100644 Binary files a/_images/sphx_glr_plot_DoYouEvenOscillate_002.png and b/_images/sphx_glr_plot_DoYouEvenOscillate_002.png differ diff --git a/_images/sphx_glr_plot_DoYouEvenOscillate_003.png b/_images/sphx_glr_plot_DoYouEvenOscillate_003.png index 372f710d..52178527 100644 Binary files a/_images/sphx_glr_plot_DoYouEvenOscillate_003.png and b/_images/sphx_glr_plot_DoYouEvenOscillate_003.png differ diff --git a/_images/sphx_glr_plot_DoYouEvenOscillate_004.png b/_images/sphx_glr_plot_DoYouEvenOscillate_004.png index 65153e18..0bdc6c19 100644 Binary files a/_images/sphx_glr_plot_DoYouEvenOscillate_004.png and b/_images/sphx_glr_plot_DoYouEvenOscillate_004.png differ diff --git a/_images/sphx_glr_plot_DoYouEvenOscillate_005.png b/_images/sphx_glr_plot_DoYouEvenOscillate_005.png index 4de3512c..eb532ff4 100644 Binary files a/_images/sphx_glr_plot_DoYouEvenOscillate_005.png and b/_images/sphx_glr_plot_DoYouEvenOscillate_005.png differ diff --git a/_images/sphx_glr_plot_DoYouEvenOscillate_006.png b/_images/sphx_glr_plot_DoYouEvenOscillate_006.png index a7c620f0..38f789f5 100644 Binary files a/_images/sphx_glr_plot_DoYouEvenOscillate_006.png and b/_images/sphx_glr_plot_DoYouEvenOscillate_006.png differ diff --git a/_images/sphx_glr_plot_DoYouEvenOscillate_007.png b/_images/sphx_glr_plot_DoYouEvenOscillate_007.png index 06697709..139ec0a3 100644 Binary files a/_images/sphx_glr_plot_DoYouEvenOscillate_007.png and b/_images/sphx_glr_plot_DoYouEvenOscillate_007.png differ diff --git a/_images/sphx_glr_plot_DoYouEvenOscillate_008.png b/_images/sphx_glr_plot_DoYouEvenOscillate_008.png index be501096..724e376a 100644 Binary files a/_images/sphx_glr_plot_DoYouEvenOscillate_008.png and b/_images/sphx_glr_plot_DoYouEvenOscillate_008.png differ diff --git a/_images/sphx_glr_plot_DoYouEvenOscillate_009.png b/_images/sphx_glr_plot_DoYouEvenOscillate_009.png index 521c9d62..a1015203 100644 Binary files a/_images/sphx_glr_plot_DoYouEvenOscillate_009.png and b/_images/sphx_glr_plot_DoYouEvenOscillate_009.png differ diff --git a/_images/sphx_glr_plot_DoYouEvenOscillate_010.png b/_images/sphx_glr_plot_DoYouEvenOscillate_010.png index 2efbe959..36340f80 100644 Binary files a/_images/sphx_glr_plot_DoYouEvenOscillate_010.png and b/_images/sphx_glr_plot_DoYouEvenOscillate_010.png differ diff --git a/_images/sphx_glr_plot_DoYouEvenOscillate_thumb.png b/_images/sphx_glr_plot_DoYouEvenOscillate_thumb.png index 4a450fd8..ba4c1520 100644 Binary files a/_images/sphx_glr_plot_DoYouEvenOscillate_thumb.png and b/_images/sphx_glr_plot_DoYouEvenOscillate_thumb.png differ diff --git a/_images/sphx_glr_plot_IfYouFilterTheyWillCome_001.png b/_images/sphx_glr_plot_IfYouFilterTheyWillCome_001.png index 8f77c69e..d20b8b11 100644 Binary files a/_images/sphx_glr_plot_IfYouFilterTheyWillCome_001.png and b/_images/sphx_glr_plot_IfYouFilterTheyWillCome_001.png differ diff --git a/_images/sphx_glr_plot_IfYouFilterTheyWillCome_002.png b/_images/sphx_glr_plot_IfYouFilterTheyWillCome_002.png index 41a7ad8f..169c3ecf 100644 Binary files a/_images/sphx_glr_plot_IfYouFilterTheyWillCome_002.png and b/_images/sphx_glr_plot_IfYouFilterTheyWillCome_002.png differ diff --git a/_images/sphx_glr_plot_IfYouFilterTheyWillCome_003.png b/_images/sphx_glr_plot_IfYouFilterTheyWillCome_003.png index 371c0422..22c90676 100644 Binary files a/_images/sphx_glr_plot_IfYouFilterTheyWillCome_003.png and b/_images/sphx_glr_plot_IfYouFilterTheyWillCome_003.png differ diff --git a/_images/sphx_glr_plot_IfYouFilterTheyWillCome_004.png b/_images/sphx_glr_plot_IfYouFilterTheyWillCome_004.png index 22b3054f..aa1da4e6 100644 Binary files a/_images/sphx_glr_plot_IfYouFilterTheyWillCome_004.png and b/_images/sphx_glr_plot_IfYouFilterTheyWillCome_004.png differ diff --git a/_images/sphx_glr_plot_IfYouFilterTheyWillCome_005.png b/_images/sphx_glr_plot_IfYouFilterTheyWillCome_005.png index 81a32ff8..b8c21076 100644 Binary files a/_images/sphx_glr_plot_IfYouFilterTheyWillCome_005.png and b/_images/sphx_glr_plot_IfYouFilterTheyWillCome_005.png differ diff --git a/_images/sphx_glr_plot_IfYouFilterTheyWillCome_thumb.png b/_images/sphx_glr_plot_IfYouFilterTheyWillCome_thumb.png index f2ee9abf..2007e583 100644 Binary files a/_images/sphx_glr_plot_IfYouFilterTheyWillCome_thumb.png and b/_images/sphx_glr_plot_IfYouFilterTheyWillCome_thumb.png differ diff --git a/_images/sphx_glr_plot_PeriodicAperiodicFeatures_001.png b/_images/sphx_glr_plot_PeriodicAperiodicFeatures_001.png index 639856fc..141da8d4 100644 Binary files a/_images/sphx_glr_plot_PeriodicAperiodicFeatures_001.png and b/_images/sphx_glr_plot_PeriodicAperiodicFeatures_001.png differ diff --git a/_images/sphx_glr_plot_PeriodicAperiodicFeatures_002.png b/_images/sphx_glr_plot_PeriodicAperiodicFeatures_002.png index d940f431..1b2bd27b 100644 Binary files a/_images/sphx_glr_plot_PeriodicAperiodicFeatures_002.png and b/_images/sphx_glr_plot_PeriodicAperiodicFeatures_002.png differ diff --git a/_images/sphx_glr_plot_PeriodicAperiodicFeatures_thumb.png b/_images/sphx_glr_plot_PeriodicAperiodicFeatures_thumb.png index 9971fcc4..c066a745 100644 Binary files a/_images/sphx_glr_plot_PeriodicAperiodicFeatures_thumb.png and b/_images/sphx_glr_plot_PeriodicAperiodicFeatures_thumb.png differ diff --git a/_images/sphx_glr_plot_WigglyPeaks_001.png b/_images/sphx_glr_plot_WigglyPeaks_001.png new file mode 100644 index 00000000..e2614d84 Binary files /dev/null and b/_images/sphx_glr_plot_WigglyPeaks_001.png differ diff --git a/_images/sphx_glr_plot_WigglyPeaks_002.png b/_images/sphx_glr_plot_WigglyPeaks_002.png new file mode 100644 index 00000000..394fbee7 Binary files /dev/null and b/_images/sphx_glr_plot_WigglyPeaks_002.png differ diff --git a/_images/sphx_glr_plot_WigglyPeaks_003.png b/_images/sphx_glr_plot_WigglyPeaks_003.png new file mode 100644 index 00000000..1c899d16 Binary files /dev/null and b/_images/sphx_glr_plot_WigglyPeaks_003.png differ diff --git a/_images/sphx_glr_plot_WigglyPeaks_004.png b/_images/sphx_glr_plot_WigglyPeaks_004.png new file mode 100644 index 00000000..790f15fb Binary files /dev/null and b/_images/sphx_glr_plot_WigglyPeaks_004.png differ diff --git a/_images/sphx_glr_plot_WigglyPeaks_005.png b/_images/sphx_glr_plot_WigglyPeaks_005.png new file mode 100644 index 00000000..24024f90 Binary files /dev/null and b/_images/sphx_glr_plot_WigglyPeaks_005.png differ diff --git a/_images/sphx_glr_plot_WigglyPeaks_006.png b/_images/sphx_glr_plot_WigglyPeaks_006.png new file mode 100644 index 00000000..7f7168a9 Binary files /dev/null and b/_images/sphx_glr_plot_WigglyPeaks_006.png differ diff --git a/_images/sphx_glr_plot_WigglyPeaks_007.png b/_images/sphx_glr_plot_WigglyPeaks_007.png new file mode 100644 index 00000000..c6bec668 Binary files /dev/null and b/_images/sphx_glr_plot_WigglyPeaks_007.png differ diff --git a/_images/sphx_glr_plot_WigglyPeaks_008.png b/_images/sphx_glr_plot_WigglyPeaks_008.png new file mode 100644 index 00000000..95641030 Binary files /dev/null and b/_images/sphx_glr_plot_WigglyPeaks_008.png differ diff --git a/_images/sphx_glr_plot_WigglyPeaks_thumb.png b/_images/sphx_glr_plot_WigglyPeaks_thumb.png new file mode 100644 index 00000000..dd7a170b Binary files /dev/null and b/_images/sphx_glr_plot_WigglyPeaks_thumb.png differ diff --git a/_images/sphx_glr_plot_aperiodic_params_001.png b/_images/sphx_glr_plot_aperiodic_params_001.png new file mode 100644 index 00000000..ac544730 Binary files /dev/null and b/_images/sphx_glr_plot_aperiodic_params_001.png differ diff --git a/_images/sphx_glr_plot_aperiodic_params_002.png b/_images/sphx_glr_plot_aperiodic_params_002.png new file mode 100644 index 00000000..116a642c Binary files /dev/null and b/_images/sphx_glr_plot_aperiodic_params_002.png differ diff --git a/_images/sphx_glr_plot_aperiodic_params_003.png b/_images/sphx_glr_plot_aperiodic_params_003.png new file mode 100644 index 00000000..e3d75882 Binary files /dev/null and b/_images/sphx_glr_plot_aperiodic_params_003.png differ diff --git a/_images/sphx_glr_plot_aperiodic_params_004.png b/_images/sphx_glr_plot_aperiodic_params_004.png new file mode 100644 index 00000000..dbdcef25 Binary files /dev/null and b/_images/sphx_glr_plot_aperiodic_params_004.png differ diff --git a/_images/sphx_glr_plot_aperiodic_params_thumb.png b/_images/sphx_glr_plot_aperiodic_params_thumb.png new file mode 100644 index 00000000..03e52def Binary files /dev/null and b/_images/sphx_glr_plot_aperiodic_params_thumb.png differ diff --git a/_images/sphx_glr_plot_data_components_001.png b/_images/sphx_glr_plot_data_components_001.png new file mode 100644 index 00000000..dbe0283f Binary files /dev/null and b/_images/sphx_glr_plot_data_components_001.png differ diff --git a/_images/sphx_glr_plot_data_components_002.png b/_images/sphx_glr_plot_data_components_002.png new file mode 100644 index 00000000..a7c48c67 Binary files /dev/null and b/_images/sphx_glr_plot_data_components_002.png differ diff --git a/_images/sphx_glr_plot_data_components_003.png b/_images/sphx_glr_plot_data_components_003.png new file mode 100644 index 00000000..d5f533ea Binary files /dev/null and b/_images/sphx_glr_plot_data_components_003.png differ diff --git a/_images/sphx_glr_plot_data_components_004.png b/_images/sphx_glr_plot_data_components_004.png new file mode 100644 index 00000000..4f4a79a0 Binary files /dev/null and b/_images/sphx_glr_plot_data_components_004.png differ diff --git a/_images/sphx_glr_plot_data_components_005.png b/_images/sphx_glr_plot_data_components_005.png new file mode 100644 index 00000000..80c8fbc3 Binary files /dev/null and b/_images/sphx_glr_plot_data_components_005.png differ diff --git a/_images/sphx_glr_plot_data_components_006.png b/_images/sphx_glr_plot_data_components_006.png new file mode 100644 index 00000000..3b7ef3d4 Binary files /dev/null and b/_images/sphx_glr_plot_data_components_006.png differ diff --git a/_images/sphx_glr_plot_data_components_007.png b/_images/sphx_glr_plot_data_components_007.png new file mode 100644 index 00000000..a7c48c67 Binary files /dev/null and b/_images/sphx_glr_plot_data_components_007.png differ diff --git a/_images/sphx_glr_plot_data_components_008.png b/_images/sphx_glr_plot_data_components_008.png new file mode 100644 index 00000000..231eb772 Binary files /dev/null and b/_images/sphx_glr_plot_data_components_008.png differ diff --git a/_images/sphx_glr_plot_data_components_009.png b/_images/sphx_glr_plot_data_components_009.png new file mode 100644 index 00000000..5c6c371c Binary files /dev/null and b/_images/sphx_glr_plot_data_components_009.png differ diff --git a/_images/sphx_glr_plot_data_components_010.png b/_images/sphx_glr_plot_data_components_010.png new file mode 100644 index 00000000..eb1d1a7b Binary files /dev/null and b/_images/sphx_glr_plot_data_components_010.png differ diff --git a/_images/sphx_glr_plot_data_components_011.png b/_images/sphx_glr_plot_data_components_011.png new file mode 100644 index 00000000..0abf033f Binary files /dev/null and b/_images/sphx_glr_plot_data_components_011.png differ diff --git a/_images/sphx_glr_plot_data_components_thumb.png b/_images/sphx_glr_plot_data_components_thumb.png new file mode 100644 index 00000000..fdde6500 Binary files /dev/null and b/_images/sphx_glr_plot_data_components_thumb.png differ diff --git a/_images/sphx_glr_plot_data_exporting_thumb.png b/_images/sphx_glr_plot_data_exporting_thumb.png new file mode 100644 index 00000000..0c9e7257 Binary files /dev/null and b/_images/sphx_glr_plot_data_exporting_thumb.png differ diff --git a/_images/sphx_glr_plot_dev_demo_001.png b/_images/sphx_glr_plot_dev_demo_001.png new file mode 100644 index 00000000..ca7cfdc0 Binary files /dev/null and b/_images/sphx_glr_plot_dev_demo_001.png differ diff --git a/_images/sphx_glr_plot_dev_demo_002.png b/_images/sphx_glr_plot_dev_demo_002.png new file mode 100644 index 00000000..fb4da0ed Binary files /dev/null and b/_images/sphx_glr_plot_dev_demo_002.png differ diff --git a/_images/sphx_glr_plot_dev_demo_003.png b/_images/sphx_glr_plot_dev_demo_003.png new file mode 100644 index 00000000..39f47741 Binary files /dev/null and b/_images/sphx_glr_plot_dev_demo_003.png differ diff --git a/_images/sphx_glr_plot_dev_demo_004.png b/_images/sphx_glr_plot_dev_demo_004.png new file mode 100644 index 00000000..b4523eaa Binary files /dev/null and b/_images/sphx_glr_plot_dev_demo_004.png differ diff --git a/_images/sphx_glr_plot_dev_demo_005.png b/_images/sphx_glr_plot_dev_demo_005.png new file mode 100644 index 00000000..503f73b1 Binary files /dev/null and b/_images/sphx_glr_plot_dev_demo_005.png differ diff --git a/_images/sphx_glr_plot_dev_demo_006.png b/_images/sphx_glr_plot_dev_demo_006.png new file mode 100644 index 00000000..bf4dd502 Binary files /dev/null and b/_images/sphx_glr_plot_dev_demo_006.png differ diff --git a/_images/sphx_glr_plot_dev_demo_007.png b/_images/sphx_glr_plot_dev_demo_007.png new file mode 100644 index 00000000..91867cf5 Binary files /dev/null and b/_images/sphx_glr_plot_dev_demo_007.png differ diff --git a/_images/sphx_glr_plot_dev_demo_008.png b/_images/sphx_glr_plot_dev_demo_008.png new file mode 100644 index 00000000..89ab6f63 Binary files /dev/null and b/_images/sphx_glr_plot_dev_demo_008.png differ diff --git a/_images/sphx_glr_plot_dev_demo_009.png b/_images/sphx_glr_plot_dev_demo_009.png new file mode 100644 index 00000000..3906b2a6 Binary files /dev/null and b/_images/sphx_glr_plot_dev_demo_009.png differ diff --git a/_images/sphx_glr_plot_dev_demo_010.png b/_images/sphx_glr_plot_dev_demo_010.png new file mode 100644 index 00000000..3906b2a6 Binary files /dev/null and b/_images/sphx_glr_plot_dev_demo_010.png differ diff --git a/_images/sphx_glr_plot_dev_demo_011.png b/_images/sphx_glr_plot_dev_demo_011.png new file mode 100644 index 00000000..b0c0a11a Binary files /dev/null and b/_images/sphx_glr_plot_dev_demo_011.png differ diff --git a/_images/sphx_glr_plot_dev_demo_012.png b/_images/sphx_glr_plot_dev_demo_012.png new file mode 100644 index 00000000..458dea10 Binary files /dev/null and b/_images/sphx_glr_plot_dev_demo_012.png differ diff --git a/_images/sphx_glr_plot_dev_demo_013.png b/_images/sphx_glr_plot_dev_demo_013.png new file mode 100644 index 00000000..22a440fc Binary files /dev/null and b/_images/sphx_glr_plot_dev_demo_013.png differ diff --git a/_images/sphx_glr_plot_dev_demo_014.png b/_images/sphx_glr_plot_dev_demo_014.png new file mode 100644 index 00000000..ab57cafa Binary files /dev/null and b/_images/sphx_glr_plot_dev_demo_014.png differ diff --git a/_images/sphx_glr_plot_dev_demo_thumb.png b/_images/sphx_glr_plot_dev_demo_thumb.png new file mode 100644 index 00000000..c99952c8 Binary files /dev/null and b/_images/sphx_glr_plot_dev_demo_thumb.png differ diff --git a/_images/sphx_glr_plot_failed_fits_thumb.png b/_images/sphx_glr_plot_failed_fits_thumb.png index 3fab0f23..0c9e7257 100644 Binary files a/_images/sphx_glr_plot_failed_fits_thumb.png and b/_images/sphx_glr_plot_failed_fits_thumb.png differ diff --git a/_images/sphx_glr_plot_fit_fooof_3d_001.png b/_images/sphx_glr_plot_fit_fooof_3d_001.png index f5eff820..8e064ffa 100644 Binary files a/_images/sphx_glr_plot_fit_fooof_3d_001.png and b/_images/sphx_glr_plot_fit_fooof_3d_001.png differ diff --git a/_images/sphx_glr_plot_fit_fooof_3d_thumb.png b/_images/sphx_glr_plot_fit_fooof_3d_thumb.png index 424c69f4..833394d8 100644 Binary files a/_images/sphx_glr_plot_fit_fooof_3d_thumb.png and b/_images/sphx_glr_plot_fit_fooof_3d_thumb.png differ diff --git a/_images/sphx_glr_plot_fooof_models_001.png b/_images/sphx_glr_plot_fooof_models_001.png index e0ca8271..95b2d281 100644 Binary files a/_images/sphx_glr_plot_fooof_models_001.png and b/_images/sphx_glr_plot_fooof_models_001.png differ diff --git a/_images/sphx_glr_plot_fooof_models_002.png b/_images/sphx_glr_plot_fooof_models_002.png index 30aaf604..90742636 100644 Binary files a/_images/sphx_glr_plot_fooof_models_002.png and b/_images/sphx_glr_plot_fooof_models_002.png differ diff --git a/_images/sphx_glr_plot_fooof_models_003.png b/_images/sphx_glr_plot_fooof_models_003.png index 4ca49c2c..0f803404 100644 Binary files a/_images/sphx_glr_plot_fooof_models_003.png and b/_images/sphx_glr_plot_fooof_models_003.png differ diff --git a/_images/sphx_glr_plot_fooof_models_004.png b/_images/sphx_glr_plot_fooof_models_004.png index d2ef0e6c..f5193e31 100644 Binary files a/_images/sphx_glr_plot_fooof_models_004.png and b/_images/sphx_glr_plot_fooof_models_004.png differ diff --git a/_images/sphx_glr_plot_fooof_models_005.png b/_images/sphx_glr_plot_fooof_models_005.png index 3f3eab83..c95a10d4 100644 Binary files a/_images/sphx_glr_plot_fooof_models_005.png and b/_images/sphx_glr_plot_fooof_models_005.png differ diff --git a/_images/sphx_glr_plot_fooof_models_006.png b/_images/sphx_glr_plot_fooof_models_006.png index 4e418cd1..f3e39c48 100644 Binary files a/_images/sphx_glr_plot_fooof_models_006.png and b/_images/sphx_glr_plot_fooof_models_006.png differ diff --git a/_images/sphx_glr_plot_fooof_models_007.png b/_images/sphx_glr_plot_fooof_models_007.png index 61f0c6dc..6d8ffec3 100644 Binary files a/_images/sphx_glr_plot_fooof_models_007.png and b/_images/sphx_glr_plot_fooof_models_007.png differ diff --git a/_images/sphx_glr_plot_fooof_models_thumb.png b/_images/sphx_glr_plot_fooof_models_thumb.png index b2be4d83..7c6c8ea7 100644 Binary files a/_images/sphx_glr_plot_fooof_models_thumb.png and b/_images/sphx_glr_plot_fooof_models_thumb.png differ diff --git a/_images/sphx_glr_plot_freq_by_freq_error_001.png b/_images/sphx_glr_plot_freq_by_freq_error_001.png index 0132a673..81a65459 100644 Binary files a/_images/sphx_glr_plot_freq_by_freq_error_001.png and b/_images/sphx_glr_plot_freq_by_freq_error_001.png differ diff --git a/_images/sphx_glr_plot_freq_by_freq_error_002.png b/_images/sphx_glr_plot_freq_by_freq_error_002.png index 2ff53827..20039783 100644 Binary files a/_images/sphx_glr_plot_freq_by_freq_error_002.png and b/_images/sphx_glr_plot_freq_by_freq_error_002.png differ diff --git a/_images/sphx_glr_plot_freq_by_freq_error_003.png b/_images/sphx_glr_plot_freq_by_freq_error_003.png index a8e348d1..87ff3525 100644 Binary files a/_images/sphx_glr_plot_freq_by_freq_error_003.png and b/_images/sphx_glr_plot_freq_by_freq_error_003.png differ diff --git a/_images/sphx_glr_plot_freq_by_freq_error_thumb.png b/_images/sphx_glr_plot_freq_by_freq_error_thumb.png index 99939e57..415b3736 100644 Binary files a/_images/sphx_glr_plot_freq_by_freq_error_thumb.png and b/_images/sphx_glr_plot_freq_by_freq_error_thumb.png differ diff --git a/_images/sphx_glr_plot_line_noise_001.png b/_images/sphx_glr_plot_line_noise_001.png new file mode 100644 index 00000000..e3893aa1 Binary files /dev/null and b/_images/sphx_glr_plot_line_noise_001.png differ diff --git a/_images/sphx_glr_plot_line_noise_002.png b/_images/sphx_glr_plot_line_noise_002.png new file mode 100644 index 00000000..81142006 Binary files /dev/null and b/_images/sphx_glr_plot_line_noise_002.png differ diff --git a/_images/sphx_glr_plot_line_noise_003.png b/_images/sphx_glr_plot_line_noise_003.png new file mode 100644 index 00000000..a94661e9 Binary files /dev/null and b/_images/sphx_glr_plot_line_noise_003.png differ diff --git a/_images/sphx_glr_plot_line_noise_004.png b/_images/sphx_glr_plot_line_noise_004.png new file mode 100644 index 00000000..e3145b0b Binary files /dev/null and b/_images/sphx_glr_plot_line_noise_004.png differ diff --git a/_images/sphx_glr_plot_line_noise_005.png b/_images/sphx_glr_plot_line_noise_005.png new file mode 100644 index 00000000..817a8183 Binary files /dev/null and b/_images/sphx_glr_plot_line_noise_005.png differ diff --git a/_images/sphx_glr_plot_line_noise_006.png b/_images/sphx_glr_plot_line_noise_006.png new file mode 100644 index 00000000..593b846e Binary files /dev/null and b/_images/sphx_glr_plot_line_noise_006.png differ diff --git a/_images/sphx_glr_plot_line_noise_007.png b/_images/sphx_glr_plot_line_noise_007.png new file mode 100644 index 00000000..1d79383c Binary files /dev/null and b/_images/sphx_glr_plot_line_noise_007.png differ diff --git a/_images/sphx_glr_plot_line_noise_008.png b/_images/sphx_glr_plot_line_noise_008.png new file mode 100644 index 00000000..a4a209c8 Binary files /dev/null and b/_images/sphx_glr_plot_line_noise_008.png differ diff --git a/_images/sphx_glr_plot_line_noise_009.png b/_images/sphx_glr_plot_line_noise_009.png new file mode 100644 index 00000000..aedec838 Binary files /dev/null and b/_images/sphx_glr_plot_line_noise_009.png differ diff --git a/_images/sphx_glr_plot_line_noise_thumb.png b/_images/sphx_glr_plot_line_noise_thumb.png new file mode 100644 index 00000000..7ee0856d Binary files /dev/null and b/_images/sphx_glr_plot_line_noise_thumb.png differ diff --git a/_images/sphx_glr_plot_manipulating_fooofs_001.png b/_images/sphx_glr_plot_manipulating_fooofs_001.png index 782eabe8..8fb60437 100644 Binary files a/_images/sphx_glr_plot_manipulating_fooofs_001.png and b/_images/sphx_glr_plot_manipulating_fooofs_001.png differ diff --git a/_images/sphx_glr_plot_manipulating_fooofs_thumb.png b/_images/sphx_glr_plot_manipulating_fooofs_thumb.png index cd20d63c..49576b1c 100644 Binary files a/_images/sphx_glr_plot_manipulating_fooofs_thumb.png and b/_images/sphx_glr_plot_manipulating_fooofs_thumb.png differ diff --git a/_images/sphx_glr_plot_mne_example_001.png b/_images/sphx_glr_plot_mne_example_001.png index e57f565e..1f8d9e45 100644 Binary files a/_images/sphx_glr_plot_mne_example_001.png and b/_images/sphx_glr_plot_mne_example_001.png differ diff --git a/_images/sphx_glr_plot_mne_example_002.png b/_images/sphx_glr_plot_mne_example_002.png index 6d7aaa41..27ead53c 100644 Binary files a/_images/sphx_glr_plot_mne_example_002.png and b/_images/sphx_glr_plot_mne_example_002.png differ diff --git a/_images/sphx_glr_plot_mne_example_003.png b/_images/sphx_glr_plot_mne_example_003.png index 4872316d..97818677 100644 Binary files a/_images/sphx_glr_plot_mne_example_003.png and b/_images/sphx_glr_plot_mne_example_003.png differ diff --git a/_images/sphx_glr_plot_mne_example_004.png b/_images/sphx_glr_plot_mne_example_004.png index c1ffacc6..3de19604 100644 Binary files a/_images/sphx_glr_plot_mne_example_004.png and b/_images/sphx_glr_plot_mne_example_004.png differ diff --git a/_images/sphx_glr_plot_mne_example_005.png b/_images/sphx_glr_plot_mne_example_005.png index 6d90b357..f3344900 100644 Binary files a/_images/sphx_glr_plot_mne_example_005.png and b/_images/sphx_glr_plot_mne_example_005.png differ diff --git a/_images/sphx_glr_plot_mne_example_006.png b/_images/sphx_glr_plot_mne_example_006.png index 7639b9c0..5cf6c1e0 100644 Binary files a/_images/sphx_glr_plot_mne_example_006.png and b/_images/sphx_glr_plot_mne_example_006.png differ diff --git a/_images/sphx_glr_plot_mne_example_thumb.png b/_images/sphx_glr_plot_mne_example_thumb.png index 746ff960..92ad8779 100644 Binary files a/_images/sphx_glr_plot_mne_example_thumb.png and b/_images/sphx_glr_plot_mne_example_thumb.png differ diff --git a/_images/sphx_glr_plot_model_components_001.png b/_images/sphx_glr_plot_model_components_001.png index 70740f17..1916773f 100644 Binary files a/_images/sphx_glr_plot_model_components_001.png and b/_images/sphx_glr_plot_model_components_001.png differ diff --git a/_images/sphx_glr_plot_model_components_002.png b/_images/sphx_glr_plot_model_components_002.png index e56067d3..e89851b3 100644 Binary files a/_images/sphx_glr_plot_model_components_002.png and b/_images/sphx_glr_plot_model_components_002.png differ diff --git a/_images/sphx_glr_plot_model_components_003.png b/_images/sphx_glr_plot_model_components_003.png index 4c4849f7..ca0bc07c 100644 Binary files a/_images/sphx_glr_plot_model_components_003.png and b/_images/sphx_glr_plot_model_components_003.png differ diff --git a/_images/sphx_glr_plot_model_components_004.png b/_images/sphx_glr_plot_model_components_004.png index e6445d0b..964477a3 100644 Binary files a/_images/sphx_glr_plot_model_components_004.png and b/_images/sphx_glr_plot_model_components_004.png differ diff --git a/_images/sphx_glr_plot_model_components_005.png b/_images/sphx_glr_plot_model_components_005.png index 5cf2ed46..630aff42 100644 Binary files a/_images/sphx_glr_plot_model_components_005.png and b/_images/sphx_glr_plot_model_components_005.png differ diff --git a/_images/sphx_glr_plot_model_components_006.png b/_images/sphx_glr_plot_model_components_006.png index 430cdb2a..3f5e6529 100644 Binary files a/_images/sphx_glr_plot_model_components_006.png and b/_images/sphx_glr_plot_model_components_006.png differ diff --git a/_images/sphx_glr_plot_model_components_007.png b/_images/sphx_glr_plot_model_components_007.png index a4ff63ea..3e28ee19 100644 Binary files a/_images/sphx_glr_plot_model_components_007.png and b/_images/sphx_glr_plot_model_components_007.png differ diff --git a/_images/sphx_glr_plot_model_components_008.png b/_images/sphx_glr_plot_model_components_008.png index 9b551d48..5ec69234 100644 Binary files a/_images/sphx_glr_plot_model_components_008.png and b/_images/sphx_glr_plot_model_components_008.png differ diff --git a/_images/sphx_glr_plot_model_components_thumb.png b/_images/sphx_glr_plot_model_components_thumb.png index ee619af6..48017741 100644 Binary files a/_images/sphx_glr_plot_model_components_thumb.png and b/_images/sphx_glr_plot_model_components_thumb.png differ diff --git a/_images/sphx_glr_plot_peak_params_001.png b/_images/sphx_glr_plot_peak_params_001.png new file mode 100644 index 00000000..b61ed226 Binary files /dev/null and b/_images/sphx_glr_plot_peak_params_001.png differ diff --git a/_images/sphx_glr_plot_peak_params_002.png b/_images/sphx_glr_plot_peak_params_002.png new file mode 100644 index 00000000..b8ae9784 Binary files /dev/null and b/_images/sphx_glr_plot_peak_params_002.png differ diff --git a/_images/sphx_glr_plot_peak_params_thumb.png b/_images/sphx_glr_plot_peak_params_thumb.png new file mode 100644 index 00000000..6a275665 Binary files /dev/null and b/_images/sphx_glr_plot_peak_params_thumb.png differ diff --git a/_images/sphx_glr_plot_power_spectra_001.png b/_images/sphx_glr_plot_power_spectra_001.png index 273aad61..f3512198 100644 Binary files a/_images/sphx_glr_plot_power_spectra_001.png and b/_images/sphx_glr_plot_power_spectra_001.png differ diff --git a/_images/sphx_glr_plot_power_spectra_002.png b/_images/sphx_glr_plot_power_spectra_002.png index 3f6b47ef..806aa90f 100644 Binary files a/_images/sphx_glr_plot_power_spectra_002.png and b/_images/sphx_glr_plot_power_spectra_002.png differ diff --git a/_images/sphx_glr_plot_power_spectra_003.png b/_images/sphx_glr_plot_power_spectra_003.png index 4afc47e1..64478f8b 100644 Binary files a/_images/sphx_glr_plot_power_spectra_003.png and b/_images/sphx_glr_plot_power_spectra_003.png differ diff --git a/_images/sphx_glr_plot_power_spectra_004.png b/_images/sphx_glr_plot_power_spectra_004.png index 4eaf5408..25ae8672 100644 Binary files a/_images/sphx_glr_plot_power_spectra_004.png and b/_images/sphx_glr_plot_power_spectra_004.png differ diff --git a/_images/sphx_glr_plot_power_spectra_005.png b/_images/sphx_glr_plot_power_spectra_005.png index ff2ad2f2..0bcf865e 100644 Binary files a/_images/sphx_glr_plot_power_spectra_005.png and b/_images/sphx_glr_plot_power_spectra_005.png differ diff --git a/_images/sphx_glr_plot_power_spectra_thumb.png b/_images/sphx_glr_plot_power_spectra_thumb.png index a8a6ea96..116c426a 100644 Binary files a/_images/sphx_glr_plot_power_spectra_thumb.png and b/_images/sphx_glr_plot_power_spectra_thumb.png differ diff --git a/_images/sphx_glr_plot_sim_params_001.png b/_images/sphx_glr_plot_sim_params_001.png index fb4b897b..47d45827 100644 Binary files a/_images/sphx_glr_plot_sim_params_001.png and b/_images/sphx_glr_plot_sim_params_001.png differ diff --git a/_images/sphx_glr_plot_sim_params_002.png b/_images/sphx_glr_plot_sim_params_002.png index 9e76a87a..40199e6d 100644 Binary files a/_images/sphx_glr_plot_sim_params_002.png and b/_images/sphx_glr_plot_sim_params_002.png differ diff --git a/_images/sphx_glr_plot_sim_params_003.png b/_images/sphx_glr_plot_sim_params_003.png index 52f67d17..56c1fe2e 100644 Binary files a/_images/sphx_glr_plot_sim_params_003.png and b/_images/sphx_glr_plot_sim_params_003.png differ diff --git a/_images/sphx_glr_plot_sim_params_thumb.png b/_images/sphx_glr_plot_sim_params_thumb.png index a82cf8e3..610e4a9e 100644 Binary files a/_images/sphx_glr_plot_sim_params_thumb.png and b/_images/sphx_glr_plot_sim_params_thumb.png differ diff --git a/_images/sphx_glr_plot_simulated_power_spectra_001.png b/_images/sphx_glr_plot_simulated_power_spectra_001.png index 1f564063..82be4447 100644 Binary files a/_images/sphx_glr_plot_simulated_power_spectra_001.png and b/_images/sphx_glr_plot_simulated_power_spectra_001.png differ diff --git a/_images/sphx_glr_plot_simulated_power_spectra_002.png b/_images/sphx_glr_plot_simulated_power_spectra_002.png index 4a0e2d35..94c7c54e 100644 Binary files a/_images/sphx_glr_plot_simulated_power_spectra_002.png and b/_images/sphx_glr_plot_simulated_power_spectra_002.png differ diff --git a/_images/sphx_glr_plot_simulated_power_spectra_003.png b/_images/sphx_glr_plot_simulated_power_spectra_003.png index aa668441..132d8212 100644 Binary files a/_images/sphx_glr_plot_simulated_power_spectra_003.png and b/_images/sphx_glr_plot_simulated_power_spectra_003.png differ diff --git a/_images/sphx_glr_plot_simulated_power_spectra_thumb.png b/_images/sphx_glr_plot_simulated_power_spectra_thumb.png index cbfc4829..b16045ea 100644 Binary files a/_images/sphx_glr_plot_simulated_power_spectra_thumb.png and b/_images/sphx_glr_plot_simulated_power_spectra_thumb.png differ diff --git a/_images/sphx_glr_plot_transforms_001.png b/_images/sphx_glr_plot_transforms_001.png index 7b83e59d..6b8723ac 100644 Binary files a/_images/sphx_glr_plot_transforms_001.png and b/_images/sphx_glr_plot_transforms_001.png differ diff --git a/_images/sphx_glr_plot_transforms_002.png b/_images/sphx_glr_plot_transforms_002.png index 6b8c481f..d51aea99 100644 Binary files a/_images/sphx_glr_plot_transforms_002.png and b/_images/sphx_glr_plot_transforms_002.png differ diff --git a/_images/sphx_glr_plot_transforms_003.png b/_images/sphx_glr_plot_transforms_003.png index a586a862..b499ea76 100644 Binary files a/_images/sphx_glr_plot_transforms_003.png and b/_images/sphx_glr_plot_transforms_003.png differ diff --git a/_images/sphx_glr_plot_transforms_004.png b/_images/sphx_glr_plot_transforms_004.png index 8b80b0b1..41f948c0 100644 Binary files a/_images/sphx_glr_plot_transforms_004.png and b/_images/sphx_glr_plot_transforms_004.png differ diff --git a/_images/sphx_glr_plot_transforms_005.png b/_images/sphx_glr_plot_transforms_005.png index 2f624df1..28f95ccb 100644 Binary files a/_images/sphx_glr_plot_transforms_005.png and b/_images/sphx_glr_plot_transforms_005.png differ diff --git a/_images/sphx_glr_plot_transforms_thumb.png b/_images/sphx_glr_plot_transforms_thumb.png index 21ac984b..08b56118 100644 Binary files a/_images/sphx_glr_plot_transforms_thumb.png and b/_images/sphx_glr_plot_transforms_thumb.png differ diff --git a/_modules/fooof/analysis/error.html b/_modules/fooof/analysis/error.html index 79878287..a925a081 100644 --- a/_modules/fooof/analysis/error.html +++ b/_modules/fooof/analysis/error.html @@ -1,24 +1,25 @@ - + - - fooof.analysis.error — fooof 1.0.0 documentation - - + + fooof.analysis.error — fooof 1.1.0 documentation + + - - - - + + + + + + - + - @@ -26,10 +27,10 @@ - - - - + + + + @@ -56,7 +57,7 @@ fooof - 1.0.0 + 1.1.0