Skill Tracer
Skills › Scientific Agent Skills › neurokit2 › epochs_events.md

epochs_events.md

204 lines · skills/neurokit2/references/epochs_events.md at 5f2bc03

Open on GitHub

Most marks come from matching words in the file, so treat them as pointers.

1# Events and epochs
2
3Checked **2026-10-01** against NeuroKit2 0.2.13 stable source/runtime and
4the live Events and Epochs API pages.
5

Events and epochs

Checked 2026-10-01 against NeuroKit2 0.2.13 stable source/runtime and the live Events and Epochs API pages.

Raw lines 1 to 5
6## Event coordinate contract
7
8Choose one canonical representation before analysis:
9
10- absolute time with a named clock and unit;
11- zero-based sample index on a named stream; and
12- event duration and condition/label metadata.
14`events_find()` uses zero-based sample positions. Its `start_at`, `end_at`,
15`duration_min`, `duration_max`, and `inter_min` arguments are sample counts, not
16seconds.
18```python
19events = nk.events_find(
20 trigger,
21 threshold=0.5,
22 threshold_keep="above",
23 duration_min=2,
24 inter_min=5,
25 event_conditions=["A", "B", "A"],
27```
29Stable signature:
31```text
32events_find(
33 event_channel, threshold="auto", threshold_keep="above",
34 start_at=0, end_at=None, duration_min=1, duration_max=None,
35 inter_min=0, discard_first=0, discard_last=0,
36 event_labels=None, event_conditions=None
38```
40The default return is a dict containing `onset`, `duration`, and `label`; optional
41conditions use the singular key `condition`. Multi-channel input can add
42`events_channel` and generates conditions from the digital combination.
44Do not infer trigger semantics from amplitude alone. Verify polarity, threshold,
45debouncing, pulse width, dropped triggers, device latency, and whether simultaneous
46digital inputs are encoded as expected.

Event coordinate contract

Choose one canonical representation before analysis:

  • absolute time with a named clock and unit;
  • zero-based sample index on a named stream; and
  • event duration and condition/label metadata.

events_find() uses zero-based sample positions. Its start_at, end_at, duration_min, duration_max, and inter_min arguments are sample counts, not seconds.

events = nk.events_find(
    trigger,
    threshold=0.5,
    threshold_keep="above",
    duration_min=2,
    inter_min=5,
    event_conditions=["A", "B", "A"],
)

Stable signature:

events_find(
  event_channel, threshold="auto", threshold_keep="above",
  start_at=0, end_at=None, duration_min=1, duration_max=None,
  inter_min=0, discard_first=0, discard_last=0,
  event_labels=None, event_conditions=None
)

The default return is a dict containing onset, duration, and label; optional conditions use the singular key condition. Multi-channel input can add events_channel and generates conditions from the digital combination.

Do not infer trigger semantics from amplitude alone. Verify polarity, threshold, debouncing, pulse width, dropped triggers, device latency, and whether simultaneous digital inputs are encoded as expected.

Raw lines 6 to 47
48## Build events explicitly when possible
50```python
51events = nk.events_create(
52 event_onsets=[1000, 2500, 4000],
53 event_durations=[100, 100, 100],
54 event_labels=["1", "2", "3"],
55 event_conditions=["A", "B", "A"],
57```
59Labels must be unique. Keep experimental trial IDs outside participant-identifying
60names.

Build events explicitly when possible

events = nk.events_create(
    event_onsets=[1000, 2500, 4000],
    event_durations=[100, 100, 100],
    event_labels=["1", "2", "3"],
    event_conditions=["A", "B", "A"],
)

Labels must be unique. Keep experimental trial IDs outside participant-identifying names.

Raw lines 48 to 61
62## `epochs_create()` semantics in 0.2.13
64```text
65epochs_create(
66 data, events=None, sampling_rate=1000,
67 epochs_start=0, epochs_end="from_events",
68 event_labels=None, event_conditions=None,
69 baseline_correction=False
71```
73- `epochs_start` and `epochs_end` are seconds relative to each event.
74- The data slice is `[start_sample, end_sample)` (end-exclusive).
75- Each epoch is a DataFrame in a dict keyed by label.
76- The original sample coordinate is stored in `Index`.
77- The DataFrame index is rebuilt with `numpy.linspace(..., endpoint=True)`, so the
78 displayed last index equals `epochs_end` even though the end sample is excluded.
79- `Label` and optional `Condition` are added as columns.
80- Events near a boundary are padded by internal buffers. Floating columns receive
81 NaN; integer columns can receive zero because of dtype preservation.
83The pinned probe for one signal, `-0.2` to `0.5` s at 100 Hz, produced 70 rows with
84an index from exactly `-0.2` through `0.5`. Do not derive sample count from that
85floating index. Use `Index`, the known sampling rate, and explicit half-open bounds.

epochs_create() semantics in 0.2.13

