""" .. _tut-event-arrays: =================== Working with events =================== This tutorial describes event representation and how event arrays are used to subselect data. As usual we'll start by importing the modules we need, loading some :ref:`example data `, and cropping the :class:`~mne.io.Raw` object to just 60 seconds before loading it into RAM to save memory: """ # Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. # %% import os import numpy as np import mne sample_data_folder = mne.datasets.sample.data_path() sample_data_raw_file = os.path.join( sample_data_folder, "MEG", "sample", "sample_audvis_raw.fif" ) raw = mne.io.read_raw_fif(sample_data_raw_file, verbose=False) raw.crop(tmax=60).load_data() # %% # The tutorial :ref:`tut-events-vs-annotations` describes in detail the # different ways of obtaining an :term:`Events array ` from a # :class:`~mne.io.Raw` object (see the section # :ref:`overview-tut-events-section` for details). Since the :ref:`sample # dataset ` includes experimental events recorded on # :term:`stim channel` ``STI 014``, we'll start this tutorial by parsing the # events from that channel using :func:`mne.find_events`: events = mne.find_events(raw, stim_channel="STI 014") # %% # .. _tut-section-events-io: # # Reading and writing events from/to a file # ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ # # Event arrays are :class:`NumPy array ` objects, so they could # be saved to disk as binary :file:`.npy` files using :func:`numpy.save`. # However, MNE-Python provides convenience functions :func:`mne.read_events` # and :func:`mne.write_events` for reading and writing event arrays as either # text files (common file extensions are :file:`.eve`, :file:`.lst`, and # :file:`.txt`) or binary :file:`.fif` files. The example dataset includes the # results of ``mne.find_events(raw)`` in a :file:`.fif` file. Since we've # truncated our :class:`~mne.io.Raw` object, it will have fewer events than the # events file loaded from disk (which contains events for the entire # recording), but the events should match for the first 60 seconds anyway: sample_data_events_file = os.path.join( sample_data_folder, "MEG", "sample", "sample_audvis_raw-eve.fif" ) events_from_file = mne.read_events(sample_data_events_file) assert np.array_equal(events, events_from_file[: len(events)]) # %% # When writing event arrays to disk, the format will be inferred from the file # extension you provide. By convention, MNE-Python expects events files to # either have an :file:`.eve` extension or to have a file basename ending in # ``-eve`` or ``_eve`` (e.g., :file:`{my_experiment}_eve.fif`), and will issue # a warning if this convention is not respected. # # # Subselecting and combining events # ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ # # The output of :func:`~mne.find_events` above (repeated here) told us the # number of events that were found, and the unique integer event IDs present: mne.find_events(raw, stim_channel="STI 014") # %% # .. admonition:: Including/excluding events # :class: sidebar hint # # Just like `~mne.pick_events`, `~mne.read_events` also has ``include`` # and ``exclude`` parameters. # # If some of those events are not of interest, you can easily subselect events # using :func:`mne.pick_events`, which has parameters ``include`` and # ``exclude``. For example, in the sample data Event ID 32 corresponds to a # subject button press, which could be excluded as: events_no_button = mne.pick_events(events, exclude=32) # %% # It is also possible to combine two Event IDs using :func:`mne.merge_events`; # the following example will combine Event IDs 1, 2 and 3 into a single event # labelled ``1``: merged_events = mne.merge_events(events, [1, 2, 3], 1) print(np.unique(merged_events[:, -1])) # %% # Note, however, that merging events is not necessary if you simply want to # pool trial types for analysis; the next section describes how MNE-Python uses # *event dictionaries* to map integer Event IDs to more descriptive label # strings. # # # Mapping Event IDs to trial descriptors # ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ # # So far in this tutorial we've only been dealing with integer Event IDs, which # were assigned based on DC voltage pulse magnitude (which is ultimately # determined by the experimenter's choices about what signals to send to the # STIM channels). Keeping track of which Event ID corresponds to which # experimental condition can be cumbersome, and it is often desirable to pool # experimental conditions during analysis. You may recall that the mapping of # integer Event IDs to meaningful descriptions for the :ref:`sample dataset # ` is given in :ref:`this table # ` in the :ref:`introductory tutorial # `. Here we simply reproduce that mapping as an # *event dictionary*: event_dict = { "auditory/left": 1, "auditory/right": 2, "visual/left": 3, "visual/right": 4, "smiley": 5, "buttonpress": 32, } # %% # Event dictionaries like this one are used when extracting epochs from # continuous data, and the resulting :class:`~mne.Epochs` object allows pooling # by requesting partial trial descriptors. For example, if we wanted to pool # all auditory trials, instead of merging Event IDs 1 and 2 using the # :func:`~mne.merge_events` function, we can make use of the fact that the keys # of ``event_dict`` contain multiple trial descriptors separated by ``/`` # characters: requesting ``'auditory'`` trials will select all epochs with # Event IDs 1 and 2; requesting ``'left'`` trials will select all epochs with # Event IDs 1 and 3. An example of this is shown later, in the # :ref:`tut-section-subselect-epochs` section of the tutorial # :ref:`tut-epochs-class`. # # # Plotting events # ^^^^^^^^^^^^^^^ # # Another use of event dictionaries is when plotting events, which can serve as # a useful check that your event signals were properly sent to the STIM # channel(s) and that MNE-Python has successfully found them. The function # :func:`mne.viz.plot_events` will plot each event versus its sample number # (or, if you provide the sampling frequency, it will plot them versus time in # seconds). It can also account for the offset between sample number and sample # index in Neuromag systems, with the ``first_samp`` parameter. # If an event dictionary is provided, it will be used to generate a legend: fig = mne.viz.plot_events( events, sfreq=raw.info["sfreq"], first_samp=raw.first_samp, event_id=event_dict ) # %% # Plotting events and raw data together # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # # Events can also be plotted alongside the :class:`~mne.io.Raw` object they # were extracted from, by passing the Event array as the ``events`` parameter # of :meth:`raw.plot `: raw.plot( events=events, start=5, duration=10, color="gray", event_color={1: "r", 2: "g", 3: "b", 4: "m", 5: "y", 32: "k"}, ) # %% # .. _`fixed-length-events`: # # Making equally-spaced Events arrays # ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ # # For some experiments (such as those intending to analyze resting-state # activity) there may not be any experimental events included in the raw # recording. In such cases, an Events array of equally-spaced events can be # generated using :func:`mne.make_fixed_length_events`: new_events = mne.make_fixed_length_events(raw, start=5, stop=50, duration=2.0) # %% # By default, the events will all be given the integer Event ID of ``1``, but # you can change that with the ``id`` parameter. It is also possible to specify # an ``overlap`` duration — i.e., if you ultimately want :term:`epochs` that # are 2.5 seconds long, but you want them to overlap by 0.5 seconds, you can # specify ``duration=2.5, overlap=0.5`` in the call to # :func:`~mne.make_fixed_length_events` (this will yield the same spacing of # events as ``duration=2, overlap=0)``.