Overview
This vignette shows a practical pupil workflow for Gazepoint GP3 /
Gazepoint Analysis exports using gp3tools.
The workflow covers:
- creating a master table;
- running a light pupil preprocessing branch;
- running a conservative artifact-cleaned pupil branch;
- auditing pupil preprocessing quality;
- summarising pupil windows;
- fitting confirmatory pupil-window models;
- running time-course models and sensitivity checks.
The vignette chunks are not evaluated during package checks, so the file can serve as a readable workflow template.
The first section uses built-in example data; the optional import chunk shows how to replace those objects with data from a private Gazepoint export folder.
When adapting the code, replace the placeholder paths and column names with those used in your own study.
1. Load example data or import your own exports
For a quick read-through, start with the lightweight synthetic example data included in the package.
These objects make the later workflow easier to follow because they already use the column names expected by the examples.
library(gp3tools)
data("gazepoint_example_master")
data("gazepoint_example_pupil_windows")
master <- gazepoint_example_master
pupil_windows <- gazepoint_example_pupil_windowsFor a real study, replace the example objects above by importing a Gazepoint export folder.
This optional chunk creates all_gaze and then rebuilds
master from the imported rows:
export_dir <- "C:/Users/YourName/Desktop/gp3_test_exports"
output_dir <- "C:/Users/YourName/Desktop/gp3_outputs"
results <- run_gazepoint_workflow(
export_dir = export_dir,
output_dir = output_dir,
prefix = "study1",
save_plots = TRUE,
create_report = TRUE
)
all_gaze <- results$all_gaze
master <- create_gazepoint_master(all_gaze)2. Validate the master table
master_audit <- audit_gazepoint_master(master)
validation <- validate_gazepoint_master(master)
master_audit$overview
validation$summary
validation$checksUse the validation output before continuing to pupil preprocessing.
If you imported real Gazepoint exports, this is the point where you should confirm that the expected participant, trial, time, gaze, and pupil columns were created correctly.
3. Light pupil preprocessing branch
Use the light branch when you need a transparent minimal preprocessing pipeline.
pupil_summary <- summarise_gazepoint_pupil(master)
flagged_pupil <- flag_gazepoint_pupil(
master,
pupil_col = "pupil"
)
interpolated_pupil <- interpolate_gazepoint_pupil(
flagged_pupil,
pupil_col = "pupil_for_preprocessing",
time_col = "time",
group_cols = c("subject", "MEDIA_ID", "trial_global")
)
baseline_corrected <- baseline_correct_gazepoint_pupil(
interpolated_pupil,
pupil_col = "pupil_interpolated",
time_col = "time",
group_cols = c("subject", "MEDIA_ID", "trial_global"),
baseline_window = c(0, 200),
min_baseline_samples = 1
)
smoothed_pupil <- smooth_gazepoint_pupil(
baseline_corrected,
pupil_col = "pupil_baseline_corrected",
time_col = "time",
group_cols = c("subject", "MEDIA_ID", "trial_global"),
window_samples = 5,
method = "mean",
align = "center",
min_points = 2
)Create pupil-window summaries.
These summaries are useful for confirmatory window analyses, where the time window should be specified before testing the main condition effect.
pupil_windows <- summarise_gazepoint_pupil_windows(
smoothed_pupil,
pupil_col = "pupil_smoothed",
time_col = "time",
windows = c(0, 500, 1000, 2000, 5000),
group_cols = c("subject", "MEDIA_ID", "trial_global", "condition"),
min_valid_samples = 1
)
pupil_windows4. Conservative artifact-cleaned branch
Use the conservative branch when blink/trackloss padding, pupil-speed artifacts, or stricter preprocessing decisions are important.
registry <- create_gazepoint_preprocessing_registry(
blink_padding_ms = 50,
interpolation_max_gap_ms = 150,
smoothing_window_samples = 5,
baseline_window = c(0, 200)
)
artifact_pupil <- flag_gazepoint_pupil_artifacts(
master,
registry = registry,
pupil_col = "pupil",
time_col = "time",
group_cols = c("subject", "MEDIA_ID", "trial_global")
)
interpolated_artifact_pupil <- interpolate_gazepoint_pupil(
artifact_pupil,
pupil_col = "pupil_clean",
time_col = "time",
group_cols = c("subject", "MEDIA_ID", "trial_global")
)
baseline_artifact_pupil <- baseline_correct_gazepoint_pupil(
interpolated_artifact_pupil,
pupil_col = "pupil_interpolated",
time_col = "time",
group_cols = c("subject", "MEDIA_ID", "trial_global"),
baseline_window = c(0, 200),
min_baseline_samples = 1
)
smoothed_artifact_pupil <- smooth_gazepoint_pupil(
baseline_artifact_pupil,
pupil_col = "pupil_baseline_corrected",
time_col = "time",
group_cols = c("subject", "MEDIA_ID", "trial_global"),
window_samples = 5,
method = "mean",
align = "center",
min_points = 2
)
pupil_windows_conservative <- summarise_gazepoint_pupil_windows(
smoothed_artifact_pupil,
pupil_col = "pupil_smoothed",
time_col = "time",
windows = c(0, 500, 1000, 2000, 5000),
group_cols = c("subject", "MEDIA_ID", "trial_global", "condition"),
min_valid_samples = 1
)5. Pupil quality audits
gap_audit <- audit_gazepoint_pupil_gaps(
interpolated_artifact_pupil,
group_cols = c("subject", "MEDIA_ID", "trial_global")
)
baseline_audit <- audit_gazepoint_pupil_baseline(
baseline_artifact_pupil,
group_cols = c("subject", "MEDIA_ID", "trial_global")
)
imbalance_audit <- audit_gazepoint_pupil_imbalance(
smoothed_artifact_pupil,
group_cols = "condition"
)
drift_audit <- audit_gazepoint_pupil_drift(
smoothed_artifact_pupil,
pupil_col = "pupil_smoothed",
time_col = "time",
group_cols = c("subject", "MEDIA_ID", "trial_global")
)
overlap_audit <- audit_gazepoint_pupil_overlap_risk(
master,
time_col = "time",
event_col = "event_label",
group_cols = c("subject", "MEDIA_ID", "trial_global")
)
gap_audit$overview
baseline_audit$overview
imbalance_audit$overview
drift_audit$overview
overlap_audit$overview6. Reliability and sensitivity checks
The checks below use the conservative pupil-window summary. In a real analysis, compare this branch with the lighter preprocessing branch to assess whether conclusions depend on preprocessing choices.
pupil_reliability <- audit_gazepoint_pupil_reliability(
pupil_windows_conservative,
subject_col = "subject",
outcome_col = "mean_pupil",
condition_col = "condition"
)
pchip_pupil <- interpolate_gazepoint_pupil_pchip(
artifact_pupil,
pupil_col = "pupil_clean",
time_col = "time",
group_cols = c("subject", "MEDIA_ID", "trial_global")
)
hampel_pupil <- flag_gazepoint_pupil_hampel(
smoothed_artifact_pupil,
pupil_col = "pupil_smoothed",
time_col = "time",
grouping_cols = c("subject", "MEDIA_ID", "trial_global"),
window_size_samples = 7,
k = 3,
min_valid_samples = 3,
corrected_col = "pupil_hampel_corrected"
)
pupil_reliability$overview
attr(pchip_pupil, "gp3_pchip_overview")
attr(hampel_pupil, "gp3_hampel_overview")7. Confirmatory pupil-window LMM
Prepare pupil-window model data:
pupil_window_model_data <- prepare_gazepoint_pupil_window_model_data(
pupil_windows_conservative,
outcome_col = "mean_pupil",
subject_col = "subject",
condition_col = "condition",
window_col = "window_label",
trial_col = "trial_global",
valid_samples_col = "n_valid_samples",
total_samples_col = "n_samples",
min_valid_samples = 1
)
dplyr::count(
pupil_window_model_data,
pupil_window_condition,
pupil_window_label,
pupil_window_model_status
)Fit the confirmatory model:
pupil_window_lmm <- fit_gazepoint_pupil_window_lmm(
pupil_window_model_data,
random_window_slopes = FALSE,
use_weights = TRUE,
REML = FALSE
)
pupil_window_lmm$model_status
pupil_window_lmm$formula
pupil_window_lmm$fixed_effects
pupil_window_lmm$comparisonRun sensitivity checks:
pupil_window_sensitivity <- fit_gazepoint_pupil_window_sensitivity(
pupil_window_model_data,
model_types = c(
"unweighted_lmm",
"weighted_lmm",
"fixed_lm",
"weighted_lm"
),
include_condition = TRUE,
include_window = TRUE,
include_interaction = TRUE
)
pupil_window_sensitivity$comparison
pupil_window_sensitivity$fixed_effects8. Pupil time-course models
Prepare binned pupil time-course data:
pupil_gamm_data <- prepare_gazepoint_pupil_gamm_data(
smoothed_artifact_pupil,
pupil_col = "pupil_smoothed",
time_col = "time",
subject_col = "subject",
condition_col = "condition",
trial_col = "trial_global",
bin_width_ms = 50,
min_valid_samples = 1
)Fit the main pupil GAMM:
pupil_gamm_fit <- fit_gazepoint_pupil_gamm(
pupil_gamm_data,
n_time_basis = 10,
discrete = TRUE
)
pupil_gamm_fit$model_status
pupil_gamm_fit$formulaRun a gaze-position/PFE sensitivity GAMM:
pupil_pfe_fit <- fit_gazepoint_pupil_pfe_gamm(
pupil_gamm_data,
n_time_basis = 10,
n_position_basis = 8,
discrete = TRUE
)
pupil_pfe_fit$sensitivity_status
pupil_pfe_fit$comparisonPrepare and fit a Growth Curve Analysis model:
pupil_gca_data <- prepare_gazepoint_gca_data(
pupil_gamm_data,
pupil_col = "mean_pupil",
time_col = "time_bin_center_ms",
subject_col = "subject",
condition_col = "condition",
degree = 3,
orthogonal = TRUE,
valid_samples_col = "n_valid_samples",
min_valid_samples = 1
)
pupil_gca_fit <- fit_gazepoint_gca(
pupil_gca_data,
REML = FALSE
)
pupil_gca_fit$model_status
pupil_gca_fit$comparison9. Cluster permutation and divergence point
Cluster-permutation and divergence-point analyses are exploratory time-course tools. Use enough permutations or bootstrap samples for the final analysis, and avoid using exploratory results to define a later confirmatory window on the same data.
cluster_data <- prepare_gazepoint_cluster_data(
pupil_gamm_data,
outcome_col = "mean_pupil",
time_col = "time_bin_center_ms",
subject_col = "subject",
condition_col = "condition"
)
cluster_results <- run_gazepoint_cluster_permutation(
cluster_data,
condition_levels = c("control", "treatment"),
n_permutations = 1000,
seed = 123
)
cluster_summary <- summarise_gazepoint_clusters(cluster_results)
cluster_summary$overview
cluster_summary$significant_clustersEstimate the earliest reliable divergence point:
divergence <- estimate_gazepoint_divergence_point(
data = pupil_gamm_data,
outcome_col = "mean_pupil",
time_col = "time_bin_center_ms",
condition_col = "condition",
participant_col = "subject",
comparison = c("control", "treatment"),
bootstrap_unit = "participant",
n_boot = 1000,
consecutive_points = 2,
seed = 123
)
divergence$overview
divergence$divergence_pointDo not use a detected exploratory cluster to define a confirmatory window and then retest that same window as if it had been specified a priori.
10. Reporting
Run diagnostics and create manuscript-ready tables:
pupil_diagnostics <- diagnose_gazepoint_glmm(
pupil_window_lmm,
model_name = "pupil_window_lmm",
use_dharma = FALSE
)
pupil_model_summary <- tidy_gazepoint_model_summary(
pupil_window_lmm,
model_name = "pupil_window_lmm"
)
pupil_diagnostics$overview
pupil_model_summary$fixed_effectsCreate a reporting checklist:
reporting <- create_gazepoint_reporting_checklist(
data = master,
objects = list(
validation = validation,
gap_audit = gap_audit,
baseline_audit = baseline_audit,
pupil_model = pupil_window_lmm,
diagnostics = pupil_diagnostics
),
analysis_type = "pupil",
study_title = "Gazepoint pupil study"
)
reporting$overview
reporting$checklist