Nothing
#' Re-scale data range
#'
#' Expand or reduce the range (min and max values) of data channels to a new
#' amplitude/dynamic range, e.g. re-scale the range of NIRS data to `c(0, 100)`.
#'
#' @usage
#' rescale_mnirs(
#' data,
#' nirs_channels = list(),
#' range,
#' verbose = TRUE
#' )
#'
#' @param nirs_channels A `list()` of character vectors indicating grouping
#' structure of mNIRS channel names to operate on (see *Details*). Must
#' match column names in `data` exactly. Retrieved from metadata if not
#' defined explicitly.
#' \describe{
#' \item{`list("A", "B", "C")`}{Will operate on each channel independently,
#' losing the relative scaling between channels.}
#' \item{`list(c("A", "B", "C"))`}{Will operate on all channels together,
#' preserving the relative scaling between channels.}
#' \item{`list(c("A", "B"), c("C", "D"))`}{Will operate on channels `A`
#' & `B` in one group, and `C` & `D` in another group, preserving
#' relative scaling within, but not between groups.}
#' }
#' @param range A numeric vector in the form `c(min, max)`, indicating the
#' range of output values to which data channels will be re-scaled.
#' @inheritParams validate_mnirs
#'
#' @details
#' `nirs_channels = list()` can be used to group data channels (column names)
#' to preserve absolute or relative scaling.
#'
#' - Channels grouped together in a vector (e.g. `list(c("A", "B"))`) will be
#' re-scaled to a common range, and the relative scaling within that group
#' will be preserved.
#'
#' - Channels in separate list vectors (e.g. `list("A", "B")`) will be
#' re-scaled independently, and relative scaling between groups will be lost.
#'
#' - A single vector of channel names (e.g. `c("A", "B")`) will group
#' channels together.
#'
#' - Channels (columns) in `data` not explicitly defined in `nirs_channels`
#' will be passed through untouched to the output data frame.
#'
#' `nirs_channels` can be retrieved automatically from `data` of class
#' *"mnirs"* which has been processed with `{mnirs}`, if not defined
#' explicitly. This will default to returning all `nirs_channels` grouped
#' together, and should be defined explicitly for other grouping arrangements.
#'
#' @returns
#' A [tibble][tibble::tibble-package] of class *"mnirs"* with metadata
#' available with `attributes()`.
#'
#' @examples
#' ## read example data
#' data <- read_mnirs(
#' file_path = example_mnirs("moxy_ramp"),
#' nirs_channels = c(smo2_left = "SmO2 Live",
#' smo2_right = "SmO2 Live(2)"),
#' time_channel = c(time = "hh:mm:ss"),
#' verbose = FALSE
#' ) |>
#' rescale_mnirs( ## un-grouped nirs channels to rescale separately
#' nirs_channels = list(smo2_left, smo2_right),
#' range = c(0, 100) ## rescale to a 0-100% functional exercise range
#' )
#'
#' data
#'
#' \donttest{
#' if (requireNamespace("ggplot2", quietly = TRUE)) {
#' plot(data, time_labels = TRUE) +
#' ggplot2::geom_hline(yintercept = c(0, 100), linetype = "dotted")
#' }
#' }
#'
#' @export
rescale_mnirs <- function(
data,
nirs_channels = list(),
range,
verbose = TRUE
) {
## validate =================================
validate_mnirs_data(data, ncol = 1)
metadata <- attributes(data)
if (missing(verbose)) {
verbose <- getOption("mnirs.verbose", default = TRUE)
}
nirs_channels <- validate_nirs_channels(
enquo(nirs_channels), data, verbose, as_list = TRUE
)
validate_numeric(
range, 2,
msg1 = "two-element",
msg2 = "between {col_blue('range[1], range[2]]')}."
)
if (
verbose &&
is.null(attr(data, "nirs_channels")) &&
!is.list(nirs_channels)
) {
cli_inform(c(
"!" = "{.fn rescale_mnirs} accepts {.arg nirs_channels} = \\
{col_blue('list()')} for channel grouping. See `?rescale_mnirs`."
))
}
## rescale range ================================
## this is actually a fast modify-in-place for loop
for (group in nirs_channels) {
group_data <- as.matrix(data[, group, drop = FALSE])
group_data_range <- range(group_data, na.rm = TRUE)
range_diff <- diff(group_data_range)
if (range_diff != 0) {
# fmt: skip
data[, group] <- (group_data - group_data_range[1]) /
range_diff * diff(range) + range[1]
}
}
## Metadata =================================
metadata$nirs_channels <- unique(unlist(nirs_channels))
return(create_mnirs_data(data, metadata))
}
Any scripts or data that you put into this service are public.
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.