Plotting Gaze Data#

The pymovements library provides a collection of built-in plotting functions to visualize gaze data in both temporal and spatial dimensions.

These functions make it easy to explore and present your data, from individual trial visualizations to aggregated participant-level analyses.

In this tutorial, you’ll learn how to:

  • load and prepare a sample dataset for plotting

  • compute the necessary events and properties

  • plot gaze traces over time (traceplot)

  • visualize fixations on a stimulus (scanpathplot)

  • generate heatmaps showing gaze density (heatmap)

  • plot the saccadic main sequence (main-sequence)

  • style the plot

All examples use the small ToyDataset that comes with pymovements.

Loading and preprocessing data#

import matplotlib.pyplot as plt
import polars as pl

import pymovements as pm

dataset = pm.Dataset('ToyDataset', path='data/ToyDataset')
dataset.download()
dataset.load()

# Convert the raw x and y coordinates in pixels to degrees of visual angle
dataset.pix2deg()

# Compute gaze velocities in dva/s from dva coordinates.
dataset.pos2vel('smooth')
INFO:pymovements.dataset.dataset:
        You are downloading the pymovements Toy Dataset. Please be aware that pymovements does not
        host or distribute any dataset resources and only provides a convenient interface to
        download the public dataset resources that were published by their respective authors.

        Please cite the referenced publication if you intend to use the dataset in your research.
        
Using already downloaded and verified file: data/ToyDataset/downloads/pymovements-toy-dataset.zip
Extracting pymovements-toy-dataset.zip to data/ToyDataset/raw
Extracting archive:   0%|          | 0/23 [00:00<?, ?file/s]
Extracting archive: 100%|██████████| 23/23 [00:00<00:00, 362.14file/s]

Dataset
  • DatasetDefinition
    DatasetDefinition
    • 'ToyDataset'
    • 'pymovements Toy Dataset'
    • 'Example toy dataset. This dataset includes monocu...'
      'Example toy dataset.\n\nThis dataset includes monocular eye tracking data from a single participant in a single\nsession. Eye movements are recorded at a sampling frequency of 1000 Hz using an EyeLink Portable\nDuo video-based eye tracker and are provided as pixel coordinates.\n\nThe participant is instructed to read 4 texts with 5 screens each.\n'
    • Experiment
      Experiment
      • EyeTracker
        EyeTracker
        • None
        • None
        • None
        • None
        • 1000
        • None
        • None
      • Screen
        Screen
        • 68
        • 30.2
        • 1024
        • 'upper left'
        • tuple (2 items)
          • 1280
          • 1024
        • tuple (2 items)
          • 38
          • 30.2
        • 38
        • 1280
        • 15.599386487782953
        • -15.599386487782953
        • 12.508044410882546
        • -12.508044410882546
    • list (1 items)
      • ResourceDefinition
        • 'gaze'
        • 'pymovements-toy-dataset.zip'
        • 'trial_{text_id:d}_{page_id:d}.csv'
        • dict (2 items)
          • <class 'int'>
          • <class 'int'>
        • None
        • dict (4 items)
          • 'timestamp'
          • 'ms'
          • (2 more)
        • '256901852c1c07581d375eef705855d6'
        • None
        • WebSource
          WebSource(url='https://github.com/pymovements/pymovements-toy-dataset/archive/refs/heads/main.zip', filename='pymovements-toy-dataset.zip', md5='256901852c1c07581d375eef705855d6', mirrors=None)
        • 'https://github.com/pymovements/pymovements-toy-dat...'
          'https://github.com/pymovements/pymovements-toy-dataset/archive/refs/heads/main.zip'
  • tuple (20 items)
    • Events
      • DataFrame (4 columns, 0 rows)
        shape: (0, 4)
        nameonsetoffsetduration
        stri64i64i64
      • None
    • Events
      • DataFrame (4 columns, 0 rows)
        shape: (0, 4)
        nameonsetoffsetduration
        stri64i64i64
      • None
    • (18 more)
  • dict (1 items)
    • DataFrame (3 columns, 20 rows)
      shape: (20, 3)
      text_idpage_idfilepath
      i64i64str
      01"pymovements-toy-dataset-main/d…
      02"pymovements-toy-dataset-main/d…
      03"pymovements-toy-dataset-main/d…
      04"pymovements-toy-dataset-main/d…
      05"pymovements-toy-dataset-main/d…
      31"pymovements-toy-dataset-main/d…
      32"pymovements-toy-dataset-main/d…
      33"pymovements-toy-dataset-main/d…
      34"pymovements-toy-dataset-main/d…
      35"pymovements-toy-dataset-main/d…
  • list (20 items)
    • Gaze
      • DataFrame (6 columns, 17223 rows)
        shape: (17_223, 6)
        timestimuli_xstimuli_ypixelpositionvelocity
        i64f64f64list[f64]list[f64]list[f64]
        1988145-1.0-1.0[206.8, 152.4][-10.697598, -8.852399][null, null]
        1988146-1.0-1.0[206.9, 152.1][-10.695183, -8.859678][null, null]
        1988147-1.0-1.0[207.0, 151.8][-10.692768, -8.866956][1.610194, -5.256267]
        1988148-1.0-1.0[207.1, 151.7][-10.690352, -8.869381][0.402548, -4.447465]
        1988149-1.0-1.0[207.0, 151.5][-10.692768, -8.874233][0.402561, -3.234462]
        2005363-1.0-1.0[361.0, 415.4][-6.932438, -2.386672][-63.266374, -21.085616]
        2005364-1.0-1.0[358.0, 414.5][-7.006376, -2.408998][-63.249652, -19.431326]
        2005365-1.0-1.0[355.8, 413.8][-7.060582, -2.426362][-60.359624, -15.710061]
        2005366-1.0-1.0[353.1, 413.2][-7.12709, -2.441245][null, null]
        2005367-1.0-1.0[351.2, 412.9][-7.173881, -2.448686][null, null]
      • Events
        Events
        • DataFrame (4 columns, 0 rows)
          shape: (0, 4)
          nameonsetoffsetduration
          stri64i64i64
        • None
      • dict (2 items)
        • 0
        • 1
      • None
      • None
      • Experiment
        Experiment
        • EyeTracker
          EyeTracker
          • None
          • None
          • None
          • None
          • 1000
          • None
          • None
        • Screen
          Screen
          • 68
          • 30.2
          • 1024
          • 'upper left'
          • tuple (2 items)
            • 1280
            • 1024
          • tuple (2 items)
            • 38
            • 30.2
          • 38
          • 1280
          • 15.599386487782953
          • -15.599386487782953
          • 12.508044410882546
          • -12.508044410882546
    • Gaze
      • DataFrame (6 columns, 29799 rows)
        shape: (29_799, 6)
        timestimuli_xstimuli_ypixelpositionvelocity
        i64f64f64list[f64]list[f64]list[f64]
        2008305-1.0-1.0[141.4, 153.6][-12.268583, -8.823284][null, null]
        2008306-1.0-1.0[141.1, 153.2][-12.275749, -8.832989][null, null]
        2008307-1.0-1.0[140.7, 152.8][-12.285302, -8.842695][-5.572617, -6.065816]
        2008308-1.0-1.0[140.6, 152.7][-12.28769, -8.845121][-3.582268, -4.043733]
        2008309-1.0-1.0[140.5, 152.6][-12.290078, -8.847547][-2.388085, -2.021821]
        2038099-1.0-1.0[273.8, 773.8][-9.071149, 6.490168][1.21962, 1.635403]
        2038100-1.0-1.0[273.8, 774.1][-9.071149, 6.497527][1.626175, 4.497406]
        2038101-1.0-1.0[273.9, 774.5][-9.06871, 6.50734][1.626186, 1.635423]
        2038102-1.0-1.0[274.0, 774.4][-9.066271, 6.504886][null, null]
        2038103-1.0-1.0[274.0, 773.9][-9.066271, 6.492621][null, null]
      • Events
        Events
        • DataFrame (4 columns, 0 rows)
          shape: (0, 4)
          nameonsetoffsetduration
          stri64i64i64
        • None
      • dict (2 items)
        • 0
        • 2
      • None
      • None
      • Experiment
        Experiment
        • EyeTracker
          EyeTracker
          • None
          • None
          • None
          • None
          • 1000
          • None
          • None
        • Screen
          Screen
          • 68
          • 30.2
          • 1024
          • 'upper left'
          • tuple (2 items)
            • 1280
            • 1024
          • tuple (2 items)
            • 38
            • 30.2
          • 38
          • 1280
          • 15.599386487782953
          • -15.599386487782953
          • 12.508044410882546
          • -12.508044410882546
    • (18 more)
  • Participants
    Participants
    • DataFrame (1 columns, 0 rows)
      shape: (0, 1)
      participant_id
      str
    • dict (1 items)
      • dict (1 items)
        • 'string'
  • PosixPath('data/ToyDataset')
  • DatasetPaths
    DatasetPaths
    • PosixPath('data/ToyDataset')
    • PosixPath('data/ToyDataset/downloads')
    • PosixPath('data/ToyDataset/events')
    • PosixPath('data/ToyDataset/precomputed_events')
    • PosixPath('data/ToyDataset/precomputed_reading_measures')
    • PosixPath('data/ToyDataset/preprocessed')
    • PosixPath('data/ToyDataset/raw')
    • PosixPath('data/ToyDataset')
    • PosixPath('data/ToyDataset/stimuli')
  • list (0 items)
  • list (0 items)
  • list (0 items)

