Description
Calling ica.plot_properties(raw) (or ica.plot_properties(raw, reject='auto'),
the default) raises IndexError: index N is out of bounds for axis 0 with size N-K for every component whenever the underlying raw contains
at least one 2-second window whose peak-to-peak amplitude exceeds the
fit-time reject threshold (ica.reject_).
This affects the report path too: mne.Report.add_ica(...) propagates the
same error (and on Windows with joblib's loky backend, the traceback gets
rewritten to "Could not pickle the task to send it to the workers").
PR #13746 (released in 1.12) addressed a related failure mode but didn't
fix this one — the OOB just moved from epoch_var[dropped_indices] to
drop_var[dropped_indices] (1.12+ line 666 of mne/viz/ica.py).
Steps to reproduce (no external data)
import numpy as np
import mne
from mne.preprocessing import ICA
sfreq, duration = 250.0, 60.0
n = int(sfreq * duration)
ch_names = ["Fp1","Fp2","F7","F3","Fz","F4","F8","T3","C3","Cz",
"C4","T4","T5","P3","Pz","P4","T6","O1","O2"]
rng = np.random.default_rng(0)
data = rng.standard_normal((19, n)) * 3e-6
# 5 mV spike in the LAST 2-sec window, so the bad-window epoch index
# is the maximum possible (= N), guaranteeing OOB on length-(N-1)
# post-rejection arrays.
data[0, n - int(0.5*sfreq) : n - int(0.4*sfreq)] += 5e-3
raw = mne.io.RawArray(
data, mne.create_info(ch_names, sfreq, "eeg"), verbose=False)
raw.set_montage("standard_1020")
ica = ICA(n_components=5, method="picard", random_state=0,
fit_params=dict(ortho=False, extended=True))
ica.fit(raw, reject=dict(eeg=500e-6)) # spike exceeds 500 µV -> drops window
ica.plot_properties(raw, picks=[0], show=False)
# IndexError: index 30 is out of bounds for axis 0 with size 29
Expected behavior
Either skip the dropped-segment markers gracefully or compute their
positions in the same index space as the per-epoch arrays.
Actual behavior
IndexError for every component. Affects ica.plot_properties,
mne.Report.add_ica, and the click-to-inspect callback from
ica.plot_components.
Root cause
In mne/viz/ica.py::_prepare_data_ica_properties, when inst is Raw
and reject='auto' (which uses ica.reject_):
1. _reject_data_segments(data, reject, ..., tstep=2) returns
drop_inds — sample-index pairs into the original signal.
2. The post-rejection data is wrapped into a shorter RawArray and
epoched into epochs_src with N - K epochs (where K = len(drop_inds)).
3. dropped_indices = [(d[0] // len(epochs_src.times)) + 1 for d in drop_inds]
computes original-space epoch numbers (values up to N).
4. In _plot_ica_properties / _fast_plot_ica_properties, those indices
are used to subscript epoch_var / drop_var, which were computed
from epochs_src and therefore live in post-rejection space
(length N - K).
epoch_var[dropped_indices] (≤1.11) and drop_var[dropped_indices]
(1.12+) overflow by exactly K whenever K ≥ 1.
Worked example (60 s @ 250 Hz, 1 bad window at the end)
epoch_len = 500 samples, N = 30 epochs total
bad window samples = [14500, 15000) -> d[0] = 14500
dropped_indices = [14500 // 500 + 1] = [30]
post-rejection length = 29
drop_var[30] -> index 30 out of bounds for axis 0 with size 29
Suggested fix
The intent at line 663–666 (on main) is "splice zero-variance entries
back into epoch_var at the original-space drop positions". drop_var
is built from dropped_src[idx] where dropped_src is the dropped_seg
returned by _reject_data_segments, and indexed with the
post-rejection-space np.arange(K) — not with dropped_indices.
So:
# current (1.12, mne/viz/ica.py:660-668):
epoch_var = np.insert(
arr=epoch_var,
obj=insertion_obj,
values=drop_var[dropped_indices], # OOB
axis=0,
)
# fix:
epoch_var = np.insert(
arr=epoch_var,
obj=insertion_obj,
values=drop_var, # already in 0..K-1 space
axis=0,
)
(I haven't traced the full data flow to verify drop_var length equals
K in every edge case)
Versions
Reproduced on 1.11.0, 1.12.0, 1.12.1, and main (HEAD as of 2026-05-01).
Diagnosis and reproducer drafted with [Claude Code](https://claude.com/claude-code) (Anthropic, Claude Opus 4.7)
Description
Calling
ica.plot_properties(raw)(orica.plot_properties(raw, reject='auto'),the default) raises
IndexError: index N is out of bounds for axis 0 with size N-Kfor every component whenever the underlyingrawcontainsat least one 2-second window whose peak-to-peak amplitude exceeds the
fit-time reject threshold (
ica.reject_).This affects the report path too:
mne.Report.add_ica(...)propagates thesame error (and on Windows with joblib's loky backend, the traceback gets
rewritten to
"Could not pickle the task to send it to the workers").PR #13746 (released in 1.12) addressed a related failure mode but didn't
fix this one — the OOB just moved from
epoch_var[dropped_indices]todrop_var[dropped_indices](1.12+ line 666 ofmne/viz/ica.py).Steps to reproduce (no external data)