% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/extract_intervals.R
\name{extract_intervals}
\alias{extract_intervals}
\title{Extract intervals from \emph{{mnirs}} data}
\usage{
extract_intervals(
  data,
  nirs_channels = NULL,
  time_channel = NULL,
  event_channel = NULL,
  sample_rate = NULL,
  start = NULL,
  end = NULL,
  span = list(c(-60, 60)),
  event_groups = c("distinct", "ensemble"),
  zero_time = FALSE,
  verbose = TRUE
)
}
\arguments{
\item{data}{A data frame of class \emph{"mnirs"} containing time series data and
metadata.}

\item{nirs_channels}{A character vector or a \code{list()} of character vectors
of mNIRS channel names to operate on within each interval (see \emph{Details}).
Names must match column names in \code{data} exactly.
\itemize{
\item Must only be specified when \code{event_groups} contains \emph{"ensemble"}-
averaged intervals. If \code{event_groups = "distinct"} no channel processing
occurs.
\item If \code{NULL} (default), channels are retrieved from \emph{"mnirs"} metadata.
}}

\item{time_channel}{A character string naming the time or sample column.
Must match a column name in \code{data} exactly.
\itemize{
\item If \code{NULL} (default), the \code{time_channel} metadata attribute of \code{data} is
used.
}}

\item{event_channel}{An \emph{optional} character string giving the name of an
event/lap column. The column may contain character event labels or integer
lap numbers.
\itemize{
\item Required when using \code{\link[=by_label]{by_label()}} or \code{\link[=by_lap]{by_lap()}} for \code{start} or \code{end}.
\item Retrieved from metadata if not defined explicitly.
}}

\item{sample_rate}{An \emph{optional} numeric sample rate (Hz) used to bin time
values for ensemble-averaging. If \code{NULL}, will be estimated from
\code{time_channel} (see \emph{Details}).}

\item{start}{Specifies where intervals begin. Either raw values -- numeric
for time values, character for event labels, explicit integer (e.g. \code{2L})
for lap numbers -- or created with \code{\link[=by_time]{by_time()}}, \code{\link[=by_label]{by_label()}}, \code{\link[=by_lap]{by_lap()}},
or \code{\link[=by_sample]{by_sample()}}.}

\item{end}{Specifies where intervals end. Either raw values -- numeric for
time values, character for event labels, explicit integer (e.g. \code{2L})
for lap numbers -- or created with \code{\link[=by_time]{by_time()}}, \code{\link[=by_label]{by_label()}}, \code{\link[=by_lap]{by_lap()}},
or \code{\link[=by_sample]{by_sample()}}.}

\item{span}{A one- or two-element numeric vector \code{c(before, after)} in units
of \code{time_channel}, or a \code{list()} of such vectors. (\emph{default}
\code{span = c(-60, 60)}. Applied additively to interval boundaries:
\itemize{
\item When both \code{start} and \code{end} are specified: \code{span[1]} shifts start times,
\code{span[2]} shifts end times.
\item When only \code{start} or only \code{end} is specified: both \code{span[1]} and
\code{span[2]} apply as a window around the event).
\item A single \emph{positive} value is recycled to shift the end times (e.g.
\code{span = 60} -> \code{c(0, 60)}).
\item A single \emph{negative} value is recycled to shift the start times (e.g.
\code{span = -60} -> \code{c(-60, 0)}).
}}

\item{event_groups}{Either a character string or a \code{list()} of integer
vectors specifying how to group intervals (see \emph{Details}).
\describe{
\item{\code{"distinct"}}{The default. Extract each interval as an independent
data frame.}
\item{\code{"ensemble"}}{Ensemble-average each specified \code{nirs_channel} across
all detected intervals, returning a single data frame.}
\item{\code{list(c(1, 2), c(3, 4))}}{Ensemble-average each specified
\code{nirs_channel} within each group and return one data frame per group.}
}}

\item{zero_time}{Logical. Default is \code{FALSE}. If \code{TRUE}, re-calculates
numeric \code{time_channel} values to start from zero within each interval
data frame.}

\item{verbose}{Logical. Default is \code{TRUE}. Display or silence (if \code{FALSE})
warnings and information messages helpful for troubleshooting. Ad
global default can be set via \code{options(mnirs.verbose = FALSE)}.}
}
\value{
A named \code{list()} of \link[tibble:tibble-package]{tibbles} of class
\emph{"mnirs"}, each with metadata available via \code{attributes()}.
}
\description{
Extract intervals from \emph{"mnirs"} time series data, specifying interval
start and end boundaries by time value, event label, lap number, or sample
index.
}
\details{
\subsection{Interval specification}{

Interval \code{start} and \code{end} boundaries are specified using helper functions,
or by passing raw values directly:

\describe{
\item{\code{\link[=by_time]{by_time()}}}{Time values in units of \code{time_channel}.}
\item{\code{\link[=by_label]{by_label()}}}{Strings to match in \code{event_channel}.
All matching occurrences are returned.}
\item{\code{\link[=by_lap]{by_lap()}}}{Lap numbers to match in \code{event_channel}. Resolves to the
first sample of each lap for \code{start}, and the last lap sample for \code{end}}
\item{\code{\link[=by_sample]{by_sample()}}}{Integer sample indices (row numbers).}
}

Raw values supplied to \code{start}/\code{end} are auto-coerced:
\itemize{
\item Numeric -> \code{\link[=by_time]{by_time()}}
\item Character -> \code{\link[=by_label]{by_label()}},
\item Explicit integer (e.g. \code{2L}) -> \code{\link[=by_lap]{by_lap()}}.
\item Use \code{\link[=by_sample]{by_sample()}} explicitly for sample indices.
}

\code{start} and \code{end} can use different specification types (e.g., start by
label, end by time). When lengths differ, the shorter is recycled.
}

\subsection{Time span window}{

\code{span} additively expands the time span window around interval boundaries.
\itemize{
\item A two-value vector expands the \code{start} and \code{end}, respectively:
\code{span = c(-60, 60)} expands the \code{start} earlier by \code{60}, and the \code{end}
later by \code{60}. For example,
\verb{start = by_time(30), end = by_time(60), span = c(-5, 10)} returns an
interval of \verb{[25, 70]}.
\item A single numeric value is recycled according to the sign: \code{span = -60}
becomes \code{c(-60, 0)} to expand the \code{start} earlier. \code{span = 60} becomes
\code{c(0, 60)} to expand the \code{end} later.
\item If only \code{start} is specified alone, both span values expand the single
boundary window: \verb{start = by_time(30), span = c(-5, 60)} returns
\verb{[25, 90]}.
}
}

\subsection{Per-interval nirs_channels for ensemble-averaging}{

When \code{event_groups = "ensemble"} or a list of numeric grouped intervals,
\code{nirs_channels} can be specified as a list of column names to override
ensemble-averaging across interval. For example, to exclude a channel
in one interval:

\if{html}{\out{<div class="sourceCode r">}}\preformatted{nirs_channels = list(
  c(A, B, C),
  c(A, C) ## channel "B" is excluded
)
}\if{html}{\out{</div>}}

If all grouped intervals can include all \code{nirs_channels}, or if
\code{event_groups = "distinct"}, a single \code{nirs_channels} character vector can
be supplied and recycled to all groups, or left as \code{NULL} for channels to
be taken from \emph{"mnirs"} metadata.
}

\subsection{Grouping intervals}{

\code{event_groups} controls whether extracted intervals are returned as distinct
data frames or ensemble-averaged.

\describe{
\item{\code{"distinct"}}{The default. Extract each interval and return a
list of independent data frames.}
\item{\code{"ensemble"}}{Ensemble-average each specified \code{nirs_channel} across
all detected intervals and return a one-item list with a single data
frame.}
\item{\code{list(c(1, 2), c(3, 4))}}{Ensemble-average each specified
\code{nirs_channel} within each group and return a list with one data frame
for each group. Any intervals detected but not specified in
\code{event_groups} are returned as distinct.}
}

\code{event_groups} lists can be named (e.g.
\code{list(low = c(1, 2), high = c(3, 4))}) and will pass those names to the
returned list of data frames.

When \code{event_groups} is a list of numeric interval numbers, list items in
\code{nirs_channels} and \code{span} are recycled to the number of groups. If lists
are only partially specified, the final item is recycled forward as needed.
Extra items are ignored.
}
}
\examples{
## read example data
data <- read_mnirs(
    example_mnirs("train.red"),
    nirs_channels = c(
        smo2_left = "SmO2 unfiltered",
        smo2_right = "SmO2 unfiltered"
    ),
    time_channel = c(time = "Timestamp (seconds passed)"),
    zero_time = TRUE,
    verbose = FALSE
) |>
    ## avoid issues ensemble-averaging irregular samples
    resample_mnirs(method = "linear", verbose = FALSE) 

## ensemble-average across multiple intervals
interval_list <- extract_intervals(
    data,                       ## channels recycled to all intervals by default
    nirs_channels = c(smo2_left, smo2_right),
    start = by_time(368, 1084), ## manually identified interval start times
    span = c(-20, 90),          ## include the last 180-sec of each interval (recycled)
    event_groups = "ensemble",  ## ensemble-average across two intervals
    zero_time = TRUE            ## re-calculate common time to start from `0`
)

interval_list[[1L]]

\donttest{
  if (requireNamespace("ggplot2", quietly = TRUE)) {
    plot(interval_list[[1L]], time_labels = TRUE) +
      ggplot2::geom_vline(xintercept = 0, linetype = "dotted")
  }
}

}