Plot Raw Samples#

To visualize the raw gaze data, we first select a recording and extract the horizontal and vertical coordinates.

# we will work with gaze data from the first recording
gaze = dataset.gaze[0]

# extract horizontal and vertical coordinates from the position column
df = gaze.samples

df = df.with_columns([
    pl.col("position").list.get(0).alias("pos_x"),
    pl.col("position").list.get(1).alias("pos_y"),
])

# Assign back
gaze.samples = df

Tsplot#

The tsplot() function produces a time series plot of gaze samples from a Gaze object. A time-series plot shows how each recorded signal changes over time, with one line per selected channel (e.g., horizontal and vertical gaze position).

In this example, we plot the pos_x and pos_y channels to examine the raw gaze signal before applying any event detection or preprocessing. We observe rapid jumps in the horizontal gaze position (pos_x), and slower, more gradual changes in the vertical gaze position (pos_y).

pm.plotting.tsplot(
    gaze,
    channels=['pos_x', 'pos_y'],
    # Set separate y-axis for each channel.
    share_y=False,
    line_color='darkblue',
)
plt.show()
../_images/a5c21ec92163f89689d53425704002262aab15297474491245b202e7767b1c0d.png

Traceplot#

The traceplot() function visualizes the raw gaze samples as a continuous trajectory across the stimulus. In a traceplot, each gaze sample is connected in temporal order, showing how the point of regard moves over time.

Traceplots are useful for:

  • Verifying that gaze data have been parsed and aligned correctly.

  • Exploring viewing behavior across conditions or participants.

  • Identifying artifacts or data quality issues.

A basic traceplot can be created with only a Gaze object:

pm.plotting.traceplot(gaze)
plt.show()
../_images/ee129c3d4d02ed3c8bd7f8c519d1f91c99b3bf0e6fd094e156a7bfa1156585bd.png

Detecting and Visualizing Events#

Eye-tracking data are typically segmented into events, i.e. fixations and saccades. Fixations represent moments when the eyes remain relatively still, allowing visual information to be processed, while saccades are the rapid movements between fixations that reposition the gaze. Detecting these events and computing their properties, such as fixation duration, saccade amplitude, and peak velocity, provides the foundation for analyzing visual behavior and understanding how participants explore a stimulus.

Fixations#

We can detect fixations by applying the I-VT or the I-DT method.

The I-VT (Velocity-Threshold Identification) method distinguishes fixation and saccade points based on their point-to-point velocities. Each point is classified as a fixation if its velocity is below the specified threshold. Consecutive fixation points are then merged into a single fixation. A threshold of 20 degrees/second is commonly used as a default maximum value. Read more about the IVT method in the documentation: pymovements.events.detection.ivt().

The I-DT (Dispersion-Threshold Identification) method finds fixations by grouping consecutive points within a maximum separation (dispersion) threshold and a minimum duration threshold. The algorithm slides a moving window across the data: if the dispersion within the window is below the threshold, the window represents a fixation and is gradually expanded until the dispersion exceeds the threshold. Read more about our implementation of the IDT method: pymovements.events.detection.idt().

We will use the I-DT algorithm with different dispersion threshold values to create two different sets of fixation events.

Key Parameters:

  • dispersion_threshold: Maximum dispersion allowed for fixation points. Default: 1.0 degrees

  • name: Custom name for the detected events

The mininum_duration default is 100 ms.

# Detect fixations with a stricter threshold (1.0 degrees)
dataset.detect_events('idt', dispersion_threshold=1.0, name='fixation_1.0_idt')