epochs_create(
  data, events=None, sampling_rate=1000,
  epochs_start=0, epochs_end="from_events",
  event_labels=None, event_conditions=None,
  baseline_correction=False
)
  • epochs_start and epochs_end are seconds relative to each event.
  • The data slice is [start_sample, end_sample) (end-exclusive).
  • Each epoch is a DataFrame in a dict keyed by label.
  • The original sample coordinate is stored in Index.
  • The DataFrame index is rebuilt with numpy.linspace(..., endpoint=True), so the displayed last index equals epochs_end even though the end sample is excluded.
  • Label and optional Condition are added as columns.
  • Events near a boundary are padded by internal buffers. Floating columns receive NaN; integer columns can receive zero because of dtype preservation.

The pinned probe for one signal, -0.2 to 0.5 s at 100 Hz, produced 70 rows with an index from exactly -0.2 through 0.5. Do not derive sample count from that floating index. Use Index, the known sampling rate, and explicit half-open bounds.

Raw lines 62 to 86
87## Boundary policy
89Decide before analysis:
91- `drop`: remove incomplete trials and report condition-wise counts;
92- `pad`: retain them with an explicit validity mask; or
93- `error`: stop and repair event/window definitions.
95Do not let NaN padding or integer zero padding silently become a physiological
96baseline. The dependency-free planner reports affected trials:
98```bash
99python skills/neurokit2/scripts/plan_epochs.py \
100 --events 1000,2500,4000 --event-unit samples \
101 --sampling-rate 100 --recording-samples 5000 \
102 --epoch-start -0.2 --epoch-end 0.8 \
103 --baseline-start -0.2 --baseline-end 0
104```
106For events supplied in seconds, use `--event-unit seconds`; the planner rejects
107onsets/windows that do not map exactly to samples.

Boundary policy

Decide before analysis:

  • drop: remove incomplete trials and report condition-wise counts;
  • pad: retain them with an explicit validity mask; or
  • error: stop and repair event/window definitions.

Do not let NaN padding or integer zero padding silently become a physiological baseline. The dependency-free planner reports affected trials:

python skills/neurokit2/scripts/plan_epochs.py \
  --events 1000,2500,4000 --event-unit samples \
  --sampling-rate 100 --recording-samples 5000 \
  --epoch-start -0.2 --epoch-end 0.8 \
  --baseline-start -0.2 --baseline-end 0

For events supplied in seconds, use --event-unit seconds; the planner rejects onsets/windows that do not map exactly to samples.

Raw lines 87 to 108
Runs code python skills/neurokit2/scripts/plan_epochs.py :99
109## Baseline correction
111`baseline_correction=True` subtracts the mean from epoch start through `t=0`
112(inclusive in the rebuilt time index). If the epoch starts after zero, it uses the
113epoch start. The operation is applied broadly to numeric columns present at that
114point, including marker/index columns.
116Prefer selective, manual correction:
118```python
119epochs = nk.epochs_create(
120 processed,
121 events,
122 sampling_rate=100,
123 epochs_start=-0.2,
124 epochs_end=0.8,
125 baseline_correction=False,
128amplitude_columns = ["EDA_Phasic"]
129onsets_by_label = dict(zip(events["label"], events["onset"]))
130for label, epoch in epochs.items():
131 relative_samples = epoch["Index"] - onsets_by_label[label]
132 baseline = epoch.loc[(relative_samples >= -20) & (relative_samples < 0), amplitude_columns]
133 if len(baseline) != 20 or baseline.isna().any().any():
134 raise ValueError("Incomplete or missing baseline; apply the trial exclusion policy")
135 epoch.loc[:, amplitude_columns] = (
136 epoch.loc[:, amplitude_columns] - baseline.mean()
137 )
138```
140This uses original sample coordinates rather than the stretched floating time index.
141Prespecify baseline interval and estimand. Baseline subtraction is not universally
142appropriate for rates, binary peaks, phase, quality, or absolute tonic levels.
143Reject/flag a trial if its baseline has missing data or artifact rather than quietly
144using fewer samples.

Baseline correction

baseline_correction=True subtracts the mean from epoch start through t=0 (inclusive in the rebuilt time index). If the epoch starts after zero, it uses the epoch start. The operation is applied broadly to numeric columns present at that point, including marker/index columns.

Prefer selective, manual correction:

epochs = nk.epochs_create(
    processed,
    events,
    sampling_rate=100,
    epochs_start=-0.2,
    epochs_end=0.8,
    baseline_correction=False,
)

amplitude_columns = ["EDA_Phasic"]
onsets_by_label = dict(zip(events["label"], events["onset"]))
for label, epoch in epochs.items():
    relative_samples = epoch["Index"] - onsets_by_label[label]
    baseline = epoch.loc[(relative_samples >= -20) & (relative_samples < 0), amplitude_columns]
    if len(baseline) != 20 or baseline.isna().any().any():
        raise ValueError("Incomplete or missing baseline; apply the trial exclusion policy")
    epoch.loc[:, amplitude_columns] = (
        epoch.loc[:, amplitude_columns] - baseline.mean()
    )

