{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "\n\n# Working with events\n\nThis tutorial describes event representation and how event arrays are used to subselect\ndata.\n\nAs usual we'll start by importing the modules we need, loading some\n`example data `, and cropping the :class:`~mne.io.Raw`\nobject to just 60 seconds before loading it into RAM to save memory:\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "# Authors: The MNE-Python contributors.\n# License: BSD-3-Clause\n# Copyright the MNE-Python contributors." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "import os\n\nimport numpy as np\n\nimport mne\n\nsample_data_folder = mne.datasets.sample.data_path()\nsample_data_raw_file = os.path.join(\n sample_data_folder, \"MEG\", \"sample\", \"sample_audvis_raw.fif\"\n)\nraw = mne.io.read_raw_fif(sample_data_raw_file, verbose=False)\nraw.crop(tmax=60).load_data()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The tutorial `tut-events-vs-annotations` describes in detail the\ndifferent ways of obtaining an :term:`Events array ` from a\n:class:`~mne.io.Raw` object (see the section\n`overview-tut-events-section` for details). Since the `sample\ndataset ` includes experimental events recorded on\n:term:`stim channel` ``STI 014``, we'll start this tutorial by parsing the\nevents from that channel using :func:`mne.find_events`:\n\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "events = mne.find_events(raw, stim_channel=\"STI 014\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "\n## Reading and writing events from/to a file\n\nEvent arrays are :class:`NumPy array ` objects, so they could\nbe saved to disk as binary :file:`.npy` files using :func:`numpy.save`.\nHowever, MNE-Python provides convenience functions :func:`mne.read_events`\nand :func:`mne.write_events` for reading and writing event arrays as either\ntext files (common file extensions are :file:`.eve`, :file:`.lst`, and\n:file:`.txt`) or binary :file:`.fif` files. The example dataset includes the\nresults of ``mne.find_events(raw)`` in a :file:`.fif` file. Since we've\ntruncated our :class:`~mne.io.Raw` object, it will have fewer events than the\nevents file loaded from disk (which contains events for the entire\nrecording), but the events should match for the first 60 seconds anyway:\n\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "sample_data_events_file = os.path.join(\n sample_data_folder, \"MEG\", \"sample\", \"sample_audvis_raw-eve.fif\"\n)\nevents_from_file = mne.read_events(sample_data_events_file)\nassert np.array_equal(events, events_from_file[: len(events)])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "When writing event arrays to disk, the format will be inferred from the file\nextension you provide. By convention, MNE-Python expects events files to\neither have an :file:`.eve` extension or to have a file basename ending in\n``-eve`` or ``_eve`` (e.g., :file:`{my_experiment}_eve.fif`), and will issue\na warning if this convention is not respected.\n\n\n## Subselecting and combining events\n\nThe output of :func:`~mne.find_events` above (repeated here) told us the\nnumber of events that were found, and the unique integer event IDs present:\n\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "mne.find_events(raw, stim_channel=\"STI 014\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ ".. admonition:: Including/excluding events\n :class: sidebar hint\n\n Just like `~mne.pick_events`, `~mne.read_events` also has ``include``\n and ``exclude`` parameters.\n\nIf some of those events are not of interest, you can easily subselect events\nusing :func:`mne.pick_events`, which has parameters ``include`` and\n``exclude``. For example, in the sample data Event ID 32 corresponds to a\nsubject button press, which could be excluded as:\n\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "events_no_button = mne.pick_events(events, exclude=32)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "It is also possible to combine two Event IDs using :func:`mne.merge_events`;\nthe following example will combine Event IDs 1, 2 and 3 into a single event\nlabelled ``1``:\n\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "merged_events = mne.merge_events(events, [1, 2, 3], 1)\nprint(np.unique(merged_events[:, -1]))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Note, however, that merging events is not necessary if you simply want to\npool trial types for analysis; the next section describes how MNE-Python uses\n*event dictionaries* to map integer Event IDs to more descriptive label\nstrings.\n\n\n## Mapping Event IDs to trial descriptors\n\nSo far in this tutorial we've only been dealing with integer Event IDs, which\nwere assigned based on DC voltage pulse magnitude (which is ultimately\ndetermined by the experimenter's choices about what signals to send to the\nSTIM channels). Keeping track of which Event ID corresponds to which\nexperimental condition can be cumbersome, and it is often desirable to pool\nexperimental conditions during analysis. You may recall that the mapping of\ninteger Event IDs to meaningful descriptions for the `sample dataset\n` is given in `this table\n` in the `introductory tutorial\n`. Here we simply reproduce that mapping as an\n*event dictionary*:\n\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "event_dict = {\n \"auditory/left\": 1,\n \"auditory/right\": 2,\n \"visual/left\": 3,\n \"visual/right\": 4,\n \"smiley\": 5,\n \"buttonpress\": 32,\n}" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Event dictionaries like this one are used when extracting epochs from\ncontinuous data, and the resulting :class:`~mne.Epochs` object allows pooling\nby requesting partial trial descriptors. For example, if we wanted to pool\nall auditory trials, instead of merging Event IDs 1 and 2 using the\n:func:`~mne.merge_events` function, we can make use of the fact that the keys\nof ``event_dict`` contain multiple trial descriptors separated by ``/``\ncharacters: requesting ``'auditory'`` trials will select all epochs with\nEvent IDs 1 and 2; requesting ``'left'`` trials will select all epochs with\nEvent IDs 1 and 3. An example of this is shown later, in the\n`tut-section-subselect-epochs` section of the tutorial\n`tut-epochs-class`.\n\n\n## Plotting events\n\nAnother use of event dictionaries is when plotting events, which can serve as\na useful check that your event signals were properly sent to the STIM\nchannel(s) and that MNE-Python has successfully found them. The function\n:func:`mne.viz.plot_events` will plot each event versus its sample number\n(or, if you provide the sampling frequency, it will plot them versus time in\nseconds). It can also account for the offset between sample number and sample\nindex in Neuromag systems, with the ``first_samp`` parameter.\nIf an event dictionary is provided, it will be used to generate a legend:\n\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "fig = mne.viz.plot_events(\n events, sfreq=raw.info[\"sfreq\"], first_samp=raw.first_samp, event_id=event_dict\n)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Plotting events and raw data together\n\nEvents can also be plotted alongside the :class:`~mne.io.Raw` object they\nwere extracted from, by passing the Event array as the ``events`` parameter\nof :meth:`raw.plot `:\n\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "raw.plot(\n events=events,\n start=5,\n duration=10,\n color=\"gray\",\n event_color={1: \"r\", 2: \"g\", 3: \"b\", 4: \"m\", 5: \"y\", 32: \"k\"},\n)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "\n## Making equally-spaced Events arrays\n\nFor some experiments (such as those intending to analyze resting-state\nactivity) there may not be any experimental events included in the raw\nrecording. In such cases, an Events array of equally-spaced events can be\ngenerated using :func:`mne.make_fixed_length_events`:\n\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "new_events = mne.make_fixed_length_events(raw, start=5, stop=50, duration=2.0)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "By default, the events will all be given the integer Event ID of ``1``, but\nyou can change that with the ``id`` parameter. It is also possible to specify\nan ``overlap`` duration \u2014 i.e., if you ultimately want :term:`epochs` that\nare 2.5 seconds long, but you want them to overlap by 0.5 seconds, you can\nspecify ``duration=2.5, overlap=0.5`` in the call to\n:func:`~mne.make_fixed_length_events` (this will yield the same spacing of\nevents as ``duration=2, overlap=0)``.\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 }