# Detect fixations with a standard threshold (2.7 degrees)
dataset.detect_events('idt', dispersion_threshold=2.7, name='fixation_2.7_idt')
Dataset
  • DatasetDefinition
    DatasetDefinition
    • 'ToyDataset'
    • 'pymovements Toy Dataset'
    • 'Example toy dataset. This dataset includes monocu...'
      'Example toy dataset.\n\nThis dataset includes monocular eye tracking data from a single participant in a single\nsession. Eye movements are recorded at a sampling frequency of 1000 Hz using an EyeLink Portable\nDuo video-based eye tracker and are provided as pixel coordinates.\n\nThe participant is instructed to read 4 texts with 5 screens each.\n'
    • Experiment
      Experiment
      • EyeTracker
        EyeTracker
        • None
        • None
        • None
        • None
        • 1000
        • None
        • None
      • Screen
        Screen
        • 68
        • 30.2
        • 1024
        • 'upper left'
        • tuple (2 items)
          • 1280
          • 1024
        • tuple (2 items)
          • 38
          • 30.2
        • 38
        • 1280
        • 15.599386487782953
        • -15.599386487782953
        • 12.508044410882546
        • -12.508044410882546
    • list (1 items)
      • ResourceDefinition
        • 'gaze'
        • 'pymovements-toy-dataset.zip'
        • 'trial_{text_id:d}_{page_id:d}.csv'
        • dict (2 items)
          • <class 'int'>
          • <class 'int'>
        • None
        • dict (4 items)
          • 'timestamp'
          • 'ms'
          • (2 more)
        • '256901852c1c07581d375eef705855d6'
        • None
        • WebSource
          WebSource(url='https://github.com/pymovements/pymovements-toy-dataset/archive/refs/heads/main.zip', filename='pymovements-toy-dataset.zip', md5='256901852c1c07581d375eef705855d6', mirrors=None)
        • 'https://github.com/pymovements/pymovements-toy-dat...'
          'https://github.com/pymovements/pymovements-toy-dataset/archive/refs/heads/main.zip'
  • tuple (20 items)
    • Events
      • DataFrame (4 columns, 133 rows)
        shape: (133, 4)
        nameonsetoffsetduration
        stri64i64i64
        "fixation_1.0_idt"19881451988333188
        "fixation_1.0_idt"19883341988552218
        "fixation_1.0_idt"19885571988693136
        "fixation_1.0_idt"19887511989019268
        "fixation_1.0_idt"19890231989179156
        "fixation_2.7_idt"20039292004090161
        "fixation_2.7_idt"20040912004363272
        "fixation_2.7_idt"20043642004883519
        "fixation_2.7_idt"20048852005116231
        "fixation_2.7_idt"20051172005298181
      • None
    • Events
      • DataFrame (4 columns, 225 rows)
        shape: (225, 4)
        nameonsetoffsetduration
        stri64i64i64
        "fixation_1.0_idt"20083052008486181
        "fixation_1.0_idt"20084872008612125
        "fixation_1.0_idt"20086132008813200
        "fixation_1.0_idt"20088432009059216
        "fixation_1.0_idt"20090602009211151
        "fixation_2.7_idt"20368402037175335
        "fixation_2.7_idt"20371762037424248
        "fixation_2.7_idt"20374622037644182
        "fixation_2.7_idt"20376452037824179
        "fixation_2.7_idt"20378252038103278
      • None
    • (18 more)
  • dict (1 items)
    • DataFrame (3 columns, 20 rows)
      shape: (20, 3)
      text_idpage_idfilepath
      i64i64str
      01"pymovements-toy-dataset-main/d…
      02"pymovements-toy-dataset-main/d…
      03"pymovements-toy-dataset-main/d…
      04"pymovements-toy-dataset-main/d…
      05"pymovements-toy-dataset-main/d…
      31"pymovements-toy-dataset-main/d…
      32"pymovements-toy-dataset-main/d…
      33"pymovements-toy-dataset-main/d…
      34"pymovements-toy-dataset-main/d…
      35"pymovements-toy-dataset-main/d…
  • list (20 items)
    • Gaze
      • DataFrame (8 columns, 17223 rows)
        shape: (17_223, 8)
        timestimuli_xstimuli_ypixelpositionvelocitypos_xpos_y
        i64f64f64list[f64]list[f64]list[f64]f64f64
        1988145-1.0-1.0[206.8, 152.4][-10.697598, -8.852399][null, null]-10.697598-8.852399
        1988146-1.0-1.0[206.9, 152.1][-10.695183, -8.859678][null, null]-10.695183-8.859678
        1988147-1.0-1.0[207.0, 151.8][-10.692768, -8.866956][1.610194, -5.256267]-10.692768-8.866956
        1988148-1.0-1.0[207.1, 151.7][-10.690352, -8.869381][0.402548, -4.447465]-10.690352-8.869381
        1988149-1.0-1.0[207.0, 151.5][-10.692768, -8.874233][0.402561, -3.234462]-10.692768-8.874233
        2005363-1.0-1.0[361.0, 415.4][-6.932438, -2.386672][-63.266374, -21.085616]-6.932438-2.386672
        2005364-1.0-1.0[358.0, 414.5][-7.006376, -2.408998][-63.249652, -19.431326]-7.006376-2.408998
        2005365-1.0-1.0[355.8, 413.8][-7.060582, -2.426362][-60.359624, -15.710061]-7.060582-2.426362
        2005366-1.0-1.0[353.1, 413.2][-7.12709, -2.441245][null, null]-7.12709-2.441245
        2005367-1.0-1.0[351.2, 412.9][-7.173881, -2.448686][null, null]-7.173881-2.448686
      • Events
        Events
        • DataFrame (4 columns, 133 rows)
          shape: (133, 4)
          nameonsetoffsetduration
          stri64i64i64
          "fixation_1.0_idt"19881451988333188
          "fixation_1.0_idt"19883341988552218
          "fixation_1.0_idt"19885571988693136
          "fixation_1.0_idt"19887511989019268
          "fixation_1.0_idt"19890231989179156
          "fixation_2.7_idt"20039292004090161
          "fixation_2.7_idt"20040912004363272
          "fixation_2.7_idt"20043642004883519
          "fixation_2.7_idt"20048852005116231
          "fixation_2.7_idt"20051172005298181
        • None
      • dict (2 items)
        • 0
        • 1
      • None
      • None
      • Experiment
        Experiment
        • EyeTracker
          EyeTracker
          • None
          • None
          • None
          • None
          • 1000
          • None
          • None
        • Screen
          Screen
          • 68
          • 30.2
          • 1024
          • 'upper left'
          • tuple (2 items)
            • 1280
            • 1024
          • tuple (2 items)
            • 38
            • 30.2
          • 38
          • 1280
          • 15.599386487782953
          • -15.599386487782953
          • 12.508044410882546
          • -12.508044410882546
    • Gaze
      • DataFrame (6 columns, 29799 rows)
        shape: (29_799, 6)
        timestimuli_xstimuli_ypixelpositionvelocity
        i64f64f64list[f64]list[f64]list[f64]
        2008305-1.0-1.0[141.4, 153.6][-12.268583, -8.823284][null, null]
        2008306-1.0-1.0[141.1, 153.2][-12.275749, -8.832989][null, null]
        2008307-1.0-1.0[140.7, 152.8][-12.285302, -8.842695][-5.572617, -6.065816]
        2008308-1.0-1.0[140.6, 152.7][-12.28769, -8.845121][-3.582268, -4.043733]
        2008309-1.0-1.0[140.5, 152.6][-12.290078, -8.847547][-2.388085, -2.021821]
        2038099-1.0-1.0[273.8, 773.8][-9.071149, 6.490168][1.21962, 1.635403]
        2038100-1.0-1.0[273.8, 774.1][-9.071149, 6.497527][1.626175, 4.497406]
        2038101-1.0-1.0[273.9, 774.5][-9.06871, 6.50734][1.626186, 1.635423]
        2038102-1.0-1.0[274.0, 774.4][-9.066271, 6.504886][null, null]
        2038103-1.0-1.0[274.0, 773.9][-9.066271, 6.492621][null, null]
      • Events
        Events
        • DataFrame (4 columns, 225 rows)
          shape: (225, 4)
          nameonsetoffsetduration
          stri64i64i64
          "fixation_1.0_idt"20083052008486181
          "fixation_1.0_idt"20084872008612125
          "fixation_1.0_idt"20086132008813200
          "fixation_1.0_idt"20088432009059216
          "fixation_1.0_idt"20090602009211151
          "fixation_2.7_idt"20368402037175335
          "fixation_2.7_idt"20371762037424248
          "fixation_2.7_idt"20374622037644182
          "fixation_2.7_idt"20376452037824179
          "fixation_2.7_idt"20378252038103278
        • None
      • dict (2 items)
        • 0
        • 2
      • None
      • None
      • Experiment
        Experiment
        • EyeTracker
          EyeTracker
          • None
          • None
          • None
          • None
          • 1000
          • None
          • None
        • Screen
          Screen
          • 68
          • 30.2
          • 1024
          • 'upper left'
          • tuple (2 items)
            • 1280
            • 1024
          • tuple (2 items)
            • 38
            • 30.2
          • 38
          • 1280
          • 15.599386487782953
          • -15.599386487782953
          • 12.508044410882546
          • -12.508044410882546
    • (18 more)
  • Participants
    Participants
    • DataFrame (1 columns, 0 rows)
      shape: (0, 1)
      participant_id
      str
    • dict (1 items)
      • dict (1 items)
        • 'string'
  • PosixPath('data/ToyDataset')
  • DatasetPaths
    DatasetPaths
    • PosixPath('data/ToyDataset')
    • PosixPath('data/ToyDataset/downloads')
    • PosixPath('data/ToyDataset/events')
    • PosixPath('data/ToyDataset/precomputed_events')
    • PosixPath('data/ToyDataset/precomputed_reading_measures')
    • PosixPath('data/ToyDataset/preprocessed')
    • PosixPath('data/ToyDataset/raw')
    • PosixPath('data/ToyDataset')
    • PosixPath('data/ToyDataset/stimuli')
  • list (0 items)
  • list (0 items)
  • list (0 items)

