{ "cells": [ { "cell_type": "markdown", "id": "54c6383a", "metadata": {}, "source": [ "# Events\n", "\n", "Events are time points marked during a recording, usually triggers that\n", "the experiment software sends to the eye tracker (e.g., \"stimulus on\",\n", "\"response\"). Each event has an onset time and a label. This tutorial\n", "shows how to look at events, select the ones you need and change them,\n", "using the `Events` class." ] }, { "cell_type": "code", "execution_count": 1, "id": "7e7b5f9a", "metadata": { "execution": { "iopub.execute_input": "2026-11-10T13:34:20.829527Z", "iopub.status.busy": "2026-11-10T13:34:20.829154Z", "iopub.status.idle": "2026-11-10T13:34:22.266361Z", "shell.execute_reply": "2026-11-10T13:34:22.264939Z" } }, "outputs": [], "source": [ "import pypillometry as pp\n", "from pypillometry import u\n", "import numpy as np\n", "import matplotlib.pyplot as plt\n", "\n", "pp.logging_set_level(\"WARNING\")\n", "\n", "d = pp.get_example_data(\"rlmw_002_short\")" ] }, { "cell_type": "markdown", "id": "fc338c3a", "metadata": {}, "source": [ "## Getting the events\n", "\n", "`d.events` holds the events of a dataset as an `Events` object. In a\n", "notebook, it is shown as a table:" ] }, { "cell_type": "code", "execution_count": 2, "id": "34c4fdf9", "metadata": { "execution": { "iopub.execute_input": "2026-11-10T13:34:22.270931Z", "iopub.status.busy": "2026-11-10T13:34:22.270590Z", "iopub.status.idle": "2026-11-10T13:34:22.288166Z", "shell.execute_reply": "2026-11-10T13:34:22.286688Z" } }, "outputs": [ { "data": { "text/html": [ "
| \n", " | Onset (ms) | \n", "Label | \n", "
|---|---|---|
| 0 | \n", "5177.0 | \n", "F_1 | \n", "
| 1 | \n", "5677.0 | \n", "S_1_1_5 | \n", "
| 2 | \n", "6773.0 | \n", "C_1_5_2 | \n", "
| 3 | \n", "7010.0 | \n", "R_1_15 | \n", "
| 4 | \n", "8776.0 | \n", "F_2 | \n", "
| 5 | \n", "9575.0 | \n", "S_2_6_2 | \n", "
| 6 | \n", "10581.0 | \n", "C_2_6_1 | \n", "
| 7 | \n", "10808.0 | \n", "R_2_20 | \n", "
| 8 | \n", "12374.0 | \n", "F_3 | \n", "
| 9 | \n", "12574.0 | \n", "S_3_2_1 | \n", "
| 10 | \n", "13733.0 | \n", "C_3_2_1 | \n", "
| 11 | \n", "13957.0 | \n", "R_3_18 | \n", "
| 12 | \n", "15973.0 | \n", "F_4 | \n", "
| 13 | \n", "16473.0 | \n", "S_4_4_1 | \n", "
| 14 | \n", "17589.0 | \n", "C_4_1_2 | \n", "
| 15 | \n", "17822.0 | \n", "R_4_11 | \n", "
| 16 | \n", "19588.0 | \n", "F_5 | \n", "
| 17 | \n", "20388.0 | \n", "S_5_3_5 | \n", "
| 18 | \n", "21156.0 | \n", "C_5_5_2 | \n", "
| 19 | \n", "21388.0 | \n", "R_5_17 | \n", "
| 20 | \n", "23187.0 | \n", "F_6 | \n", "
| 21 | \n", "23987.0 | \n", "S_6_4_5 | \n", "
| 22 | \n", "24916.0 | \n", "C_6_5_2 | \n", "
| 23 | \n", "25153.0 | \n", "R_6_20 | \n", "
| 24 | \n", "26802.0 | \n", "F_7 | \n", "
| 25 | \n", "27002.0 | \n", "S_7_3_1 | \n", "
| 26 | \n", "28116.0 | \n", "C_7_1_2 | \n", "
| 27 | \n", "28352.0 | \n", "R_7_6 | \n", "
| 28 | \n", "30401.0 | \n", "F_8 | \n", "
| 29 | \n", "30601.0 | \n", "S_8_6_5 | \n", "
| 30 | \n", "31508.0 | \n", "C_8_6_1 | \n", "
| 31 | \n", "31734.0 | \n", "R_8_18 | \n", "
| 32 | \n", "34000.0 | \n", "F_9 | \n", "
| 33 | \n", "34799.0 | \n", "S_9_4_6 | \n", "
| 34 | \n", "35700.0 | \n", "C_9_6_2 | \n", "
| 35 | \n", "35932.0 | \n", "R_9_19 | \n", "
| 36 | \n", "37615.0 | \n", "F_10 | \n", "
| 37 | \n", "38415.0 | \n", "S_10_2_5 | \n", "
| 38 | \n", "39412.0 | \n", "C_10_5_2 | \n", "
| 39 | \n", "39648.0 | \n", "R_10_18 | \n", "
Total: 40 events
" ], "text/plain": [ "Events: 40 events | units=ms" ] }, "execution_count": 2, "metadata": {}, "output_type": "execute_result" } ], "source": [ "events = d.events\n", "events" ] }, { "cell_type": "markdown", "id": "b2349a29", "metadata": {}, "source": [ "The onsets are in ms. `to_units()` returns the events with the onsets in\n", "other units:" ] }, { "cell_type": "code", "execution_count": 3, "id": "61498db4", "metadata": { "execution": { "iopub.execute_input": "2026-11-10T13:34:22.291714Z", "iopub.status.busy": "2026-11-10T13:34:22.291366Z", "iopub.status.idle": "2026-11-10T13:34:22.299927Z", "shell.execute_reply": "2026-11-10T13:34:22.298713Z" } }, "outputs": [ { "data": { "text/html": [ "| \n", " | Onset (sec) | \n", "Label | \n", "
|---|---|---|
| 0 | \n", "5.177 | \n", "F_1 | \n", "
| 1 | \n", "5.677 | \n", "S_1_1_5 | \n", "
| 2 | \n", "6.773 | \n", "C_1_5_2 | \n", "
| 3 | \n", "7.010 | \n", "R_1_15 | \n", "
Total: 4 events
" ], "text/plain": [ "Events: 4 events | units=sec" ] }, "execution_count": 3, "metadata": {}, "output_type": "execute_result" } ], "source": [ "d.events.to_units(\"sec\")[:4]" ] }, { "cell_type": "code", "execution_count": 4, "id": "85fdca11", "metadata": { "execution": { "iopub.execute_input": "2026-11-10T13:34:22.302487Z", "iopub.status.busy": "2026-11-10T13:34:22.302127Z", "iopub.status.idle": "2026-11-10T13:34:22.308742Z", "shell.execute_reply": "2026-11-10T13:34:22.307685Z" } }, "outputs": [ { "data": { "text/plain": [ "array([0.08628333, 0.09461667, 0.11288333, 0.11683333])" ] }, "execution_count": 4, "metadata": {}, "output_type": "execute_result" } ], "source": [ "events.to_units(\"min\").onsets[:4]" ] }, { "cell_type": "markdown", "id": "49c0d9f3", "metadata": {}, "source": [ "The onsets and labels are stored as numpy arrays. An `Events` object has a\n", "length and can be iterated over and indexed like a list. Indexing returns\n", "a new `Events` object:" ] }, { "cell_type": "code", "execution_count": 5, "id": "b235a79a", "metadata": { "execution": { "iopub.execute_input": "2026-11-10T13:34:22.312150Z", "iopub.status.busy": "2026-11-10T13:34:22.311795Z", "iopub.status.idle": "2026-11-10T13:34:22.317262Z", "shell.execute_reply": "2026-11-10T13:34:22.316262Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "40\n", "F_1 at 5177 ms\n", "S_1_1_5 at 5677 ms\n", "C_1_5_2 at 6773 ms\n" ] } ], "source": [ "print(len(events))\n", "for onset, label in events[:3]:\n", " print(f\"{label:10s} at {onset:.0f} ms\")" ] }, { "cell_type": "code", "execution_count": 6, "id": "c34b2a98", "metadata": { "execution": { "iopub.execute_input": "2026-11-10T13:34:22.319793Z", "iopub.status.busy": "2026-11-10T13:34:22.319485Z", "iopub.status.idle": "2026-11-10T13:34:22.325410Z", "shell.execute_reply": "2026-11-10T13:34:22.324537Z" } }, "outputs": [ { "data": { "text/plain": [ "(array([5177., 5677., 6773., 7010., 8776.]),\n", " array(['F_1', 'S_1_1_5', 'C_1_5_2', 'R_1_15', 'F_2'], dtype='Total: 10 events
" ], "text/plain": [ "Events: 10 events | units=ms" ] }, "execution_count": 7, "metadata": {}, "output_type": "execute_result" } ], "source": [ "events.filter(\"S_\")" ] }, { "cell_type": "markdown", "id": "b3cf92c4", "metadata": {}, "source": [ "**A function** is called with each label and selects the events for which\n", "it returns `True`. In this dataset, the labels of the `R` events end with\n", "a number; here we select those where it is larger than 18:" ] }, { "cell_type": "code", "execution_count": 8, "id": "a8d6a63b", "metadata": { "execution": { "iopub.execute_input": "2026-11-10T13:34:22.339491Z", "iopub.status.busy": "2026-11-10T13:34:22.339197Z", "iopub.status.idle": "2026-11-10T13:34:22.347037Z", "shell.execute_reply": "2026-11-10T13:34:22.345896Z" } }, "outputs": [ { "data": { "text/html": [ "| \n", " | Onset (ms) | \n", "Label | \n", "
|---|---|---|
| 0 | \n", "10808.0 | \n", "R_2_20 | \n", "
| 1 | \n", "25153.0 | \n", "R_6_20 | \n", "
| 2 | \n", "35932.0 | \n", "R_9_19 | \n", "
Total: 3 events
" ], "text/plain": [ "Events: 3 events | units=ms" ] }, "execution_count": 8, "metadata": {}, "output_type": "execute_result" } ], "source": [ "def high_number(label):\n", " parts = label.split(\"_\")\n", " return parts[0] == \"R\" and int(parts[-1]) > 18\n", "\n", "events.filter(high_number)" ] }, { "cell_type": "markdown", "id": "bf3fffeb", "metadata": {}, "source": [ "**A tuple** `(start, end)` selects events by their onset, in the units of\n", "the `Events` object (here, ms):" ] }, { "cell_type": "code", "execution_count": 9, "id": "60f62d72", "metadata": { "execution": { "iopub.execute_input": "2026-11-10T13:34:22.350043Z", "iopub.status.busy": "2026-11-10T13:34:22.349733Z", "iopub.status.idle": "2026-11-10T13:34:22.357919Z", "shell.execute_reply": "2026-11-10T13:34:22.356695Z" } }, "outputs": [ { "data": { "text/html": [ "| \n", " | Onset (ms) | \n", "Label | \n", "
|---|---|---|
| 0 | \n", "10581.0 | \n", "C_2_6_1 | \n", "
| 1 | \n", "10808.0 | \n", "R_2_20 | \n", "
| 2 | \n", "12374.0 | \n", "F_3 | \n", "
| 3 | \n", "12574.0 | \n", "S_3_2_1 | \n", "
| 4 | \n", "13733.0 | \n", "C_3_2_1 | \n", "
| 5 | \n", "13957.0 | \n", "R_3_18 | \n", "
| 6 | \n", "15973.0 | \n", "F_4 | \n", "
| 7 | \n", "16473.0 | \n", "S_4_4_1 | \n", "
| 8 | \n", "17589.0 | \n", "C_4_1_2 | \n", "
| 9 | \n", "17822.0 | \n", "R_4_11 | \n", "
| 10 | \n", "19588.0 | \n", "F_5 | \n", "
Total: 11 events
" ], "text/plain": [ "Events: 11 events | units=ms" ] }, "execution_count": 9, "metadata": {}, "output_type": "execute_result" } ], "source": [ "events.filter((10_000, 20_000))" ] }, { "cell_type": "markdown", "id": "6d512c26", "metadata": {}, "source": [ "Since `filter()` returns a new `Events` object, filters can be chained,\n", "e.g., the `S` events in the first 20 seconds:" ] }, { "cell_type": "code", "execution_count": 10, "id": "8dd1bd00", "metadata": { "execution": { "iopub.execute_input": "2026-11-10T13:34:22.360938Z", "iopub.status.busy": "2026-11-10T13:34:22.360609Z", "iopub.status.idle": "2026-11-10T13:34:22.367879Z", "shell.execute_reply": "2026-11-10T13:34:22.367056Z" } }, "outputs": [ { "data": { "text/html": [ "| \n", " | Onset (ms) | \n", "Label | \n", "
|---|---|---|
| 0 | \n", "5677.0 | \n", "S_1_1_5 | \n", "
| 1 | \n", "9575.0 | \n", "S_2_6_2 | \n", "
| 2 | \n", "12574.0 | \n", "S_3_2_1 | \n", "
| 3 | \n", "16473.0 | \n", "S_4_4_1 | \n", "
Total: 4 events
" ], "text/plain": [ "Events: 4 events | units=ms" ] }, "execution_count": 10, "metadata": {}, "output_type": "execute_result" } ], "source": [ "events.filter(\"S_\").filter((0, 20_000))" ] }, { "cell_type": "markdown", "id": "286fd0a8", "metadata": {}, "source": [ "`test_selector()` shows which events of a dataset a selector picks out, which\n", "is useful while writing a selection function:" ] }, { "cell_type": "code", "execution_count": 11, "id": "70985d8d", "metadata": { "execution": { "iopub.execute_input": "2026-11-10T13:34:22.371320Z", "iopub.status.busy": "2026-11-10T13:34:22.370965Z", "iopub.status.idle": "2026-11-10T13:34:22.377970Z", "shell.execute_reply": "2026-11-10T13:34:22.376523Z" } }, "outputs": [ { "data": { "text/plain": [ "array(['R_2_20', 'R_6_20', 'R_9_19'], dtype='| \n", " | Onset (sec) | \n", "Label | \n", "
|---|---|---|
| 0 | \n", "1.0 | \n", "start | \n", "
| 1 | \n", "2.5 | \n", "probe | \n", "
| 2 | \n", "4.0 | \n", "end | \n", "
Total: 3 events
" ], "text/plain": [ "Events: 3 events | units=sec" ] }, "execution_count": 14, "metadata": {}, "output_type": "execute_result" } ], "source": [ "my_events = pp.Events([1, 2.5, 4] * u.sec, [\"start\", \"probe\", \"end\"])\n", "my_events" ] }, { "cell_type": "markdown", "id": "b9608dbb", "metadata": {}, "source": [ "`Events` cannot be changed in place; `set_events()` replaces the events of\n", "a dataset with new ones. For example, we can\n", "shorten the labels to just the event type (the first letter). The onsets\n", "stay the same:" ] }, { "cell_type": "code", "execution_count": 15, "id": "12164cd4", "metadata": { "execution": { "iopub.execute_input": "2026-11-10T13:34:22.821032Z", "iopub.status.busy": "2026-11-10T13:34:22.820591Z", "iopub.status.idle": "2026-11-10T13:34:22.830141Z", "shell.execute_reply": "2026-11-10T13:34:22.828808Z" } }, "outputs": [ { "data": { "text/html": [ "| \n", " | Onset (ms) | \n", "Label | \n", "
|---|---|---|
| 0 | \n", "5177.0 | \n", "F | \n", "
| 1 | \n", "5677.0 | \n", "S | \n", "
| 2 | \n", "6773.0 | \n", "C | \n", "
| 3 | \n", "7010.0 | \n", "R | \n", "
| 4 | \n", "8776.0 | \n", "F | \n", "
| 5 | \n", "9575.0 | \n", "S | \n", "
Total: 6 events
" ], "text/plain": [ "Events: 6 events | units=ms" ] }, "execution_count": 15, "metadata": {}, "output_type": "execute_result" } ], "source": [ "short_labels = [label.split(\"_\")[0] for label in events.labels]\n", "d.set_events(pp.Events(events.onsets, short_labels))\n", "d.events[:6]" ] }, { "cell_type": "markdown", "id": "f0ed0a02", "metadata": {}, "source": [ "Like the other `set_*` methods, `set_events()` always changes the object\n", "in place; use `d.copy().set_events(...)` to keep the original.\n", "\n", "As another example, we add the onset of each blink as an event. Blinks\n", "are stored as `Intervals` (see the [blinks tutorial](blinks.ipynb)); we\n", "take their start times in ms, combine them with the existing events and\n", "sort everything by time:" ] }, { "cell_type": "code", "execution_count": 16, "id": "e050b227", "metadata": { "execution": { "iopub.execute_input": "2026-11-10T13:34:22.833551Z", "iopub.status.busy": "2026-11-10T13:34:22.833202Z", "iopub.status.idle": "2026-11-10T13:34:23.990397Z", "shell.execute_reply": "2026-11-10T13:34:23.989310Z" } }, "outputs": [ { "data": { "text/html": [ "| \n", " | Onset (ms) | \n", "Label | \n", "
|---|---|---|
| 0 | \n", "5177.0 | \n", "F | \n", "
| 1 | \n", "5408.0 | \n", "blink | \n", "
| 2 | \n", "5677.0 | \n", "S | \n", "
| 3 | \n", "6773.0 | \n", "C | \n", "
| 4 | \n", "7010.0 | \n", "R | \n", "
| 5 | \n", "7562.0 | \n", "blink | \n", "
| 6 | \n", "7864.0 | \n", "blink | \n", "
| 7 | \n", "8130.0 | \n", "blink | \n", "
| 8 | \n", "8776.0 | \n", "F | \n", "
| 9 | \n", "9575.0 | \n", "S | \n", "
| 10 | \n", "10484.0 | \n", "blink | \n", "
| 11 | \n", "10581.0 | \n", "C | \n", "
Total: 12 events
" ], "text/plain": [ "Events: 12 events | units=ms" ] }, "execution_count": 16, "metadata": {}, "output_type": "execute_result" } ], "source": [ "d.pupil.blinks_detect()\n", "blinks = d.get_blinks(\"left\", \"pupil\", units=\"ms\")[\"left_pupil\"]\n", "blink_onsets = [start for start, end in blinks]\n", "\n", "events = d.events\n", "onsets = np.concatenate([events.onsets, blink_onsets])\n", "labels = np.concatenate([events.labels, [\"blink\"] * len(blink_onsets)])\n", "order = np.argsort(onsets)\n", "d.set_events(pp.Events(onsets[order], labels[order]))\n", "\n", "d.events[:12]" ] }, { "cell_type": "markdown", "id": "1ab62019", "metadata": {}, "source": [ "The blink onsets can now be used like any other event, e.g., to look at\n", "the pupil around blinks with `d.get_epochs(\"blink\", ...)`." ] }, { "cell_type": "markdown", "id": "meta-pointer", "metadata": {}, "source": [ "## Metadata\n", "\n", "Events can also carry more information, such as the trial, the condition or the reaction time, decomposed from the labels or taken from a behaviour log. Events can then be selected by it, e.g., `events.filter(\"S_\", cond=\"easy\")`. See the [event metadata tutorial](event_metadata.ipynb)." ] } ], "metadata": { "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.15.1" } }, "nbformat": 4, "nbformat_minor": 5 }