-
-
Notifications
You must be signed in to change notification settings - Fork 1.5k
[MRG] Add events/annotations tutorial #5608
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
21 commits
Select commit
Hold shift + click to select a range
80c6966
Add tutorial
ec6d9ad
illustrate orig_time
c63b559
Add orig_time in annotations __repr__
5e83507
clean up
c82b367
clean up
ac146d5
more clean up
06c715e
Add whatsnew
70e8a80
fix broken link
0fa243d
remove old link reference
cdb1183
pep8
e92fdbf
a deeper explanation of the tripplets
8de310b
remove meas_date from the explanation, and point where to read about it
94eee8a
more
agramfort bc3ca06
format tutorial
a9c0e66
more
7622844
FIX: Minor fixes
larsoner f291830
pass on text
agramfort cce8cb7
Add str support to _handle_meas_date
3901065
allow passing orig_time in ISO8601 format
agramfort 174d94a
Migrate whatever was missing in _handle_meas_date form #5699
60912ed
print 6 decimals
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,170 @@ | ||
| """ | ||
| The **events** and :class:`Annotations <mne.Annotations>` data structures | ||
| ========================================================================= | ||
|
|
||
| Events and :class:`Annotations <mne.Annotations>` are quite similar. | ||
| This tutorial highlights their differences and similarities, and tries to shed | ||
| some light on which one is preferred to use in different situations when using | ||
| MNE. | ||
|
|
||
| Here are the definitions from the :ref:`glossary`. | ||
|
|
||
| events | ||
| Events correspond to specific time points in raw data; e.g., triggers, | ||
| experimental condition events, etc. MNE represents events with integers | ||
| that are stored in numpy arrays of shape (n_events, 3). Such arrays are | ||
| classically obtained from a trigger channel, also referred to as stim | ||
| channel. | ||
|
|
||
| annotations | ||
| An annotation is defined by an onset, a duration, and a string | ||
| description. It can contain information about the experiments, but | ||
| also details on signals marked by a human: bad data segments, | ||
| sleep scores, sleep events (spindles, K-complex) etc. | ||
|
|
||
| Both events and :class:`Annotations <mne.Annotations>` can be seen as triplets | ||
| where the first element answers to **when** something happens and the last | ||
| element refers to **what** it is. | ||
| The main difference is that events represent the onset in samples taking into | ||
| account the first sample value | ||
| (:attr:`raw.first_samp <mne.io.Raw.first_samp>`), and the description is | ||
| an integer value. | ||
| In contrast, :class:`Annotations <mne.Annotations>` represents the | ||
| ``onset`` in seconds (relative to the reference ``orig_time``), | ||
| and the ``description`` is an arbitrary string. | ||
| There is no correspondence between the second element of events and | ||
| :class:`Annotations <mne.Annotations>`. | ||
| For events, the second element corresponds to the previous value on the | ||
| stimulus channel from which events are extracted. In practice, the second | ||
| element is therefore in most cases zero. | ||
| The second element of :class:`Annotations <mne.Annotations>` is a float | ||
| indicating its duration in seconds. | ||
|
|
||
| See :ref:`sphx_glr_auto_examples_io_plot_read_events.py` | ||
| for a complete example of how to read, select, and visualize **events**; | ||
| and :ref:`sphx_glr_auto_tutorials_plot_artifacts_correction_rejection.py` to | ||
| learn how :class:`Annotations <mne.Annotations>` are used to mark bad segments | ||
| of data. | ||
|
|
||
| An example of events and annotations | ||
| ------------------------------------ | ||
|
|
||
| The following example shows the recorded events in `sample_audvis_raw.fif` and | ||
| marks bad segments due to eye blinks. | ||
| """ | ||
|
|
||
| import os.path as op | ||
| import numpy as np | ||
|
|
||
| import mne | ||
|
|
||
| # Load the data | ||
| data_path = mne.datasets.sample.data_path() | ||
| fname = op.join(data_path, 'MEG', 'sample', 'sample_audvis_raw.fif') | ||
| raw = mne.io.read_raw_fif(fname) | ||
|
|
||
| # Plot the events | ||
| events = mne.find_events(raw) | ||
|
|
||
| # Specify event_id dictionary based on the experiment | ||
| event_id = {'Auditory/Left': 1, 'Auditory/Right': 2, | ||
| 'Visual/Left': 3, 'Visual/Right': 4, | ||
| 'smiley': 5, 'button': 32} | ||
| color = {1: 'green', 2: 'yellow', 3: 'red', 4: 'c', 5: 'black', 32: 'blue'} | ||
|
|
||
| mne.viz.plot_events(events, raw.info['sfreq'], raw.first_samp, color=color, | ||
| event_id=event_id) | ||
|
|
||
| # Create some annotations specifying onset, duration and description | ||
| annotated_blink_raw = raw.copy() | ||
| eog_events = mne.preprocessing.find_eog_events(raw) | ||
| n_blinks = len(eog_events) | ||
| # Center to cover the whole blink with full duration of 0.5s: | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this may be a bit misleading - the events are centered and we are actually de-cenetering them by pushing them back in time to mark onset, not event center. |
||
| onset = eog_events[:, 0] / raw.info['sfreq'] - 0.25 | ||
| duration = np.repeat(0.5, n_blinks) | ||
| description = ['bad blink'] * n_blinks | ||
| annot = mne.Annotations(onset, duration, description, | ||
| orig_time=raw.info['meas_date']) | ||
| annotated_blink_raw.set_annotations(annot) | ||
|
|
||
| annotated_blink_raw.plot() # plot the annotated raw | ||
|
|
||
|
|
||
| ############################################################################### | ||
| # Working with Annotations | ||
| # ------------------------ | ||
| # | ||
| # An important element of :class:`Annotations <mne.Annotations>` is | ||
| # ``orig_time`` which is the time reference for the ``onset``. | ||
| # It is key to understand that when calling | ||
| # :func:`raw.set_annotations <mne.io.Raw.set_annotations>`, the given | ||
| # annotations are copied and transformed so that | ||
| # :class:`raw.annotations.orig_time <mne.Annotations>` | ||
| # matches the recording time of the raw object. | ||
| # Refer to the documentation of :class:`Annotations <mne.Annotations>` to see | ||
| # the expected behavior depending on ``meas_date`` and ``orig_time``. | ||
| # Where ``meas_date`` is the recording time stored in | ||
| # :class:`Info <mne.Info>`. | ||
| # You can find more information about :class:`Info <mne.Info>` in | ||
| # :ref:`sphx_glr_auto_tutorials_plot_info.py`. | ||
| # | ||
| # We'll now manipulate some simulated annotations. | ||
| # The first annotations has ``orig_time`` set to ``None`` while the | ||
| # second is set to a chosen POSIX timestamp for illustration purposes. | ||
|
|
||
| ############################################################################### | ||
|
|
||
| # Create an annotation object without orig_time | ||
| annot_none = mne.Annotations(onset=[0, 2, 9], duration=[0.5, 4, 0], | ||
| description=['foo', 'bar', 'foo'], | ||
| orig_time=None) | ||
| print(annot_none) | ||
|
|
||
| # Create an annotation object with orig_time | ||
| orig_time = '2002-12-03 19:01:31.676071' | ||
| annot_orig = mne.Annotations(onset=[22, 24, 31], duration=[0.5, 4, 0], | ||
| description=['foo', 'bar', 'foo'], | ||
| orig_time=orig_time) | ||
| print(annot_orig) | ||
|
|
||
| ############################################################################### | ||
| # Now we create two raw objects, set the annotations and plot them to compare | ||
| # them. | ||
|
|
||
| # Create two cropped copies of raw with the two previous annotations | ||
| raw_a = raw.copy().crop(tmax=12).set_annotations(annot_none) | ||
| raw_b = raw.copy().crop(tmax=12).set_annotations(annot_orig) | ||
|
|
||
| # Plot the raw objects | ||
| raw_a.plot() | ||
| raw_b.plot() | ||
|
|
||
| # Show the annotations in the raw objects | ||
| print(raw_a.annotations) | ||
| print(raw_b.annotations) | ||
|
|
||
| # Show that the onsets are the same | ||
| np.set_printoptions(precision=6) | ||
| print(raw_a.annotations.onset) | ||
| print(raw_b.annotations.onset) | ||
|
|
||
| ############################################################################### | ||
| # | ||
| # Notice that for the case where ``orig_time`` is ``None``, | ||
| # one assumes that the orig_time is the time of the first sample of data. | ||
|
|
||
| raw_delta = (1 / raw.info['sfreq']) | ||
| print('raw.first_sample is {}'.format(raw.first_samp * raw_delta)) | ||
| print('annot_none.onset[0] is {}'.format(annot_none.onset[0])) | ||
| print('raw_a.annotations.onset[0] is {}'.format(raw_a.annotations.onset[0])) | ||
|
|
||
| ############################################################################### | ||
| # | ||
| # It is possible to concatenate two annotations with the + operator like for | ||
| # lists if both share the same ``orig_time`` | ||
|
|
||
| annot = mne.Annotations(onset=[10], duration=[0.5], | ||
| description=['foobar'], | ||
| orig_time=orig_time) | ||
| annot = annot_orig + annot # concatenation | ||
| print(annot) | ||
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.