Learn R Programming

⚠️There's a newer version (2.1.1) of this package.Take me there.

eyeris: Flexible, Extensible, & Reproducible Pupillometry Preprocessing

Motivation

Despite decades of pupillometry research, many established packages and workflows unfortunately lack design principles based on (F)indability (A)ccessbility (I)nteroperability (R)eusability (FAIR) principles. eyeris, on the other hand follows a thoughtful design philosophy that results in an intuitive, modular, performant, and extensible pupillometry data preprocessing framework. Much of these design principles were heavily inspired by Nipype.

eyeris also provides a highly opinionated pipeline for tonic and phasic pupillometry preprocessing (inspired by fMRIPrep). These opinions are the product of many hours of discussions from core members and signal processing experts from the Stanford Memory Lab (Shawn Schwartz, Mingjian He, Haopei Yang, Alice Xue, and Anthony Wagner).

eyeris also introduces a BIDS-like structure for organizing derivative (preprocessed) pupillometry data, as well as an intuitive workflow for inspecting preprocessed pupillometry epochs within beautiful, interactive HTML report files (see demonstration below ⬇️)! The package also includes gaze heatmaps that show the distribution of eye coordinates across the entire screen area, helping you assess data quality and participant attention patterns. These heatmaps are automatically generated in the BIDS reports and can also be created manually.

Installation

stable release from CRAN

You can install the stable release of eyeris from CRAN with:

install.packages("eyeris")

or

# install.packages("pak")
pak::pak("eyeris")

development version from GitHub

You can install the development version of eyeris from GitHub with:

# install.packages("devtools")
devtools::install_github("shawntz/eyeris", ref = "dev")

Example

the glassbox() “prescription” function

This is a basic example of how to use eyeris out of the box with our very opinionated set of steps and parameters that one should start out with when preprocessing pupillometry data. Critically, this is a “glassbox” – as opposed to a “blackbox” – since each step and parameter implemented herein is fully open and accessible to you. We designed each pipeline step / function to be like legos – they are intentionally and carefully designed in a way that allows you to flexibly construct and compare different pipelines.

We hope you enjoy! -shawn

set.seed(32)

library(eyeris)
#> 
#> eyeris v2.0.0 - Lumpy Space Princess ꒰•ᴗ•。꒱۶
#> Welcome! Type ?`eyeris` to get started.

demo_data <- eyelink_asc_demo_dataset()

eyeris_preproc <- glassbox(
  demo_data,
  lpfilt = list(plot_freqz = FALSE)
)
#> ✔ [  OK  ] - Running eyeris::load_asc()
#> ℹ [ INFO ] - Processing block: block_1
#> ✔ [  OK  ] - Running eyeris::deblink() for block_1
#> ✔ [  OK  ] - Running eyeris::detransient() for block_1
#> ✔ [  OK  ] - Running eyeris::interpolate() for block_1
#> ✔ [  OK  ] - Running eyeris::lpfilt() for block_1
#> ! [ SKIP ] - Skipping eyeris::downsample() for block_1
#> ! [ SKIP ] - Skipping eyeris::bin() for block_1
#> ! [ SKIP ] - Skipping eyeris::detrend() for block_1
#> ✔ [  OK  ] - Running eyeris::zscore() for block_1
#> ✔ [  OK  ] - Running eyeris::summarize_confounds()

step-wise correction of pupillary signal

plot(eyeris_preproc, add_progressive_summary = TRUE)

final pre-post correction of pupillary signal (raw ➡ preprocessed)

start_time <- min(eyeris_preproc$timeseries$block_1$time_secs)
end_time <- max(eyeris_preproc$timeseries$block_1$time_secs)

plot(eyeris_preproc,
  # steps = c(1, 5), # uncomment to specify a subset of preprocessing steps to plot; by default, all steps will plot in the order in which they were executed by eyeris
  preview_window = c(start_time, end_time),
  add_progressive_summary = TRUE
)
#> ! [ INFO ] - Plotting block 1 from possible blocks: 1
#> ℹ [ INFO ] - Plotting with sampling rate: 1000 Hz

#> ℹ [ INFO ] - Creating progressive summary plot for block_1
#> ✔ [  OK  ] - Progressive summary plot created successfully!

