1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167
|
"""
.. _tut_epochs_objects:
The :class:`Epochs <mne.Epochs>` data structure: epoched data
=============================================================
:class:`Epochs <mne.Epochs>` objects are a way of representing continuous
data as a collection of time-locked trials, stored in an array of shape
``(n_events, n_channels, n_times)``. They are useful for many statistical
methods in neuroscience, and make it easy to quickly overview what occurs
during a trial.
"""
import mne
import os.path as op
import numpy as np
from matplotlib import pyplot as plt
###############################################################################
# :class:`Epochs <mne.Epochs>` objects can be created in three ways:
# 1. From a :class:`Raw <mne.io.Raw>` object, along with event times
# 2. From an :class:`Epochs <mne.Epochs>` object that has been saved as a
# `.fif` file
# 3. From scratch using :class:`EpochsArray <mne.EpochsArray>`. See
# :ref:`tut_creating_data_structures`
data_path = mne.datasets.sample.data_path()
# Load a dataset that contains events
raw = mne.io.read_raw_fif(
op.join(data_path, 'MEG', 'sample', 'sample_audvis_raw.fif'))
# If your raw object has a stim channel, you can construct an event array
# easily
events = mne.find_events(raw, stim_channel='STI 014')
# Show the number of events (number of rows)
print('Number of events:', len(events))
# Show all unique event codes (3rd column)
print('Unique event codes:', np.unique(events[:, 2]))
# Specify event codes of interest with descriptive labels.
# This dataset also has visual left (3) and right (4) events, but
# to save time and memory we'll just look at the auditory conditions
# for now.
event_id = {'Auditory/Left': 1, 'Auditory/Right': 2}
###############################################################################
# Now, we can create an :class:`mne.Epochs` object with the events we've
# extracted. Note that epochs constructed in this manner will not have their
# data available until explicitly read into memory, which you can do with
# :func:`get_data <mne.Epochs.get_data>`. Alternatively, you can use
# `preload=True`.
#
# Expose the raw data as epochs, cut from -0.1 s to 1.0 s relative to the event
# onsets
epochs = mne.Epochs(raw, events, event_id, tmin=-0.1, tmax=1,
baseline=(None, 0), preload=True)
print(epochs)
###############################################################################
# Epochs behave similarly to :class:`mne.io.Raw` objects. They have an
# :class:`info <mne.Info>` attribute that has all of the same
# information, as well as a number of attributes unique to the events contained
# within the object.
print(epochs.events[:3])
print(epochs.event_id)
###############################################################################
# You can select subsets of epochs by indexing the :class:`Epochs <mne.Epochs>`
# object directly. Alternatively, if you have epoch names specified in
# `event_id` then you may index with strings instead.
print(epochs[1:5])
print(epochs['Auditory/Right'])
###############################################################################
# Note the '/'s in the event code labels. These separators allow tag-based
# selection of epoch sets; every string separated by '/' can be entered, and
# returns the subset of epochs matching any of the strings. E.g.,
print(epochs['Right'])
print(epochs['Right', 'Left'])
###############################################################################
# Note that MNE will not complain if you ask for tags not present in the
# object, as long as it can find some match: the below example is parsed as
# (inclusive) 'Right' OR 'Left'. However, if no match is found, an error is
# returned.
epochs_r = epochs['Right']
epochs_still_only_r = epochs_r[['Right', 'Left']]
print(epochs_still_only_r)
try:
epochs_still_only_r["Left"]
except KeyError:
print("Tag-based selection without any matches raises a KeyError!")
###############################################################################
# It is also possible to iterate through :class:`Epochs <mne.Epochs>` objects
# in this way. Note that behavior is different if you iterate on `Epochs`
# directly rather than indexing:
# These will be epochs objects
for i in range(3):
print(epochs[i])
# These will be arrays
for ep in epochs[:2]:
print(ep)
###############################################################################
# You can manually remove epochs from the Epochs object by using
# :func:`epochs.drop(idx) <mne.Epochs.drop>`, or by using rejection or flat
# thresholds with :func:`epochs.drop_bad(reject, flat) <mne.Epochs.drop_bad>`.
# You can also inspect the reason why epochs were dropped by looking at the
# list stored in ``epochs.drop_log`` or plot them with
# :func:`epochs.plot_drop_log() <mne.Epochs.plot_drop_log>`. The indices
# from the original set of events are stored in ``epochs.selection``.
epochs.drop([0], reason='User reason')
epochs.drop_bad(reject=dict(grad=2500e-13, mag=4e-12, eog=200e-6), flat=None)
print(epochs.drop_log)
epochs.plot_drop_log()
print('Selection from original events:\n%s' % epochs.selection)
print('Removed events (from numpy setdiff1d):\n%s'
% (np.setdiff1d(np.arange(len(events)), epochs.selection).tolist(),))
print('Removed events (from list comprehension -- should match!):\n%s'
% ([li for li, log in enumerate(epochs.drop_log) if len(log) > 0]))
###############################################################################
# If you wish to save the epochs as a file, you can do it with
# :func:`mne.Epochs.save`. To conform to MNE naming conventions, the
# epochs file names should end with '-epo.fif'.
epochs_fname = op.join(data_path, 'MEG', 'sample', 'sample-epo.fif')
epochs.save(epochs_fname)
###############################################################################
# Later on you can read the epochs with :func:`mne.read_epochs`. For reading
# EEGLAB epochs files see :func:`mne.read_epochs_eeglab`. We can also use
# ``preload=False`` to save memory, loading the epochs from disk on demand.
epochs = mne.read_epochs(epochs_fname, preload=False)
###############################################################################
# If you wish to look at the average across trial types, then you may do so,
# creating an :class:`Evoked <mne.Evoked>` object in the process. Instances
# of `Evoked` are usually created by calling :func:`mne.Epochs.average`. For
# creating `Evoked` from other data structures see :class:`mne.EvokedArray` and
# :ref:`tut_creating_data_structures`.
ev_left = epochs['Auditory/Left'].average()
ev_right = epochs['Auditory/Right'].average()
f, axs = plt.subplots(3, 2, figsize=(10, 5))
_ = f.suptitle('Left / Right auditory', fontsize=20)
_ = ev_left.plot(axes=axs[:, 0], show=False, time_unit='s')
_ = ev_right.plot(axes=axs[:, 1], show=False, time_unit='s')
plt.tight_layout()
###############################################################################
# To export and manipulate Epochs using Pandas see
# :ref:`sphx_glr_auto_tutorials_plot_epochs_to_data_frame.py`,
# or to work directly with metadata in MNE-Python see
# :ref:`sphx_glr_auto_tutorials_plot_metadata_epochs.py`.
|