ICA, ICLabel, Rejection, and Visual Diagnostics#

EEGPrep follows the EEGLAB component-review workflow: compute ICA, label components, inspect labels and diagnostic displays, flag likely artifacts, then remove flagged components when review is complete.

Use the Sample ICA Dataset#

The fastest way to learn the workflow is to load the ICA tutorial data:

from pathlib import Path
from eegprep import pop_loadset

EEG = pop_loadset(Path("sample_data") / "eeglab_data_epochs_ica.set")

The GUI equivalent is File > Load existing dataset.

Run ICA When Needed#

For datasets without ICA fields, use Tools > Decompose data by ICA or call:

from eegprep import pop_runica

EEG, com = pop_runica(EEG, icatype="picard", gui=False, return_com=True)

The default GUI offers runica, robust runica, AMICA, and Picard choices. Standalone AMICA requires an AMICA executable configured outside the Python package.

AMICA input uses a channels-by-frames matrix. EEGPrep writes its binary input as little-endian float32 values, with all channels of each frame together, matching MATLAB’s runamica15. Versions affected by issue #435 wrote entire channels consecutively, scrambling the samples read by AMICA. Recompute affected AMICA decompositions and downstream component labels and rejection decisions from the original data.

Picard accepts EEGLAB’s PCA option through options. A positive value is the requested component count; a negative value subtracts dimensions from the selected channel count. For example, options={"pca": -1} computes one fewer component than channels, which is useful after average referencing. The initial unmixing matrix is sized to the reduced decomposition while remaining deterministic.

Picard starts from an identity matrix by default. To choose a reproducible random starting point, call eeg_picard(EEG, random_state=42) or pass options={"seed": 42} to pop_runica with icatype="picard". An explicit w_init matrix takes precedence over the seed. Passing random_state=None explicitly uses NumPy’s global random state, as in Python Picard. Different starts can converge to equivalent ICA solutions.

eeg_picard and eeg_runica then scale each component so the RMS of its mixing column is 1, matching EEGLAB eeg_checkset with option_scaleicarms on. The unscaled weights and sphere are stored in EEG["etc"]["icaweights_beforerms"] and EEG["etc"]["icasphere_beforerms"]. ICLabel uses those scaled activations and topographies, so label probabilities change if the scale is skipped.

ICLabel Workflow#

Run ICLabel after ICA:

from eegprep import eeg_icalabelstat, pop_icflag, pop_iclabel, pop_subcomp, pop_viewprops

EEG, label_com = pop_iclabel(EEG, "default", return_com=True)
stats = eeg_icalabelstat(EEG, threshold=0.9, verbose=False)
figures = pop_viewprops(EEG, typecomp=0, chanorcomp=[1, 2, 3])
EEG, flag_com = pop_icflag(EEG, return_com=True)
EEG, remove_com = pop_subcomp(EEG, [], return_com=True)

pop_iclabel stores class probabilities in EEG["etc"]["ic_classification"]["ICLabel"]["classifications"]. The class order is Brain, Muscle, Eye, Heart, Line Noise, Channel Noise, and Other.

GUI Review#

Choose Tools > Classify components using ICLabel.

Choose Plot > Component properties.

Review scalp maps, activity, spectra, ICLabel probabilities, and any stored DIPFIT projection.

Toggle component rejection marks and press OK.

Inspect EEG["reject"]["gcompreject"], LASTCOM, and ALLCOM[-1] from eegprep-console.

Choose Tools > Remove components from data only after review.

Dashboard reject toggles write pending marks to EEG.reject.gcompreject only when the user presses OK, so GUI review and eegprep-console history remain synchronized.

Label Statistics#

eeg_icalabelstat mirrors EEGLAB’s threshold-count summary and returns the same information in a Python dictionary:

stats = eeg_icalabelstat(EEG, threshold=0.9, verbose=False)
print(stats["counts"])
print(stats["component_indices"])

Returned values include per-class counts above threshold, one-based component indices, mean probabilities, dominant-class counts, and rejected/kept tallies from EEG.reject.gcompreject.

Flagging Rules#

Use pop_icflag defaults for an EEGLAB-like first pass, or pass a 7-by-2 threshold matrix in ICLabel class order:

import numpy as np
from eegprep import pop_icflag

EEG, com = pop_icflag(
    EEG,
    threshold=np.array(
        [
            [0, 0],
            [0.8, 1.0],
            [0.8, 1.0],
            [0, 0],
            [0, 0],
            [0, 0],
            [0, 0],
        ]
    ),
    return_com=True,
)

Review flags visually before removing components. Automatic labels are a guide, not a replacement for expert inspection.

Visual Diagnostics#

pop_viewprops(EEG, typecomp=0) opens EEGPrep’s native component-property browser. With ICLabel classifications present, component mode opens the pop_prop_extended dashboard with scalp map, activity browser, ERP/image summary, spectrum, class probabilities, component accept/reject controls, and DIPFIT projections when localized dipoles are already stored in EEG.dipfit.

The activity browser uses EEGLAB-facing one-based component indices and preserves event display state through the scroll_event option.

Network Availability#

The standalone Python engine ships the default ICLabel network (netICL.mat). EEGLAB lite and beta network artifacts are not bundled in the Python package; requesting them with engine=None raises a clear limitation. They can still be requested through engine="matlab" or engine="octave" when that runtime has an EEGLAB ICLabel checkout with those artifacts.