{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "\n\n# The Spectrum and EpochsSpectrum classes: frequency-domain data\n\nThis tutorial shows how to create and visualize frequency-domain representations of your\ndata, starting from continuous :class:`~mne.io.Raw`, discontinuous :class:`~mne.Epochs`,\nor averaged :class:`~mne.Evoked` data.\n\nAs usual we'll start by importing the modules we need, and loading our\n`sample dataset `:\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "import numpy as np\n\nimport mne\n\nsample_data_folder = mne.datasets.sample.data_path()\nsample_data_raw_file = sample_data_folder / \"MEG\" / \"sample\" / \"sample_audvis_raw.fif\"\nraw = mne.io.read_raw_fif(sample_data_raw_file, verbose=False).crop(tmax=60)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "All three sensor-space containers (:class:`~mne.io.Raw`,\n:class:`~mne.Epochs`, and :class:`~mne.Evoked`) have a\n:meth:`~mne.io.Raw.compute_psd` method with the same options.\n\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "raw.compute_psd()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "By default, the spectral estimation method will be the\n:footcite:t:`Welch1967` method for continuous data, and the multitaper\nmethod :footcite:`Slepian1978` for epoched or averaged data. This default can\nbe overridden by passing ``method='welch'`` or ``method='multitaper'`` to the\n:meth:`~mne.io.Raw.compute_psd` method.\n\nThere are many other options available as well; for example we can compute a\nspectrum from a given span of times, for a chosen frequency range, and for a\nsubset of the available channels:\n\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "raw.compute_psd(method=\"multitaper\", tmin=10, tmax=20, fmin=5, fmax=30, picks=\"eeg\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "You can also pass some parameters to the underlying spectral estimation\nfunction, such as the FFT window length and overlap for the Welch method; see\nthe docstrings of :class:`mne.time_frequency.Spectrum` (esp. its\n``method_kw`` parameter) and the spectral estimation functions\n:func:`~mne.time_frequency.psd_array_welch` and\n:func:`~mne.time_frequency.psd_array_multitaper` for details.\n\nFor epoched data, the class of the spectral estimate will be\n:class:`mne.time_frequency.EpochsSpectrum` instead of\n:class:`mne.time_frequency.Spectrum`, but most of the API is the same for the\ntwo classes. For example, both have a\n:meth:`~mne.time_frequency.EpochsSpectrum.get_data` method with an option to\nreturn the bin frequencies:\n\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "with mne.use_log_level(\"WARNING\"): # hide some irrelevant info messages\n events = mne.find_events(raw, stim_channel=\"STI 014\")\n event_dict = {\n \"auditory/left\": 1,\n \"auditory/right\": 2,\n \"visual/left\": 3,\n \"visual/right\": 4,\n }\n epochs = mne.Epochs(\n raw, events, tmin=-0.3, tmax=0.7, event_id=event_dict, preload=True\n )\nepo_spectrum = epochs.compute_psd()\npsds, freqs = epo_spectrum.get_data(return_freqs=True)\nprint(f\"\\nPSDs shape: {psds.shape}, freqs shape: {freqs.shape}\")\nepo_spectrum" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Additionally, both :class:`~mne.time_frequency.Spectrum` and\n:class:`~mne.time_frequency.EpochsSpectrum` have ``__getitem__`` methods,\nmeaning their data can be accessed by square-bracket indexing. For\n:class:`~mne.time_frequency.Spectrum` objects (computed from\n:class:`~mne.io.Raw` or :class:`~mne.Evoked` data), the indexing works\nsimilar to a :class:`~mne.io.Raw` object or a\n:class:`NumPy array`:\n\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "evoked = epochs[\"auditory\"].average()\nevk_spectrum = evoked.compute_psd()\n# the first 3 frequency bins for the first 4 channels:\nprint(evk_spectrum[:4, :3])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ ".. hint::\n :class: sidebar\n\n If the original :class:`~mne.Epochs` object had a metadata dataframe\n attached, the derived :class:`~mne.time_frequency.EpochsSpectrum` will\n inherit that metadata and will hence also support subselecting epochs via\n `Pandas query strings `.\n\nIn contrast, the :class:`~mne.time_frequency.EpochsSpectrum` has indexing\nsimilar to :class:`~mne.Epochs` objects: you can use string values to select\nspectral estimates for specific epochs based on their condition names, and\nwhat you get back is a new instance of\n:class:`~mne.time_frequency.EpochsSpectrum` rather than a\n:class:`NumPy array` of the data values. Selection via\n:term:`hierarchical event descriptors` (HEDs) is also possible:\n\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "# get both \"visual/left\" and \"visual/right\" epochs:\nepo_spectrum[\"visual\"]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Visualizing Spectrum objects\n\nBoth :class:`~mne.time_frequency.Spectrum` and\n:class:`~mne.time_frequency.EpochsSpectrum` objects have plotting methods\n:meth:`~mne.time_frequency.Spectrum.plot` (frequency \u00d7 power),\n:meth:`~mne.time_frequency.Spectrum.plot_topo` (frequency \u00d7 power separately\nfor each sensor), and :meth:`~mne.time_frequency.Spectrum.plot_topomap`\n(interpolated scalp topography of power, in specific frequency bands). A few\nplot options are demonstrated below; see the docstrings for full details.\n\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "evk_spectrum.plot(picks=\"data\", exclude=\"bads\", amplitude=False)\nevk_spectrum.plot_topo(color=\"k\", fig_facecolor=\"w\", axis_facecolor=\"w\")" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "evk_spectrum.plot_topomap(ch_type=\"eeg\", agg_fun=np.median)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Migrating legacy code\n\nBelow is a quick-reference table of equivalent code from before and after the\nintroduction of the :class:`~mne.time_frequency.Spectrum` and\n:class:`~mne.time_frequency.EpochsSpectrum` classes.\n\n.. table:: Quick reference for common Spectral class actions\n :widths: auto\n\n +---------------------------------------------------+----------------------------------------------------------------------+\n | Old | New |\n +===================================================+======================================================================+\n | ``mne.time_frequency.psd_welch(raw)`` | ``raw.compute_psd().get_data(return_freqs=True)`` |\n +---------------------------------------------------+----------------------------------------------------------------------+\n | ``mne.time_frequency.psd_multitaper(raw)`` | ``raw.compute_psd(method='multitaper').get_data(return_freqs=True)`` |\n +---------------------------------------------------+----------------------------------------------------------------------+\n | ``raw.plot_psd(fmin, fmax, dB, area_mode='std')`` | ``raw.compute_psd(fmin, fmax).plot(dB, ci='std')`` |\n +---------------------------------------------------+----------------------------------------------------------------------+\n | ``raw.plot_psd_topo(n_fft, overlap, axes)`` | ``raw.compute_psd(n_fft, overlap).plot_topo(axes)`` |\n +---------------------------------------------------+----------------------------------------------------------------------+\n | ``epochs.plot_psd_topomap(tmax, bands)`` | ``epochs.compute_psd(tmax).plot_topomap(bands)`` |\n +---------------------------------------------------+----------------------------------------------------------------------+\n\n\n

Warning

The functions ``mne.time_frequency.psd_welch`` and\n ``mne.time_frequency.psd_multitaper`` have been removed; new code\n should use the :meth:`Raw.compute_psd()`,\n :meth:`Epochs.compute_psd()`, and\n :meth:`Evoked.compute_psd()` methods, and pass\n ``method='welch'`` or ``method='multitaper'`` as a parameter.\n\n The class methods :meth:`Raw.plot_psd()`,\n :meth:`Epochs.plot_psd()`,\n :meth:`Raw.plot_psd_topo()`, and\n :meth:`Epochs.plot_psd_topomap()` have been\n kept in the API to support legacy code, but should be avoided when writing\n new code.

\n\n\n## References\n.. footbibliography::\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.12.2" } }, "nbformat": 4, "nbformat_minor": 0 }