pybemobil.preproc.EEGPreprocessor#
- class pybemobil.preproc.EEGPreprocessor(loader, *, channel_types=None, rename_channels=None, pre_hook=None, line_noise_freq='europe', line_noise_method='adaptive', line_noise_kwargs=None, get_bad_chs_kwargs=None, annotate_breaks=False, annotate_break_kwargs=None, filter_bands=(0.1, 100.0), asr=False, filter_bands_ica=(1.75, None), downsample_ica=250.0, ica_method='jamica', jamica_kwargs=None, fit_ica=True, reject_by_annotation=True, thresh=-1, exclude_labels=None, include_labels=None, fit_dipoles=False, trans=None, rv_thresh=None, remove_outside_head=False, rng_seed=None, event_id=None, skip_if_exists=False, make_report=True, save_bids_raw=True, bids_root=None, overwrite_bids_raw=False, verbose=True)[source]#
Bases:
objectPreprocess EEG.
preprocessing pipeline: ZapLine → bad channels → filter → ASR → ICA → dipole fitting → average re-reference → interpolate → save.
Three recordings come out of the pipeline:
raw_source: the input exactly as passed torun_raw()(nothing done). In BIDS this is considered ‘raw’ format; it is written to the raw part of the BIDS dataset (save_bids_raw), not to the derivatives.raw_pre_ica: every step except ICA (renaming, pre-hook, line-noise removal, bad-channel detection, break annotation, bandpass, average reference projection, ASR). This is the data ICA is fitted on and applied to. Bad channels are marked but not yet interpolated, and the average reference is still an unapplied projection, so thatreapply_ica()can redo the final stage.raw_clean: everything done (ICA applied, average reference applied, bad channels interpolated).
Parameters are listed in pipeline order.
- Parameters:
- loader
XDFLoader|None Configured loader used by
run()to read raw files. Not required when callingrun_raw()directly.- channel_types
dict|None Channel name → MNE type mapping applied right after loading (only used by
run()).- rename_channels
dict|str|None Channel renaming applied at the very start of
run_raw().dict: explicit{old_name: new_name}mapping.str: strip this prefix from every channel name that starts with it (e.g."BrainVision RDA_").None(default): no renaming.
- pre_hook
callable()|None Arbitrary transformation applied to the raw object after channel renaming and before any signal processing.
The callable receives the
mne.io.Rawobject as its only argument and must return one of:the modified
rawobject, ora
(raw, description)tuple, where description is a short string (≤ 120 characters) describing what the hook did. The description is appended to the provenance metadata stored on the raw object and saved with the pipeline outputs.
Use
pre_hookfor one-off operations that do not belong in the general pipeline but must happen before filtering, such as cropping the recording, injecting custom annotations, correcting a known hardware artefact, or converting units. The hook runs before ZapLine, bad-channel detection, and all subsequent steps, so any changes it makes are seen by the entire pipeline.Example:
def my_hook(raw): raw.crop(tmin=5.0) # drop the first 5 s return raw, "cropped first 5 s" preprocessor = EEGPreprocessor(loader, pre_hook=my_hook)
- line_noise_freq
float|"europe"|"usa" Fundamental line-noise frequency in Hz. Harmonics are computed automatically up to (but not exceeding) the Nyquist frequency of the recording. Accepted values:
float: explicit fundamental (e.g.50.0or60.0)."europe": shortcut for 50 Hz (default)."usa": shortcut for 60 Hz.
The fundamental is passed to the line-noise removal step (when line_noise_method is not
None), which removes its harmonics itself; the full harmonic array is used byget_bad_chs()for notch-filtered bad-channel detection.- line_noise_method
str|None DSS-based spectral cleaning algorithm applied before bandpass filtering.
Noneskips line-noise removal. Default is"adaptive"(matching BeMoBIL). One of:"adaptive"ZapLine-plus (mne-denoise) with adaptive frequency detection.
"zapline"Standard ZapLine (mne-denoise), fixed-frequency.
"dss_line"Single-pass DSS (meegkit).
"dss_line_iter"Iterative DSS (meegkit).
- line_noise_kwargs
dict|None Extra keyword arguments forwarded to the backend of line_noise_method via
remove_line()’s method_kwargs (e.g.{"threshold": 4.0}for ZapLine or{"nremove": 2}for"dss_line").Noneuses defaults.- get_bad_chs_kwargs
dict|None Extra keyword arguments forwarded to
get_bad_chs(). Supported keys (all optional):"pyprep_kwargs"(dict): passed to PyPREP’sNoisyChannels;random_stateis always overwritten with rng_seed."notch_width"(float, default1.0): width of the notch filter used during bad-channel detection."line_noise_crit"(float | None, defaultNone): z-score threshold for the per-channel line-noise criterion;None(default) disables this check - recommended when ZapLine has run."deviation_threshold"(float, default3.5): z-score threshold for PyPREP’s amplitude-deviation criterion. Tighter than PyPREP’s built-in default of5.0to improve sensitivity on MoBI data; raise to reduce false positives."ransac"(bool | None, defaultNone): run PyPREP RANSAC whenNone(auto) orTrue; auto-detects from montage presence. SetFalseto disable explicitly.
- annotate_breaksbool
If
True, runmne.preprocessing.annotate_break()to mark inter-block breaks (and other gaps between events) asBAD_breakannotations, which are then excluded (viareject_by_annotation) from bad-channel detection, ICA fitting, and other downstream steps. Break detection can be overzealous on some recordings (e.g. sparse or irregular event structure), flagging most of the recording as “bad” even though the data itself is fine. DefaultFalse(skip this step entirely); setTrueto enable it, tuning behaviour via annotate_break_kwargs if needed.- annotate_break_kwargs
dict|None Forwarded to
mne.preprocessing.annotate_break(). Ignored whenannotate_breaks=False.- filter_bands
tupleoffloat (l_freq, h_freq)for the main bandpass filter applied before ASR and ICA.- asrbool |
dict Controls Artifact Subspace Reconstruction (ASR).
False(default): skip ASR;raw_pre_icais the bandpassed, average-reference-projected data.True: run ASR with the default parameters ofcompute_asr().dict: run ASR and pass the dict as keyword arguments tocompute_asr()(e.g.{"cutoff": 10, "estimator": "lwf"}).
Either way,
raw_pre_icais the data ICA is applied to, and it is saved as*_desc-preica_eeg.fifso that ICA can be re-applied with a different set of excluded components viareapply_ica().- filter_bands_ica
tupleoffloat (l_freq, h_freq)for the ICA-specific bandpass filter.- downsample_ica
float|None Target sampling rate for ICA fitting.
Noneskips downsampling.- ica_method
str ICA algorithm.
"jamica"(default) uses jamica, a JAX-accelerated reimplementation of AMICA, viajamica.fit_ica(), which returns a standard MNE ICA object directly; falls back to picard if the package is not installed. Any other string is forwarded as themethodargument tomne.preprocessing.ICA(e.g."picard","fastica"). Ignored whenfit_ica=False.- jamica_kwargs
dict|None Extra keyword arguments forwarded to
jamica.fit_ica()whenica_method="jamica", e.g.{"max_iter": 2000}. AMICA’s likelihood-based sample rejection is on by default, as in the MATLAB BeMoBIL pipeline ({"fit_params": {"do_reject": True, "rejsig": 3.0, "numrej": 10}});fit_paramsyou pass are merged over these defaults, so{"fit_params": {"do_reject": False}}disables it. Seecompute_ica(). Ignored when a non-jamica method is used orfit_ica=False.- fit_icabool
If
False, skip ICA entirely (raw_cleanequalsraw_pre_ica).- reject_by_annotationbool
If
True(default), data underBAD_*annotations (e.g.BAD_breakfrom annotate_breaks) are left out of the ICA fit and of ICLabel.- thresh
float ICLabel decision threshold. Set to
-1(default, matching BeMoBIL) to use popularity-vote mode: each IC is assigned to whichever class has the highest predicted probability; it is excluded if that class is not in include_labels (or is in exclude_labels). Any value in[0, 1]switches to probability-threshold mode: an IC is excluded only when its winning class is one to remove and that class’s probability is at least this value; ICs whose winning class is uncertain are kept.- exclude_labels
listofstr|None ICLabel categories to exclude. Mutually exclusive with include_labels.
- include_labels
setofstr|None ICLabel categories to keep; all others are excluded.
None(default) means all classes except"eye blink"(matching BeMoBIL’siclabel_classes = [1 2 4 5 6 7]), unless exclude_labels is given. Mutually exclusive with exclude_labels.- fit_dipolesbool
If
True, fit a dipole to each ICA component topography using the fsaverage BEM. Requires a montage with digitisation.- trans
mne.transforms.Transform|"fit"|"fsaverage"|None Head→MRI transform for dipole fitting.
Noneand"fsaverage"use the MNE built-in template;"fit"runs automatic coregistration. Ignored whenfit_dipoles=False.- rv_thresh
float|None Residual-variance threshold for dipole fitting. Components whose best-fitting dipole has RV >= rv_thresh are set to
Nonein thedipolesandresidualsoutput lists.Nonekeeps all dipoles. Typical value:0.15(15 %).- remove_outside_headbool
If
True, components whose dipole falls outside the head model (position norm > 0.13 m) are set toNonein the output lists.- rng_seed
int|None Random seed for ICA and PyPREP (RANSAC).
Nonedraws a fresh seed for each run; the seed actually used is recorded in the provenance descriptor, so any run can be reproduced.- event_id
dict|None Event map recorded in provenance metadata (no effect on processing).
- skip_if_existsbool
If
Trueandoverwrite=False, skip the entire computation when the primary output file*_desc-clean_eeg.fifalready exists and return the previously saved results instead.- make_reportbool
If
True(default) and fname_out is provided, generate anmne.Reportsummarising the preprocessing outputs and save it alongside the other derivatives as*_report.html.- save_bids_rawbool
If
True(default) and fname_out is provided, also writeraw_source(the untouched input) to the raw part of the BIDS dataset withmne_bids.write_raw_bids(), e.g.<bids_root>/sub-P003/ses-S001/eeg/sub-P003_ses-S001_task-..._eeg.vhdrplus sidecars. Subject, session, task, run and acquisition are taken from the file name of fname_out. This is a one-time conversion: if the BIDS raw already exists it is left alone (seeoverwrite_bids_raw). A failure here is reported as a warning and does not stop the pipeline.- bids_root
str|Path|None Root of the BIDS dataset for
save_bids_raw.None(default) infers it as the folder containing thederivativesdirectory that fname_out is in.- overwrite_bids_rawbool
If
True, replace an existing BIDS raw for this run. Independent of theoverwriteargument ofrun()/run_raw(), which only affects the derivatives. DefaultFalse.- verbosebool |
str|int MNE verbosity level during processing.
- loader
- Parameters:
channel_types (dict | None)
pre_hook (object)
line_noise_method (str | None)
line_noise_kwargs (dict | None)
get_bad_chs_kwargs (dict | None)
annotate_breaks (bool)
annotate_break_kwargs (dict | None)
downsample_ica (float | None)
ica_method (str)
jamica_kwargs (dict | None)
fit_ica (bool)
reject_by_annotation (bool)
thresh (float)
exclude_labels (list | None)
include_labels (set | None)
fit_dipoles (bool)
trans (object)
rv_thresh (float | None)
remove_outside_head (bool)
rng_seed (int | None)
event_id (dict | None)
skip_if_exists (bool)
make_report (bool)
save_bids_raw (bool)
bids_root (str | Path | None)
overwrite_bids_raw (bool)
- __init__(loader, *, channel_types=None, rename_channels=None, pre_hook=None, line_noise_freq='europe', line_noise_method='adaptive', line_noise_kwargs=None, get_bad_chs_kwargs=None, annotate_breaks=False, annotate_break_kwargs=None, filter_bands=(0.1, 100.0), asr=False, filter_bands_ica=(1.75, None), downsample_ica=250.0, ica_method='jamica', jamica_kwargs=None, fit_ica=True, reject_by_annotation=True, thresh=-1, exclude_labels=None, include_labels=None, fit_dipoles=False, trans=None, rv_thresh=None, remove_outside_head=False, rng_seed=None, event_id=None, skip_if_exists=False, make_report=True, save_bids_raw=True, bids_root=None, overwrite_bids_raw=False, verbose=True)[source]#
- Parameters:
channel_types (dict | None)
pre_hook (object)
line_noise_method (str | None)
line_noise_kwargs (dict | None)
get_bad_chs_kwargs (dict | None)
annotate_breaks (bool)
annotate_break_kwargs (dict | None)
downsample_ica (float | None)
ica_method (str)
jamica_kwargs (dict | None)
fit_ica (bool)
reject_by_annotation (bool)
thresh (float)
exclude_labels (list | None)
include_labels (set | None)
fit_dipoles (bool)
trans (object)
rv_thresh (float | None)
remove_outside_head (bool)
rng_seed (int | None)
event_id (dict | None)
skip_if_exists (bool)
make_report (bool)
save_bids_raw (bool)
overwrite_bids_raw (bool)
Methods
__init__(loader, *[, channel_types, ...])reapply_ica(fname_out, *[, exclude, add, ...])Re-apply a saved ICA with a manually edited set of excluded ICs.
run(fname_in[, fname_out, overwrite])Load fname_in and run the full preprocessing pipeline.
run_raw(raw[, fname_out, overwrite, tier2])Run the preprocessing pipeline on an already-loaded raw object.
- reapply_ica(fname_out, *, exclude=None, add=(), remove=(), save=True, make_report=None)[source]#
Re-apply a saved ICA with a manually edited set of excluded ICs.
Loads the outputs of a previous
run_raw()call from disk, changesica.excludeand repeats only the final pipeline stage (ICA application, average reference, bad-channel interpolation). Bad-channel detection, ASR, ICA fitting and dipole fitting are not re-run.- Parameters:
- fname_out
str|Path The fname_out used for the original run.
- exclude
listofint|None Full list of ICs to exclude, replacing the automatic selection. If
None, start from the savedica.excludeand apply add / remove.- add
listofint ICs to exclude in addition to the saved ones. Ignored when exclude is given.
- remove
listofint ICs to keep even though they were excluded before. Ignored when exclude is given.
- savebool
If
True(default), overwrite the clean recording (*_desc-clean_eeg.fif), the ICA file (*_ica.fif) and, if made, the report.- make_reportbool |
None Regenerate the HTML report.
None(default) usesmake_report.
- fname_out
- Returns:
Same3-tupleasrun_raw():(raw_clean, report, metadata).
- Parameters:
- Return type:
- run(fname_in, fname_out=None, *, overwrite=False)[source]#
Load fname_in and run the full preprocessing pipeline.
Uses
loader(anXDFLoader), whoseload()returns aMultimodalRecording. Only the Tier-1rawobject is preprocessed;tier2is forwarded torun_raw()for the report’s drop-out plots, andeventsis discarded (callrun_raw()directly if you need it).The montage set by the loader is kept. Only when the loaded data has no montage is the 10-05 template applied (
colin27_1005, namedstandard_1005before MNE 1.13); channels not in the template get a warning.- Parameters:
- fname_in
str|Path Path to the raw input file (XDF or any MNE-readable format).
- fname_out
str|Path|None Where to save the derivatives, as a BIDS-style path such as
<root>/derivatives/pybemobil/sub-01/eeg/sub-01_task-walk_eeg.fif. Its entities name all outputs (seeget_derivative_paths()), e.g.sub-01_task-walk_desc-clean_eeg.fif. PassNoneto skip saving.- overwritebool
Overwrite existing derivatives. Does not affect the BIDS raw (see
overwrite_bids_raw).
- fname_in
- Returns:
Sameasrun_raw().
- Parameters:
- Return type:
- run_raw(raw, fname_out=None, *, overwrite=False, tier2=None)[source]#
Run the preprocessing pipeline on an already-loaded raw object.
Channel types and montage must already be set by the caller. raw itself is not modified; the pipeline works on a copy.
- Parameters:
- raw
mne.io.BaseRaw Recording to preprocess.
- fname_out
str|Path|None Where to save the derivatives, as a BIDS-style path such as
<root>/derivatives/pybemobil/sub-01/eeg/sub-01_task-walk_eeg.fif. Its entities name all outputs (seeget_derivative_paths()), e.g.sub-01_task-walk_desc-clean_eeg.fif. PassNoneto skip saving.- overwritebool
Overwrite existing derivatives. Does not affect the BIDS raw (see
overwrite_bids_raw).- tier2
dict|None Tier-2 streams from
MultimodalRecording(e.g.rec.tier2), kept at native rate and not merged into raw. When provided andmake_report=True, each stream is plotted in full (decimated envelope, with drop-outs shaded) in its own report section.None(default) skips this section.
- raw
- Returns:
- raw_clean
mne.io.Raw Fully processed recording: ICA applied (and ASR, if enabled), average reference applied, bad channels interpolated.
- report
mne.Report|None Quality report (populated when
make_report=True, elseNone).- metadata
dict All other pipeline outputs, keyed by name:
raw_source(mne.io.Raw): the input exactly as passed torun_raw()(the same object), nothing done. Written to the BIDS raw folder whensave_bids_raw=True; when loaded from cache, read back from there (Noneif not found).raw_pre_ica(mne.io.Raw): every step except ICA (line-noise removal, bandpass, ASR if enabled). The data ICA is fitted on. Bad channels are marked but not interpolated and the average reference is still an unapplied projection. Saved as*_desc-preica_eeg.fif; input toreapply_ica().ica(mne.preprocessing.ICA): the fitted ICA, withica.excludeset from the ICLabel classification. An unfitted stub whenfit_ica=False.ic_labels(dict): ICLabel output per component ("labels"and"y_pred_proba"). Empty whenfit_ica=False.dipoles(listofmne.Dipole|None): one equivalent current dipole per IC,Nonewhere removed byrv_threshorremove_outside_head. Empty unlessfit_dipoles=True.residuals(listofmne.Evoked|None): residual field of each dipole fit, aligned withdipoles.trans(mne.transforms.Transform|None): the head-to-MRI transform used for dipole fitting.Noneunlessfit_dipoles=True.bad_ch_dict(dict): detected bad channels."all_bads"is the combined list;"pyprep","faster","bad_by_line_noise"and"bad_by_manual"hold the per-method results.
- raw_clean
- Parameters:
- Return type: