Skip to content

Warn when Epochs events fall outside the raw data range (#12989)#14004

Merged
tsbinns merged 18 commits into
mne-tools:mainfrom
CedricConday:fix/warn-out-of-bounds-events
Jul 13, 2026
Merged

Warn when Epochs events fall outside the raw data range (#12989)#14004
tsbinns merged 18 commits into
mne-tools:mainfrom
CedricConday:fix/warn-out-of-bounds-events

Conversation

@CedricConday

@CedricConday CedricConday commented Jun 30, 2026

Copy link
Copy Markdown
Contributor

Fixes #12989

What was wrong

When mne.Epochs is created from an events array containing sample numbers outside the data, the corresponding epochs are silently dropped with no indication that the events were out of bounds. This is easy to hit when events was generated at a different sampling frequency, or contains samples before first_samp.

Fix

At construction, compute each epoch's sample window (the same start/stop math used by _get_epoch_from_raw) and warn if any fall before the start or past the end of the raw data, reporting how many.

Test

Adds test_epochs_warn_out_of_bounds_events: an event past the end of the data now raises a RuntimeWarning. Verified it does not warn on main (the silent-drop behavior) and warns with this change.


AI-assisted, human-reviewed — I'm an AI engineer; I find, fix, and test with AI (Claude Code), then review and verify before opening.

@tsbinns

tsbinns commented Jun 30, 2026

Copy link
Copy Markdown
Contributor

Thanks for opening this PR @CedricConday!

I agree with the discussion in the issue that there should be an option to control whether a warning is emitted. That would also be in line with how we handle the similar situation for setting annotations in Raw objects that are outside the data boundaries:

mne-python/mne/io/base.py

Lines 714 to 719 in 90b8cee

def set_annotations(
self, annotations, emit_warning=True, on_missing="raise", *, verbose=None
):
"""Setter for annotations.
This setter checks if they are inside the data range.

CedricConday added a commit to CedricConday/mne-python that referenced this pull request Jun 30, 2026
Mirrors the on_missing pattern used for out-of-range Raw annotations
(_on_missing helper): 'raise' | 'warn' (default) | 'ignore'. Addresses
maintainer review on mne-toolsgh-14004.
@CedricConday

Copy link
Copy Markdown
Contributor Author

Thanks @tsbinns! Added an on_outside parameter ('raise' | 'warn' | 'ignore', default 'warn') routed through the _on_missing helper, mirroring the out-of-range Raw annotations handling you linked. Updated the docstring, changelog entry, and tests (warn / raise / ignore + the in-range no-warn case). Happy to change the default or the name if you'd prefer.

@tsbinns tsbinns left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Thanks for adding the extra control @CedricConday!
Just a few comments.

Comment thread mne/epochs.py Outdated
Comment thread mne/epochs.py
Comment thread mne/tests/test_epochs.py Outdated
@tsbinns

tsbinns commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

@CedricConday Please also link your GitHub account to CircleCI so that the documentation build will run, and we can verify that looks good.

CedricConday and others added 11 commits July 3, 2026 10:50
Events whose epoch window lies (partly) outside the raw data are silently
dropped, which is surprising e.g. when events come from a different sampling
frequency or contain samples before first_samp. Warn at construction listing
how many events are out of bounds. Adds a regression test.
Warn only when an event's sample number falls outside the recorded data
([first_samp, first_samp + n_times)) — the issue's actual scenario (events
at a different sampling frequency, or before first_samp). The earlier check
on the epoch *window* also fired for in-range events whose window merely
clips the edge (wide tmax / negative tmin on short data), which is normal
and broke several existing tests. Full test_epochs.py is green under -W error.
Mirrors the on_missing pattern used for out-of-range Raw annotations
(_on_missing helper): 'raise' | 'warn' (default) | 'ignore'. Addresses
maintainer review on mne-toolsgh-14004.
…x test

- on_outside made keyword-only in both Epochs and EpochsArray
- Warning logic moved from Epochs to BaseEpochs._oob_check for reuse
- EpochsArray now accepts and forwards on_outside to BaseEpochs
- Test uses pytest.raises instead of pytest.warns per mne warnings-as-errors policy
…-as-errors, add missing BaseEpochs on_outside doc
…event file (mne-toolsgh-12989)

test_warnings and test_n_components_none pass the complete event file against a
shorter/cropped raw, so some events fall past the data and are dropped — expected
here. Pass on_outside='ignore' at those call sites so the new default warning does
not trip warnings-as-errors. No behavior change to the tests' actual assertions.
@CedricConday CedricConday force-pushed the fix/warn-out-of-bounds-events branch from ed3a816 to 11f6a3b Compare July 3, 2026 11:43
@CedricConday

Copy link
Copy Markdown
Contributor Author

Thanks for the review @tsbinns — I've addressed all of it: on_outside is now keyword-only on both Epochs and EpochsArray, the check moved into BaseEpochs (so EpochsArray is covered) and runs after selection is applied, and the test no longer catches the warning. I also traced the CI matrix failures to three ICA tests that feed the full event file to a shorter raw — they now pass on_outside="ignore", since dropping the out-of-range events is expected there. Ready for another look when you have a moment.

…ne-toolsgh-12989)

test_n_components_none crops raw to (1.5, stop) but reads the full event
file, so some events fall past the cropped data and are dropped as
expected. Pass on_outside='ignore' at that call site so the new default
warning does not trip warnings-as-errors. A prior commit fixed the two
sibling ICA tests but missed this one. Test-only; no behavior change.
@tsbinns

tsbinns commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

@CedricConday Thanks for updates. Just to let you know that I haven't forgotten about this, but I won't be able to review until the weekend.

@tsbinns tsbinns left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

@CedricConday Just a few small things.

This comment remains unadressed, so please have a look at that: #14004 (comment)

Comment thread mne/epochs.py Outdated
Comment thread mne/epochs.py Outdated
Comment thread mne/epochs.py Outdated
Comment thread mne/epochs.py Outdated
Comment thread mne/epochs.py Outdated
self.detrend = detrend

self._raw = raw
self._oob_check(on_outside)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This can be moved into the if events is not None block above, since it is only relevant in this case.

Comment thread doc/changes/dev/14004.bugfix.rst Outdated
- Changelog: mark as newfeature (not bugfix) and reword
- Move the out-of-bounds check into the events-not-None branch, after
  selection has been applied, and pass raw explicitly
- Reword the warning to describe the data range rather than sample
  numbers, and say the epoch cannot be created (not "dropped")
- Rename _oob_check -> _check_events_outside_data
- DRY the on_outside docstring via a new docdict entry (on_outside_epochs)
- Make on_outside keyword-only in BaseEpochs
- Test: match the new wording and drop the redundant catch_warnings,
  since warnings are already treated as errors in the suite
@CedricConday

Copy link
Copy Markdown
Contributor Author

I addressed all 6 issues you mentioned.

CedricConday and others added 2 commits July 12, 2026 17:54
test_docdict_order requires docdict keys to appear in sorted order in
the source; place on_outside_epochs between on_missing_montage and
on_rank_mismatch.
@tsbinns

tsbinns commented Jul 13, 2026

Copy link
Copy Markdown
Contributor

@larsoner You'd weighed in on #12989. Are you happy with the proposed solution?

@larsoner

Copy link
Copy Markdown
Member

Yes it seems reasonable! But I think you should push a commit with [circle full] so we can ensure we haven't broken any examples/tutorials along the way that might also need an "ignore" passed

@tsbinns tsbinns enabled auto-merge (squash) July 13, 2026 21:08
@tsbinns tsbinns merged commit dc9a315 into mne-tools:main Jul 13, 2026
32 checks passed
@tsbinns

tsbinns commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

Thanks @CedricConday!

larsoner added a commit to larsoner/mne-python that referenced this pull request Jul 14, 2026
* upstream/main:
  Make scrollbar handlers draggable (mne-tools#14040)
  [pre-commit.ci] pre-commit autoupdate (mne-tools#14052)
  Warn when Epochs events fall outside the raw data range (mne-tools#12989) (mne-tools#14004)
  Ensure epochs being concatenated have compatible event ids (mne-tools#14051)
  Widen main content area (mne-tools#14015)
  MAINT: remove dead gain/bits/value_range fields from _read_header in … (mne-tools#14047)
  ENH: replace `_get_blocks` binary reader with mffpy Reader API (mne-tools#14043)
  MAINT: Update dependency specifiers (mne-tools#14048)
  [dependabot]: Bump the actions group with 2 updates (mne-tools#14049)
  Simplify doc building with more refleak (mne-tools#14045)
  ENH: add overlay Brain GUI (mne-tools#14031)
  ENH: support multiple simultaneous overlays in Brain.add_data (mne-tools#13995)
  Add option to show a zero line in browser (mne-tools#14018)
  FIX: pass cmap name string not tuple to interactive topomap slider kwargs (mne-tools#14039)
  Doc/add ai policy pointer (mne-tools#14037)
  Allow subclasses of FigureClass to be passed to plot_raw/plot_epochs (mne-tools#13979)
  MAINT: Replace manual PNS binary block reader in `_read_segment_file` with `mffpy` (mne-tools#14030)
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.

Warn if event sample number is out of bound for raw when creating Epochs

3 participants