The hardware and bandwidth for this mirror is donated by dogado GmbH, the Webhosting and Full Service-Cloud Provider. Check out our Wordpress Tutorial.
If you wish to report a bug, or if you are interested in having us mirror your free-software or open-source project, please feel free to contact us at mirror[@]dogado.de.

Synthetic Gazepoint pupillometry case study

Purpose

This case study is entirely synthetic. Its statistics are software demonstrations and are not empirical evidence about Gazepoint hardware, participants, or psychological processes.

sim <- simulate_pupil_timecourse(
  n_participants = 8,
  trials_per_participant = 6,
  sampling_frequency = 20,
  time_window = c(-0.5, 1.5),
  condition_difference = 0.18,
  blink_trial_probability = 0.04,
  include_gaze = TRUE,
  include_luminance = TRUE,
  seed = 20260814
)

A Gazepoint-like mapping audit

The raw simulator is vendor-neutral. The next object creates a small Gazepoint-like view solely to exercise the verified field bridge.

gp_like <- data.frame(
  TIME = sim$data$event_time[1:20],
  LPD = 15 + sim$data$pupil_mm[1:20],
  LPV = as.integer(!is.na(sim$data$pupil_mm[1:20])),
  BPOGX = sim$data$gaze_x[1:20],
  BPOGY = sim$data$gaze_y[1:20],
  BPOGV = 1
)
gazepoint_pupil_mapping_table(inspect_gazepoint_pupil_schema(gp_like))
#>        field                        role              unit      eye
#> 1       TIME                        time           seconds     none
#> 2  TIME_TICK                   time_tick             ticks     none
#> 3      LPOGX                 left_gaze_x normalized_screen     left
#> 4      LPOGY                 left_gaze_y normalized_screen     left
#> 5      LPOGV             left_gaze_valid normalized_screen     left
#> 6      RPOGX                right_gaze_x normalized_screen    right
#> 7      RPOGY                right_gaze_y normalized_screen    right
#> 8      RPOGV            right_gaze_valid normalized_screen    right
#> 9      BPOGX                 best_gaze_x normalized_screen combined
#> 10     BPOGY                 best_gaze_y normalized_screen combined
#> 11     BPOGV             best_gaze_valid normalized_screen combined
#> 12      LPCX         left_pupil_camera_x     camera_pixels     left
#> 13      LPCY         left_pupil_camera_y     camera_pixels     left
#> 14       LPD  left_pupil_diameter_pixels            pixels     left
#> 15       LPS            left_pupil_scale             scale     left
#> 16       LPV            left_pupil_valid         indicator     left
#> 17      RPCX        right_pupil_camera_x     camera_pixels    right
#> 18      RPCY        right_pupil_camera_y     camera_pixels    right
#> 19       RPD right_pupil_diameter_pixels            pixels    right
#> 20       RPS           right_pupil_scale             scale    right
#> 21       RPV           right_pupil_valid         indicator    right
#> 22     LEYEX                  left_eye_x            metres     left
#> 23     LEYEY                  left_eye_y            metres     left
#> 24     LEYEZ                  left_eye_z            metres     left
#> 25   LPUPILD  left_pupil_diameter_metres            metres     left
#> 26   LPUPILV         left_pupil_3d_valid         indicator     left
#> 27     REYEX                 right_eye_x            metres    right
#> 28     REYEY                 right_eye_y            metres    right
#> 29     REYEZ                 right_eye_z            metres    right
#> 30   RPUPILD right_pupil_diameter_metres            metres    right
#> 31   RPUPILV        right_pupil_3d_valid         indicator    right
#>                                  source_specification present
#> 1  Gazepoint Open Gaze API v2-era field specification    TRUE
#> 2  Gazepoint Open Gaze API v2-era field specification   FALSE
#> 3  Gazepoint Open Gaze API v2-era field specification   FALSE
#> 4  Gazepoint Open Gaze API v2-era field specification   FALSE
#> 5  Gazepoint Open Gaze API v2-era field specification   FALSE
#> 6  Gazepoint Open Gaze API v2-era field specification   FALSE
#> 7  Gazepoint Open Gaze API v2-era field specification   FALSE
#> 8  Gazepoint Open Gaze API v2-era field specification   FALSE
#> 9  Gazepoint Open Gaze API v2-era field specification    TRUE
#> 10 Gazepoint Open Gaze API v2-era field specification    TRUE
#> 11 Gazepoint Open Gaze API v2-era field specification    TRUE
#> 12 Gazepoint Open Gaze API v2-era field specification   FALSE
#> 13 Gazepoint Open Gaze API v2-era field specification   FALSE
#> 14 Gazepoint Open Gaze API v2-era field specification    TRUE
#> 15 Gazepoint Open Gaze API v2-era field specification   FALSE
#> 16 Gazepoint Open Gaze API v2-era field specification    TRUE
#> 17 Gazepoint Open Gaze API v2-era field specification   FALSE
#> 18 Gazepoint Open Gaze API v2-era field specification   FALSE
#> 19 Gazepoint Open Gaze API v2-era field specification   FALSE
#> 20 Gazepoint Open Gaze API v2-era field specification   FALSE
#> 21 Gazepoint Open Gaze API v2-era field specification   FALSE
#> 22 Gazepoint Open Gaze API v2-era field specification   FALSE
#> 23 Gazepoint Open Gaze API v2-era field specification   FALSE
#> 24 Gazepoint Open Gaze API v2-era field specification   FALSE
#> 25 Gazepoint Open Gaze API v2-era field specification   FALSE
#> 26 Gazepoint Open Gaze API v2-era field specification   FALSE
#> 27 Gazepoint Open Gaze API v2-era field specification   FALSE
#> 28 Gazepoint Open Gaze API v2-era field specification   FALSE
#> 29 Gazepoint Open Gaze API v2-era field specification   FALSE
#> 30 Gazepoint Open Gaze API v2-era field specification   FALSE
#> 31 Gazepoint Open Gaze API v2-era field specification   FALSE

