-
Notifications
You must be signed in to change notification settings - Fork 1.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[BUG] Correct annotation onset for exportation to EDF and EEGLAB #12656
base: main
Are you sure you want to change the base?
Changes from 2 commits
b2aa09b
1643b3c
c837852
bbe6501
1eda973
78eb8ac
590cf16
970303c
cc96f10
51b8c1f
bd2fa76
f8f118a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -122,6 +122,43 @@ def test_export_raw_eeglab(tmp_path): | |
raw.export(temp_fname, overwrite=True) | ||
|
||
|
||
@pytest.mark.parametrize("tmin", (0, 1, 5, 10)) | ||
def test_export_raw_eeglab_annotations(tmp_path, tmin): | ||
"""Test that exporting EEGLAB preserves annotations and corects for raw.first_time.""" | ||
pytest.importorskip("eeglabio") | ||
raw = read_raw_fif(fname_raw, preload=True) | ||
raw.apply_proj() | ||
annotations = Annotations( | ||
onset=[0.01, 0.05, 0.90, 1.05], | ||
duration=[0, 1, 0, 0], | ||
description=["test1", "test2", "test3", "test4"], | ||
ch_names=[["MEG 0113"], ["MEG 0113", "MEG 0132"], [], ["MEG 0143"]], | ||
) | ||
raw.set_annotations(annotations) | ||
raw.crop(tmin) | ||
|
||
# export | ||
temp_fname = tmp_path / "test.set" | ||
raw.export(temp_fname) | ||
|
||
# read in the file | ||
with pytest.warns(RuntimeWarning, match="is above the 99th percentile"): | ||
raw_read = read_raw_eeglab(temp_fname, preload=True, montage_units="m") | ||
assert raw_read.first_time == 0 | ||
|
||
valid_annot = raw.annotations.onset >= tmin | ||
assert_array_almost_equal( | ||
raw.annotations.onset[valid_annot] - raw.first_time, | ||
raw_read.annotations.onset - raw_read.first_time, | ||
) | ||
assert_array_equal( | ||
raw.annotations.duration[valid_annot], raw_read.annotations.duration | ||
) | ||
assert_array_equal( | ||
raw.annotations.description[valid_annot], raw_read.annotations.description | ||
) | ||
|
||
|
||
def _create_raw_for_edf_tests(stim_channel_index=None): | ||
rng = np.random.RandomState(12345) | ||
ch_types = [ | ||
|
@@ -217,8 +254,9 @@ def test_edf_physical_range(tmp_path): | |
|
||
|
||
@edfio_mark() | ||
def test_export_edf_annotations(tmp_path): | ||
"""Test that exporting EDF preserves annotations.""" | ||
@pytest.mark.parametrize("tmin", (0, 0.005, 0.03, 1)) | ||
def test_export_edf_annotations(tmp_path, tmin): | ||
"""Test that exporting EDF preserves annotations and corects for raw.first_time.""" | ||
raw = _create_raw_for_edf_tests() | ||
annotations = Annotations( | ||
onset=[0.01, 0.05, 0.90, 1.05], | ||
|
@@ -227,17 +265,39 @@ def test_export_edf_annotations(tmp_path): | |
ch_names=[["0"], ["0", "1"], [], ["1"]], | ||
) | ||
raw.set_annotations(annotations) | ||
raw.crop(tmin) | ||
assert raw.first_time == tmin | ||
|
||
if tmin % 1 == 0: | ||
expectation = nullcontext() | ||
else: | ||
expectation = pytest.warns( | ||
RuntimeWarning, match="EDF format requires equal-length data blocks" | ||
) | ||
Comment on lines
+318
to
+323
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What is this check doing? If you are checking for There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Because the constructed raw signal is 2 sec long and edfio can segment it into 2 data records of 1 sec. If a non-integer amount of time is cropped, then the signal is no longer a multiple of 1 sec and edfio will append zeroes and issue a RuntimeWarning. Maybe this should have been a test on its own but I'm adding it here since pytest wouldn't pass me otherwise. As for the |
||
|
||
# export | ||
temp_fname = tmp_path / "test.edf" | ||
raw.export(temp_fname) | ||
with expectation: | ||
raw.export(temp_fname, physical_range=(0, 10)) | ||
|
||
# read in the file | ||
raw_read = read_raw_edf(temp_fname, preload=True) | ||
assert_array_equal(raw.annotations.onset, raw_read.annotations.onset) | ||
assert_array_equal(raw.annotations.duration, raw_read.annotations.duration) | ||
assert_array_equal(raw.annotations.description, raw_read.annotations.description) | ||
assert_array_equal(raw.annotations.ch_names, raw_read.annotations.ch_names) | ||
assert raw_read.first_time == 0 | ||
|
||
valid_annot = raw.annotations.onset >= tmin | ||
assert_array_almost_equal( | ||
raw.annotations.onset[valid_annot] - raw.first_time, | ||
raw_read.annotations.onset - raw_read.first_time, | ||
) | ||
assert_array_equal( | ||
raw.annotations.duration[valid_annot], raw_read.annotations.duration | ||
) | ||
assert_array_equal( | ||
raw.annotations.description[valid_annot], raw_read.annotations.description | ||
) | ||
assert_array_equal( | ||
raw.annotations.ch_names[valid_annot], raw_read.annotations.ch_names | ||
) | ||
|
||
|
||
@edfio_mark() | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually should this annotation test for EEGLAB been written before, the bug should be noticable because the test Raw has actually been cropped. The saved onset would not correspond to the original onset.