Calculating Fixation Properties#

The property location will be used for visualization purposes. It is added as a separate column named location in the events DataFrame, containing the centroid coordinates of each fixation.

Key Parameter:

  • position_column: Specifies which coordinate system to use for the property. By default, fixation centroids are computed in degrees of visual angle. To obtain fixation centroids in pixel coordinates, this parameter must be explicitly set to pixel.

# Compute fixation locations using pixel coordinates
dataset.compute_event_properties(("location", {'position_column': 'pixel'}))
Dataset
  • DatasetDefinition
    DatasetDefinition
    • 'ToyDataset'
    • 'pymovements Toy Dataset'
    • 'Example toy dataset. This dataset includes monocu...'
      'Example toy dataset.\n\nThis dataset includes monocular eye tracking data from a single participant in a single\nsession. Eye movements are recorded at a sampling frequency of 1000 Hz using an EyeLink Portable\nDuo video-based eye tracker and are provided as pixel coordinates.\n\nThe participant is instructed to read 4 texts with 5 screens each.\n'
    • Experiment
      Experiment
      • EyeTracker
        EyeTracker
        • None
        • None
        • None
        • None
        • 1000
        • None
        • None
      • Screen
        Screen
        • 68
        • 30.2
        • 1024
        • 'upper left'
        • tuple (2 items)
          • 1280
          • 1024
        • tuple (2 items)
          • 38
          • 30.2
        • 38
        • 1280
        • 15.599386487782953
        • -15.599386487782953
        • 12.508044410882546
        • -12.508044410882546
    • list (1 items)
      • ResourceDefinition
        • 'gaze'
        • 'pymovements-toy-dataset.zip'
        • 'trial_{text_id:d}_{page_id:d}.csv'
        • dict (2 items)
          • <class 'int'>
          • <class 'int'>
        • None
        • dict (4 items)
          • 'timestamp'
          • 'ms'
          • (2 more)
        • '256901852c1c07581d375eef705855d6'
        • None
        • WebSource
          WebSource(url='https://github.com/pymovements/pymovements-toy-dataset/archive/refs/heads/main.zip', filename='pymovements-toy-dataset.zip', md5='256901852c1c07581d375eef705855d6', mirrors=None)
        • 'https://github.com/pymovements/pymovements-toy-dat...'
          'https://github.com/pymovements/pymovements-toy-dataset/archive/refs/heads/main.zip'
  • tuple (20 items)
    • Events
      • DataFrame (5 columns, 133 rows)
        shape: (133, 5)
        nameonsetoffsetdurationlocation
        stri64i64i64list[f64]
        "fixation_1.0_idt"19881451988333188[206.379894, 151.608995]
        "fixation_1.0_idt"19883341988552218[166.777626, 147.768037]
        "fixation_1.0_idt"19885571988693136[251.581752, 153.005839]
        "fixation_1.0_idt"19887511989019268[375.653903, 156.864684]
        "fixation_1.0_idt"19890231989179156[447.535032, 153.984713]
        "fixation_2.7_idt"20039292004090161[512.546914, 480.77963]
        "fixation_2.7_idt"20040912004363272[612.157875, 484.94652]
        "fixation_2.7_idt"20043642004883519[742.400962, 484.479615]
        "fixation_2.7_idt"20048852005116231[894.493966, 480.440948]
        "fixation_2.7_idt"20051172005298181[932.2, 481.715385]
      • None
    • Events
      • DataFrame (5 columns, 225 rows)
        shape: (225, 5)
        nameonsetoffsetdurationlocation
        stri64i64i64list[f64]
        "fixation_1.0_idt"20083052008486181[142.429121, 152.132418]
        "fixation_1.0_idt"20084872008612125[161.310317, 136.746032]
        "fixation_1.0_idt"20086132008813200[227.342289, 140.28806]
        "fixation_1.0_idt"20088432009059216[407.776498, 146.75576]
        "fixation_1.0_idt"20090602009211151[384.065789, 149.804605]
        "fixation_2.7_idt"20368402037175335[963.833036, 721.000298]
        "fixation_2.7_idt"20371762037424248[887.351406, 719.088755]
        "fixation_2.7_idt"20374622037644182[212.069399, 768.237705]
        "fixation_2.7_idt"20376452037824179[174.477222, 781.421111]
        "fixation_2.7_idt"20378252038103278[270.465591, 773.858781]
      • None
    • (18 more)
  • dict (1 items)
    • DataFrame (3 columns, 20 rows)
      shape: (20, 3)
      text_idpage_idfilepath
      i64i64str
      01"pymovements-toy-dataset-main/d…
      02"pymovements-toy-dataset-main/d…
      03"pymovements-toy-dataset-main/d…
      04"pymovements-toy-dataset-main/d…
      05"pymovements-toy-dataset-main/d…
      31"pymovements-toy-dataset-main/d…
      32"pymovements-toy-dataset-main/d…
      33"pymovements-toy-dataset-main/d…
      34"pymovements-toy-dataset-main/d…
      35"pymovements-toy-dataset-main/d…
  • list (20 items)
    • Gaze
      • DataFrame (8 columns, 17223 rows)
        shape: (17_223, 8)
        timestimuli_xstimuli_ypixelpositionvelocitypos_xpos_y
        i64f64f64list[f64]list[f64]list[f64]f64f64
        1988145-1.0-1.0[206.8, 152.4][-10.697598, -8.852399][null, null]-10.697598-8.852399
        1988146-1.0-1.0[206.9, 152.1][-10.695183, -8.859678][null, null]-10.695183-8.859678
        1988147-1.0-1.0[207.0, 151.8][-10.692768, -8.866956][1.610194, -5.256267]-10.692768-8.866956
        1988148-1.0-1.0[207.1, 151.7][-10.690352, -8.869381][0.402548, -4.447465]-10.690352-8.869381
        1988149-1.0-1.0[207.0, 151.5][-10.692768, -8.874233][0.402561, -3.234462]-10.692768-8.874233
        2005363-1.0-1.0[361.0, 415.4][-6.932438, -2.386672][-63.266374, -21.085616]-6.932438-2.386672
        2005364-1.0-1.0[358.0, 414.5][-7.006376, -2.408998][-63.249652, -19.431326]-7.006376-2.408998
        2005365-1.0-1.0[355.8, 413.8][-7.060582, -2.426362][-60.359624, -15.710061]-7.060582-2.426362
        2005366-1.0-1.0[353.1, 413.2][-7.12709, -2.441245][null, null]-7.12709-2.441245
        2005367-1.0-1.0[351.2, 412.9][-7.173881, -2.448686][null, null]-7.173881-2.448686
      • Events
        Events
        • DataFrame (5 columns, 133 rows)
          shape: (133, 5)
          nameonsetoffsetdurationlocation
          stri64i64i64list[f64]
          "fixation_1.0_idt"19881451988333188[206.379894, 151.608995]
          "fixation_1.0_idt"19883341988552218[166.777626, 147.768037]
          "fixation_1.0_idt"19885571988693136[251.581752, 153.005839]
          "fixation_1.0_idt"19887511989019268[375.653903, 156.864684]
          "fixation_1.0_idt"19890231989179156[447.535032, 153.984713]
          "fixation_2.7_idt"20039292004090161[512.546914, 480.77963]
          "fixation_2.7_idt"20040912004363272[612.157875, 484.94652]
          "fixation_2.7_idt"20043642004883519[742.400962, 484.479615]
          "fixation_2.7_idt"20048852005116231[894.493966, 480.440948]
          "fixation_2.7_idt"20051172005298181[932.2, 481.715385]
        • None
      • dict (2 items)
        • 0
        • 1
      • None
      • None
      • Experiment
        Experiment
        • EyeTracker
          EyeTracker
          • None
          • None
          • None
          • None
          • 1000
          • None
          • None
        • Screen
          Screen
          • 68
          • 30.2
          • 1024
          • 'upper left'
          • tuple (2 items)
            • 1280
            • 1024
          • tuple (2 items)
            • 38
            • 30.2
          • 38
          • 1280
          • 15.599386487782953
          • -15.599386487782953
          • 12.508044410882546
          • -12.508044410882546
    • Gaze
      • DataFrame (6 columns, 29799 rows)
        shape: (29_799, 6)
        timestimuli_xstimuli_ypixelpositionvelocity
        i64f64f64list[f64]list[f64]list[f64]
        2008305-1.0-1.0[141.4, 153.6][-12.268583, -8.823284][null, null]
        2008306-1.0-1.0[141.1, 153.2][-12.275749, -8.832989][null, null]
        2008307-1.0-1.0[140.7, 152.8][-12.285302, -8.842695][-5.572617, -6.065816]
        2008308-1.0-1.0[140.6, 152.7][-12.28769, -8.845121][-3.582268, -4.043733]
        2008309-1.0-1.0[140.5, 152.6][-12.290078, -8.847547][-2.388085, -2.021821]
        2038099-1.0-1.0[273.8, 773.8][-9.071149, 6.490168][1.21962, 1.635403]
        2038100-1.0-1.0[273.8, 774.1][-9.071149, 6.497527][1.626175, 4.497406]
        2038101-1.0-1.0[273.9, 774.5][-9.06871, 6.50734][1.626186, 1.635423]
        2038102-1.0-1.0[274.0, 774.4][-9.066271, 6.504886][null, null]
        2038103-1.0-1.0[274.0, 773.9][-9.066271, 6.492621][null, null]
      • Events
        Events
        • DataFrame (5 columns, 225 rows)
          shape: (225, 5)
          nameonsetoffsetdurationlocation
          stri64i64i64list[f64]
          "fixation_1.0_idt"20083052008486181[142.429121, 152.132418]
          "fixation_1.0_idt"20084872008612125[161.310317, 136.746032]
          "fixation_1.0_idt"20086132008813200[227.342289, 140.28806]
          "fixation_1.0_idt"20088432009059216[407.776498, 146.75576]
          "fixation_1.0_idt"20090602009211151[384.065789, 149.804605]
          "fixation_2.7_idt"20368402037175335[963.833036, 721.000298]
          "fixation_2.7_idt"20371762037424248[887.351406, 719.088755]
          "fixation_2.7_idt"20374622037644182[212.069399, 768.237705]
          "fixation_2.7_idt"20376452037824179[174.477222, 781.421111]
          "fixation_2.7_idt"20378252038103278[270.465591, 773.858781]
        • None
      • dict (2 items)
        • 0
        • 2
      • None
      • None
      • Experiment
        Experiment
        • EyeTracker
          EyeTracker
          • None
          • None
          • None
          • None
          • 1000
          • None
          • None
        • Screen
          Screen
          • 68
          • 30.2
          • 1024
          • 'upper left'
          • tuple (2 items)
            • 1280
            • 1024
          • tuple (2 items)
            • 38
            • 30.2
          • 38
          • 1280
          • 15.599386487782953
          • -15.599386487782953
          • 12.508044410882546
          • -12.508044410882546
    • (18 more)
  • Participants
    Participants
    • DataFrame (1 columns, 0 rows)
      shape: (0, 1)
      participant_id
      str
    • dict (1 items)
      • dict (1 items)
        • 'string'
  • PosixPath('data/ToyDataset')
  • DatasetPaths
    DatasetPaths
    • PosixPath('data/ToyDataset')
    • PosixPath('data/ToyDataset/downloads')
    • PosixPath('data/ToyDataset/events')
    • PosixPath('data/ToyDataset/precomputed_events')
    • PosixPath('data/ToyDataset/precomputed_reading_measures')
    • PosixPath('data/ToyDataset/preprocessed')
    • PosixPath('data/ToyDataset/raw')
    • PosixPath('data/ToyDataset')
    • PosixPath('data/ToyDataset/stimuli')
  • list (0 items)
  • list (0 items)
  • list (0 items)

