Note
Go to the end to download the full example code.
From History to a Replayable Script#
This example shows the EEGPrep scripting loop:
run
pop_*steps withreturn_com=Trueto capture command strings,accumulate them in an
EEGPrepSessionsoALLCOM,LASTCOMandEEG["history"]match what the GUI would record,write the recorded history with
pop_saveh(),write the executable Python version of the same pipeline and replay it with
pop_runscript(),verify the replay reproduces the interactive result bit-for-bit.
Recorded command strings are EEGLAB-syntax for parity and portability, so the replayable artifact is a Python script you keep alongside them.
Imports and headless setup#
import matplotlib
matplotlib.use("Agg")
import tempfile
from pathlib import Path
import numpy as np
import eegprep
from eegprep import (
EEGPrepSession,
eegh,
pop_eegfiltnew,
pop_epoch,
pop_loadset,
pop_rmbase,
pop_reref,
pop_runscript,
pop_saveh,
)
REPO_ROOT = Path(eegprep.__file__).resolve().parents[2] # sphinx-gallery defines no __file__
SAMPLE = REPO_ROOT / "sample_data" / "eeglab_data.set"
_MASKS: list[tuple[str, str]] = [(str(REPO_ROOT), "<repo>")]
def mask(text: str) -> str:
"""Replace machine-specific paths so the rendered page is reproducible."""
for actual, label in _MASKS:
text = text.replace(actual, label)
return text
Interactive-style pass, recording history#
Every step returns (EEG, com). session.add_history appends to
ALLCOM and updates LASTCOM exactly as a GUI menu action would.
session = EEGPrepSession()
EEG = pop_loadset(str(SAMPLE))
EEG["history"] = "" # start from a clean dataset history for this example
session.store_current(EEG, new=True)
session.add_history(f"EEG = pop_loadset({str(SAMPLE)!r});")
EEG, com = pop_eegfiltnew(session.EEG, locutoff=1, hicutoff=40, plotfreqz=False, return_com=True)
session.store_current(EEG, command=com)
EEG, com = pop_reref(session.EEG, [], return_com=True)
session.store_current(EEG, command=com)
EEG, com = pop_epoch(session.EEG, ["square"], [-1, 2], return_com=True)
session.store_current(EEG, command=com)
EEG, com = pop_rmbase(session.EEG, [-1000, 0], return_com=True)
session.store_current(EEG, command=com)
interactive = session.EEG
print(f"epoched: nbchan={interactive['nbchan']} pnts={interactive['pnts']} trials={interactive['trials']}")
print(mask(f"LASTCOM: {session.LASTCOM}"))
epoched: nbchan=32 pnts=384 trials=80
LASTCOM: EEG = pop_rmbase( EEG, [-1000 0], []);
Session history vs dataset history#
ALLCOM is the whole session. eegh() renders it newest-first, the way
the console eegh magic does. EEG["history"] is per-dataset and, as in
EEGLAB, load/save commands are not part of it.
print("--- eegh() session history ---")
print(mask(eegh(None, session.ALLCOM)))
print("--- EEG['history'] dataset history ---")
print(mask(str(interactive["history"]).strip()))
--- eegh() session history ---
1. EEG = pop_rmbase( EEG, [-1000 0], []);
2. EEG = pop_epoch( EEG, { 'square' }, [-1 2]);
3. EEG = pop_reref( EEG, []);
4. EEG = pop_eegfiltnew(EEG, 'locutoff', 1, 'hicutoff', 40);
5. EEG = pop_loadset('<repo>/sample_data/eeglab_data.set');
--- EEG['history'] dataset history ---
EEG = pop_eegfiltnew(EEG, 'locutoff', 1, 'hicutoff', 40);
EEG = pop_reref( EEG, []);
EEG = pop_epoch( EEG, { 'square' }, [-1 2]);
EEG = pop_rmbase( EEG, [-1000 0], []);
Saving the recorded history#
pop_saveh writes the recorded command strings. They are EEGLAB-syntax, so
treat this file as an audit trail rather than something EEGPrep can re-run.
workdir = Path(tempfile.mkdtemp(prefix="eegprep_history_"))
_MASKS.append((str(workdir), "<tmpdir>"))
saveh_com = pop_saveh(session.ALLCOM, "eegprephist.m", workdir)
print(mask(saveh_com))
# Skip the "generated on <date>" banner: it would change on every docs build.
saved = (workdir / "eegprephist.m").read_text().strip().splitlines()
print(mask("\n".join(line for line in saved if "generated on" not in line)))
pop_saveh(ALLCOM, 'eegprephist.m', '<tmpdir>');
% ------------------------------------------------
EEG = pop_loadset('<repo>/sample_data/eeglab_data.set');
EEG = pop_eegfiltnew(EEG, 'locutoff', 1, 'hicutoff', 40);
EEG = pop_reref( EEG, []);
EEG = pop_epoch( EEG, { 'square' }, [-1 2]);
EEG = pop_rmbase( EEG, [-1000 0], []);
eegprep.eeglab();
The replayable Python script#
This is the artifact you keep under version control: the same steps as plain Python, with explicit assignment of every return value.
script = f'''from eegprep import pop_eegfiltnew, pop_epoch, pop_reref, pop_rmbase, pop_loadset
EEG = pop_loadset({str(SAMPLE)!r})
EEG, com_filter = pop_eegfiltnew(EEG, locutoff=1, hicutoff=40, plotfreqz=False, return_com=True)
EEG, com_reref = pop_reref(EEG, [], return_com=True)
EEG, com_epoch = pop_epoch(EEG, ["square"], [-1, 2], return_com=True)
EEG, com_rmbase = pop_rmbase(EEG, [-1000, 0], return_com=True)
ALLCOM = [com_filter, com_reref, com_epoch, com_rmbase]
'''
script_path = workdir / "replay_pipeline.py"
script_path.write_text(script, encoding="utf-8")
505
Replay and verify#
pop_runscript executes a .py history script in a namespace you supply,
which is how the GUI’s File > History scripts > Run script feeds results
back into the shared session.
namespace: dict = {}
run_com = pop_runscript(script_path, namespace)
print(mask(str(run_com)))
replayed = namespace["EEG"]
assert np.array_equal(np.asarray(replayed["data"]), np.asarray(interactive["data"]))
assert replayed["trials"] == interactive["trials"]
print(f"replay matches interactive run: {np.asarray(replayed['data']).shape}")
print("replayed ALLCOM:")
for line in namespace["ALLCOM"]:
print(mask(f" {line}"))
LASTCOM = pop_runscript('<tmpdir>/replay_pipeline.py');
replay matches interactive run: (32, 384, 80)
replayed ALLCOM:
EEG = pop_eegfiltnew(EEG, 'locutoff', 1, 'hicutoff', 40);
EEG = pop_reref( EEG, []);
EEG = pop_epoch( EEG, { 'square' }, [-1 2]);
EEG = pop_rmbase( EEG, [-1000 0], []);
Total running time of the script: (0 minutes 0.292 seconds)