This uses original sample coordinates rather than the stretched floating time index. Prespecify baseline interval and estimand. Baseline subtraction is not universally appropriate for rates, binary peaks, phase, quality, or absolute tonic levels. Reject/flag a trial if its baseline has missing data or artifact rather than quietly using fewer samples.

Raw lines 109 to 145
146## Conversions
148`epochs_to_df()` stacks epochs and adds a `Time` column; the stable probe observed
149`Signal`, `Index`, `Label`, `Condition`, and `Time`.
151`epochs_to_array()` does not take a `column` argument in 0.2.13. Equal-length,
152single-signal epochs produced shape `(time, epochs)` in the pinned probe. Multiple
153signal columns add an intermediate dimension. Unequal epochs are not supported.
155`epochs_average()` signature is:
157```text
158epochs_average(epochs, which=None, indices=["mean", "std", "ci"], show=False)
159```
161For `which="Signal"`, the pinned schema contained `Time`, `Signal_Mean`,
162`Signal_SD`, `Signal_CI_low`, and `Signal_CI_high` (plus a reset-index column).
163This is not a universal event-related feature schema.

Conversions

epochs_to_df() stacks epochs and adds a Time column; the stable probe observed Signal, Index, Label, Condition, and Time.

epochs_to_array() does not take a column argument in 0.2.13. Equal-length, single-signal epochs produced shape (time, epochs) in the pinned probe. Multiple signal columns add an intermediate dimension. Unequal epochs are not supported.

epochs_average() signature is:

epochs_average(epochs, which=None, indices=["mean", "std", "ci"], show=False)

For which="Signal", the pinned schema contained Time, Signal_Mean, Signal_SD, Signal_CI_low, and Signal_CI_high (plus a reset-index column). This is not a universal event-related feature schema.

Raw lines 146 to 164
165## Signal-specific analysis
167Functions such as `ecg_eventrelated()`, `eda_eventrelated()`,
168`rsp_eventrelated()`, `ppg_eventrelated()`, `emg_eventrelated()`, and
169`eog_eventrelated()` inspect available processed columns. Their output changes when
170quality, phase, amplitude, condition, or trend columns are absent.
172Use explicit dispatch:
174```python
175ecg_features = nk.ecg_analyze(
176 epochs, sampling_rate=100, method="event-related"
178```
180`method="auto"` chooses event-related analysis when mean duration is under 10 seconds.
181That software threshold is not scientific justification for a window or analysis.

Signal-specific analysis

Functions such as ecg_eventrelated(), eda_eventrelated(), rsp_eventrelated(), ppg_eventrelated(), emg_eventrelated(), and eog_eventrelated() inspect available processed columns. Their output changes when quality, phase, amplitude, condition, or trend columns are absent.

Use explicit dispatch:

ecg_features = nk.ecg_analyze(
    epochs, sampling_rate=100, method="event-related"
)

method="auto" chooses event-related analysis when mean duration is under 10 seconds. That software threshold is not scientific justification for a window or analysis.

Raw lines 165 to 182
Starts an agent dispatch :172
183## Trial QC and statistics
185Before averaging:
1871. inspect trigger detection against the raw marker channel;
1882. quantify boundary padding and missing baseline/post-event samples;
1893. apply modality-specific artifact rules without looking at condition outcomes;
1904. report retained trials per participant and condition;
1915. avoid threshold tuning on the same effects being tested; and
1926. model participant/trial hierarchy rather than treating epochs as independent.
194There is no universal minimum number of trials or universal epoch window. Determine
195both from the expected response, acquisition, study design, reliability, and power
196analysis.

Trial QC and statistics

Before averaging:

  1. inspect trigger detection against the raw marker channel;
  2. quantify boundary padding and missing baseline/post-event samples;
  3. apply modality-specific artifact rules without looking at condition outcomes;
  4. report retained trials per participant and condition;
  5. avoid threshold tuning on the same effects being tested; and
  6. model participant/trial hierarchy rather than treating epochs as independent.

There is no universal minimum number of trials or universal epoch window. Determine both from the expected response, acquisition, study design, reliability, and power analysis.

Raw lines 183 to 197
198## Sources checked 2026-10-01
200- [Official Events API](https://neuropsychology.github.io/NeuroKit/functions/events.html)
201- [Official Epochs API](https://neuropsychology.github.io/NeuroKit/functions/epochs.html)
202- [Official event-related example](https://neuropsychology.github.io/NeuroKit/examples/bio_eventrelated/bio_eventrelated.html)
203- [Stable v0.2.13 epoch source](https://github.com/neuropsychology/NeuroKit/blob/v0.2.13/neurokit2/epochs/epochs_create.py)
204- [SPR EEG/ERP guideline index](https://sprweb.org/guidelines-papers)