--- title: "Getting Started with PhysioCore" output: rmarkdown::html_vignette vignette: > %\VignetteIndexEntry{Getting Started with PhysioCore} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} --- ```{r setup, include = FALSE} knitr::opts_chunk$set( collapse = TRUE, comment = "#>" ) ``` ## Introduction PhysioCore provides the `PhysioExperiment` class, a Bioconductor-compatible data structure for multi-modal physiological signal data. Built on top of `SummarizedExperiment`, it adds a sampling rate slot and convenience functions for channel management, event handling, and signal utilities. This vignette covers the basics of creating `PhysioExperiment` objects, accessing and modifying their contents, and managing channel metadata. ## Creating a PhysioExperiment The `PhysioExperiment()` constructor accepts assay data (as a list of matrices or arrays), channel metadata via `colData`, and a sampling rate in Hz. ```{r create-basic, eval=FALSE} library(PhysioCore) # Simulate 4 seconds of 4-channel EEG data at 250 Hz n_time <- 1000 n_channels <- 4 sr <- 250 eeg_data <- matrix(rnorm(n_time * n_channels), nrow = n_time, ncol = n_channels) pe <- PhysioExperiment( assays = list(raw = eeg_data), colData = S4Vectors::DataFrame( label = c("Fz", "Cz", "Pz", "Oz"), type = rep("EEG", n_channels) ), samplingRate = sr ) pe ``` ### Multiple Assays You can store multiple processing stages as separate assays. For example, a raw signal and a filtered version: ```{r multiple-assays, eval=FALSE} pe_multi <- PhysioExperiment( assays = list( raw = eeg_data, filtered = eeg_data * 0.8 # placeholder for filtered data ), colData = S4Vectors::DataFrame( label = c("Fz", "Cz", "Pz", "Oz"), type = rep("EEG", n_channels) ), samplingRate = sr ) SummarizedExperiment::assayNames(pe_multi) ``` ## Accessing Basic Properties ### Sampling Rate ```{r sampling-rate, eval=FALSE} # Get sampling rate samplingRate(pe) # Set sampling rate samplingRate(pe) <- 500 samplingRate(pe) ``` ### Dimensions and Duration ```{r dimensions, eval=FALSE} # Number of time points x channels dim(pe) # Total number of time points length(pe) # Signal duration in seconds duration(pe) # Time vector in seconds head(timeIndex(pe)) ``` ### Default Assay The first assay is treated as the default for operations that do not specify an assay explicitly: ```{r default-assay, eval=FALSE} defaultAssay(pe) ``` ## Channel Management PhysioCore provides a rich set of functions for managing channel metadata. ### Reading Channel Information ```{r channel-info, eval=FALSE} # Full channel metadata (returns a DataFrame) channelInfo(pe) # Channel labels channelNames(pe) # Number of channels nChannels(pe) ``` ### Setting Channel Properties ```{r channel-properties, eval=FALSE} # Rename channels channelNames(pe) <- c("F3", "C3", "P3", "O1") channelNames(pe) # Or rename specific channels pe <- renameChannels(pe, old_names = "F3", new_names = "Fz") # Set channel types pe <- setChannelTypes(pe, c("EEG", "EEG", "EEG", "EEG")) # Set channel types by name pe <- setChannelTypes(pe, c(Fz = "EEG")) # Set physical units pe <- setChannelUnits(pe, "uV") ``` ### Subsetting Channels ```{r channel-subsetting, eval=FALSE} # Pick channels by name pe_frontal <- pickChannels(pe, c("Fz", "C3")) nChannels(pe_frontal) # Pick channels by index pe_subset <- pickChannels(pe, c(1, 3)) # Drop channels pe_dropped <- dropChannels(pe, "O1") nChannels(pe_dropped) # Get channel indices by type eeg_idx <- getChannelsByType(pe, "EEG") ``` ### Electrode Positions and Montages ```{r electrode-positions, eval=FALSE} # Apply a standard 10-20 montage pe <- applyMontage(pe, "10-20") # Read electrode positions positions <- getElectrodePositions(pe) head(positions) # Set custom positions custom_pos <- data.frame( x = c(0, 0, 0, 0), y = c(0.71, 0, -0.71, -1.0), z = c(0.71, 1.0, 0.71, 0) ) pe <- setElectrodePositions(pe, custom_pos) ``` ### Reference Electrode ```{r reference, eval=FALSE} # Set the reference electrode pe <- setReference(pe, "average") getReference(pe) ``` ## Subsetting and Combining ### Time-based Subsetting ```{r time-subsetting, eval=FALSE} # Extract a time window (in seconds) pe_window <- extractWindow(pe, tmin = 1.0, tmax = 3.0) duration(pe_window) # Index-based subsetting pe_first50 <- pe[1:50, ] dim(pe_first50) ``` ### Combining Objects ```{r combining, eval=FALSE} # Combine by channels (same time points required) pe1 <- pickChannels(pe, c(1, 2)) pe2 <- pickChannels(pe, c(3, 4)) pe_combined <- cbindPhysio(pe1, pe2) nChannels(pe_combined) # Combine by time (same channels required) pe_first <- pe[1:500, ] pe_second <- pe[501:1000, ] pe_concat <- rbindPhysio(pe_first, pe_second) length(pe_concat) ``` ## Summary Statistics ```{r summary, eval=FALSE} # Per-channel summary statistics summary(pe) # Convert to data.frame for further analysis df <- as.data.frame(pe) head(df) ``` ## NA Handling PhysioCore provides utilities for checking and handling missing values: ```{r na-handling, eval=FALSE} # Check for NA presence hasNA(pe) # Detailed NA check checkNA(pe) # NA summary across all assays naSummary(pe) # Replace NA values in an assay pe_clean <- replaceNA(pe, method = "interpolate") # Handle NA in a numeric vector x <- c(1, NA, 3, NA, 5) handleNA(x, method = "interpolate") handleNA(x, method = "locf") # Fill edge NA values y <- c(NA, NA, 1, 2, 3, NA) fillEdgeNA(y, method = "extend") ``` ## Next Steps - See `vignette("event-handling", package = "PhysioCore")` for working with experimental events and triggers. - Explore the PhysioAnalysis, PhysioPreprocess, and PhysioIO packages for signal processing, filtering, and file I/O capabilities built on PhysioCore. ## Session Info ```{r session-info, eval=FALSE} sessionInfo() ```