Repository: mne-tools/mne-python

Issue:
DOC: time of events and first_samp
hi,

how can i plot the events on top of the eeg versus time plot ?
i found the events/versus sample using find events. but when i divide versus the sampling rate i don't have at all the same values in time than the eeg. there must be an offset. 
I'ld like to plot some eeg data with the "events" on top of it.

regards 


Discussion:
raw.plot(events=events)

but don't resample raw after finding the evens otherwise they won't match.

>but don't resample raw after finding the evens otherwise they won't match.

To be precise, we recommend

`raw, events = raw.resample(new_sfreq, events=events)`

Thanks but in this particular case I don't plot using mne.
I would need to find the time for raws recording and time for events in the same unit.

if you have events you can time in seconds with


events_times  = (events[:, 0] - raw.first_samp) / raw.info['sfreq']

time of 0s will be beginning of the file.

HTH

ok thanks
At some point we should add a tutorial that discusses:

1. `find_events`, with event masking
2. `events` column values
3. `raw.first_samp`, what it is, how it changes with `.crop`, how to get event times relative to the start of the instance
4. `Annotations` and `orig_time`

I'll re-open and re-title this issue so we do this at some point.
@massich you have been working on these things quite a bit recently, could you make a `plot_timing.py` tutorial or something similar to cover these topics in the next two weeks to make it into 0.17?
yes
Moving to 0.18, not a blocker
Regarding the events and masking, there are several things I don't understand. 

See this:
```py
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)

events = mne.find_events(raw)

[print('{0:3d} --> {0:{fill}8b}'.format(id, fill='0')) for id in np.unique(events[:,2])]
```

```sh
  1 --> 00000001
  2 --> 00000010
  3 --> 00000011
  4 --> 00000100
  5 --> 00000101
 32 --> 00100000
```

If the events, are binary mapped events then 3 should not be **visual/left** but both audios. (but I guess, that this depends on the vendor and this vendor they are not independent bits).

Then if I do this, this works.
```py
events = mne.find_events(raw, mask=258)
```

So far so good.

But this breaks:
```py
In [32]: %paste
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)

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(mne.find_events(raw,mask=3), raw.info['sfreq'], raw.first_samp, color=color, event_id=event_id)
## -- End pasted text --
Traceback (most recent call last):
  File "<ipython-input-32-2c850fa9ff7f>", line 16, in <module>
    mne.viz.plot_events(mne.find_events(raw,mask=3), raw.info['sfreq'], raw.first_samp, color=color, event_id=event_id)
  File "/home/sik/code/mne-python/mne/viz/misc.py", line 504, in plot_events
    % this_event)
ValueError: 4 from event_id is not present in events.
```

@larsoner are all these the things you were referring when you were talking about event columns and masking? in points 1 and 2?
They seem related yes. `mask` is a binary mask (behavior dependent on what `mask_type` is) and the resulting `events[:, 2]` are the detected event numbers.

The error you hit is because you supplied an `event_id` that is not in the `events` that you supplied. In theory we should have an option to handle this the same way we do with `on_missing` in `Epochs`.
for me behavior is as expected but maybe error message should be more
explicit.

@drammock can you see if this is taken care of yet, and if not, add to the documentation todo?

Resolving patch:
diff --git a/mne/viz/misc.py b/mne/viz/misc.py
--- a/mne/viz/misc.py
+++ b/mne/viz/misc.py
@@ -449,18 +449,19 @@ def plot_events(events, sfreq=None, first_samp=0, color=None, event_id=None,
         The sample frequency. If None, data will be displayed in samples (not
         seconds).
     first_samp : int
-        The index of the first sample. Typically the raw.first_samp
-        attribute. It is needed for recordings on a Neuromag
-        system as the events are defined relative to the system
-        start and not to the beginning of the recording.
+        The index of the first sample. Recordings made on Neuromag systems
+        number samples relative to the system start (not relative to the
+        beginning of the recording). In such cases the ``raw.first_samp``
+        attribute can be passed here. Default is 0.
     color : dict | None
-        Dictionary of event_id value and its associated color. If None,
+        Dictionary of event_id integers as keys and colors as values. If None,
         colors are automatically drawn from a default list (cycled through if
-        number of events longer than list of default colors).
+        number of events longer than list of default colors). Color can be any
+        valid :doc:`matplotlib color <tutorials/colors/colors>`.
     event_id : dict | None
-        Dictionary of event label (e.g. 'aud_l') and its associated
-        event_id value. Label used to plot a legend. If None, no legend is
-        drawn.
+        Dictionary of event labels (e.g. 'aud_l') as keys and their associated
+        event_id values. Labels are used to plot a legend. If None, no legend
+        is drawn.
     axes : instance of Axes
        The subplot handle.
     equal_spacing : bool
@@ -902,8 +903,8 @@ def _handle_event_colors(unique_events, color, unique_events_id):
     else:
         for this_event in color:
             if this_event not in unique_events_id:
-                raise ValueError('%s from color is not present in events '
-                                 'or event_id.' % this_event)
+                raise ValueError('Event ID %s is in the color dict but is not '
+                                 'present in events or event_id.' % this_event)
 
         for this_event in unique_events_id:
             if this_event not in color:


Test patch: