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)
raw.crop(tmax=60).load_data()

"""
Explanation: Parsing events from raw data
This tutorial describes how to read experimental events from raw recordings,
and how to convert between the two different representations of events within
MNE-Python (Events arrays and Annotations objects).
In the introductory tutorial &lt;overview-tut-events-section&gt; we saw an
example of reading experimental events from a :term:"STIM" channel &lt;stim
channel&gt;; here we'll discuss :term:events and :term:annotations more
broadly, give more detailed information about reading from STIM channels, and
give an example of reading events that are in a marker file or included in
the data file as an embedded array. The tutorials tut-event-arrays and
tut-annotate-raw discuss how to plot, combine, load, save, and
export :term:events and ~mne.Annotations (respectively), and the
latter tutorial also covers interactive annotation of ~mne.io.Raw
objects.
We'll begin by loading the Python modules we need, and loading the same
example data &lt;sample-dataset&gt; we used in the introductory tutorial
&lt;tut-overview&gt;, but to save memory we'll crop the ~mne.io.Raw object
to just 60 seconds before loading it into RAM:
End of explanation
"""


raw.copy().pick_types(meg=False, stim=True).plot(start=3, duration=6)

"""
Explanation: The Events and Annotations data structures
Generally speaking, both the Events and ~mne.Annotations data
structures serve the same purpose: they provide a mapping between times
during an EEG/MEG recording and a description of what happened at those
times. In other words, they associate a when with a what. The main
differences are:

Units: the Events data structure represents the when in terms of
   samples, whereas the ~mne.Annotations data structure represents
   the when in seconds.
Limits on the description: the Events data structure represents the
   what as an integer "Event ID" code, whereas the ~mne.Annotations data
   structure represents the what as a string.
How duration is encoded: Events in an Event array do not have a
   duration (though it is possible to represent duration with pairs of
   onset/offset events within an Events array), whereas each element of an
   ~mne.Annotations object necessarily includes a duration (though
   the duration can be zero if an instantaneous event is desired).
Internal representation: Events are stored as an ordinary
   :class:NumPy array &lt;numpy.ndarray&gt;, whereas ~mne.Annotations is
   a :class:list-like class defined in MNE-Python.

What is a STIM channel?
A :term:stim channel (short for "stimulus channel") is a channel that does
not receive signals from an EEG, MEG, or other sensor. Instead, STIM channels
record voltages (usually short, rectangular DC pulses of fixed magnitudes
sent from the experiment-controlling computer) that are time-locked to
experimental events, such as the onset of a stimulus or a button-press
response by the subject (those pulses are sometimes called TTL_ pulses,
event pulses, trigger signals, or just "triggers"). In other cases, these
pulses may not be strictly time-locked to an experimental event, but instead
may occur in between trials to indicate the type of stimulus (or experimental
condition) that is about to occur on the upcoming trial.
The DC pulses may be all on one STIM channel (in which case different
experimental events or trial types are encoded as different voltage
magnitudes), or they may be spread across several channels, in which case the
channel(s) on which the pulse(s) occur can be used to encode different events
or conditions. Even on systems with multiple STIM channels, there is often
one channel that records a weighted sum of the other STIM channels, in such a
way that voltage levels on that channel can be unambiguously decoded as
particular event types. On older Neuromag systems (such as that used to
record the sample data) this "summation channel" was typically STI 014;
on newer systems it is more commonly STI101. You can see the STIM
channels in the raw data file here:
End of explanation
"""


events = mne.find_events(raw, stim_channel='STI 014')
print(events[:5])  # show the first 5

"""
Explanation: You can see that STI 014 (the summation channel) contains pulses of
different magnitudes whereas pulses on other channels have consistent
magnitudes. You can also see that every time there is a pulse on one of the
other STIM channels, there is a corresponding pulse on STI 014.
.. TODO: somewhere in prev. section, link out to a table of which systems
   have STIM channels vs. which have marker files or embedded event arrays
   (once such a table has been created).
Converting a STIM channel signal to an Events array
If your data has events recorded on a STIM channel, you can convert them into
an events array using ~mne.find_events. The sample number of the onset
(or offset) of each pulse is recorded as the event time, the pulse magnitudes
are converted into integers, and these pairs of sample numbers plus integer
codes are stored in :class:NumPy arrays &lt;numpy.ndarray&gt; (usually called
"the events array" or just "the events"). In its simplest form, the function
requires only the ~mne.io.Raw object, and the name of the channel(s)
from which to read events:
End of explanation
"""


testing_data_folder = mne.datasets.testing.data_path()
eeglab_raw_file = os.path.join(testing_data_folder, 'EEGLAB', 'test_raw.set')
eeglab_raw = mne.io.read_raw_eeglab(eeglab_raw_file)
print(eeglab_raw.annotations)

"""
Explanation: .. sidebar:: The middle column of the Events array
MNE-Python events are actually *three* values: in between the sample
number and the integer event code is a value indicating what the event
code was on the immediately preceding sample. In practice, that value is
almost always ``0``, but it can be used to detect the *endpoint* of an
event whose duration is longer than one sample. See the documentation of
`~mne.find_events` for more details.

If you don't provide the name of a STIM channel, ~mne.find_events
will first look for MNE-Python config variables &lt;tut-configure-mne&gt;
for variables MNE_STIM_CHANNEL, MNE_STIM_CHANNEL_1, etc. If those are
not found, channels STI 014 and STI101 are tried, followed by the
first channel with type "STIM" present in raw.ch_names. If you regularly
work with data from several different MEG systems with different STIM channel
names, setting the MNE_STIM_CHANNEL config variable may not be very
useful, but for researchers whose data is all from a single system it can be
a time-saver to configure that variable once and then forget about it.
~mne.find_events has several options, including options for aligning
events to the onset or offset of the STIM channel pulses, setting the minimum
pulse duration, and handling of consecutive pulses (with no return to zero
between them). For example, you can effectively encode event duration by
passing output='step' to ~mne.find_events; see the documentation
of ~mne.find_events for details. More information on working with
events arrays (including how to plot, combine, load, and save event arrays)
can be found in the tutorial tut-event-arrays.
Reading embedded events as Annotations
Some EEG/MEG systems generate files where events are stored in a separate
data array rather than as pulses on one or more STIM channels. For example,
the EEGLAB format stores events as a collection of arrays in the :file:.set
file. When reading those files, MNE-Python will automatically convert the
stored events into an ~mne.Annotations object and store it as the
:attr:~mne.io.Raw.annotations attribute of the ~mne.io.Raw object:
End of explanation
"""