Creating the Scanpath Plot#

The scanpathplot() function visualizes the sequence of fixations as circles placed at their spatial locations, with circle size indicating fixation duration. Each fixation has an arrow pointing to the next fixation in viewing order.

# show all unique event names in the gaze events frame
gaze.events.frame.select('name').unique().to_series().to_list()
['fixation_1.0_idt', 'fixation_2.7_idt']
pm.plotting.scanpathplot(gaze, event_name='fixation_1.0_idt')
plt.show()
../_images/d6c3d72d094cbf28dc9a00670fa84b07985b11c0f7a8454edeb89deab3cd4dcd.png
pm.plotting.scanpathplot(gaze, event_name='fixation_2.7_idt')
plt.show()
../_images/e74b0452916981d2299e533465c0af616ffcfa41feb7a03757aeba934998559e.png

By default, arrows are curved to prevent overlap with the stimulus (e.g., text). The curvature of the arrows is controlled by the arrow_rad parameter. Setting arrow_rad to zero disables the curvature and results in straight arrows, as shown below.

pm.plotting.scanpathplot(gaze, event_name='fixation_2.7_idt', arrow_rad=0.0)
plt.show()
../_images/d8363f65e5bae172ef4c5cb95b59360508abdc5640989983f803b4cfe6e0e474.png

