Reading Tobii Data from Tobii Pro Lab

Reading Tobii Data from Tobii Pro Lab#

import pupeyes as pe
import pandas as pd

At present, PupEyes does not support exported data from Tobii Pro Lab because these files already seem processed and ready for data analysis with basic Pandas syntax. For example, below is data kindly shared by Jason Geller for an experiment in which participants watched a video with eye movements recorded.

# file name
path = './data/sample_data_video.tsv'

# read data
df = pd.read_csv(path, 
                 sep='\t', 
                 low_memory=False # suppress dtypes warning
                 )

df.head()
Recording timestamp [ms] Computer timestamp [ms] Sensor Project name Export date Participant name Recording date Recording start time Recording duration [ms] Event ... Pupil diameter filtered [mm] Eye openness left [mm] Eye openness right [mm] Eye openness filtered [mm] Validity left Validity right Presented Stimulus name Eye movement type Eye movement event duration [ms] Eye movement type index
0 0 3185423 NaN Demo 7/31/25 Participant1 3/5/25 04:06.2 102618 RecordingStart ... NaN NaN NaN NaN NaN NaN NaN Fixation 4144.0 1.0
1 2 3185425 Eye Tracker Demo 7/31/25 Participant1 3/5/25 04:06.2 102618 NaN ... 3.230 9.69 9.94 9.815 Valid Valid NaN Fixation 4144.0 1.0
2 19 3185442 Eye Tracker Demo 7/31/25 Participant1 3/5/25 04:06.2 102618 NaN ... 3.231 10.12 10.19 10.155 Valid Valid NaN Fixation 4144.0 1.0
3 36 3185458 Eye Tracker Demo 7/31/25 Participant1 3/5/25 04:06.2 102618 NaN ... 3.249 10.29 10.37 10.330 Valid Valid NaN Fixation 4144.0 1.0
4 52 3185475 Eye Tracker Demo 7/31/25 Participant1 3/5/25 04:06.2 102618 NaN ... 3.195 9.85 10.26 10.055 Valid Valid NaN Fixation 4144.0 1.0

5 rows × 29 columns

Note

Check here for the meaning of these columns: https://go.tobii.com/Tobii-Pro-Lab-data-export-info

# some basic data cleaning seems sufficient

# select columns of interest
use_cols = ['Recording timestamp [ms]', 'Participant name', 'Gaze point X [DACS px]', 'Gaze point Y [DACS px]', 'Presented Stimulus name', 'Pupil diameter filtered [mm]']
samples = df[use_cols]

# select rows where stimulus is presented
samples = samples[samples['Presented Stimulus name']=='Inattentional Blindness - The Monkey Business Illusion 720'].reset_index(drop=True)

samples.head()
Recording timestamp [ms] Participant name Gaze point X [DACS px] Gaze point Y [DACS px] Presented Stimulus name Pupil diameter filtered [mm]
0 2669 Participant1 1067.0 584.0 Inattentional Blindness - The Monkey Business ... 3.238
1 2686 Participant1 1067.0 584.0 Inattentional Blindness - The Monkey Business ... 3.281
2 2702 Participant1 1067.0 584.0 Inattentional Blindness - The Monkey Business ... 3.207
3 2719 Participant1 1067.0 584.0 Inattentional Blindness - The Monkey Business ... 3.243
4 2736 Participant1 1067.0 584.0 Inattentional Blindness - The Monkey Business ... 3.294
# do preprocessing
p = pe.PupilProcessor(
    data=samples, # pass your data
    trial_identifier=['Participant name','Presented Stimulus name'], # column(s) that disambiguate one trial from another in your data
    x_col = 'Gaze point X [DACS px]',
    y_col = 'Gaze point Y [DACS px]',
    pupil_col = 'Pupil diameter filtered [mm]',
    time_col = 'Recording timestamp [ms]',
    samp_freq = 120, # Hz
    device='tobii_prolab',
    eyetracker_missing_value=pd.NA
    ).deblink().artifact_rejection().smooth(window=5).check_missing().interpolate(missing_threshold=.4)
Device: tobii_prolab
Eye-tracker missing value is <NA>. Replacing with 0.
Sampling frequency check skipped for tobii_prolab data.
PupilProcessor initialized with 121493 samples
Pupil column: Pupil diameter filtered [mm], Time column: Recording timestamp [ms], X column: Gaze point X [DACS px], Y column: Gaze point Y [DACS px]
Trial identifier: ['Participant name', 'Presented Stimulus name'], Number of trials: 3
Running deblink using sampling frequency 120Hz
✓ Deblinking completed!
  → New column: 'Pupil diameter filtered [mm]_db' (blinks removed)
  → Previous column 'Pupil diameter filtered [mm]' preserved.
  → 0 trial(s) failed.
✓ Artifact rejection completed!
  → New column: 'Pupil diameter filtered [mm]_db_ar' (artifacts removed)
  → Previous column 'Pupil diameter filtered [mm]_db' preserved.
  → 0 trial(s) failed.
✓ Smoothing completed!
  → New column: 'Pupil diameter filtered [mm]_db_ar_sm' (smoothed)
  → Previous column 'Pupil diameter filtered [mm]_db_ar' preserved.
  → 0 trial(s) failed.
✓ Missing values checked!
  → 0 trial(s) failed.
✓ Interpolation completed!
  → New column: 'Pupil diameter filtered [mm]_db_ar_sm_it' (interpolated)
  → Previous column 'Pupil diameter filtered [mm]_db_ar_sm' preserved.
  → 1 trial(s) failed.

   Participant name                            Presented Stimulus name
0     Participant1  Inattentional Blindness - The Monkey Business ...
p.summary()
Participant name Presented Stimulus name n_samples run_deblink pct_deblink run_speed pct_speed run_size pct_size run_smooth run_check_missing missing run_interpolate pct_interpolate
0 Participant1 Inattentional Blindness - The Monkey Business ... 5980 True 0.673411 True 0.0 True 0 True True 0.683445 False 0.683445
1 P1 Inattentional Blindness - The Monkey Business ... 61000 True 0.050377 True 0.046689 True 0 True True 0.144115 True 0.144115
2 P3 Inattentional Blindness - The Monkey Business ... 54513 True 0.022178 True 0.018014 True 0 True True 0.056005 True 0.056005
viewer = pe.PupilViewer(p)

#viewer.run()

Warning

I do not use Tobii nor Pro Lab, so please take my words for caution. Although very unlikely, but if your computer explodes after running these code, I’m not responsible for that! If you have suggestions for improving the code, feel free to submit an issue.