print(len(eeglab_raw.annotations))
print(set(eeglab_raw.annotations.duration))
print(set(eeglab_raw.annotations.description))
print(eeglab_raw.annotations.onset[0])

"""
Explanation: The core data within an ~mne.Annotations object is accessible
through three of its attributes: onset, duration, and
description. Here we can see that there were 154 events stored in the
EEGLAB file, they all had a duration of zero seconds, there were two
different types of events, and the first event occurred about 1 second after
the recording began:
End of explanation
"""


events_from_annot, event_dict = mne.events_from_annotations(eeglab_raw)
print(event_dict)
print(events_from_annot[:5])

"""
Explanation: More information on working with ~mne.Annotations objects, including
how to add annotations to ~mne.io.Raw objects interactively, and how
to plot, concatenate, load, save, and export ~mne.Annotations
objects can be found in the tutorial tut-annotate-raw.
Converting between Events arrays and Annotations objects
Once your experimental events are read into MNE-Python (as either an Events
array or an ~mne.Annotations object), you can easily convert between
the two formats as needed. You might do this because, e.g., an Events array
is needed for epoching continuous data, or because you want to take advantage
of the "annotation-aware" capability of some functions, which automatically
omit spans of data if they overlap with certain annotations.
To convert an ~mne.Annotations object to an Events array, use the
function mne.events_from_annotations on the ~mne.io.Raw file
containing the annotations. This function will assign an integer Event ID to
each unique element of raw.annotations.description, and will return the
mapping of descriptions to integer Event IDs along with the derived Event
array. By default, one event will be created at the onset of each annotation;
this can be modified via the chunk_duration parameter of
~mne.events_from_annotations to create equally spaced events within
each annotation span (see chunk-duration, below, or see
fixed-length-events for direct creation of an Events array of
equally-spaced events).
End of explanation
"""


custom_mapping = {'rt': 77, 'square': 42}
(events_from_annot,
 event_dict) = mne.events_from_annotations(eeglab_raw, event_id=custom_mapping)
print(event_dict)
print(events_from_annot[:5])

"""
Explanation: If you want to control which integers are mapped to each unique description
value, you can pass a :class:dict specifying the mapping as the
event_id parameter of ~mne.events_from_annotations; this
:class:dict will be returned unmodified as the event_dict.
Note that this event_dict can be used when creating ~mne.Epochs from
~mne.io.Raw objects, as demonstrated in the tutorial
tut-epochs-class.
End of explanation
"""


mapping = {1: 'auditory/left', 2: 'auditory/right', 3: 'visual/left',
           4: 'visual/right', 5: 'smiley', 32: 'buttonpress'}
annot_from_events = mne.annotations_from_events(
    events=events, event_desc=mapping, sfreq=raw.info['sfreq'],
    orig_time=raw.info['meas_date'])
raw.set_annotations(annot_from_events)

"""
Explanation: To make the opposite conversion (from an Events array to an
~mne.Annotations object), you can create a mapping from integer
Event ID to string descriptions, use ~mne.annotations_from_events
to construct the ~mne.Annotations object, and call the
~mne.io.Raw.set_annotations method to add the annotations to the
~mne.io.Raw object.
Because the sample data &lt;sample-dataset&gt; was recorded on a Neuromag
system (where sample numbering starts when the acquisition system is
initiated, not when the recording is initiated), we also need to pass in
the orig_time parameter so that the onsets are properly aligned relative
to the start of recording:
End of explanation
"""


raw.plot(start=5, duration=5)

"""
Explanation: Now, the annotations will appear automatically when plotting the raw data,
and will be color-coded by their label value:
End of explanation
"""


# create the REM annotations
rem_annot = mne.Annotations(onset=[5, 41],
                            duration=[16, 11],
                            description=['REM'] * 2)
raw.set_annotations(rem_annot)
(rem_events,
 rem_event_dict) = mne.events_from_annotations(raw, chunk_duration=1.5)

"""
Explanation: Making multiple events per annotation
As mentioned above, you can generate equally-spaced events from an
~mne.Annotations object using the chunk_duration parameter of
~mne.events_from_annotations. For example, suppose we have an
annotation in our ~mne.io.Raw object indicating when the subject was
in REM sleep, and we want to perform a resting-state analysis on those spans
of data. We can create an Events array with a series of equally-spaced events
within each "REM" span, and then use those events to generate (potentially
overlapping) epochs that we can analyze further.
End of explanation
"""


print(np.round((rem_events[:, 0] - raw.first_samp) / raw.info['sfreq'], 3))

"""
Explanation: Now we can check that our events indeed fall in the ranges 5-21 seconds and
41-52 seconds, and are ~1.5 seconds apart (modulo some jitter due to the
sampling frequency). Here are the event times rounded to the nearest
millisecond:
End of explanation
"""