LPD is labelled as pixels by the bridge. The example does not convert those synthetic values into millimetres.

Contract through specification

contract <- create_pupil_contract(
  outcome_col = "pupil_mm",
  participant_col = "participant_id",
  trial_col = "trial_id",
  item_col = "item_id",
  condition_col = "condition",
  time_col = "event_time",
  pupil_unit = "millimetres",
  sampling_frequency = 20,
  eye = "combined",
  blink_col = "blink",
  interpolation_col = "interpolated",
  gaze_x_col = "gaze_x",
  gaze_y_col = "gaze_y",
  luminance_col = "luminance",
  baseline_window = c(-0.5, 0),
  preprocessing_provenance = "gp3bayes deterministic simulator"
)
prepared <- prepare_pupil_timecourse(sim$data, contract)
readiness <- audit_pupil_readiness(prepared)
measurement <- audit_pupil_measurement_context(prepared)
spec <- specify_pupil_timecourse_model(
  prepared,
  smooth_basis_dimension = 6,
  autocorrelation = "ar1"
)
pupil_readiness_table(readiness)
#>                                   metric       value status
#> 1                                   rows        1968   pass
#> 2                           participants           8   pass
#> 3                                 trials          48   pass
#> 4                                  items          12   pass
#> 5                             conditions           2   pass
#> 6                  estimated_sampling_hz          20   pass
#> 7               median_sampling_interval        0.05   pass
#> 8                   sampling_interval_cv 1.38814e-15   pass
#> 9               missing_pupil_proportion           0   pass
#> 10                      blink_proportion           0   pass
#> 11               interpolated_proportion           0   pass
#> 12                    invalid_proportion        <NA> review
#> 13                     baseline_coverage           1   pass
#> 14               trials_lacking_baseline           0   pass
#> 15                             pupil_min     3.18649   pass
#> 16                             pupil_max     5.30599   pass
#> 17               minimum_trial_time_span           2 review
#> 18               maximum_trial_time_span           2 review
#> 19                        gaze_available        TRUE   pass
#> 20              gaze_condition_imbalance  0.00178244 review
#> 21         left_right_pupil_disagreement        <NA> review
#> 22                   luminance_available        TRUE   pass
#> 23         luminance_condition_imbalance 3.24082e-05 review
#> 24                    contrast_available       FALSE review
#> 25                pfe_corrected_upstream       FALSE review
#> 26 preprocessing_provenance_completeness       0.333 review
#>                                                                       detail
#> 1                                                                           
#> 2  One-participant data cannot support population participant heterogeneity.
#> 3                                                                           
#> 4                                                Item hierarchy is optional.
#> 5                         A condition contrast requires at least two levels.
#> 6                                                            Declared 20 Hz.
#> 7                                                                           
#> 8            AR(1) sample-order dependence requires regular-enough sampling.
#> 9           Missingness is reported, not automatically repaired or excluded.
#> 10                                                                          
#> 11                                                                          
#> 12                                                                          
#> 13                                                                          
#> 14                                                                          
#> 15                                                                          
#> 16                                                                          
#> 17                       Smallest observed within-trial event-time coverage.
#> 18                        Largest observed within-trial event-time coverage.
#> 19                                                                          
#> 20                   Descriptive between-condition gaze-position difference.
#> 21                                Median absolute paired-channel difference.
#> 22                                                                          
#> 23                  Descriptive between-condition mean luminance difference.
#> 24                                                                          
#> 25           PFE status is contextual evidence, not an automatic correction.
#> 26
pupil_measurement_audit_table(measurement)
#>          domain available   observed
#> 1         blink      TRUE          0
#> 2 interpolation      TRUE          0
#> 3      baseline      TRUE  -0.5 to 0
#> 4      sampling      TRUE 1.3881e-15
#> 5 gaze_position      TRUE  0.0031145
#> 6           pfe      TRUE      FALSE
#> 7     luminance      TRUE 3.2408e-05
#> 8      contrast     FALSE       <NA>
#> 9  time_on_task     FALSE       <NA>
#>                                                       interpretation
#> 1                                   Reported data-loss context only.
#> 2                      Reported upstream interpolation context only.
#> 3                         Baseline declaration; no automatic choice.
#> 4              Sampling irregularity context for temporal modelling.
#> 5 Between-condition mean gaze-position difference; descriptive only.
#> 6  Upstream PFE-correction declaration; no automatic PFE correction.
#> 7     Between-condition mean luminance difference; descriptive only.
#> 8              Contrast availability/range; no automatic adjustment.
#> 9                             Recording-time support when available.
pupil_specification_table(spec)
#>                     field
#> 1                  family
#> 2              likelihood
#> 3                    link
#> 4                 formula
#> 5      temporal_structure
#> 6  smooth_basis_dimension
#> 7    condition_trajectory
#> 8         autocorrelation
#> 9     participant_effects
#> 10 participant_trajectory
#> 11           item_effects
#> 12             covariates
#> 13           outcome_unit
#> 14     baseline_operation
#> 15   unrestricted_formula
#>                                                                                                                                                                 value
#> 1                                                                                                                                                               pupil
#> 2                                                                                                                                                            Gaussian
#> 3                                                                                                                                                            identity
#> 4  .pupil_model ~ .condition + s(.event_time, by = .condition, k = 6) +      (1 | .participant) + (1 | .item) + ar(time = .sample_index,      gr = .series_id, p = 1)
#> 5                                                                                                                                                              smooth
#> 6                                                                                                                                                                   6
#> 7                                                                                                                                                                TRUE
#> 8                                                                                                                                                                 ar1
#> 9                                                                                                                                                    random_intercept
#> 10                                                                                                                                                               none
#> 11                                                                                                                                                               TRUE
#> 12                                                                                                                                                                   
#> 13                                                                                                                                                        millimetres
#> 14                                                                                                                                                               none
#> 15                                                                                                                                                              FALSE

