Hello,
I started having a look, one point came-up:
- Rejection of epochs via autoreject: you chose to fit the ICA on epochs instead of the raw recording, and you compute a PTP rejection threshold on the epochs via
autoreject
. But then, instead of dropping the “bad” epochs, you provide this rejection threshold to ica.fit(..., reject=reject)
. As per the documentation, this reject
argument is only used if you fit on a Raw
, not on Epochs
, in which case you should directly use drop_bad
to remove the bad epochs.
That said, this point does not explain the issue. I am able to reproduce, for anyone interested, here is a MWE shortening the provided script:
from pathlib import Path
from mne import Annotations, Epochs, make_fixed_length_events
from mne.io import read_raw_brainvision
from mne.preprocessing import ICA, annotate_break
fname = Path("data") / "brainvision_raw" / "WENA09AG.vhdr"
raw = read_raw_brainvision(fname, preload=True)
raw.set_montage("brainproducts-RNP-BA-128")
raw.drop_channels("ECG")
raw.annotations.delete(raw.annotations.description == "New Segment/")
break_annotations = annotate_break(
raw=raw, min_break_duration=20, t_start_after_previous=2, t_stop_before_next=2
)
end_onset = raw.annotations[-1]["onset"] + 2.0 # add 2 seconds
end_duration = raw.times[-1] - end_onset
end_annotation = Annotations(
onset=end_onset,
duration=end_duration,
description="BAD_end",
orig_time=raw.annotations.orig_time,
)
raw.set_annotations(raw.annotations + break_annotations + end_annotation)
# filter and reref
raw.filter(1, 30)
raw.set_eeg_reference(ref_channels="average")
tstep = 1.0
events_ica = make_fixed_length_events(raw, duration=tstep)
epochs_ica = Epochs(
raw,
events_ica,
tmin=0.0,
tmax=tstep,
reject_by_annotation=True,
baseline=None,
preload=True,
)
random_state = 42
ica_n_components = .99
ica = ICA(n_components=0.99, random_state=42)
ica.fit(epochs_ica)
ica.exclude = [0, 1] # eye-movements
ica.plot_overlay(inst=raw)
I’ll have a deeper look when I can, nothing which explains this second plot comes up to mind in that part. It is however “fixed” by fitting on the non-re referenced raw directly.
from pathlib import Path
from mne import Annotations
from mne.io import read_raw_brainvision
from mne.preprocessing import ICA, annotate_break
fname = Path("data") / "brainvision_raw" / "WENA09AG.vhdr"
raw = read_raw_brainvision(fname, preload=True)
raw.set_montage("brainproducts-RNP-BA-128")
raw.drop_channels("ECG")
raw.annotations.delete(raw.annotations.description == "New Segment/")
break_annotations = annotate_break(
raw=raw, min_break_duration=20, t_start_after_previous=2, t_stop_before_next=2
)
end_onset = raw.annotations[-1]["onset"] + 2.0 # add 2 seconds
end_duration = raw.times[-1] - end_onset
end_annotation = Annotations(
onset=end_onset,
duration=end_duration,
description="BAD_end",
orig_time=raw.annotations.orig_time,
)
raw.set_annotations(raw.annotations + break_annotations + end_annotation)
# filter and reref
raw.filter(1, 30)
random_state = 42
ica_n_components = .99
ica = ICA(n_components=0.99, random_state=42)
ica.fit(raw)
ica.exclude = [0, 1]
ica.plot_overlay(inst=raw)

EDIT: Removing my erroneous comment on the filters. They are correct.
EDIT 2: Second plot still looks wrong, I would expect to see the blink deflection in red.
Best,
Mathieu