plot_gaze_heatmap(
  eyeris = eyeris_preproc,
  block = 1
)

Logging eyeris commands with eyelogger()

The eyelogger() utility lets you run any eyeris command (or block of R code) while automatically capturing all console output and errors to timestamped log files. This is especially useful for reproducibility, debugging, or running batch jobs.

How it works: - All standard output (stdout) and standard error (stderr) are saved to log files in a directory you specify (or a temporary directory by default). - Each run produces two log files: - <timestamp>.out: all console output - <timestamp>.err: all warnings and errors

Usage

You can wrap any eyeris command or block of code in eyelogger({ ... }):

library(eyeris)

# log a simple code block with messages, warnings, and prints
eyelogger({
  message("eyeris `glassbox()` completed successfully.")
  warning("eyeris `glassbox()` completed with warnings.")
  print("some eyeris-related information.")
})

# log a real eyeris pipeline run, saving logs to a custom directory
log_dir <- file.path(tempdir(), "eyeris_logs")
eyelogger({
  glassbox(eyelink_asc_demo_dataset(), interactive_preview = FALSE)
}, log_dir = log_dir)

Parameters

  • eyeris_cmd: The code to run (wrap in {} for multiple lines).
  • log_dir: Directory to save logs (default: a temporary directory).
  • timestamp_format: Format for log file names (default: "%Y%m%d_%H%M%S").

What you get

After running, you’ll find log files in your specified directory, e.g.:

20240614_153012.out   # console output
20240614_153012.err   # warnings and errors

This makes it easy to keep a record of your preprocessing runs and debug any issues that arise.


eyeris dependency graph :see_no_evil:


Contributing to eyeris

Thank you for considering contributing to the open-source eyeris R package; there are many ways one could contribute to eyeris.

We believe the best preprocessing practices emerge from collective expertise and rigorous discussion. Please see the contribution guidelines for more information on how to get started..

Code of Conduct

Please note that the eyeris project is released with a Contributor Code of Conduct. By contributing to this project, you agree to abide by its terms.

Suggestions, questions, issues?

