--- title: "Event Handling in PhysioCore" output: rmarkdown::html_vignette vignette: > %\VignetteIndexEntry{Event Handling in PhysioCore} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} --- ```{r setup, include = FALSE} knitr::opts_chunk$set( collapse = TRUE, comment = "#>" ) ``` ## Introduction Physiological experiments typically involve discrete events such as stimulus presentations, participant responses, and experimental condition markers. PhysioCore provides the `PhysioEvents` class and a set of functions for creating, querying, filtering, and modifying event information within `PhysioExperiment` objects. This vignette covers the event system in detail: creating events, attaching them to data objects, querying and filtering, and converting between time and sample representations. ## The PhysioEvents Class `PhysioEvents` is a lightweight S4 class that stores event data as a `DataFrame` with four columns: - **onset**: event onset time in seconds - **duration**: event duration in seconds - **type**: event category (e.g., "stimulus", "response") - **value**: event label or value (e.g., "target", "hit") ### Creating Events ```{r create-events, eval=FALSE} library(PhysioCore) # Create events with full specification events <- PhysioEvents( onset = c(1.0, 2.5, 4.0, 5.5, 7.0), duration = c(0.5, 0.5, 0.5, 0.5, 0.5), type = c("stimulus", "response", "stimulus", "response", "stimulus"), value = c("target", "hit", "distractor", "false_alarm", "target") ) events ``` ### Default Values When creating events, only `onset` is strictly required. Other fields receive sensible defaults: ```{r create-defaults, eval=FALSE} # Duration defaults to 0, type to "event", value to "" simple_events <- PhysioEvents( onset = c(1, 2, 3, 4, 5) ) simple_events # Single type is recycled across all events stim_events <- PhysioEvents( onset = c(1, 2, 3, 4, 5), type = "stimulus" ) stim_events ``` ### Inspecting Events ```{r inspect-events, eval=FALSE} # Number of events nEvents(events) # The show method prints a summary events ``` ## Attaching Events to PhysioExperiment Events are stored in the `metadata` slot of a `PhysioExperiment` object. Use `setEvents()` to attach them. ```{r attach-events, eval=FALSE} # Create a PhysioExperiment pe <- PhysioExperiment( assays = list(raw = matrix(rnorm(2500), nrow = 2500, ncol = 4)), colData = S4Vectors::DataFrame( label = c("Fz", "Cz", "Pz", "Oz"), type = rep("EEG", 4) ), samplingRate = 250 ) # Attach events pe <- setEvents(pe, events) # Count events attached to the object nEvents(pe) ``` ### Setting Events from a Data Frame You can also pass a plain `data.frame` to `setEvents()`, which will be automatically converted to a `PhysioEvents` object: ```{r events-from-df, eval=FALSE} event_df <- data.frame( onset = c(0.5, 1.5, 2.5), duration = c(0.2, 0.2, 0.2), type = c("stimulus", "stimulus", "stimulus"), value = c("A", "B", "A") ) pe <- setEvents(pe, event_df) getEvents(pe) ``` ## Retrieving Events Use `getEvents()` to retrieve events from a `PhysioExperiment`. You can optionally filter by event type. ```{r get-events, eval=FALSE} # First, set up events with mixed types pe <- setEvents(pe, PhysioEvents( onset = c(1.0, 1.8, 2.5, 3.2, 4.0, 4.7), type = c("stimulus", "response", "stimulus", "response", "stimulus", "response"), value = c("target", "hit", "distractor", "correct_reject", "target", "hit") )) # Get all events all_events <- getEvents(pe) all_events # Get only stimulus events stim <- getEvents(pe, type = "stimulus") stim # Get only response events resp <- getEvents(pe, type = "response") nEvents(resp) ``` ## Adding Events Use `addEvents()` to append new events to existing ones. Events are automatically sorted by onset time. ```{r add-events, eval=FALSE} # Start with stimulus events pe <- PhysioExperiment( assays = list(raw = matrix(rnorm(2500), nrow = 2500, ncol = 4)), samplingRate = 250 ) pe <- addEvents(pe, onset = c(1, 3, 5), type = "stimulus", value = "target") nEvents(pe) # 3 # Add response events pe <- addEvents(pe, onset = c(1.5, 3.4), type = "response", value = c("hit", "hit") ) nEvents(pe) # 5 # Events are sorted by onset time getEvents(pe) ``` ## Removing Events Use `removeEvents()` to remove events by type, by index, or remove all events. ```{r remove-events, eval=FALSE} # Remove all response events pe_stim_only <- removeEvents(pe, type = "response") nEvents(pe_stim_only) # Remove specific events by index pe_fewer <- removeEvents(pe, indices = c(1, 2)) nEvents(pe_fewer) # Remove all events pe_no_events <- removeEvents(pe) nEvents(pe_no_events) # 0 ``` ## Time and Sample Conversion PhysioCore provides functions to convert between time in seconds and sample indices, which is useful for aligning events with signal data. ```{r time-conversion, eval=FALSE} pe <- PhysioExperiment( assays = list(raw = matrix(rnorm(2500), nrow = 2500, ncol = 4)), samplingRate = 250 ) # Convert times to sample indices sample_idx <- timeToSamples(pe, c(0.0, 1.0, 2.0)) sample_idx # 1, 251, 501 # Convert sample indices back to times times <- samplesToTime(pe, c(1, 251, 501)) times # 0.0, 1.0, 2.0 ``` ## Working with Event Windows A common workflow is to extract data around events. You can combine event retrieval with time-based subsetting: ```{r event-windows, eval=FALSE} # Set up experiment with events pe <- PhysioExperiment( assays = list(raw = matrix(rnorm(25000), nrow = 25000, ncol = 4)), colData = S4Vectors::DataFrame(label = c("Fz", "Cz", "Pz", "Oz")), samplingRate = 250 ) pe <- addEvents(pe, onset = c(10, 30, 50, 70), type = "stimulus", value = "target" ) # Extract a window around the first event events_df <- getEvents(pe) first_onset <- events_df@events$onset[1] # Extract 1 second before to 2 seconds after the event pe_epoch <- extractWindow(pe, tmin = first_onset - 1, tmax = first_onset + 2) duration(pe_epoch) # approximately 3 seconds ``` ## Events and Time Concatenation When combining `PhysioExperiment` objects along the time axis using `rbindPhysio()`, event onsets in the second object are automatically offset by the duration of the first: ```{r rbind-events, eval=FALSE} pe1 <- PhysioExperiment( assays = list(raw = matrix(rnorm(1000), nrow = 1000, ncol = 4)), samplingRate = 250 ) pe1 <- addEvents(pe1, onset = c(1, 2), type = "stimulus") pe2 <- PhysioExperiment( assays = list(raw = matrix(rnorm(1000), nrow = 1000, ncol = 4)), samplingRate = 250 ) pe2 <- addEvents(pe2, onset = c(1, 2), type = "stimulus") pe_combined <- rbindPhysio(pe1, pe2) # Events from pe2 are offset by the duration of pe1 (4 seconds) getEvents(pe_combined) ``` ## Summary The PhysioCore event system provides: - **PhysioEvents()**: constructor for event objects with onset, duration, type, and value fields - **setEvents() / getEvents()**: attach and retrieve events from PhysioExperiment objects - **addEvents() / removeEvents()**: incrementally modify the event set - **nEvents()**: count events - **timeToSamples() / samplesToTime()**: convert between time and sample representations These tools form the foundation for event-related analyses such as epoching and ERP computation in downstream packages. ## Session Info ```{r session-info, eval=FALSE} sessionInfo() ```