We can create an enhanced visualization by overlaying the scanpath plot with the traceplot. This shows both the fixations, their duration, and the raw gaze trajectory.

pm.plotting.scanpathplot(gaze, event_name='fixation_2.7_idt', add_traceplot=True, add_arrows=False)
plt.show()
../_images/1b556c40c38d6cc4374acca0fc901a8f287e60c127fe301355d1f858738fe9b7.png

Heatmap Plotting#

The heatmap visualizes the spatial distribution of gaze samples across the experiment screen. Each cell’s color value reflects the cumulative time (in seconds) that the gaze samples were recorded at that position.

We can use the heatmap() from the pymovements library with the default values for gridsize (10x10), interpolation, and the colorbar.

pm.plotting.heatmap(gaze)
plt.show()
../_images/4a5ff5a85271422f714266a7aec1b1566a19dd713613c92c373dac39bb679112.png

Furthermore, we can customize various aspects of the heatmap plot, such as the grid size, color map, and the labels.

pm.plotting.heatmap(
    gaze=gaze,
    position_column='pixel',
    origin='upper',
    show_cbar=True,
    cbar_label='Time [s]',
    title='Gaze Heatmap with Interpolation On',
    xlabel='X [pix]',
    ylabel='Y [pix]',
    gridsize=[10, 10],
)
plt.show()
../_images/a3387ffeb205c0f92469bb1b503bdacc0f7be0287871ad0379f012444b359626.png

To better understand the effect of the gridsize parameter on the heatmap, we can turn off the interpolation. By doing this, we can clearly visualize the individual bins used to calculate the heatmap. With interpolation turned off, the heatmap will display the raw bin values rather than a smoothed representation.

pm.plotting.heatmap(
    gaze,
    position_column='pixel',
    origin='upper',
    show_cbar=True,
    cbar_label='Time [s]',
    title='Gaze Heatmap with Interpolation Off',
    xlabel='X [pix]',
    ylabel='Y [pix]',
    gridsize=[10, 10],
    interpolation='none'
)
plt.show()
../_images/029053f748985dbca0767731971a41cdbdd25f0396273ec6d1a456cb7402df2a.png

Increasing the gridsize parameter results in a finer grid and more detailed heatmap representation. With a higher grid size, we divide the plot into smaller bins, which can capture more nuances in the data distribution

pm.plotting.heatmap(
    dataset.gaze[5],
    position_column='pixel',
    origin='upper',
    show_cbar=True,
    cbar_label='Time [s]',
    title='Gaze Heatmap with Higher Grid Size',
    xlabel='X [pix]',
    ylabel='Y [pix]',
    gridsize=[25, 25]
)
plt.show()
../_images/508268c66eb27078f8a7848b136e6096b53dd5d84ee94f89638e23831ab74231.png

Detect Saccades and Compute Amplitude and Peak Velocity#

Saccades are rapid eye movements that shift the point of fixation from one location to another. We detect saccades (or micro-saccades) from the velocity sequence of gaze data using the microsaccades() algorithm. This algorithm implements a noise-adaptive velocity threshold, meaning that the detection threshold automatically scales with the noise level of the velocity signal.

Key Parameters:

  • threshold_factor: Multiplier used to determine the velocity threshold relative to the noise level of the signal. The default value is 6. A higher factor makes the algorithm more conservative (detects fewer saccades), while a lower factor makes it more sensitive.

  • minimum_duration: Defines how long a velocity peak must persist to be classified as a saccade. The duration is expressed in the same units as timesteps. If no timesteps are provided, the value refers to the number of samples (default = 6), which corresponds to about 12 ms at a 500 Hz sampling rate. Shorter events are ignored as noise.