Please use the issues tab (https://github.com/shawntz/eyeris/issues) to make note of any bugs, comments, suggestions, feedback, etc… all are welcomed and appreciated, thanks!

Copy Link

Version

Install

install.packages('eyeris')

Monthly Downloads

575

Version

2.0.0

License

MIT + file LICENSE

Issues

Pull Requests

Stars

Forks

Maintainer

Shawn Schwartz

Last Published

July 26th, 2025

Functions in eyeris (2.0.0)

check_epoch_manual_input_dfs

Check epoch manual input dataframe format
deblink_pupil

Internal function to remove blink artifacts from pupil data
check_pupil_cols

Check if pupil_raw column exists
detransient

Remove pupil samples that are physiologically unlikely
downsample

Downsample pupil time series with anti-aliasing filtering
glassbox

The opinionated "glass box" eyeris pipeline
get_timestamps

Obtain timestamps from events data
check_epoch_msg_values

Check epoch message values against available events
detransient_pupil

Internal function to remove transient artifacts from pupil data
check_start_end_timestamps

Check start and end timestamps are balanced
error_handler

Handle errors with custom error classes
epoch_start_msg_and_limits

Epoch using a start message with fixed limits around it
epoch

Epoch (and baseline) pupil data based on custom event message structure
downsample_pupil

Internal function to downsample pupil data
get_block_numbers

Extract block numbers from eyeris object or character vector
eyelink_asc_demo_dataset

Access example EyeLink .asc demo dataset file provided by the eyeris package.
format_call_stack

Format call stack information for display
clean_string

Clean string by removing non-alphanumeric characters
find_baseline_structure

Find baseline structure name for a given epoch
make_gallery

Create interactive epoch gallery report
epoch_and_baseline_block

Block-by-block epoch and baseline handler
extract_baseline_epochs

Extract baseline epochs from timeseries data
check_data

Check if object is of class eyeris
check_column

Check if column exists in dataframe
detrend

Detrend the pupil time series
get_confounds_for_step

Calculate confounds for a single pupil data step
detrend_pupil

Internal function to detrend pupil data
parse_eyelink_info

Parse EyeLink version and model information
make_md_table

Create markdown table from dataframe
pipeline_handler

Build a generic operation (extension) for the eyeris pipeline
check_epoch_manual_input_data

Check epoch manual input data structure
check_epoch_input

Check epoch input for plotting
count_epochs

Count epochs and validate data is epoched
lpfilt

Lowpass filtering of time series data
robust_plot

Robust plotting function with error handling
render_report

Render R Markdown report
plot_with_seed

Plot with seed handling for glassbox pipeline
epoch_manually

Manually epoch using provided start/end dataframes of timestamps
counter_bar

Create a counter progress bar
evaluate_pipeline_step_params

Evaluate pipeline step parameters
compute_baseline

Compute baseline correction for epoch data
draw_na_lines

Draw vertical lines at NA positions
normalize_gaze_coords

Normalize gaze coordinates to screen-relative units
parse_call_stack

Parse call stack information
slice_epochs_no_limits

Slice epochs with no explicit limits
convert_nested_dt

Convert nested data.table objects to tibbles
epoch_only_start_msg

Epoch based on a single event message (without explicit limits)
lpfilt_pupil

Internal function to lowpass filter pupil data
progress_bar

Create a progress bar for tracking operations
print_lightbox_img_html

Print lightbox image HTML
eyelogger

Run eyeris commands with automatic logging of R console's stdout and stderr
load_asc

Load and parse SR Research EyeLink .asc files
interpolate_pupil

Interpolate missing pupil data using linear interpolation
eyeris-package

eyeris: Flexible, Extensible, & Reproducible Pupillometry Preprocessing
prompt_user

Prompt user for continuation
slice_epochs_with_limits

Slice epochs with explicit limits
eyeris_color_palette

Default color palette for eyeris plotting functions
draw_random_epochs

Draw random epochs for plotting
export_confounds_to_csv

Export confounds data to CSV files
interpolate

Interpolate missing pupil samples
index_metadata

Index metadata from dataframe
filter_epochs

Filter epoch names from eyeris object
tick

Tick a progress bar
sanitize_event_tag

Sanitize event tag string into canonical epoch label
make_md_table_multiline

Create multiline markdown table from dataframe
make_prog_summary_plot

Create progressive preprocessing summary plot
save_detrend_plots

Save detrend plots for each block
epoch_pupil

Main epoching and baselining logic
process_epoch_and_baselines

Epoch and baseline processor
speed

Calculate pupil speed using finite differences
epoch_start_end_msg

Epoch using a start and an end message (explicit timestamps)
print_plots

Print plots in markdown format
zscore

Z-score pupil timeseries data
make_baseline_label

Create baseline label for epoch data
make_epoch_label

Generate epoch label from events and data
summarize_confounds

Extract confounding variables calculated separately for each pupil data file
plot.eyeris

Plot pre-processed pupil data from eyeris
zscore_pupil

Internal function to z-score pupil data
make_report

Create eyeris report
plot_gaze_heatmap

Create gaze heatmap of eye coordinates
plot_detrend_overlay

Internal helper to plot detrending overlay
slice_epoch

Slice epoch from raw timeseries data
plot_pupil_distribution

Plot pupil distribution histogram
save_progressive_summary_plots

Save progressive summary plots for each block
tag_gaze_coords

Tag gaze coordinates as on/off screen
merge_events_with_timeseries

Process event messages and merge with timeseries
tag_blinks

Tag blinks in pupil data
bin

Bin pupil time series by averaging within time bins
bin_pupil

Bin pupil data into specified time bins
deblink

NA-pad blink events / missing data
check_and_create_dir

Check and create directory if it doesn't exist
check_baseline_mean

Check if baseline mean is zero
check_baseline_inputs

Check baseline input arguments
check_baseline_epoch_counts

Check baseline and epoch counts match
calc_euclidean_dist

Calculate Euclidean distance between points
calculate_epoched_confounds

Calculate confounds for epoched data
add_unique_event_identifiers

Add unique event identifiers to handle duplicate event messages
alert

Display formatted alert messages
add_unique_identifiers_to_df

Add unique identifiers to a single events data frame
bidsify

Save out pupil timeseries data in a BIDS-like structure
check_input

Check if input argument is provided
check_limits

Check limits in wildcard mode
check_time_monotonic

Check time series monotonicity