Detecting Gaze Events#
What you will learn in this tutorial:#
how to detect saccades using the microsaccades algorithm
how to detect fixations using the I-DT and I-VT algorithms
Preparations#
We import pymovements as the alias pm for convenience.
[1]:
import polars as pl
import pymovements as pm
/home/docs/checkouts/readthedocs.org/user_builds/pymovements/envs/v0.15.0/lib/python3.9/site-packages/tqdm/auto.py:21: TqdmWarning: IProgress not found. Please update jupyter and ipywidgets. See https://ipywidgets.readthedocs.io/en/stable/user_install.html
from .autonotebook import tqdm as notebook_tqdm
Let’s start by downloading our ToyDataset and loading in its data:
[2]:
dataset = pm.Dataset('ToyDataset', path='data/ToyDataset')
dataset.download()
dataset.load()
Downloading http://github.com/aeye-lab/pymovements-toy-dataset/zipball/6cb5d663317bf418cec0c9abe1dde5085a8a8ebd/ to data/ToyDataset/downloads/pymovements-toy-dataset.zip
pymovements-toy-dataset.zip: 100%|██████████| 3.06M/3.06M [00:00<00:00, 24.1MB/s]
Checking integrity of pymovements-toy-dataset.zip
Extracting pymovements-toy-dataset.zip to data/ToyDataset/raw
100%|██████████| 20/20 [00:00<00:00, 194.03it/s]
[2]:
<pymovements.dataset.dataset.Dataset at 0x7faad7146730>
Now let’s do some basic preprocessing:
[3]:
dataset.pix2deg()
dataset.pos2vel('smooth')
dataset.gaze[0].frame.head()
100%|██████████| 20/20 [00:00<00:00, 718.87it/s]
100%|██████████| 20/20 [00:00<00:00, 666.48it/s]
[3]:
| text_id | page_id | time | x_right_pix | y_right_pix | y_right_pos | x_right_pos | x_right_vel | y_right_vel |
|---|---|---|---|---|---|---|---|---|
| i64 | i64 | f64 | f64 | f64 | f64 | f64 | f64 | f64 |
| 0 | 1 | 1.988145e6 | 206.8 | 152.4 | -12.005591 | -7.528075 | 1.221164 | -3.589697 |
| 0 | 1 | 1.988146e6 | 206.9 | 152.1 | -12.01277 | -7.525633 | 2.442343 | -7.179203 |
| 0 | 1 | 1.988147e6 | 207.0 | 151.8 | -12.019949 | -7.52319 | 1.628238 | -5.184827 |
| 0 | 1 | 1.988148e6 | 207.1 | 151.7 | -12.022342 | -7.520748 | 0.407059 | -4.386968 |
| 0 | 1 | 1.988149e6 | 207.0 | 151.5 | -12.027128 | -7.52319 | 0.407069 | -3.190445 |
Detecting Events#
pymovements provides a range of event detection methods for several types of gaze events.
See the reference for pymovements.events to get an overview of all the supported methods.
For this tutorial we will use the microsaccades algorithm for detecting saccades and the I-DT and I-VT algorithms for detecting fixations.
We start out by detecting saccades.
[4]:
dataset.detect_events('microsaccades', minimum_duration=12)
20it [00:00, 71.09it/s]
[4]:
<pymovements.dataset.dataset.Dataset at 0x7faad7146730>
The detected events are added as rows with the name saccade to the event dataframe:
[5]:
dataset.events[0].frame.head()
[5]:
| name | onset | offset | duration | text_id | page_id |
|---|---|---|---|---|---|
| str | i64 | i64 | i64 | i64 | i64 |
| "saccade" | 1988323 | 1988337 | 14 | 0 | 1 |
| "saccade" | 1988547 | 1988567 | 20 | 0 | 1 |
| "saccade" | 1988737 | 1988760 | 23 | 0 | 1 |
| "saccade" | 1988765 | 1988777 | 12 | 0 | 1 |
| "saccade" | 1989014 | 1989031 | 17 | 0 | 1 |
Next we will detect fixations using the I-DT and I-VT algorithms.
To be able to differentiate between the detected events, we specify custom event names for each algorithm:
[6]:
dataset.detect_events('idt', dispersion_threshold=2.7, name='fixation.idt')
dataset.detect_events('ivt', velocity_threshold=20, name='fixation.ivt')
20it [00:09, 2.18it/s]
20it [00:00, 359.24it/s]
[6]:
<pymovements.dataset.dataset.Dataset at 0x7faad7146730>
This has added new rows with the fixation events to the event dataframe.
[7]:
dataset.events[0].frame.filter(pl.col('name') == 'fixation.idt').head()
[7]:
| name | onset | offset | duration | text_id | page_id |
|---|---|---|---|---|---|
| str | i64 | i64 | i64 | i64 | i64 |
| "fixation.idt" | 1988145 | 1988563 | 418 | 0 | 1 |
| "fixation.idt" | 1988564 | 1988750 | 186 | 0 | 1 |
| "fixation.idt" | 1988751 | 1989178 | 427 | 0 | 1 |
| "fixation.idt" | 1989179 | 1989436 | 257 | 0 | 1 |
| "fixation.idt" | 1989437 | 1989600 | 163 | 0 | 1 |
[8]:
dataset.events[0].frame.filter(pl.col('name') == 'fixation.ivt').head()
[8]:
| name | onset | offset | duration | text_id | page_id |
|---|---|---|---|---|---|
| str | i64 | i64 | i64 | i64 | i64 |
| "fixation.ivt" | 1988145 | 1988322 | 177 | 0 | 1 |
| "fixation.ivt" | 1988351 | 1988546 | 195 | 0 | 1 |
| "fixation.ivt" | 1988592 | 1988736 | 144 | 0 | 1 |
| "fixation.ivt" | 1988788 | 1989013 | 225 | 0 | 1 |
| "fixation.ivt" | 1989060 | 1989170 | 110 | 0 | 1 |
What you have learned in this tutorial:#
detecting saccades by using the microsaccades algorithm
detecting fixations by using the I-DT and I-VT algorithms