# detect saccades using the microsaccades algorithm
dataset.detect_events('microsaccades', minimum_duration=6, threshold_factor=6)
Dataset
  • DatasetDefinition
    DatasetDefinition
    • 'ToyDataset'
    • 'pymovements Toy Dataset'
    • 'Example toy dataset. This dataset includes monocu...'
      'Example toy dataset.\n\nThis dataset includes monocular eye tracking data from a single participant in a single\nsession. Eye movements are recorded at a sampling frequency of 1000 Hz using an EyeLink Portable\nDuo video-based eye tracker and are provided as pixel coordinates.\n\nThe participant is instructed to read 4 texts with 5 screens each.\n'
    • Experiment
      Experiment
      • EyeTracker
        EyeTracker
        • None
        • None
        • None
        • None
        • 1000
        • None
        • None
      • Screen
        Screen
        • 68
        • 30.2
        • 1024
        • 'upper left'
        • tuple (2 items)
          • 1280
          • 1024
        • tuple (2 items)
          • 38
          • 30.2
        • 38
        • 1280
        • 15.599386487782953
        • -15.599386487782953
        • 12.508044410882546
        • -12.508044410882546
    • list (1 items)
      • ResourceDefinition
        • 'gaze'
        • 'pymovements-toy-dataset.zip'
        • 'trial_{text_id:d}_{page_id:d}.csv'
        • dict (2 items)
          • <class 'int'>
          • <class 'int'>
        • None
        • dict (4 items)
          • 'timestamp'
          • 'ms'
          • (2 more)
        • '256901852c1c07581d375eef705855d6'
        • None
        • WebSource
          WebSource(url='https://github.com/pymovements/pymovements-toy-dataset/archive/refs/heads/main.zip', filename='pymovements-toy-dataset.zip', md5='256901852c1c07581d375eef705855d6', mirrors=None)
        • 'https://github.com/pymovements/pymovements-toy-dat...'
          'https://github.com/pymovements/pymovements-toy-dataset/archive/refs/heads/main.zip'
  • tuple (20 items)
    • Events
      • DataFrame (5 columns, 275 rows)
        shape: (275, 5)
        nameonsetoffsetdurationlocation
        stri64i64i64list[f64]
        "fixation_1.0_idt"19881451988333188[206.379894, 151.608995]
        "fixation_1.0_idt"19883341988552218[166.777626, 147.768037]
        "fixation_1.0_idt"19885571988693136[251.581752, 153.005839]
        "fixation_1.0_idt"19887511989019268[375.653903, 156.864684]
        "fixation_1.0_idt"19890231989179156[447.535032, 153.984713]
        "saccade"2005110200512616null
        "saccade"2005128200513810null
        "saccade"2005288200534557null
        "saccade"200534720053569null
        "saccade"200535920053656null
      • None
    • Events
      • DataFrame (5 columns, 458 rows)
        shape: (458, 5)
        nameonsetoffsetdurationlocation
        stri64i64i64list[f64]
        "fixation_1.0_idt"20083052008486181[142.429121, 152.132418]
        "fixation_1.0_idt"20084872008612125[161.310317, 136.746032]
        "fixation_1.0_idt"20086132008813200[227.342289, 140.28806]
        "fixation_1.0_idt"20088432009059216[407.776498, 146.75576]
        "fixation_1.0_idt"20090602009211151[384.065789, 149.804605]
        "saccade"2037638203765416null
        "saccade"2037656203766610null
        "saccade"2037812203783018null
        "saccade"203783220378397null
        "saccade"203784520378516null
      • None
    • (18 more)
  • dict (1 items)
    • DataFrame (3 columns, 20 rows)
      shape: (20, 3)
      text_idpage_idfilepath
      i64i64str
      01"pymovements-toy-dataset-main/d…
      02"pymovements-toy-dataset-main/d…
      03"pymovements-toy-dataset-main/d…
      04"pymovements-toy-dataset-main/d…
      05"pymovements-toy-dataset-main/d…
      31"pymovements-toy-dataset-main/d…
      32"pymovements-toy-dataset-main/d…
      33"pymovements-toy-dataset-main/d…
      34"pymovements-toy-dataset-main/d…
      35"pymovements-toy-dataset-main/d…
  • list (20 items)
    • Gaze
      • DataFrame (8 columns, 17223 rows)
        shape: (17_223, 8)
        timestimuli_xstimuli_ypixelpositionvelocitypos_xpos_y
        i64f64f64list[f64]list[f64]list[f64]f64f64
        1988145-1.0-1.0[206.8, 152.4][-10.697598, -8.852399][null, null]-10.697598-8.852399
        1988146-1.0-1.0[206.9, 152.1][-10.695183, -8.859678][null, null]-10.695183-8.859678
        1988147-1.0-1.0[207.0, 151.8][-10.692768, -8.866956][1.610194, -5.256267]-10.692768-8.866956
        1988148-1.0-1.0[207.1, 151.7][-10.690352, -8.869381][0.402548, -4.447465]-10.690352-8.869381
        1988149-1.0-1.0[207.0, 151.5][-10.692768, -8.874233][0.402561, -3.234462]-10.692768-8.874233
        2005363-1.0-1.0[361.0, 415.4][-6.932438, -2.386672][-63.266374, -21.085616]-6.932438-2.386672
        2005364-1.0-1.0[358.0, 414.5][-7.006376, -2.408998][-63.249652, -19.431326]-7.006376-2.408998
        2005365-1.0-1.0[355.8, 413.8][-7.060582, -2.426362][-60.359624, -15.710061]-7.060582-2.426362
        2005366-1.0-1.0[353.1, 413.2][-7.12709, -2.441245][null, null]-7.12709-2.441245
        2005367-1.0-1.0[351.2, 412.9][-7.173881, -2.448686][null, null]-7.173881-2.448686
      • Events
        Events
        • DataFrame (5 columns, 275 rows)
          shape: (275, 5)
          nameonsetoffsetdurationlocation
          stri64i64i64list[f64]
          "fixation_1.0_idt"19881451988333188[206.379894, 151.608995]
          "fixation_1.0_idt"19883341988552218[166.777626, 147.768037]
          "fixation_1.0_idt"19885571988693136[251.581752, 153.005839]
          "fixation_1.0_idt"19887511989019268[375.653903, 156.864684]
          "fixation_1.0_idt"19890231989179156[447.535032, 153.984713]
          "saccade"2005110200512616null
          "saccade"2005128200513810null
          "saccade"2005288200534557null
          "saccade"200534720053569null
          "saccade"200535920053656null
        • None
      • dict (2 items)
        • 0
        • 1
      • None
      • None
      • Experiment
        Experiment
        • EyeTracker
          EyeTracker
          • None
          • None
          • None
          • None
          • 1000
          • None
          • None
        • Screen
          Screen
          • 68
          • 30.2
          • 1024
          • 'upper left'
          • tuple (2 items)
            • 1280
            • 1024
          • tuple (2 items)
            • 38
            • 30.2
          • 38
          • 1280
          • 15.599386487782953
          • -15.599386487782953
          • 12.508044410882546
          • -12.508044410882546
    • Gaze
      • DataFrame (6 columns, 29799 rows)
        shape: (29_799, 6)
        timestimuli_xstimuli_ypixelpositionvelocity
        i64f64f64list[f64]list[f64]list[f64]
        2008305-1.0-1.0[141.4, 153.6][-12.268583, -8.823284][null, null]
        2008306-1.0-1.0[141.1, 153.2][-12.275749, -8.832989][null, null]
        2008307-1.0-1.0[140.7, 152.8][-12.285302, -8.842695][-5.572617, -6.065816]
        2008308-1.0-1.0[140.6, 152.7][-12.28769, -8.845121][-3.582268, -4.043733]
        2008309-1.0-1.0[140.5, 152.6][-12.290078, -8.847547][-2.388085, -2.021821]
        2038099-1.0-1.0[273.8, 773.8][-9.071149, 6.490168][1.21962, 1.635403]
        2038100-1.0-1.0[273.8, 774.1][-9.071149, 6.497527][1.626175, 4.497406]
        2038101-1.0-1.0[273.9, 774.5][-9.06871, 6.50734][1.626186, 1.635423]
        2038102-1.0-1.0[274.0, 774.4][-9.066271, 6.504886][null, null]
        2038103-1.0-1.0[274.0, 773.9][-9.066271, 6.492621][null, null]
      • Events
        Events
        • DataFrame (5 columns, 458 rows)
          shape: (458, 5)
          nameonsetoffsetdurationlocation
          stri64i64i64list[f64]
          "fixation_1.0_idt"20083052008486181[142.429121, 152.132418]
          "fixation_1.0_idt"20084872008612125[161.310317, 136.746032]
          "fixation_1.0_idt"20086132008813200[227.342289, 140.28806]
          "fixation_1.0_idt"20088432009059216[407.776498, 146.75576]
          "fixation_1.0_idt"20090602009211151[384.065789, 149.804605]
          "saccade"2037638203765416null
          "saccade"2037656203766610null
          "saccade"2037812203783018null
          "saccade"203783220378397null
          "saccade"203784520378516null
        • None
      • dict (2 items)
        • 0
        • 2
      • None
      • None
      • Experiment
        Experiment
        • EyeTracker
          EyeTracker
          • None
          • None
          • None
          • None
          • 1000
          • None
          • None
        • Screen
          Screen
          • 68
          • 30.2
          • 1024
          • 'upper left'
          • tuple (2 items)
            • 1280
            • 1024
          • tuple (2 items)
            • 38
            • 30.2
          • 38
          • 1280
          • 15.599386487782953
          • -15.599386487782953
          • 12.508044410882546
          • -12.508044410882546
    • (18 more)
  • Participants
    Participants
    • DataFrame (1 columns, 0 rows)
      shape: (0, 1)
      participant_id
      str
    • dict (1 items)
      • dict (1 items)
        • 'string'
  • PosixPath('data/ToyDataset')
  • DatasetPaths
    DatasetPaths
    • PosixPath('data/ToyDataset')
    • PosixPath('data/ToyDataset/downloads')
    • PosixPath('data/ToyDataset/events')
    • PosixPath('data/ToyDataset/precomputed_events')
    • PosixPath('data/ToyDataset/precomputed_reading_measures')
    • PosixPath('data/ToyDataset/preprocessed')
    • PosixPath('data/ToyDataset/raw')
    • PosixPath('data/ToyDataset')
    • PosixPath('data/ToyDataset/stimuli')
  • list (0 items)
  • list (0 items)
  • list (0 items)
