Skip to content

EDFRawIO: treat annotations without a duration as events - #1968

Open
aaronkanzer wants to merge 1 commit into
NeuralEnsemble:masterfrom
aaronkanzer:fix/edf-annotation-events
Open

aaronkanzer wants to merge 1 commit into
NeuralEnsemble:masterfrom
aaronkanzer:fix/edf-annotation-events

Conversation

@aaronkanzer

Copy link
Copy Markdown
Contributor

In EDF+ files, most instantaneous annotations have no duration field, and pyedflib reports a missing duration as -1. EDFRawIO only treats a duration of exactly 0 as an event, so these annotations land on the "Epoch" channel with a duration of -1 s and the "Event" channel stays empty. Two smaller problems come with it:

  • The time window uses strict bounds, so an annotation at t=0 is dropped.
  • event_count returns the total number of annotations for both channels, so for a file with annotations neo's own rawio_compliance.read_events fails with "Wrong shape 0, 3".
import numpy as np, pyedflib
from neo.rawio import EDFRawIO

w = pyedflib.EdfWriter("t.edf", 1, file_type=pyedflib.FILETYPE_EDFPLUS)
w.setSignalHeaders([dict(label="ch", dimension="uV", sample_frequency=100,
                         physical_min=-100, physical_max=100,
                         digital_min=-32768, digital_max=32767)])
w.writeSamples([np.zeros(1000)])
w.writeAnnotation(0, -1, "start")     # no duration field in the file
w.writeAnnotation(2.5, -1, "stim")
w.writeAnnotation(0, 1.5, "baseline")
w.close()

r = EDFRawIO("t.edf"); r.parse_header()
for i in range(2):
    print(r.event_count(event_channel_index=i), r.get_event_timestamps(event_channel_index=i))

Observed (0.14.6 and master):

3 (array([]), None, array([]))
3 (array([2.5, 0. ]), array([-1. ,  1.5]), array(['stim', 'baseline']))

Expected:

2 (array([0. , 2.5]), None, array(['start', 'stim']))
1 (array([0.]), array([1.5]), array(['baseline']))

MNE reads the same file as start and stim with duration 0 and baseline with 1.5.

Fix: classify an annotation as an event when its duration is <= 0 and as an epoch otherwise, make the window bounds inclusive, clamp negative durations when computing an annotation's end, and count events and epochs separately. A regression test builds the file with pyedflib. This is separate from the gain change in #1920, which touched the same file but not the annotation handling.

pyedflib reports a missing annotation duration as -1. EDFRawIO only
treated a duration of exactly 0 as an event, so every instantaneous
EDF+ annotation ended up on the epoch channel with a duration of -1 s
and the event channel stayed empty. The time window also used strict
bounds, which dropped annotations at t=0, and event_count returned the
total number of annotations for both channels.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant