Skip to content

Fix EEGLAB events after dropped epochs#14067

Draft
viranovskaya wants to merge 3 commits into
mne-tools:mainfrom
viranovskaya:fix/eeglab-epoch-events
Draft

Fix EEGLAB events after dropped epochs#14067
viranovskaya wants to merge 3 commits into
mne-tools:mainfrom
viranovskaya:fix/eeglab-epoch-events

Conversation

@viranovskaya

@viranovskaya viranovskaya commented Jul 18, 2026

Copy link
Copy Markdown
Contributor

Reference issue

Fixes #13535.

What does this implement/fix?

When epochs had been dropped, epochs.selection still referred to the original trials. Passing these indices to eeglabio could produce out-of-range epoch numbers and latencies, followed by dummy events or an eeg_checkset failure.

This change maps events to the epochs that are actually being exported and recalculates their latencies in the concatenated EEGLAB dataset.

I added a regression test with dropped middle epochs. The exported file now contains one event per retained epoch, valid 1-based epoch numbers, and no dummy events.

Event sample numbers after importing the .set file back into MNE now refer to the exported epoched dataset rather than the original continuous recording. This matches how EEGLAB represents events in epoched data.

Additional information

Tested with eeglabio 0.1.2 and 0.1.3.

Comment thread mne/export/_eeglab.py
Comment on lines 77 to +78
if "epoch_indices" in getfullargspec(eeglabio.epochs.export_set).kwonlyargs:
kwargs["epoch_indices"] = epochs.selection
kwargs["epoch_indices"] = np.arange(1, len(epochs) + 1)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there any reason to pass this at all anymore? I assume if you don't pass it, it defaults to np.arange, no?

@viranovskaya viranovskaya Jul 18, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good question. In most cases, omitting epoch_indices gives the same result. But when zero time is the final sample (tmax=0), eeglabio assigns the event to the next epoch and resets the latencies. I updated the regression test to cover this case; it fails without the explicit indices and passes with them. So I kept the argument and added a short comment.

Comment thread mne/export/_eeglab.py
events = epochs.events.copy()
events[:, 0] = (
np.arange(len(epochs)) * len(epochs.times) + epochs.time_as_index(0)[0]
)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is odd... if you do this there is no longer any reference to the absolute time in the original recording. It suggests events[:, 2] is the only thing correctly used by eeglabio.epochs.export_set. Is it?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, the absolute sample from the original continuous recording is intentionally not retained in this field. For epoched EEGLAB files, eeglabio uses column 0 as latency in the concatenated epochs array and column 2 as the event type; column 1 is unused. Keeping the original sample numbers is what caused events to point to the wrong epochs after dropping epochs. I clarified this in the code comment.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ohhh.... so I think this fix actually belongs in eeglabio. It should handle the translation from MNE-Python events (which it currently takes) to whatever eeglab wants.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That makes sense. I moved the translation into eeglabio and added tests for dropped epochs and the tmax=0 boundary: jackz314/eeglabio#26. I’ll update this PR once the upstream behavior is settled.

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.

Potential bug in eeglabio exporting

2 participants