# compute amplitude and peak velocity of the detected saccades
dataset.compute_event_properties(['amplitude', 'peak_velocity'])

#  the DataFrame with detected events should now contain the following columns:
#  name, onset, offset, duration, amplitude, peak_velocity, location
dataset.events[0]
Events
  • DataFrame (7 columns, 275 rows)
    shape: (275, 7)
    nameonsetoffsetdurationlocationamplitudepeak_velocity
    stri64i64i64list[f64]f64f64
    "fixation_1.0_idt"19881451988333188[206.379894, 151.608995]1.031626129.856451
    "fixation_1.0_idt"19883341988552218[166.777626, 147.768037]0.873256180.394462
    "fixation_1.0_idt"19885571988693136[251.581752, 153.005839]0.879847162.993188
    "fixation_1.0_idt"19887511989019268[375.653903, 156.864684]0.988497199.578073
    "fixation_1.0_idt"19890231989179156[447.535032, 153.984713]0.924994176.901126
    "saccade"2005110200512616null1.405354137.917594
    "saccade"2005128200513810null0.4409861.197926
    "saccade"2005288200534557null14.682541352.550667
    "saccade"200534720053569null0.62986185.484987
    "saccade"200535920053656null0.36826866.68761
  • None

Plotting the Saccadic Main Sequence#

The saccadic main sequence describes the characteristic relationship between a saccade’s amplitude and its peak velocity: larger saccades tend to be faster, following a nonlinear, saturating curve. It is commonly used to validate saccade detection and assess data quality, since deviations from the expected pattern can indicate recording errors or atypical oculomotor behavior.

Optionally, a linear fit can be added to the plot (via fit=True), together with an evaluation metric (fit_measure='r2' or 's') to quantify how well the detected saccades follow the expected main-sequence relationship.

We employ the main_sequence_plot() function to createt this visualization.

# show the first three event dataframes.
# note that you can adjust the styling of the plot, e.g. setting a low
# alpha value allows you to change transparency to see overlapping data points
for event_df in dataset.events[:3]:
    pm.plotting.main_sequence_plot(
        event_df,
        event_name='saccade',
        fit=True,
        title='Main sequence plot',
        marker='x',
        marker_size=30,
        marker_color='green',
        marker_alpha=0.5,
    )
    plt.show()
../_images/c5b817ab4554889a6471eb9e97710d8c123a4d2992d4099ee173e6e6bfa58670.png ../_images/b5bfc376e8d096e2069e1f553c77e0b98010fbffe56856e5a3125f6a1946dec5.png ../_images/a726afe5bb90b38e8c9dd4b0fbb39663a6fec5c825ff568be02162122a6e2917.png