Backend and post-fit stages

fit <- fit_pupil_model_backend(spec, backend = "cmdstanr", cores = 2)
trajectory <- estimate_pupil_trajectory(
  predict_pupil_trajectory(fit, ndraws = 200)
)
window <- estimate_pupil_window(
  predict_pupil_trajectory(fit, ndraws = 200),
  window = c(0.3, 1.0)
)
auc <- estimate_pupil_auc(
  predict_pupil_trajectory(fit, ndraws = 200),
  window = c(0.3, 1.0)
)
ppc <- check_pupil_posterior_predictive(fit, ndraws = 200)
diag <- diagnose_pupil_fit(fit)

plan <- create_pupil_validation_plan(
  prepared,
  target = "new_trial_known_participant",
  K = 4
)
validation <- validate_pupil_model(fit, plan, execute = TRUE)

Sensitivity

spec_for_sensitivity <- specify_pupil_timecourse_model(
  prepared,
  autocorrelation = "none",
  smooth_basis_dimension = 5
)
suite <- create_pupil_sensitivity_suite(
  spec_for_sensitivity,
  baseline_windows = list(c(-0.5, -0.1), c(-0.4, -0.1)),
  baseline_window_operation = "subtract",
  interpolation_policy = c("retain", "exclude_flagged"),
  gaze_adjustment = c("none", "declared_covariates"),
  luminance_adjustment = c("none", "declared_covariate"),
  analysis_windows = list(c(0.3, 1.0))
)
head(pupil_sensitivity_table(suite))
#>   scenario_id                 axis               value
#> 1        S001      baseline_window           -0.5,-0.1
#> 2        S002      baseline_window           -0.4,-0.1
#> 3        S003 interpolation_policy              retain
#> 4        S004 interpolation_policy     exclude_flagged
#> 5        S005      gaze_adjustment                none
#> 6        S006      gaze_adjustment declared_covariates

All windows and sensitivity dimensions are declared. No simulated estimate is presented as an empirical effect, and no scenario is automatically selected.

These binaries (installable software) and packages are in development.
They may not be fully stable and should be used with caution. We make no claims about them.
Health stats visible at Monitor.