pyTracking: Analyzing eye-tracking data in python:

Published: 07/03/2023


I am a PhD candidate in Neuroscience at McGill University with interests in computational neuroscience. My research focuses on EEG, source reconstruction, and eye-tracking. My PhD work has focused on integrating EEG, neuroimaging, and eye-tracking data acquisition. For GSoC 2023, I am working to add support for eye-tracking to MNE-Python, the default Python package for analyzing neurophysiological data. This will make it easier for researchers to analyze eye-tracking data and gain insights into human cognition. You can learn more about the project and how you can contribute on MNE-Python's website.


Weeks 3-4

By now, we are able to load eye-tracking data, visualize the signals, and check the eye-tracking calibration quality (see week 1's blog post) for more on that).

In the last two weeks, I pivoted towards developing helper functions for pre-processing steps that researchers often need to carry out before the data can be analyzed.

For example, take blink interpolation, which is frequently applied in pupillometry research: Eye-trackers typically record the x- and y-coordinates of the screen that the eye is gazing at, and the pupil size. Naturallly, participants will blink during any given eye-tracking experiment, resulting in data loss (see the figure below).

In pupillometry research in particular, it is common to interpolate the missing pupil size data during blinks. The basic idea is that blinks are very short in duration (< 300ms), while the pupil response (i.e., the rate at which pupil size changes) is fairly slow. Thus, it is generally acceptable to interpolate the missing pupil data.


Let's plot the same data from above, after we interpolate missing data during the blink periods with our newly developed function:


import mne
from mne.datasets.eyelink import data_path
from mne.preprocessing.eyetracking import interpolate_blinks

# Load some data
fpath = data_path() / "sub-01_task-plr_eyetrack.asc"
raw =, create_annotations=["blinks"})
events = mne.find_events(raw, min_duration=0.01, shortest_event=1, uint_cast=True)
event_dict = {"Flash": 2}

# Interpolate missing data during blinks
interpolate_blinks(raw, buffer=(0.025, .2), interpolate_gaze=True)
raw.plot(events=et_events, event_id=event_dict, event_color="g")



Great! Next week, we'll synchronize this data with some simultaneously recorded EEG data. In my next blog post, I'll explain the experimental task in more detail, and we'll visualize the evoked responses to the experiment stimuli.