| Title: | Flexible, Extensible, & Reproducible Pupillometry Preprocessing |
|---|---|
| Description: | Pupillometry offers a non-invasive window into the mind and has been used extensively as a psychophysiological readout of arousal signals linked with cognitive processes like attention, stress, and emotional states [Clewett et al. (2020) <doi:10.1038/s41467-020-17851-9>; Kret & Sjak-Shie (2018) <doi:10.3758/s13428-018-1075-y>; Strauch (2024) <doi:10.1016/j.tins.2024.06.002>]. Yet, despite decades of pupillometry research, many established packages and workflows to date lack design patterns based on Findability, Accessibility, Interoperability, and Reusability (FAIR) principles [see Wilkinson et al. (2016) <doi:10.1038/sdata.2016.18>]. 'eyeris' provides a modular, performant, and extensible preprocessing framework for pupillometry data with BIDS-like organization and interactive output reports [Esteban et al. (2019) <doi:10.1038/s41592-018-0235-4>; Gorgolewski et al. (2016) <doi:10.1038/sdata.2016.44>]. Development was supported, in part, by the Stanford Wu Tsai Human Performance Alliance, Stanford Ric Weiland Graduate Fellowship, Stanford Center for Mind, Brain, Computation and Technology, NIH National Institute on Aging Grants (R01-AG065255, R01-AG079345), NSF GRFP (DGE-2146755), McKnight Brain Research Foundation Clinical Translational Research Scholarship in Cognitive Aging and Age-Related Memory Loss, American Brain Foundation, and the American Academy of Neurology. |
| Authors: | Shawn Schwartz [aut, cre] (ORCID: <https://orcid.org/0000-0001-6444-8451>), Mingjian He [ctb], Haopei Yang [ctb], Alice Xue [ctb], Gustavo Santiago-Reyes [ctb] |
| Maintainer: | Shawn Schwartz <[email protected]> |
| License: | MIT + file LICENSE |
| Version: | 3.1.0 |
| Built: | 2026-06-05 19:55:33 UTC |
| Source: | https://github.com/shawntz/eyeris |
This method provides a structured way to save out pupil data in a BIDS-like structure. The method saves out epoched data as well as the raw pupil time series, and formats the directory and filename structures based on the metadata you provide.
bidsify( eyeris, save_all = TRUE, epochs_list = NULL, bids_dir = NULL, participant_id = NULL, session_num = NULL, task_name = NULL, run_num = NULL, save_raw = TRUE, html_report = TRUE, report_seed = 0, report_epoch_grouping_var_col = "matched_event", verbose = TRUE, csv_enabled = TRUE, db_enabled = FALSE, db_path = "my-project", parallel_processing = FALSE, merge_epochs = deprecated(), merge_runs = deprecated(), pdf_report = deprecated() )bidsify( eyeris, save_all = TRUE, epochs_list = NULL, bids_dir = NULL, participant_id = NULL, session_num = NULL, task_name = NULL, run_num = NULL, save_raw = TRUE, html_report = TRUE, report_seed = 0, report_epoch_grouping_var_col = "matched_event", verbose = TRUE, csv_enabled = TRUE, db_enabled = FALSE, db_path = "my-project", parallel_processing = FALSE, merge_epochs = deprecated(), merge_runs = deprecated(), pdf_report = deprecated() )
eyeris |
An object of class |
save_all |
Logical flag indicating whether all epochs are to be saved
or only a subset of them. Defaults to |
epochs_list |
List of epochs to be saved. Defaults to |
bids_dir |
Base bids_directory. Defaults to |
participant_id |
BIDS subject ID. Defaults to |
session_num |
BIDS session ID. Defaults to |
task_name |
BIDS task ID. Defaults to |
run_num |
BIDS run ID. Optional override for the run number when there's
only one block of data present in a given |
save_raw |
Logical flag indicating whether to save_raw pupil data in
addition to epoched data. Defaults to |
html_report |
Logical flag indicating whether to save out the |
report_seed |
Random seed for the plots that will appear in the report
Defaults to |
report_epoch_grouping_var_col |
String name of grouping column to use
for epoch-by-epoch diagnostic plots in an interactive rendered HTML report.
Column name must exist (i.e., be a custom grouping variable name set within
the metadata template of your |
verbose |
A flag to indicate whether to print detailed logging messages.
Defaults to |
csv_enabled |
Logical flag indicating whether to write CSV output files.
Defaults to |
db_enabled |
Logical flag indicating whether to write data to a |
db_path |
Database filename or path. Defaults to |
parallel_processing |
Logical flag to manually enable parallel database
processing. When |
merge_epochs |
(Deprecated) This parameter is deprecated and will be ignored. All epochs are now saved as separate files following BIDS conventions. This parameter will be removed in a future version |
merge_runs |
(Deprecated) This parameter is deprecated and will be ignored. All runs are now saved as separate files following BIDS conventions. This parameter will be removed in a future version |
pdf_report |
(Deprecated) Use |
In the future, we intend for this function to save out the data in an official BIDS format for eyetracking data (see the proposal currently under review here). At this time, however, this function instead takes a more BIDS-inspired approach to organizing the output files for preprocessed pupil data.
Invisibly returns NULL. Called for its side effects
# bleed around blink periods just long enough to remove majority of # deflections due to eyelid movements demo_data <- eyelink_asc_demo_dataset() # example with unepoched data demo_data |> eyeris::glassbox() |> eyeris::bidsify( bids_dir = tempdir(), # <- MAKE SURE TO UPDATE TO YOUR DESIRED LOCAL PATH participant_id = "001", session_num = "01", task_name = "assocret", run_num = "01", save_raw = TRUE, # save out raw time series html_report = TRUE, # generate interactive report document report_seed = 0 # make randomly selected plot epochs reproducible ) # example with epoched data demo_data |> eyeris::glassbox() |> eyeris::epoch( events = "PROBE_{startstop}_{trial}", limits = c(-1, 1), # grab 1 second prior to and 1 second post event label = "prePostProbe" # custom epoch label name ) |> eyeris::bidsify( bids_dir = tempdir(), # <- MAKE SURE TO UPDATE TO YOUR DESIRED LOCAL PATH participant_id = "001", session_num = "01", task_name = "assocret", run_num = "01" ) # example with run_num for single block data demo_data <- eyelink_asc_demo_dataset() demo_data |> eyeris::glassbox() |> eyeris::epoch( events = "PROBE_{startstop}_{trial}", limits = c(-1, 1), label = "prePostProbe" ) |> eyeris::bidsify( bids_dir = tempdir(), participant_id = "001", session_num = "01", task_name = "assocret", run_num = "03" # override default run-01 (block_1) to use run-03 instead ) # example with database storage enabled demo_data |> eyeris::glassbox() |> eyeris::epoch( events = "PROBE_{startstop}_{trial}", limits = c(-1, 1), label = "prePostProbe" ) |> eyeris::bidsify( bids_dir = tempdir(), participant_id = "001", session_num = "01", task_name = "assocret", db_enabled = TRUE, # enable eyerisdb database storage db_path = "my-project" # custom project database name ) # example for large-scale cloud compute (database only, no CSV files) demo_data |> eyeris::glassbox() |> eyeris::bidsify( bids_dir = tempdir(), participant_id = "001", session_num = "01", task_name = "assocret", csv_enabled = FALSE, # disable CSV files db_enabled = TRUE # database storage only )# bleed around blink periods just long enough to remove majority of # deflections due to eyelid movements demo_data <- eyelink_asc_demo_dataset() # example with unepoched data demo_data |> eyeris::glassbox() |> eyeris::bidsify( bids_dir = tempdir(), # <- MAKE SURE TO UPDATE TO YOUR DESIRED LOCAL PATH participant_id = "001", session_num = "01", task_name = "assocret", run_num = "01", save_raw = TRUE, # save out raw time series html_report = TRUE, # generate interactive report document report_seed = 0 # make randomly selected plot epochs reproducible ) # example with epoched data demo_data |> eyeris::glassbox() |> eyeris::epoch( events = "PROBE_{startstop}_{trial}", limits = c(-1, 1), # grab 1 second prior to and 1 second post event label = "prePostProbe" # custom epoch label name ) |> eyeris::bidsify( bids_dir = tempdir(), # <- MAKE SURE TO UPDATE TO YOUR DESIRED LOCAL PATH participant_id = "001", session_num = "01", task_name = "assocret", run_num = "01" ) # example with run_num for single block data demo_data <- eyelink_asc_demo_dataset() demo_data |> eyeris::glassbox() |> eyeris::epoch( events = "PROBE_{startstop}_{trial}", limits = c(-1, 1), label = "prePostProbe" ) |> eyeris::bidsify( bids_dir = tempdir(), participant_id = "001", session_num = "01", task_name = "assocret", run_num = "03" # override default run-01 (block_1) to use run-03 instead ) # example with database storage enabled demo_data |> eyeris::glassbox() |> eyeris::epoch( events = "PROBE_{startstop}_{trial}", limits = c(-1, 1), label = "prePostProbe" ) |> eyeris::bidsify( bids_dir = tempdir(), participant_id = "001", session_num = "01", task_name = "assocret", db_enabled = TRUE, # enable eyerisdb database storage db_path = "my-project" # custom project database name ) # example for large-scale cloud compute (database only, no CSV files) demo_data |> eyeris::glassbox() |> eyeris::bidsify( bids_dir = tempdir(), participant_id = "001", session_num = "01", task_name = "assocret", csv_enabled = FALSE, # disable CSV files db_enabled = TRUE # database storage only )
This function bins pupillometry data by dividing time into equal intervals and averaging the data within each bin. Unlike downsampling, binning averages data points within each time bin.
bin(eyeris, bins_per_second, method = "mean", call_info = NULL)bin(eyeris, bins_per_second, method = "mean", call_info = NULL)
eyeris |
An object of class |
bins_per_second |
The number of bins to create per second of data |
method |
The binning method: "mean" (default) or "median" |
call_info |
A list of call information and parameters. If not provided,
it will be generated from the function call. Defaults to |
Binning divides one second of pupillary data into X bins and averages pupillometry data around each bin center. The resulting time points will be: 1/2X, 3/2X, 5/2X, ..., etc. where X is the number of bins per second.
This approach is commonly used in pupillometry research to study temporal dynamics of pupil dilatory response; however, it should be used with caution (as averaging within bins can distort the pupillary dynamics).
An eyeris object with binned data and updated sampling rate
This function is part of the glassbox() preprocessing pipeline and is not
intended for direct use in most cases. Provide parameters via
bin = list(...).
Advanced users may call it directly if needed.
glassbox() for the recommended way to run this step as
part of the full eyeris glassbox preprocessing pipeline
downsample() for downsampling functionality
demo_data <- eyelink_asc_demo_dataset() # bin data into 10 bins per second using the (default) "mean" method demo_data |> eyeris::glassbox(bin = list(bins_per_second = 10, method = "mean")) |> plot(seed = 0)demo_data <- eyelink_asc_demo_dataset() # bin data into 10 bins per second using the (default) "mean" method demo_data |> eyeris::glassbox(bin = list(bins_per_second = 10, method = "mean")) |> plot(seed = 0)
Deblinking (a.k.a. NA-padding) of time series data. The intended use of this method is to remove blink-related artifacts surrounding periods of missing data. For instance, when an individual blinks, there are usually rapid decreases followed by increases in pupil size, with a chunk of data missing in-between these 'spike'-looking events. The deblinking procedure here will NA-pad each missing data point by your specified number of ms.
deblink(eyeris, extend = 50, call_info = NULL)deblink(eyeris, extend = 50, call_info = NULL)
eyeris |
An object of class |
extend |
Either a single number indicating the number of milliseconds to
pad forward/backward around each missing sample, or, a vector of length two
indicating different numbers of milliseconds pad forward/backward around each
missing sample, in the format |
call_info |
A list of call information and parameters. If not provided, it will be generated from the function call |
This function is automatically called by glassbox() by default. If needed,
customize the parameters for deblink by providing a parameter list. Use
glassbox(deblink = FALSE) to disable this step as needed.
Users should prefer using glassbox() rather than invoking this function
directly unless they have a specific reason to customize the pipeline
manually.
An eyeris object with a new column: pupil_raw_{...}_deblink
This function is part of the glassbox() preprocessing pipeline and is not
intended for direct use in most cases. Provide parameters via
deblink = list(...).
Advanced users may call it directly if needed.
glassbox() for the recommended way to run this step as
part of the full eyeris glassbox preprocessing pipeline
demo_data <- eyelink_asc_demo_dataset() # 50 ms in both directions (the default) demo_data |> eyeris::glassbox(deblink = list(extend = 50)) |> plot(seed = 0) # 40 ms backward, 50 ms forward demo_data |> # set deblink to FALSE (instead of a list of params) # to skip step (not recommended) eyeris::glassbox(deblink = list(extend = c(40, 50))) |> plot(seed = 0)demo_data <- eyelink_asc_demo_dataset() # 50 ms in both directions (the default) demo_data |> eyeris::glassbox(deblink = list(extend = 50)) |> plot(seed = 0) # 40 ms backward, 50 ms forward demo_data |> # set deblink to FALSE (instead of a list of params) # to skip step (not recommended) eyeris::glassbox(deblink = list(extend = c(40, 50))) |> plot(seed = 0)
The intended use of this method is for removing pupil samples that emerge
more quickly than would be physiologically expected. This is accomplished by
rejecting samples that exceed a "speed"-based threshold (i.e., median
absolute deviation from sample-to-sample). This threshold is computed based
on the constant n, which defaults to the value 16.
detransient(eyeris, n = 16, mad_thresh = NULL, call_info = NULL)detransient(eyeris, n = 16, mad_thresh = NULL, call_info = NULL)
eyeris |
An object of class |
n |
A constant used to compute the median absolute deviation (MAD)
threshold. Defaults to |
mad_thresh |
Default
then, with the default multiplier
In this situation, any speed
|
call_info |
A list of call information and parameters. If not provided,
it will be generated from the function call. Defaults to |
This function is automatically called by glassbox() by default. If needed,
customize the parameters for detransient by providing a parameter list. Use
glassbox(detransient = FALSE) to disable this step as needed.
Users should prefer using glassbox() rather than invoking this function
directly unless they have a specific reason to customize the pipeline
manually.
Computed properties:
pupil_speed: Compute speed of pupil by approximating the derivative
of x (pupil) with respect to y (time) using finite differences.
Let and
be two numeric vectors with
; then, the finite differences are computed as:
This produces an output vector
defined by:
For the first element:
For the last element:
For the intermediate elements ():
median_speed: The median of the computed pupil_speed:
mad_val: The median absolute deviation (MAD) of pupil_speed
from the median:
mad_thresh: A threshold computed from the median speed and the MAD,
using a constant multiplier (default value: 16):
An eyeris object with a new column in time series:
pupil_raw_{...}_detransient
This function is part of the glassbox() preprocessing pipeline and is not
intended for direct use in most cases. Provide parameters via
detransient = list(...).
Advanced users may call it directly if needed.
glassbox() for the recommended way to run this step as
part of the full eyeris glassbox preprocessing pipeline.
demo_data <- eyelink_asc_demo_dataset() demo_data |> eyeris::glassbox( detransient = list(n = 16) # set to FALSE to skip step (not recommended) ) |> plot(seed = 0)demo_data <- eyelink_asc_demo_dataset() demo_data |> eyeris::glassbox( detransient = list(n = 16) # set to FALSE to skip step (not recommended) ) |> plot(seed = 0)
Linearly detrend_pupil data by fitting a linear model of pupil_data ~ time,
and return the fitted betas and the residuals (pupil_data - fitted_values).
detrend(eyeris, call_info = NULL)detrend(eyeris, call_info = NULL)
eyeris |
An object of class |
call_info |
A list of call information and parameters. If not provided,
it will be generated from the function call. Defaults to |
This function is automatically called by glassbox() if detrend = TRUE.
Users should prefer using glassbox() rather than invoking this function
directly unless they have a specific reason to customize the pipeline
manually.
An eyeris object with two new columns in time series:
detrend_fitted_betas, and pupil_raw_{...}_detrend
This function is part of the glassbox() preprocessing pipeline and is not
intended for direct use in most cases. Use glassbox(detrend = TRUE).
Advanced users may call it directly if needed.
glassbox() for the recommended way to run this step as
part of the full eyeris glassbox preprocessing pipeline
demo_data <- eyelink_asc_demo_dataset() demo_data |> eyeris::glassbox(detrend = TRUE) |> # set to FALSE to skip step (default) plot(seed = 0)demo_data <- eyelink_asc_demo_dataset() demo_data |> eyeris::glassbox(detrend = TRUE) |> # set to FALSE to skip step (default) plot(seed = 0)
This function downsamples pupillometry data by applying an anti-aliasing filter before decimation. Unlike binning, downsampling preserves the original temporal dynamics without averaging within bins.
downsample( eyeris, target_fs, plot_freqz = FALSE, rp = 1, rs = 35, call_info = NULL )downsample( eyeris, target_fs, plot_freqz = FALSE, rp = 1, rs = 35, call_info = NULL )
eyeris |
An object of class |
target_fs |
The target sampling frequency in Hz after downsampling. |
plot_freqz |
Boolean flag for displaying filter frequency response (default FALSE). |
rp |
Passband ripple in dB (default 1). |
rs |
Stopband attenuation in dB (default 35). |
call_info |
A list of call information and parameters. If not provided, it will be generated from the function call. |
Downsampling reduces the sampling frequency by decimating data points.
The function automatically designs an anti-aliasing filter using the
lpfilt() function with carefully chosen parameters:
ws (stopband frequency) = Fs_new / 2 (Nyquist freq of new sampling rate)
wp (passband frequency) = ws - max(5, Fs_nq * 0.2)
An error is raised if wp < 4 to prevent loss of pupillary responses
The resulting time points will be: 0, 1/X, 2/X, 3/X, ..., etc. where X is the new sampling frequency.
An eyeris object with downsampled data and updated sampling rate.
This function is part of the glassbox() preprocessing pipeline and is not
intended for direct use in most cases. Provide parameters via
downsample = list(...).
Advanced users may call it directly if needed.
glassbox() for the recommended way to run this step as
part of the full eyeris glassbox preprocessing pipeline.
bin() for binning functionality.
demo_data <- eyelink_asc_demo_dataset() # downsample pupil data recorded at 1000 Hz to 100 Hz with the default params demo_data |> eyeris::glassbox(downsample = list(target_fs = 100)) |> plot(seed = 0)demo_data <- eyelink_asc_demo_dataset() # downsample pupil data recorded at 1000 Hz to 100 Hz with the default params demo_data |> eyeris::glassbox(downsample = list(target_fs = 100)) |> plot(seed = 0)
Intended to be used as the final preprocessing step. This function creates
data epochs of either fixed or dynamic durations with respect to provided
events and time limits, and also includes an intuitive metadata parsing
feature where additional trial data embedded within event messages can easily
be identified and joined into the resulting epoched data frames.
epoch( eyeris, events, limits = NULL, label = NULL, baseline = FALSE, baseline_type = c("sub", "div"), baseline_events = NULL, baseline_period = NULL, hz = NULL, verbose = TRUE, call_info = NULL, calc_baseline = deprecated(), apply_baseline = deprecated() )epoch( eyeris, events, limits = NULL, label = NULL, baseline = FALSE, baseline_type = c("sub", "div"), baseline_events = NULL, baseline_period = NULL, hz = NULL, verbose = TRUE, call_info = NULL, calc_baseline = deprecated(), apply_baseline = deprecated() )
eyeris |
An object of class |
events |
Either (1) a single string representing the event message to
perform trial extraction around, using specified list( data.frame(time = c(...), msg = c(...)), # start events data.frame(time = c(...), msg = c(...)), # end events 1 # block number ) where the first data.frame indicates the For event-modes |
limits |
A vector of 2 values (start, end) in seconds, indicating where
trial extraction should occur centered around any given |
label |
An (optional) string you can provide to customize the name of
the resulting |
baseline |
(New) A single parameter that controls baseline
correction. Set to |
baseline_type |
Whether to perform subtractive ( |
baseline_events |
Similar to |
baseline_period |
A vector of 2 values (start, end) in seconds,
indicating the window of data that will be used to perform the baseline
correction, which will be centered around the single string "start" message
string provided in |
hz |
Data sampling rate. If not specified, will use the value contained within the tracker's metadata |
verbose |
A flag to indicate whether to print detailed logging messages
Defaults to |
call_info |
A list of call information and parameters. If not provided, it will be generated from the function call |
calc_baseline |
(Deprecated) Use |
apply_baseline |
(Deprecated) Use |
An eyeris object with a new nested list of data frames: $epoch_*.
The epochs are organized hierarchically by block and preprocessing step.
Each epoch contains the pupil time series data for the specified time window
around each event message, along with metadata about the event.
When using bidsify() to export the data, filenames will include both
epoch and baseline event information for clarity.
demo_data <- eyelink_asc_demo_dataset() eye_preproc <- eyeris::glassbox(demo_data) # example 1: select 1 second before/after matched event message "PROBE*" eye_preproc |> eyeris::epoch(events = "PROBE*", limits = c(-1, 1)) # example 2: select all samples between each trial eye_preproc |> eyeris::epoch(events = "TRIALID {trial}") # example 3: grab the 1 second following probe onset eye_preproc |> eyeris::epoch( events = "PROBE_START_{trial}", limits = c(0, 1) ) # example 4: 1 second prior to and 1 second after probe onset eye_preproc |> eyeris::epoch( events = "PROBE_START_{trial}", limits = c(-1, 1), label = "prePostProbe" # custom epoch label name ) # example 5: manual start/end event pairs # note: here, the `msg` column of each data frame is optional eye_preproc |> eyeris::epoch( events = list( data.frame(time = c(11334491), msg = c("TRIALID 22")), # start events data.frame(time = c(11337158), msg = c("RESPONSE_22")), # end events 1 # block number ), label = "example5" ) # example 6: manual start/end event pairs # note: set `msg` to NA if you only want to pass in start/end timestamps eye_preproc |> eyeris::epoch( events = list( data.frame(time = c(11334491), msg = NA), # start events data.frame(time = c(11337158), msg = NA), # end events 1 # block number ), label = "example6" ) ## examples with baseline arguments enabled # example 7: use mean of 1-s preceding "PROBE_START" (i.e. "DELAY_STOP") # to perform subtractive baselining of the 1-s PROBE epochs. eye_preproc |> eyeris::epoch( events = "PROBE_START_{trial}", limits = c(0, 1), # grab 0 seconds prior to and 1 second post PROBE event label = "prePostProbe", # custom epoch label name baseline = TRUE, # calculate and apply baseline correction baseline_type = "sub", # "sub"tractive baseline calculation is default baseline_events = "DELAY_STOP_*", baseline_period = c(-1, 0) ) # example 8: use mean of time period between set start/end event messages # (i.e. between "DELAY_START" and "DELAY_STOP"). In this case, the # `baseline_period` argument will be ignored since both a "start" and "end" # message string are provided to the `baseline_events` argument. eye_preproc |> eyeris::epoch( events = "PROBE_START_{trial}", limits = c(0, 1), # grab 0 seconds prior to and 1 second post PROBE event label = "prePostProbe", # custom epoch label name baseline = TRUE, # calculate and apply baseline correction baseline_type = "sub", # "sub"tractive baseline calculation is default baseline_events = c( "DELAY_START_*", "DELAY_STOP_*" ) ) # example 9: additional (potentially helpful) example start_events <- data.frame( time = c(11334491, 11338691), msg = c("TRIALID 22", "TRIALID 23") ) end_events <- data.frame( time = c(11337158, 11341292), msg = c("RESPONSE_22", "RESPONSE_23") ) block_number <- 1 eye_preproc |> eyeris::epoch( events = list(start_events, end_events, block_number), label = "example9" )demo_data <- eyelink_asc_demo_dataset() eye_preproc <- eyeris::glassbox(demo_data) # example 1: select 1 second before/after matched event message "PROBE*" eye_preproc |> eyeris::epoch(events = "PROBE*", limits = c(-1, 1)) # example 2: select all samples between each trial eye_preproc |> eyeris::epoch(events = "TRIALID {trial}") # example 3: grab the 1 second following probe onset eye_preproc |> eyeris::epoch( events = "PROBE_START_{trial}", limits = c(0, 1) ) # example 4: 1 second prior to and 1 second after probe onset eye_preproc |> eyeris::epoch( events = "PROBE_START_{trial}", limits = c(-1, 1), label = "prePostProbe" # custom epoch label name ) # example 5: manual start/end event pairs # note: here, the `msg` column of each data frame is optional eye_preproc |> eyeris::epoch( events = list( data.frame(time = c(11334491), msg = c("TRIALID 22")), # start events data.frame(time = c(11337158), msg = c("RESPONSE_22")), # end events 1 # block number ), label = "example5" ) # example 6: manual start/end event pairs # note: set `msg` to NA if you only want to pass in start/end timestamps eye_preproc |> eyeris::epoch( events = list( data.frame(time = c(11334491), msg = NA), # start events data.frame(time = c(11337158), msg = NA), # end events 1 # block number ), label = "example6" ) ## examples with baseline arguments enabled # example 7: use mean of 1-s preceding "PROBE_START" (i.e. "DELAY_STOP") # to perform subtractive baselining of the 1-s PROBE epochs. eye_preproc |> eyeris::epoch( events = "PROBE_START_{trial}", limits = c(0, 1), # grab 0 seconds prior to and 1 second post PROBE event label = "prePostProbe", # custom epoch label name baseline = TRUE, # calculate and apply baseline correction baseline_type = "sub", # "sub"tractive baseline calculation is default baseline_events = "DELAY_STOP_*", baseline_period = c(-1, 0) ) # example 8: use mean of time period between set start/end event messages # (i.e. between "DELAY_START" and "DELAY_STOP"). In this case, the # `baseline_period` argument will be ignored since both a "start" and "end" # message string are provided to the `baseline_events` argument. eye_preproc |> eyeris::epoch( events = "PROBE_START_{trial}", limits = c(0, 1), # grab 0 seconds prior to and 1 second post PROBE event label = "prePostProbe", # custom epoch label name baseline = TRUE, # calculate and apply baseline correction baseline_type = "sub", # "sub"tractive baseline calculation is default baseline_events = c( "DELAY_START_*", "DELAY_STOP_*" ) ) # example 9: additional (potentially helpful) example start_events <- data.frame( time = c(11334491, 11338691), msg = c("TRIALID 22", "TRIALID 23") ) end_events <- data.frame( time = c(11337158, 11341292), msg = c("RESPONSE_22", "RESPONSE_23") ) block_number <- 1 eye_preproc |> eyeris::epoch( events = list(start_events, end_events, block_number), label = "example9" )
Returns the file path to the demo binocular .asc EyeLink pupil data file
included in the eyeris package.
eyelink_asc_binocular_demo_dataset()eyelink_asc_binocular_demo_dataset()
This dataset is a mock dataset trimmed from a larger data file. The original data file was obtained from: https://github.com/scott-huberty/eyelinkio/blob/main/src/eyelinkio/tests/data/test_raw_binocular.edf
A character string giving the full file path to the demo .asc
EyeLink pupil data file
path_to_binocular_demo_dataset <- eyelink_asc_binocular_demo_dataset() print(path_to_binocular_demo_dataset)path_to_binocular_demo_dataset <- eyelink_asc_binocular_demo_dataset() print(path_to_binocular_demo_dataset)
Returns the file path to the demo .asc EyeLink pupil data file
included in the eyeris package.
eyelink_asc_demo_dataset()eyelink_asc_demo_dataset()
A character string giving the full file path to the demo .asc
EyeLink pupil data file
path_to_demo_dataset <- eyelink_asc_demo_dataset() print(path_to_demo_dataset)path_to_demo_dataset <- eyelink_asc_demo_dataset() print(path_to_demo_dataset)
eyeris commands with automatic logging of R console's stdout and stderrThis utility function evaluates eyeris commands while automatically
capturing and recording both standard output (stdout) and standard error
(stderr) to timestamped log files in your desired log directory.
eyelogger( eyeris_cmd, log_dir = file.path(tempdir(), "eyeris_logs"), timestamp_format = "%Y%m%d_%H%M%S" )eyelogger( eyeris_cmd, log_dir = file.path(tempdir(), "eyeris_logs"), timestamp_format = "%Y%m%d_%H%M%S" )
eyeris_cmd |
An |
log_dir |
Character path to the desired log directory. Is set to the
temporary directory given by |
timestamp_format |
Format string passed to |
Each run produces two log files:
<timestamp>.out: records all console output
<timestamp>.err: records all warnings and errors
The result of the evaluated eyeris command (invisibly)
eyelogger({ message("eyeris `glassbox()` completed successfully.") warning("eyeris `glassbox()` completed with warnings.") print("some eyeris-related information.") }) eyelogger({ glassbox(eyelink_asc_demo_dataset(), interactive_preview = FALSE) }, log_dir = file.path(tempdir(), "eyeris_logs"))eyelogger({ message("eyeris `glassbox()` completed successfully.") warning("eyeris `glassbox()` completed with warnings.") print("some eyeris-related information.") }) eyelogger({ glassbox(eyelink_asc_demo_dataset(), interactive_preview = FALSE) }, log_dir = file.path(tempdir(), "eyeris_logs"))
A custom color palette designed for visualizing pupil data preprocessing steps. This palette is based on the RColorBrewer Set1 palette and provides distinct, visually appealing colors for different preprocessing stages.
eyeris_color_palette()eyeris_color_palette()
The palette includes 7 colors optimized for:
High contrast and visibility
Colorblind-friendly design
Consistent visual hierarchy across preprocessing steps
Professional appearance in reports and publications
Colors are designed to work well with both light and dark backgrounds and maintain readability when overlaid in time series plots.
A character vector of 7 hex color codes representing the default eyeris color palette
# get the default color palette colors <- eyeris_color_palette() print(colors) # use in a plot plot(1:7, 1:7, col = colors, pch = 19, cex = 3)# get the default color palette colors <- eyeris_color_palette() print(colors) # use in a plot plot(1:7, 1:7, col = colors, pch = 19, cex = 3)
A comprehensive wrapper function that simplifies extracting eyeris data from
the database. Provides easy one-liner access to aggregate data across multiple
subjects for each data type, without requiring SQL knowledge.
eyeris_db_collect( bids_dir, db_path = "my-project", subjects = NULL, data_types = NULL, sessions = NULL, tasks = NULL, epoch_labels = NULL, eye_suffixes = NULL, verbose = TRUE )eyeris_db_collect( bids_dir, db_path = "my-project", subjects = NULL, data_types = NULL, sessions = NULL, tasks = NULL, epoch_labels = NULL, eye_suffixes = NULL, verbose = TRUE )
bids_dir |
Path to the BIDS directory containing the database |
db_path |
Database name (defaults to "my-project", becomes "my-project.eyerisdb") |
subjects |
Vector of subject IDs to include. If NULL (default), includes all subjects |
data_types |
Vector of data types to extract. If NULL (default), extracts all available types. Valid types: "blinks", "events", "timeseries", "epochs", "epoch_summary", "run_confounds", "confounds_events", "confounds_summary" |
sessions |
Vector of session IDs to include. If NULL (default), includes all sessions |
tasks |
Vector of task names to include. If NULL (default), includes all tasks |
epoch_labels |
Vector of epoch labels to include. If NULL (default), includes all epochs. Only applies to epoch-related data types |
eye_suffixes |
Vector of eye suffixes to include. If NULL (default), includes all eyes. Typically c("eye-L", "eye-R") for binocular data |
verbose |
Logical. Whether to print progress messages (default TRUE) |
A named list of data frames, one per data type
demo_data <- eyelink_asc_demo_dataset() demo_data |> eyeris::glassbox() |> eyeris::epoch( events = "PROBE_{startstop}_{trial}", limits = c(-1, 1), label = "prePostProbe" ) |> eyeris::bidsify( bids_dir = tempdir(), participant_id = "001", session_num = "01", task_name = "assocret", run_num = "03", # override default run-01 (block_1) to use run-03 instead db_enabled = TRUE # enable database storage ) # extract all data for all subjects (returns list of data frames) all_data <- eyeris_db_collect(tempdir()) # view available data types names(all_data) # access specific data type blinks_data <- all_data$blinks epochs_data <- all_data$epochs # extract specific subjects and data types subset_data <- eyeris_db_collect( bids_dir = tempdir(), subjects = c("001"), data_types = c("blinks", "epochs", "timeseries") ) # extract epoch data for specific epoch label epoch_data <- eyeris_db_collect( bids_dir = tempdir(), data_types = "epochs", epoch_labels = "prepostprobe" )demo_data <- eyelink_asc_demo_dataset() demo_data |> eyeris::glassbox() |> eyeris::epoch( events = "PROBE_{startstop}_{trial}", limits = c(-1, 1), label = "prePostProbe" ) |> eyeris::bidsify( bids_dir = tempdir(), participant_id = "001", session_num = "01", task_name = "assocret", run_num = "03", # override default run-01 (block_1) to use run-03 instead db_enabled = TRUE # enable database storage ) # extract all data for all subjects (returns list of data frames) all_data <- eyeris_db_collect(tempdir()) # view available data types names(all_data) # access specific data type blinks_data <- all_data$blinks epochs_data <- all_data$epochs # extract specific subjects and data types subset_data <- eyeris_db_collect( bids_dir = tempdir(), subjects = c("001"), data_types = c("blinks", "epochs", "timeseries") ) # extract epoch data for specific epoch label epoch_data <- eyeris_db_collect( bids_dir = tempdir(), data_types = "epochs", epoch_labels = "prepostprobe" )
User-friendly function to connect to an existing eyeris project database.
This function provides easy access for users to query their eyeris data.
eyeris_db_connect(bids_dir, db_path = "my-project")eyeris_db_connect(bids_dir, db_path = "my-project")
bids_dir |
Path to the BIDS directory containing the database |
db_path |
Database name (defaults to "my-project", becomes "my-project.eyerisdb")
If just a filename, will look in |
Database connection object for use with other eyeris database functions
# step 1: create a database using bidsify with db_enabled = TRUE # (This example assumes you have already run bidsify to create a database) # temp dir for testing temp_dir <- tempdir() # step 2: connect to eyeris DB (will fail gracefully if no DB exists) tryCatch({ con <- eyeris_db_connect(temp_dir) tables <- eyeris_db_list_tables(con) # read timeseries data for a specific subject data <- eyeris_db_read(con, data_type = "timeseries", subject = "001") # close connection when done eyeris_db_disconnect(con) }, error = function(e) { message("No eyeris DB found - create one first with bidsify(db_enabled = TRUE)") })# step 1: create a database using bidsify with db_enabled = TRUE # (This example assumes you have already run bidsify to create a database) # temp dir for testing temp_dir <- tempdir() # step 2: connect to eyeris DB (will fail gracefully if no DB exists) tryCatch({ con <- eyeris_db_connect(temp_dir) tables <- eyeris_db_list_tables(con) # read timeseries data for a specific subject data <- eyeris_db_read(con, data_type = "timeseries", subject = "001") # close connection when done eyeris_db_disconnect(con) }, error = function(e) { message("No eyeris DB found - create one first with bidsify(db_enabled = TRUE)") })
User-friendly function to disconnect from the eyeris project database.
eyeris_db_disconnect(con)eyeris_db_disconnect(con)
con |
Database connection object |
Logical indicating success
Lists all tables in the eyeris project database with optional filtering.
eyeris_db_list_tables(con, data_type = NULL, subject = NULL)eyeris_db_list_tables(con, data_type = NULL, subject = NULL)
con |
Database connection |
data_type |
Optional filter by data type |
subject |
Optional filter by subject ID |
Character vector of table names
Reads eyeris data from the project database with dplyr-style interface.
eyeris_db_read( con, data_type = NULL, subject = NULL, session = NULL, task = NULL, run = NULL, eye_suffix = NULL, epoch_label = NULL, table_name = NULL )eyeris_db_read( con, data_type = NULL, subject = NULL, session = NULL, task = NULL, run = NULL, eye_suffix = NULL, epoch_label = NULL, table_name = NULL )
con |
Database connection |
data_type |
Type of data to read ("timeseries", "epochs", "epoch_timeseries", "epoch_summary", "events", "blinks") |
subject |
Optional subject ID filter |
session |
Optional session ID filter |
task |
Optional task name filter |
run |
Optional run number filter |
eye_suffix |
Optional eye suffix filter |
epoch_label |
Optional epoch label filter (for epoched data) |
table_name |
Exact table name (overrides other parameters) |
Data frame with requested data
Merges multiple chunked eyerisdb files back into a single database file.
Uses the reconstruction metadata file created by eyeris_db_split_for_sharing()
to ensure proper reconstruction.
eyeris_db_reconstruct_from_chunks( chunked_dir, output_path, reconstruction_file = NULL, verbose = TRUE )eyeris_db_reconstruct_from_chunks( chunked_dir, output_path, reconstruction_file = NULL, verbose = TRUE )
chunked_dir |
Directory containing the chunked database files and reconstruction metadata |
output_path |
Full path for the reconstructed database (e.g., "/path/to/reconstructed.eyerisdb") |
reconstruction_file |
Path to the reconstruction metadata JSON file. If NULL (default), searches for "*_reconstruction_info.json" in chunked_dir |
verbose |
Whether to print progress messages (default: TRUE) |
List containing information about the reconstruction process
## Not run: # Reconstruct database from chunked files reconstruction_info <- eyeris_db_reconstruct_from_chunks( chunked_dir = "/path/to/chunked_db/project-name", output_path = "/path/to/reconstructed-project.eyerisdb" ) # Specify custom reconstruction file location reconstruction_info <- eyeris_db_reconstruct_from_chunks( chunked_dir = "/path/to/chunked_db/project-name", output_path = "/path/to/reconstructed-project.eyerisdb", reconstruction_file = "/path/to/custom_reconstruction_info.json" ) ## End(Not run)## Not run: # Reconstruct database from chunked files reconstruction_info <- eyeris_db_reconstruct_from_chunks( chunked_dir = "/path/to/chunked_db/project-name", output_path = "/path/to/reconstructed-project.eyerisdb" ) # Specify custom reconstruction file location reconstruction_info <- eyeris_db_reconstruct_from_chunks( chunked_dir = "/path/to/chunked_db/project-name", output_path = "/path/to/reconstructed-project.eyerisdb", reconstruction_file = "/path/to/custom_reconstruction_info.json" ) ## End(Not run)
Creates multiple smaller eyerisdb files from a single large database for easier distribution via platforms with file size limits (GitHub, OSF, data repositories, etc.). Data can be chunked by data type, by number of chunks, or by maximum file size. Includes metadata to facilitate reconstruction of the original database.
eyeris_db_split_for_sharing( bids_dir, db_path = "my-project", output_dir = NULL, chunk_strategy = "by_data_type", n_chunks = 4, max_chunk_size_mb = 100, data_types = NULL, group_by_epoch_label = TRUE, include_metadata = TRUE, verbose = TRUE )eyeris_db_split_for_sharing( bids_dir, db_path = "my-project", output_dir = NULL, chunk_strategy = "by_data_type", n_chunks = 4, max_chunk_size_mb = 100, data_types = NULL, group_by_epoch_label = TRUE, include_metadata = TRUE, verbose = TRUE )
bids_dir |
Path to the BIDS directory containing the source database |
db_path |
Source database name (defaults to "my-project", becomes "my-project.eyerisdb") |
output_dir |
Directory to save chunked databases (defaults to bids_dir/derivatives/chunked_db) |
chunk_strategy |
Strategy for chunking: "by_data_type", "by_count", or "by_size" (default: "by_data_type") |
n_chunks |
Number of chunks to create when chunk_strategy = "by_count" (default: 4) |
max_chunk_size_mb |
Maximum size per chunk in MB when chunk_strategy = "by_size" (default: 100) |
data_types |
Vector of data types to include. If NULL (default), includes all available |
group_by_epoch_label |
If TRUE (default), processes epoch-related data types separately by epoch label |
include_metadata |
Whether to include eyeris metadata columns in chunked databases (default: TRUE) |
verbose |
Whether to print progress messages (default: TRUE) |
List containing information about created chunked databases and reconstruction instructions
## Not run: # These examples require an existing eyeris database # Chunk by data type (each data type gets its own database file) chunk_info <- eyeris_db_split_for_sharing( bids_dir = "/path/to/bids", db_path = "large-project", chunk_strategy = "by_data_type" ) # Chunk into 6 files by count chunk_info <- eyeris_db_split_for_sharing( bids_dir = "/path/to/bids", db_path = "large-project", chunk_strategy = "by_count", n_chunks = 6 ) # Chunk by size (max 50MB per file) chunk_info <- eyeris_db_split_for_sharing( bids_dir = "/path/to/bids", db_path = "large-project", chunk_strategy = "by_size", max_chunk_size_mb = 50 ) ## End(Not run)## Not run: # These examples require an existing eyeris database # Chunk by data type (each data type gets its own database file) chunk_info <- eyeris_db_split_for_sharing( bids_dir = "/path/to/bids", db_path = "large-project", chunk_strategy = "by_data_type" ) # Chunk into 6 files by count chunk_info <- eyeris_db_split_for_sharing( bids_dir = "/path/to/bids", db_path = "large-project", chunk_strategy = "by_count", n_chunks = 6 ) # Chunk by size (max 50MB per file) chunk_info <- eyeris_db_split_for_sharing( bids_dir = "/path/to/bids", db_path = "large-project", chunk_strategy = "by_size", max_chunk_size_mb = 50 ) ## End(Not run)
Provides a quick overview of the contents of an eyeris database,
including available subjects, sessions, tasks, and data types.
eyeris_db_summary(bids_dir, db_path = "my-project", verbose = TRUE)eyeris_db_summary(bids_dir, db_path = "my-project", verbose = TRUE)
bids_dir |
Path to the BIDS directory containing the database |
db_path |
Database name (defaults to "my-project", becomes "my-project.eyerisdb") |
verbose |
Logical. Whether to print detailed output (default TRUE) |
A named list containing summary information about the database contents
demo_data <- eyelink_asc_demo_dataset() demo_data |> eyeris::glassbox() |> eyeris::epoch( events = "PROBE_{startstop}_{trial}", limits = c(-1, 1), label = "prePostProbe" ) |> eyeris::bidsify( bids_dir = file.path(tempdir(), "my-cool-memory-project"), participant_id = "001", session_num = "01", task_name = "assocret", run_num = "03", # override default run-01 (block_1) to use run-03 instead db_enabled = TRUE, db_path = "my-cool-memory-study", ) # get database summary summary <- eyeris_db_summary( file.path( tempdir(), "my-cool-memory-project" ), db_path = "my-cool-memory-study" ) # view available subjects summary$subjects # view available data types summary$data_types # view table counts summary$table_countsdemo_data <- eyelink_asc_demo_dataset() demo_data |> eyeris::glassbox() |> eyeris::epoch( events = "PROBE_{startstop}_{trial}", limits = c(-1, 1), label = "prePostProbe" ) |> eyeris::bidsify( bids_dir = file.path(tempdir(), "my-cool-memory-project"), participant_id = "001", session_num = "01", task_name = "assocret", run_num = "03", # override default run-01 (block_1) to use run-03 instead db_enabled = TRUE, db_path = "my-cool-memory-study", ) # get database summary summary <- eyeris_db_summary( file.path( tempdir(), "my-cool-memory-project" ), db_path = "my-cool-memory-study" ) # view available subjects summary$subjects # view available data types summary$data_types # view table counts summary$table_counts
High-level wrapper function to export large eyeris databases to chunked CSV or Parquet files by data type. Uses chunked processing to handle very large datasets without memory issues.
eyeris_db_to_chunked_files( bids_dir, db_path = "my-project", output_dir = NULL, chunk_size = 1e+06, file_format = "csv", data_types = NULL, subjects = NULL, max_file_size_mb = 50, group_by_epoch_label = TRUE, verbose = TRUE )eyeris_db_to_chunked_files( bids_dir, db_path = "my-project", output_dir = NULL, chunk_size = 1e+06, file_format = "csv", data_types = NULL, subjects = NULL, max_file_size_mb = 50, group_by_epoch_label = TRUE, verbose = TRUE )
bids_dir |
Path to the BIDS directory containing the database |
db_path |
Database name (defaults to "my-project", becomes "my-project.eyerisdb") |
output_dir |
Directory to save output files (defaults to bids_dir/derivatives/eyerisdb_export) |
chunk_size |
Number of rows to process per chunk (default: 1000000) |
file_format |
Output format: "csv" or "parquet" (default: "csv") |
data_types |
Vector of data types to export. If NULL (default), exports all available |
subjects |
Vector of subject IDs to include. If NULL (default), includes all subjects |
max_file_size_mb |
Maximum file size in MB per output file (default: 50). When exceeded, automatically creates numbered files (e.g., data_01-of-03.csv, data_02-of-03.csv) |
group_by_epoch_label |
If TRUE (default), processes epoch-related data types separately by epoch label to reduce memory footprint and produce label-specific files. When FALSE, epochs with different labels are merged into single large files (not recommended). |
verbose |
Whether to print progress messages (default: TRUE) |
List containing information about exported files
## Not run: # These examples require an existing eyeris database # Export entire database to CSV files if (file.exists(file.path(tempdir(), "derivatives", "large-project.eyerisdb"))) { export_info <- eyeris_db_to_chunked_files( bids_dir = tempdir(), db_path = "large-project", chunk_size = 50000, file_format = "csv" ) } # Export specific data types to Parquet if (file.exists(file.path(tempdir(), "derivatives", "large-project.eyerisdb"))) { export_info <- eyeris_db_to_chunked_files( bids_dir = tempdir(), db_path = "large-project", data_types = c("timeseries", "events"), file_format = "parquet", chunk_size = 75000 ) } ## End(Not run)## Not run: # These examples require an existing eyeris database # Export entire database to CSV files if (file.exists(file.path(tempdir(), "derivatives", "large-project.eyerisdb"))) { export_info <- eyeris_db_to_chunked_files( bids_dir = tempdir(), db_path = "large-project", chunk_size = 50000, file_format = "csv" ) } # Export specific data types to Parquet if (file.exists(file.path(tempdir(), "derivatives", "large-project.eyerisdb"))) { export_info <- eyeris_db_to_chunked_files( bids_dir = tempdir(), db_path = "large-project", data_types = c("timeseries", "events"), file_format = "parquet", chunk_size = 75000 ) } ## End(Not run)
Utility function that takes an eyerisdb DuckDB database and splits it into N reasonably sized parquet files for easy management with GitHub, downloading, and distribution. Data is first grouped by table type (timeseries, epochs, events, etc.) since each has different columnar structures, then each group is split into the specified number of files. Files are organized in folders matching the database name for easy identification.
eyeris_db_to_parquet( bids_dir, db_path = "my-project", n_files_per_type = 1, output_dir = NULL, max_file_size = 512, data_types = NULL, verbose = TRUE, include_metadata = TRUE, epoch_labels = NULL, group_by_epoch_label = TRUE )eyeris_db_to_parquet( bids_dir, db_path = "my-project", n_files_per_type = 1, output_dir = NULL, max_file_size = 512, data_types = NULL, verbose = TRUE, include_metadata = TRUE, epoch_labels = NULL, group_by_epoch_label = TRUE )
bids_dir |
Path to the BIDS directory containing the database |
db_path |
Database name (defaults to "my-project", becomes "my-project.eyerisdb") |
n_files_per_type |
Number of parquet files to create per data type (default: 1) |
output_dir |
Directory to save parquet files (defaults to bids_dir/derivatives/parquet) |
max_file_size |
Maximum file size in MB per parquet file (default: 512) Used as a constraint when n_files_per_type would create files larger than this |
data_types |
Vector of data types to include. If NULL (default), includes all available. Valid types: "timeseries", "epochs", "epoch_summary", "events", "blinks", "confounds_*" |
verbose |
Whether to print progress messages (default: TRUE) |
include_metadata |
Whether to include eyeris metadata columns in output (default: TRUE) |
epoch_labels |
Optional character vector of epoch labels to include (e.g., "prepostprobe"). Only applies to epoch-related data types. If NULL, includes all labels. |
group_by_epoch_label |
If TRUE, processes epoch-related data types separately by epoch label to reduce memory footprint and produce label-specific parquet files (default: TRUE). |
List containing information about created parquet files
This function creates temporary tables during parquet export when the arrow package is not available. All temporary tables are automatically cleaned up, but if the process crashes, leftover tables may remain. The function checks for and warns about existing temporary tables before starting.
# create demo database demo_data <- eyelink_asc_demo_dataset() demo_data |> eyeris::glassbox() |> eyeris::epoch( events = "PROBE_{startstop}_{trial}", limits = c(-1, 1), label = "prePostProbe" ) |> eyeris::bidsify( bids_dir = tempdir(), participant_id = "001", session_num = "01", task_name = "memory", db_enabled = TRUE, db_path = "memory-task" ) # split into 3 parquet files per data type - creates memory-task/ folder split_info <- eyeris_db_to_parquet( bids_dir = tempdir(), db_path = "memory-task", n_files_per_type = 3 ) # split with size constraint and specific data types using the same database split_info <- eyeris_db_to_parquet( bids_dir = tempdir(), db_path = "memory-task", n_files_per_type = 5, max_file_size = 50, # max 50MB per file data_types = c("timeseries", "epochs", "events") )# create demo database demo_data <- eyelink_asc_demo_dataset() demo_data |> eyeris::glassbox() |> eyeris::epoch( events = "PROBE_{startstop}_{trial}", limits = c(-1, 1), label = "prePostProbe" ) |> eyeris::bidsify( bids_dir = tempdir(), participant_id = "001", session_num = "01", task_name = "memory", db_enabled = TRUE, db_path = "memory-task" ) # split into 3 parquet files per data type - creates memory-task/ folder split_info <- eyeris_db_to_parquet( bids_dir = tempdir(), db_path = "memory-task", n_files_per_type = 3 ) # split with size constraint and specific data types using the same database split_info <- eyeris_db_to_parquet( bids_dir = tempdir(), db_path = "memory-task", n_files_per_type = 5, max_file_size = 50, # max 50MB per file data_types = c("timeseries", "epochs", "events") )
eyeris pipelineThis glassbox function (in contrast to a "black box" function where you run
it and get a result but have no (or little) idea as to how you got from input
to output) has a few primary benefits over calling each exported function
from eyeris separately.
glassbox( file, interactive_preview = FALSE, preview_n = 3, preview_duration = 5, preview_window = NULL, verbose = TRUE, ..., confirm = deprecated(), num_previews = deprecated(), detrend_data = deprecated(), skip_detransient = deprecated() )glassbox( file, interactive_preview = FALSE, preview_n = 3, preview_duration = 5, preview_window = NULL, verbose = TRUE, ..., confirm = deprecated(), num_previews = deprecated(), detrend_data = deprecated(), skip_detransient = deprecated() )
file |
An SR Research EyeLink |
interactive_preview |
A flag to indicate whether to run the |
preview_n |
Number of random example "epochs" to generate for previewing the effect of each preprocessing step on the pupil time series |
preview_duration |
Time in seconds of each randomly selected preview |
preview_window |
The start and stop raw timestamps used to subset the
preprocessed data from each step of the |
verbose |
A logical flag to indicate whether to print status messages to
the console. Defaults to |
... |
Additional arguments to override the default, prescribed settings |
confirm |
(Deprecated) Use |
num_previews |
(Deprecated) Use |
detrend_data |
(Deprecated) A flag to indicate whether to run the
|
skip_detransient |
(Deprecated) A flag to indicate whether to skip
the |
First, this glassbox function provides a highly opinionated prescription of
steps and starting parameters we believe any pupillometry researcher should
use as their defaults when preprocessing pupillometry data.
Second, and not mutually exclusive from the first point, using this function should ideally reduce the probability of accidental mishaps when "reimplementing" the steps from the preprocessing pipeline both within and across projects. We hope to streamline the process in such a way that you could collect a pupillometry dataset and within a few minutes assess the quality of those data while simultaneously running a full preprocessing pipeline in 1-ish line of code!
Third, glassbox provides an "interactive" framework where you can evaluate
the consequences of the parameters within each step on your data in real
time, facilitating a fairly easy-to-use workflow for parameter optimization
on your particular dataset. This process essentially takes each of the
opinionated steps and provides a pre-/post-plot of the time series data for
each step so you can adjust parameters and re-run the pipeline until you are
satisfied with the choices of your parameters and their consequences on your
pupil time series data.
Preprocessed pupil data contained within an object of class eyeris
demo_data <- eyelink_asc_demo_dataset() # (1) examples using the default prescribed parameters and pipeline recipe ## (a) run an automated pipeline with no real-time inspection of parameters output <- eyeris::glassbox(demo_data) start_time <- min(output$timeseries$block_1$time_secs) end_time <- max(output$timeseries$block_1$time_secs) # by default, verbose = TRUE. To suppress messages, set verbose = FALSE. plot( output, steps = c(1, 5), preview_window = c(start_time, end_time), seed = 0 ) ## (b) run a interactive workflow (with confirmation prompts after each step) output <- eyeris::glassbox(demo_data, interactive_preview = TRUE, seed = 0) # (2) examples of overriding the default parameters output <- eyeris::glassbox( demo_data, interactive_preview = FALSE, # TRUE to visualize each step in real-time deblink = list(extend = 40), lpfilt = list(plot_freqz = TRUE) # overrides verbose parameter ) # to suppress messages, set verbose = FALSE in plot(): plot(output, seed = 0, verbose = FALSE) # (3) examples of disabling certain steps output <- eyeris::glassbox( demo_data, detransient = FALSE, detrend = FALSE, zscore = FALSE ) plot(output, seed = 0)demo_data <- eyelink_asc_demo_dataset() # (1) examples using the default prescribed parameters and pipeline recipe ## (a) run an automated pipeline with no real-time inspection of parameters output <- eyeris::glassbox(demo_data) start_time <- min(output$timeseries$block_1$time_secs) end_time <- max(output$timeseries$block_1$time_secs) # by default, verbose = TRUE. To suppress messages, set verbose = FALSE. plot( output, steps = c(1, 5), preview_window = c(start_time, end_time), seed = 0 ) ## (b) run a interactive workflow (with confirmation prompts after each step) output <- eyeris::glassbox(demo_data, interactive_preview = TRUE, seed = 0) # (2) examples of overriding the default parameters output <- eyeris::glassbox( demo_data, interactive_preview = FALSE, # TRUE to visualize each step in real-time deblink = list(extend = 40), lpfilt = list(plot_freqz = TRUE) # overrides verbose parameter ) # to suppress messages, set verbose = FALSE in plot(): plot(output, seed = 0, verbose = FALSE) # (3) examples of disabling certain steps output <- eyeris::glassbox( demo_data, detransient = FALSE, detrend = FALSE, zscore = FALSE ) plot(output, seed = 0)
Linear interpolation of time series data. The intended use of this method
is for filling in missing pupil samples (NAs) in the time series. This method
uses "na.approx()" function from the zoo package, which implements linear
interpolation using the "approx()" function from the stats package.
Currently, NAs at the beginning and the end of the data are replaced with
values on either end, respectively, using the "rule = 2" argument in the
approx() function.
interpolate(eyeris, verbose = TRUE, call_info = NULL)interpolate(eyeris, verbose = TRUE, call_info = NULL)
eyeris |
An object of class |
verbose |
A flag to indicate whether to print detailed logging messages.
Defaults to |
call_info |
A list of call information and parameters. If not provided, it will be generated from the function call |
This function is automatically called by glassbox() by default. Use
glassbox(interpolate = FALSE) to disable this step as needed.
Users should prefer using glassbox() rather than invoking this function
directly unless they have a specific reason to customize the pipeline
manually.
An eyeris object with a new column in timeseries:
pupil_raw_{...}_interpolate
This function is part of the glassbox() preprocessing pipeline and is not
intended for direct use in most cases. Use glassbox(interpolate = TRUE).
Advanced users may call it directly if needed.
glassbox() for the recommended way to run this step as
part of the full eyeris glassbox preprocessing pipeline.
demo_data <- eyelink_asc_demo_dataset() demo_data |> # set to FALSE to skip (not recommended) eyeris::glassbox(interpolate = TRUE) |> plot(seed = 0)demo_data <- eyelink_asc_demo_dataset() demo_data |> # set to FALSE to skip (not recommended) eyeris::glassbox(interpolate = TRUE) |> plot(seed = 0)
.asc filesThis function builds upon the eyelinker::read.asc() function to parse the
messages and metadata within the EyeLink .asc file. After loading and
additional processing, this function returns an S3 eyeris class for use in
all subsequent eyeris pipeline steps and functions.
load_asc( file, block = "auto", binocular_mode = c("average", "left", "right", "both"), verbose = TRUE )load_asc( file, block = "auto", binocular_mode = c("average", "left", "right", "both"), verbose = TRUE )
file |
An SR Research EyeLink |
block |
Optional block number specification. The following are valid options:
|
binocular_mode |
Optional binocular mode specification. The following are valid options:
|
verbose |
Logical. Whether to print verbose output (default TRUE). |
This function is automatically called by glassbox() by default. If
needed, customize the parameters for load_asc by providing a parameter
list.
Users should prefer using glassbox() rather than invoking this
function directly unless they have a specific reason to customize the
pipeline manually.
An object of S3 class eyeris with the following attributes:
file: Path to the original .asc file.
timeseries: Data frame of all raw time series data from the
tracker.
events: Data frame of all event messages and their time
stamps.
blinks: Data frame of all blink events.
info: Data frame of various metadata parsed from the file
header.
latest: eyeris variable for tracking pipeline run history.
For binocular data with binocular_mode = "both", returns a list
containing:
left: An eyeris object for the left eye data.
right: An eyeris object for the right eye data.
original_file: Path to the original .asc file.
This function is part of the glassbox() preprocessing pipeline and is not
intended for direct use in most cases. Provide parameters via
load_asc = list(...).
Advanced users may call it directly if needed.
eyelinker::read.asc() which this function wraps.
glassbox() for the recommended way to run this step
as part of the full eyeris glassbox preprocessing pipeline.
demo_data <- eyelink_asc_demo_dataset() demo_data |> eyeris::glassbox(load_asc = list(block = 1)) # Other useful parameter configurations ## (1) Basic usage (no block column specified) demo_data |> eyeris::load_asc() ## (2) Manual specification of block number demo_data |> eyeris::load_asc(block = 3) ## (3) Auto-detect multiple recording segments embedded within the same ## file (i.e., the default behavior) demo_data |> eyeris::load_asc(block = "auto") ## (4) Omit block column demo_data |> eyeris::load_asc(block = NULL)demo_data <- eyelink_asc_demo_dataset() demo_data |> eyeris::glassbox(load_asc = list(block = 1)) # Other useful parameter configurations ## (1) Basic usage (no block column specified) demo_data |> eyeris::load_asc() ## (2) Manual specification of block number demo_data |> eyeris::load_asc(block = 3) ## (3) Auto-detect multiple recording segments embedded within the same ## file (i.e., the default behavior) demo_data |> eyeris::load_asc(block = "auto") ## (4) Omit block column demo_data |> eyeris::load_asc(block = NULL)
The intended use of this method is for smoothing, although by specifying
wp and ws differently one can achieve highpass or bandpass filtering
as well. However, only lowpass filtering should be done on pupillometry data.
lpfilt( eyeris, wp = 4, ws = 8, rp = 1, rs = 35, plot_freqz = FALSE, call_info = NULL )lpfilt( eyeris, wp = 4, ws = 8, rp = 1, rs = 35, plot_freqz = FALSE, call_info = NULL )
eyeris |
An object of class |
wp |
The end of passband frequency in Hz (desired lowpass cutoff).
Defaults to |
ws |
The start of stopband frequency in Hz (required lowpass cutoff).
Defaults to |
rp |
Required maximal ripple within passband in dB. Defaults to |
rs |
Required minimal attenuation within stopband in dB.
Defaults to |
plot_freqz |
A flag to indicate whether to display the filter frequency
response. Defaults to |
call_info |
A list of call information and parameters. If not provided,
it will be generated from the function call. Defaults to |
This function is automatically called by glassbox() by default. If needed,
customize the parameters for lpfilt by providing a parameter list. Use
glassbox(lpfilt = FALSE) to disable this step as needed.
Users should prefer using glassbox() rather than invoking this function
directly unless they have a specific reason to customize the pipeline
manually.
An eyeris object with a new column in time series:
pupil_raw_{...}_lpfilt
This function is part of the glassbox() preprocessing pipeline and is not
intended for direct use in most cases. Provide parameters via
lpfilt = list(...).
Advanced users may call it directly if needed.
glassbox() for the recommended way to run this step as
part of the full eyeris glassbox preprocessing pipeline
demo_data <- eyelink_asc_demo_dataset() demo_data |> # set lpfilt to FALSE (instead of a list of params) to skip step eyeris::glassbox(lpfilt = list(plot_freqz = TRUE)) |> plot(seed = 0)demo_data <- eyelink_asc_demo_dataset() demo_data |> # set lpfilt to FALSE (instead of a list of params) to skip step eyeris::glassbox(lpfilt = list(plot_freqz = TRUE)) |> plot(seed = 0)
eyeris pipelinepipeline_handler enables flexible integration of custom data
processing functions into the eyeris pipeline. Under the hood,
each preprocessing function in eyeris is a wrapper around a
core operation that gets tracked, versioned, and stored using this
pipeline_handler method. As such, custom pipeline steps must conform
to the eyeris protocol for maximum compatibility with the downstream
functions we provide.
pipeline_handler(eyeris, operation, new_suffix, ...)pipeline_handler(eyeris, operation, new_suffix, ...)
eyeris |
An object of class |
operation |
The name of the function to apply to the time series data.
This custom function should accept a data frame |
new_suffix |
A character string indicating the suffix you would like to be appended to the name of the previous operation's column, which will be used for the new column name in the updated preprocessed data frame(s) |
... |
Additional (optional) arguments passed to the |
Following the eyeris protocol also ensures:
all operations follow a predictable structure, and
that new pupil data columns based on previous operations in the chain are able to be dynamically constructed within the core time series data frame.
An updated eyeris object with the new column added to the
timeseries data frame and the latest pointer updated to the name of the
most recently added column plus all previous columns (ie, the history "trace"
of preprocessing steps from start-to-present)
For more details, please check out the following vignettes:
Anatomy of an eyeris Object
vignette("anatomy", package = "eyeris")
Building Your Own Custom Pipeline Extensions
vignette("custom-extensions", package = "eyeris")
# first, define your custom data preprocessing function winsorize_pupil <- function(x, prev_op, lower = 0.01, upper = 0.99) { vec <- x[[prev_op]] q <- quantile(vec, probs = c(lower, upper), na.rm = TRUE) vec[vec < q[1]] <- q[1] vec[vec > q[2]] <- q[2] vec } # second, construct your `pipeline_handler` method wrapper winsorize <- function(eyeris, lower = 0.01, upper = 0.99, call_info = NULL) { # create call_info if not provided call_info <- if (is.null(call_info)) { list( call_stack = match.call(), parameters = list(lower = lower, upper = upper) ) } else { call_info } # handle binocular objects if (eyeris:::is_binocular_object(eyeris)) { # process left and right eyes independently left_result <- eyeris$left |> pipeline_handler( winsorize_pupil, "winsorize", lower = lower, upper = upper, call_info = call_info ) right_result <- eyeris$right |> pipeline_handler( winsorize_pupil, "winsorize", lower = lower, upper = upper, call_info = call_info ) # return combined structure list_out <- list( left = left_result, right = right_result, original_file = eyeris$original_file, raw_binocular_object = eyeris$raw_binocular_object ) class(list_out) <- "eyeris" return(list_out) } else { # regular eyeris object, process normally eyeris |> pipeline_handler( winsorize_pupil, "winsorize", lower = lower, upper = upper, call_info = call_info ) } } # and voilà, you can now connect your custom extension # directly into your custom `eyeris` pipeline definition! custom_eye <- system.file("extdata", "memory.asc", package = "eyeris") |> eyeris::load_asc(block = "auto") |> eyeris::deblink(extend = 50) |> winsorize() plot(custom_eye, seed = 1)# first, define your custom data preprocessing function winsorize_pupil <- function(x, prev_op, lower = 0.01, upper = 0.99) { vec <- x[[prev_op]] q <- quantile(vec, probs = c(lower, upper), na.rm = TRUE) vec[vec < q[1]] <- q[1] vec[vec > q[2]] <- q[2] vec } # second, construct your `pipeline_handler` method wrapper winsorize <- function(eyeris, lower = 0.01, upper = 0.99, call_info = NULL) { # create call_info if not provided call_info <- if (is.null(call_info)) { list( call_stack = match.call(), parameters = list(lower = lower, upper = upper) ) } else { call_info } # handle binocular objects if (eyeris:::is_binocular_object(eyeris)) { # process left and right eyes independently left_result <- eyeris$left |> pipeline_handler( winsorize_pupil, "winsorize", lower = lower, upper = upper, call_info = call_info ) right_result <- eyeris$right |> pipeline_handler( winsorize_pupil, "winsorize", lower = lower, upper = upper, call_info = call_info ) # return combined structure list_out <- list( left = left_result, right = right_result, original_file = eyeris$original_file, raw_binocular_object = eyeris$raw_binocular_object ) class(list_out) <- "eyeris" return(list_out) } else { # regular eyeris object, process normally eyeris |> pipeline_handler( winsorize_pupil, "winsorize", lower = lower, upper = upper, call_info = call_info ) } } # and voilà, you can now connect your custom extension # directly into your custom `eyeris` pipeline definition! custom_eye <- system.file("extdata", "memory.asc", package = "eyeris") |> eyeris::load_asc(block = "auto") |> eyeris::deblink(extend = 50) |> winsorize() plot(custom_eye, seed = 1)
Creates correlation plots showing the relationship between left and right eye measurements for pupil size, x-coordinates, and y-coordinates. This function is useful for validating binocular data quality and assessing the correlation between the two eyes.
plot_binocular_correlation( eyeris, block = 1, variables = c("pupil", "x", "y"), main = "", col_palette = "viridis", sample_rate = NULL, verbose = TRUE )plot_binocular_correlation( eyeris, block = 1, variables = c("pupil", "x", "y"), main = "", col_palette = "viridis", sample_rate = NULL, verbose = TRUE )
eyeris |
An object of class |
block |
Block number to plot (default: 1) |
variables |
Variables to plot correlations for. Defaults to
|
main |
Title for the overall plot (default: "Binocular Correlation") |
col_palette |
Color palette for the plots (default: "viridis") |
sample_rate |
Sample rate in Hz (optional, for time-based sampling) |
verbose |
Logical flag to indicate whether to print status messages (default: TRUE) |
No return value; creates correlation plots
# For binocular data loaded with binocular_mode = "both" binocular_data <- load_asc(eyelink_asc_binocular_demo_dataset(), binocular_mode = "both") plot_binocular_correlation(binocular_data) # For binocular data loaded with binocular_mode = "average" # (correlation plot will show original left vs right before averaging) avg_data <- load_asc(eyelink_asc_binocular_demo_dataset(), binocular_mode = "average") plot_binocular_correlation(avg_data$raw_binocular_object)# For binocular data loaded with binocular_mode = "both" binocular_data <- load_asc(eyelink_asc_binocular_demo_dataset(), binocular_mode = "both") plot_binocular_correlation(binocular_data) # For binocular data loaded with binocular_mode = "average" # (correlation plot will show original left vs right before averaging) avg_data <- load_asc(eyelink_asc_binocular_demo_dataset(), binocular_mode = "average") plot_binocular_correlation(avg_data$raw_binocular_object)
Creates a heatmap showing the distribution of eye_x and eye_y coordinates across the entire screen area. The heatmap shows where the participant looked most frequently during the recording period.
plot_gaze_heatmap( eyeris, block = 1, screen_width = NULL, screen_height = NULL, n_bins = 50, col_palette = "viridis", main = "Gaze Heatmap", xlab = "Screen X (pixels)", ylab = "Screen Y (pixels)", sample_rate = NULL, eye_suffix = NULL )plot_gaze_heatmap( eyeris, block = 1, screen_width = NULL, screen_height = NULL, n_bins = 50, col_palette = "viridis", main = "Gaze Heatmap", xlab = "Screen X (pixels)", ylab = "Screen Y (pixels)", sample_rate = NULL, eye_suffix = NULL )
eyeris |
An object of class |
block |
Block number to plot (default: 1) |
screen_width |
Screen width in pixels from |
screen_height |
Screen height in pixels from |
n_bins |
Number of bins for the heatmap grid (default: 50) |
col_palette |
Color palette for the heatmap (default: "viridis") |
main |
Title for the plot (default: "Fixation Heatmap") |
xlab |
X-axis label (default: "Screen X (pixels)") |
ylab |
Y-axis label (default: "Screen Y (pixels)") |
sample_rate |
Sample rate in Hz (optional) |
eye_suffix |
Eye suffix for binocular data (default: NULL) |
No return value; creates a heatmap plot
demo_data <- eyelink_asc_demo_dataset() eyeris_preproc <- glassbox(demo_data) plot_gaze_heatmap(eyeris = eyeris_preproc, block = 1)demo_data <- eyelink_asc_demo_dataset() eyeris_preproc <- glassbox(demo_data) plot_gaze_heatmap(eyeris = eyeris_preproc, block = 1)
eyeris
S3 plotting method for objects of class eyeris. Plots a single-panel
timeseries for a subset of the pupil time series at each preprocessing step.
The intended use of this function is to provide a simple method for
qualitatively assessing the consequences of the preprocessing recipe and
parameters on the raw pupillary signal.
## S3 method for class 'eyeris' plot( x, ..., steps = NULL, preview_n = NULL, preview_duration = NULL, preview_window = NULL, seed = NULL, block = 1, plot_distributions = FALSE, suppress_prompt = TRUE, verbose = TRUE, add_progressive_summary = FALSE, eye = c("left", "right", "both"), num_previews = deprecated() )## S3 method for class 'eyeris' plot( x, ..., steps = NULL, preview_n = NULL, preview_duration = NULL, preview_window = NULL, seed = NULL, block = 1, plot_distributions = FALSE, suppress_prompt = TRUE, verbose = TRUE, add_progressive_summary = FALSE, eye = c("left", "right", "both"), num_previews = deprecated() )
x |
An object of class |
... |
Additional arguments to be passed to |
steps |
Which steps to plot; defaults to |
preview_n |
Number of random example "epochs" to generate for previewing the effect of each preprocessing step on the pupil time series |
preview_duration |
Time in seconds of each randomly selected preview |
preview_window |
The start and stop raw timestamps used to subset the
preprocessed data from each step of the |
seed |
Random seed for current plotting session. Leave NULL to select
|
block |
For multi-block recordings, specifies which block to plot.
Defaults to 1. When a single |
plot_distributions |
Logical flag to indicate whether to plot both
diagnostic pupil time series and accompanying histograms of the pupil
samples at each processing step. Defaults to |
suppress_prompt |
Logical flag to disable interactive confirmation
prompts during plotting. Defaults to |
verbose |
A logical flag to indicate whether to print status messages to
the console. Defaults to |
add_progressive_summary |
Logical flag to indicate whether to add a
progressive summary plot after plotting. Defaults to |
eye |
For binocular data, specifies which eye to plot: "left", "right", or "both". Defaults to "left". For "both", currently plots left eye data (use eye="right" for right eye data) |
num_previews |
(Deprecated) Use |
No return value; iteratively plots a subset of the pupil time series from each preprocessing step run
# first, generate the preprocessed pupil data my_eyeris_data <- system.file("extdata", "memory.asc", package = "eyeris") |> eyeris::load_asc() |> eyeris::deblink(extend = 50) |> eyeris::detransient() |> eyeris::interpolate() |> eyeris::lpfilt(plot_freqz = TRUE) |> eyeris::zscore() # controlling the time series range (i.e., preview window) in your plots: ## example 1: using the default 10000 to 20000 ms time subset plot(my_eyeris_data, seed = 0, add_progressive_summary = TRUE) ## example 2: using a custom time subset (i.e., 1 to 500 ms) plot( my_eyeris_data, preview_window = c(0.01, 0.5), seed = 0, add_progressive_summary = TRUE ) # controlling which block of data you would like to plot: ## example 1: plots first block (default) plot(my_eyeris_data, seed = 0) ## example 2: plots a specific block plot(my_eyeris_data, block = 1, seed = 0) ## example 3: plots a specific block along with a custom preview window ## (i.e., 1000 to 2000 ms) plot( my_eyeris_data, block = 1, preview_window = c(1, 2), seed = 0 )# first, generate the preprocessed pupil data my_eyeris_data <- system.file("extdata", "memory.asc", package = "eyeris") |> eyeris::load_asc() |> eyeris::deblink(extend = 50) |> eyeris::detransient() |> eyeris::interpolate() |> eyeris::lpfilt(plot_freqz = TRUE) |> eyeris::zscore() # controlling the time series range (i.e., preview window) in your plots: ## example 1: using the default 10000 to 20000 ms time subset plot(my_eyeris_data, seed = 0, add_progressive_summary = TRUE) ## example 2: using a custom time subset (i.e., 1 to 500 ms) plot( my_eyeris_data, preview_window = c(0.01, 0.5), seed = 0, add_progressive_summary = TRUE ) # controlling which block of data you would like to plot: ## example 1: plots first block (default) plot(my_eyeris_data, seed = 0) ## example 2: plots a specific block plot(my_eyeris_data, block = 1, seed = 0) ## example 3: plots a specific block along with a custom preview window ## (i.e., 1000 to 2000 ms) plot( my_eyeris_data, block = 1, preview_window = c(1, 2), seed = 0 )
Handles really large databases by processing queries in reasonably sized chunks to avoid memory issues. Data can be written to CSV or Parquet files as it's processed.
process_chunked_query( con, query, chunk_size = 1e+06, output_file = NULL, process_chunk = NULL, verbose = TRUE )process_chunked_query( con, query, chunk_size = 1e+06, output_file = NULL, process_chunk = NULL, verbose = TRUE )
con |
Database connection |
query |
SQL query string to execute |
chunk_size |
Number of rows to fetch per chunk (default: 1000000) |
output_file |
Optional output file path for writing chunks. If provided, chunks will be appended to this file. File format determined by extension (.csv or .parquet) |
process_chunk |
Optional function to process each chunk. Function should accept a data.frame and return logical indicating success. If not provided and output_file is specified, chunks are written to file. |
verbose |
Whether to print progress messages (default: TRUE) |
List containing summary information about the chunked processing
## Not run: # These examples require an existing eyeris database con <- eyeris_db_connect("/path/to/bids", "my-project") # Process large query and write to CSV process_chunked_query( con, "SELECT * FROM large_table WHERE condition = 'something'", chunk_size = 50000, output_file = "large_export.csv" ) # Process large query with custom chunk processing process_chunked_query( con, "SELECT * FROM large_table", chunk_size = 25000, process_chunk = function(chunk) { # Custom processing here processed_data <- some_analysis(chunk) return(TRUE) } ) eyeris_db_disconnect(con) ## End(Not run)## Not run: # These examples require an existing eyeris database con <- eyeris_db_connect("/path/to/bids", "my-project") # Process large query and write to CSV process_chunked_query( con, "SELECT * FROM large_table WHERE condition = 'something'", chunk_size = 50000, output_file = "large_export.csv" ) # Process large query with custom chunk processing process_chunked_query( con, "SELECT * FROM large_table", chunk_size = 25000, process_chunk = function(chunk) { # Custom processing here processed_data <- some_analysis(chunk) return(TRUE) } ) eyeris_db_disconnect(con) ## End(Not run)
Convenience function to read the parquet files created by eyeris_db_to_parquet back into a single data frame or list of data frames by data type.
read_eyeris_parquet( parquet_dir, db_name = NULL, data_type = NULL, return_list = FALSE, pattern = "*.parquet", verbose = TRUE )read_eyeris_parquet( parquet_dir, db_name = NULL, data_type = NULL, return_list = FALSE, pattern = "*.parquet", verbose = TRUE )
parquet_dir |
Directory containing the parquet files, or path to database-specific folder |
db_name |
Optional database name to read from (if parquet_dir contains multiple database folders) |
data_type |
Optional data type to read (if NULL, reads all data types) |
return_list |
Whether to return a list by data type (TRUE) or combined data frame (FALSE, default) |
pattern |
Pattern to match parquet files (default: "*.parquet") |
verbose |
Whether to print progress messages (default: TRUE) |
Combined data frame from all parquet files, or list of data frames by data type
# Minimal self-contained example that avoids database creation if (requireNamespace("arrow", quietly = TRUE)) { # create a temporary folder structure: parquet/<db_name> base_dir <- file.path(tempdir(), "derivatives", "parquet") db_name <- "example-db" dir.create(file.path(base_dir, db_name), recursive = TRUE, showWarnings = FALSE) # write two small parquet parts for a single data type part1 <- data.frame(time = 1:5, value = 1:5) part2 <- data.frame(time = 6:10, value = 6:10) arrow::write_parquet( part1, file.path( base_dir, db_name, paste0(db_name, "_timeseries_part-01-of-02.parquet") ) ) arrow::write_parquet( part2, file.path( base_dir, db_name, paste0(db_name, "_timeseries_part-02-of-02.parquet") ) ) # read them back as combined data frame data <- read_eyeris_parquet(base_dir, db_name = db_name) # read as list by data type data_by_type <- read_eyeris_parquet(base_dir, db_name = db_name, return_list = TRUE) # read specific data type only timeseries_data <- read_eyeris_parquet(base_dir, db_name = db_name, data_type = "timeseries") }# Minimal self-contained example that avoids database creation if (requireNamespace("arrow", quietly = TRUE)) { # create a temporary folder structure: parquet/<db_name> base_dir <- file.path(tempdir(), "derivatives", "parquet") db_name <- "example-db" dir.create(file.path(base_dir, db_name), recursive = TRUE, showWarnings = FALSE) # write two small parquet parts for a single data type part1 <- data.frame(time = 1:5, value = 1:5) part2 <- data.frame(time = 6:10, value = 6:10) arrow::write_parquet( part1, file.path( base_dir, db_name, paste0(db_name, "_timeseries_part-01-of-02.parquet") ) ) arrow::write_parquet( part2, file.path( base_dir, db_name, paste0(db_name, "_timeseries_part-02-of-02.parquet") ) ) # read them back as combined data frame data <- read_eyeris_parquet(base_dir, db_name = db_name) # read as list by data type data_by_type <- read_eyeris_parquet(base_dir, db_name = db_name, return_list = TRUE) # read specific data type only timeseries_data <- read_eyeris_parquet(base_dir, db_name = db_name, data_type = "timeseries") }
Calculates various confounding variables for pupil data, including blink
statistics, gaze position metrics, and pupil size characteristics. These
confounds are calculated separately for each preprocessing step, recording
block, and epoched time series in the eyeris object.
summarize_confounds(eyeris)summarize_confounds(eyeris)
eyeris |
An object of class |
An eyeris object with a new nested list of data frames:
$confounds
The confounds are organized hierarchically by block and preprocessing step.
Each step contains metrics such as:
Blink rate and duration statistics
Gaze position (x,y) mean and standard deviation
Pupil size mean, standard deviation, and range
Missing data percentage
# load demo dataset demo_data <- eyelink_asc_demo_dataset() # calculate confounds for all blocks and preprocessing steps confounds <- demo_data |> eyeris::glassbox() |> eyeris::epoch( events = "PROBE_{type}_{trial}", limits = c(-1, 1), # grab 1 second prior to and 1 second post event label = "prePostProbe" # custom epoch label name ) |> eyeris::summarize_confounds() # access confounds for entire time series for a specific block and step confounds$confounds$unepoched_timeseries # access confounds for a specific epoched time series # for a specific block and step confounds$confounds$epoched_timeseries confounds$confounds$epoched_epoch_wide# load demo dataset demo_data <- eyelink_asc_demo_dataset() # calculate confounds for all blocks and preprocessing steps confounds <- demo_data |> eyeris::glassbox() |> eyeris::epoch( events = "PROBE_{type}_{trial}", limits = c(-1, 1), # grab 1 second prior to and 1 second post event label = "prePostProbe" # custom epoch label name ) |> eyeris::summarize_confounds() # access confounds for entire time series for a specific block and step confounds$confounds$unepoched_timeseries # access confounds for a specific epoched time series # for a specific block and step confounds$confounds$epoched_timeseries confounds$confounds$epoched_epoch_wide
The intended use of this method is to scale the arbitrary units of the pupil
size time series to have a mean of 0 and a standard deviation of 1. This
is accomplished by mean centering the data points and then dividing them by
their standard deviation (i.e., z-scoring the data, similar to
base::scale()). Opting to z-score your pupil data helps with trial-level
and between-subjects analyses where arbitrary units of pupil size recorded by
the tracker do not scale across participants, and therefore make analyses
that depend on data from more than one participant difficult to interpret.
zscore(eyeris, call_info = NULL)zscore(eyeris, call_info = NULL)
eyeris |
An object of class |
call_info |
A list of call information and parameters. If not provided, it will be generated from the function call |
This function is automatically called by glassbox() by default. Use
glassbox(zscore = FALSE) to disable this step as needed.
Users should prefer using glassbox() rather than invoking this function
directly unless they have a specific reason to customize the pipeline
manually.
In general, it is common to z-score pupil data within any given participant, and furthermore, z-score that participant's data as a function of block number (for tasks/experiments where participants complete more than one block of trials) to account for potential time-on-task effects across task/experiment blocks.
As such, if you use the eyeris package as intended, you should NOT need
to specify any groups for the participant/block-level situations described
above. This is because eyeris is designed to preprocess a single block of
pupil data for a single participant, one at a time. Therefore, when you later
merge all of the preprocessed data from eyeris, each individual,
preprocessed block of data for each participant will have already been
independently scaled from the others.
Additionally, if you intend to compare mean z-scored pupil size across task conditions, such as that for memory successes vs. memory failures, then do NOT set your behavioral outcome (i.e., success/failure) variable as a grouping variable within your analysis. If you do, you will consequently obtain a mean pupil size of 0 and standard deviation of 1 within each group (since the scaled pupil size would be calculated on the time series from each outcome variable group, separately). Instead, you should compute the z-score on the entire pupil time series (before epoching the data), and then split and take the mean of the z-scored time series as a function of condition variable.
An eyeris object with a new column in time series:
pupil_raw_{...}_z
This function is part of the glassbox() preprocessing pipeline and is not
intended for direct use in most cases. Use glassbox(zscore = TRUE).
Advanced users may call it directly if needed.
glassbox() for the recommended way to run this step as
part of the full eyeris glassbox preprocessing pipeline
demo_data <- eyelink_asc_demo_dataset() demo_data |> eyeris::glassbox(zscore = TRUE) |> # set to FALSE to skip (not recommended) plot(seed = 0)demo_data <- eyelink_asc_demo_dataset() demo_data |> eyeris::glassbox(zscore = TRUE) |> # set to FALSE to skip (not recommended) plot(seed = 0)