# returns scale factor with which to multiply `input` in order to scale to
# desired euol
si_dist_to_si_dist_fct <- function(from, to){
confuns::check_one_of(
input = to,
against = validUnitsOfLengthSI(),
suggest = FALSE
)
fct_from <- base::unname(euol_factors[from])
fct_to <- base::unname(euol_factors[to])
fct_out <- fct_from/fct_to
return(fct_out)
}
# estimate ----------------------------------------------------------------
estimate_r2_for_sas_run <- function(object,
ids,
distance,
core,
resolution,
angle_span = c(0, 360),
noise_levels = base::seq(from = 0, to = 100, length.out = 11),
n_sim = 25,
control = NULL,
bcs_exclude = character(),
verbose = NULL,
...){
deprecated(...)
hlpr_assign_arguments(object)
if(is.null(control)){ control <- sgs_loess_control}
unit <- getDefaultUnit(object)
if(base::length(resolution) == 1){
resolution <- rep(resolution, 2)
}
resolution <- as_unit(resolution, unit = unit, object = object)
# step 1 data simulation
simulations <-
purrr::map(
.x = base::names(model_formulas_R2_est),
.f = function(mname){
id <-
base::toupper(mname) %>%
stringr::str_remove_all(pattern = "[^A-Z]")
list(id = id, n = n_sim, model = mname)
}
) %>%
purrr::set_names(nm = base::names(model_formulas_R2_est))
sim_mtr <-
simulate_expression_pattern_sas(
object = object,
ids = ids,
simulations = simulations,
core = core,
resolution = resolution[2],
distance = distance,
noise_levels = noise_levels,
noise_types = "ed",
model_add = model_formulas_R2_est,
seed = 123,
verbose = verbose
)
object <-
createMolecularAssay(
object = object,
modality = "simR2",
active_mtr = "sim",
mtr_proc = list(sim = sim_mtr),
activate = TRUE,
overwrite = TRUE,
verbose = FALSE
)
variables <- base::rownames(sim_mtr)
gc()
resolution <- resolution[1]
# step 2 screening
coords_df <-
getCoordsDfSA(
object = object,
ids = ids,
distance = distance,
resolution = resolution,
angle_span = angle_span,
dist_unit = unit,
core = core,
variables = variables,
periphery = FALSE,
verbose = FALSE
) %>%
dplyr::filter(!barcodes %in% {{bcs_exclude}})
variables <- variables[variables %in% base::names(coords_df)]
tot_dist <- compute_dist_screened(coords_df)
if(unit != "px"){
tot_dist <- units::set_units(tot_dist, value = unit, mode = "standard")
}
resolution <- as_unit(resolution, unit = unit, object = object)
cf <-
compute_correction_factor_sas(
object = object,
id = ids,
distance = distance,
core = core,
coords_df_sa = coords_df
)
span <- base::as.numeric(resolution/tot_dist) / cf
expr_est_pos <- compute_expression_estimates(coords_df)
nv <- base::length(variables)
confuns::give_feedback(
msg = glue::glue("Evaluating..."),
verbose = verbose
)
pb <- confuns::create_progress_bar(total = nv)
sas_df <-
purrr::map_df(
.x = variables,
.f = function(var){
pb$tick()
# fit loess
coords_df[["x.var.x"]] <- coords_df[[var]]
loess_model <-
stats::loess(
formula = x.var.x ~ dist,
data = coords_df,
span = span,
control = base::do.call(stats::loess.control, args = control)
)
gradient <-
infer_gradient(
loess_model = loess_model,
expr_est_pos = expr_est_pos,
ro = c(0,1)
)
out <-
tibble::tibble(
variables = var,
tot_var = compute_total_variation(gradient)
)
return(out)
}
) %>%
add_benchmarking_variables() %>%
dplyr::ungroup() %>%
dplyr::mutate(model_sim = confuns::str_extract_after(variables, pattern = "SE\\.", match = "[A-Z]*"))
gc()
# step 3 compute R2
r2_df <-
purrr::map_df(
.x = base::unique(sas_df$model_sim),
.f = function(ms){
so <-
dplyr::filter(sas_df, model_sim == {{ms}}) %>%
stats::lm(data = ., formula = noise_perc ~ tot_var) %>%
base::summary()
tibble::tibble(
model = {{ms}},
r2 = so[["adj.r.squared"]]
)
}
)
out <- list(r2_df = r2_df, sas_df = sas_df)
return(out)
}
estimate_r2_for_sts_run <- function(object,
id,
resolution,
width,
noise_levels = base::seq(from = 0, to = 100, length.out = 11),
n_sim = 20,
control = NULL,
verbose = NULL){
hlpr_assign_arguments(object)
if(base::is.null(control)){
control <- sgs_loess_control
}
simulations <-
purrr::map(
.x = base::names(model_formulas_R2_est),
.f = function(mname){
id <-
base::toupper(mname) %>%
stringr::str_remove_all(pattern = "[^A-Z]")
list(
id = id,
n = n_sim,
model = mname
)
}
) %>%
purrr::set_names(nm = base::names(model_formulas_R2_est))
sim_mtr <-
simulate_expression_pattern_sts(
object = object,
id = id,
simulations = simulations,
resolution = resolution,
width = width,
noise_levels = noise_levels,
noise_types = "ed",
model_add = model_formulas_R2_est,
seed = 123,
verbose = T
)
object <-
createMolecularAssay(
object = object,
modality = "simR2",
active_mtr = "sim",
mtr_proc = list(sim = sim_mtr),
activate = TRUE,
overwrite = TRUE,
verbose = FALSE
)
variables <- base::rownames(sim_mtr)
unit <- getDefaultUnit(object)
coords_df <-
getCoordsDfST(
object = object,
id = id,
resolution = resolution,
width = width,
variables = variables,
dist_unit = unit,
verbose = FALSE
)
coords_df <- dplyr::filter(coords_df, rel_loc == "inside")
# max_dist does not depend on `core` option
min_dist <- as_unit(input = 0, unit = unit, object = object)
max_dist <- getTrajectoryLength(object, id = id, unit = unit)
resolution <- as_unit(resolution, unit = unit, object = object)
tot_dist <- max_dist - min_dist
span <- base::as.numeric(resolution/tot_dist)
expr_est_pos <- compute_expression_estimates(coords_df)
pb <- confuns::create_progress_bar(total = base::length(variables))
sgs_df <-
purrr::map_df(
.x = variables,
.f = function(var){
pb$tick()
# fit loess
coords_df[["x.var.x"]] <- coords_df[[var]]
loess_model <-
stats::loess(
formula = x.var.x ~ dist,
data = coords_df,
span = span,
control = base::do.call(stats::loess.control, args = control)
)
gradient <-
infer_gradient(
loess_model = loess_model,
expr_est_pos = expr_est_pos,
ro = c(0,1)
)
out <-
tibble::tibble(
variables = var,
tot_var = compute_total_variation(gradient)
)
return(out)
}
) %>%
add_benchmarking_variables() %>%
dplyr::mutate(model_sim = confuns::str_extract_after(variables, pattern = "SE\\.", match = "[A-Z]*"))
r2_df <-
purrr::map_df(
.x = base::unique(sgs_df$model_sim),
.f = function(ms){
so <-
dplyr::filter(sgs_df, model_sim == {{ms}}) %>%
stats::lm(data = ., formula = noise_perc ~ tot_var) %>%
base::summary()
tibble::tibble(
model = {{ms}},
r2 = so[["adj.r.squared"]]
)
}
)
out <- list(r2_df = r2_df, sts_df = sgs_df)
return(out)
}
# evaluate ----------------------------------------------------------------
#' @keywords internal
evaluate_model_fits <- function(input_df,
var_order ){
n <- dplyr::n_distinct(input_df[[var_order]])
max_auc <- base::max(input_df[[var_order]])
eval_df <-
dplyr::group_by(input_df, variables, models) %>%
dplyr::filter(!base::all(base::is.na(values))) %>%
dplyr::summarize(
rmse = compute_rmse(gradient = values, model = values_models),
mae = compute_mae(gradient = values, model = values_models)
) %>%
dplyr::ungroup()
eval_df <-
dplyr::select(
eval_df,
variables,
models,
dplyr::any_of(c( "p_value", "corr", "raoc", "rauc", "rmse", "mae", "fr_dist")))
return(eval_df)
}
extract_bin_dist_val <- function(bins_dist, fn = "mean"){
confuns::check_one_of(
input = fn,
against = c("mean", "min", "max")
)
mtr <-
stringr::str_remove_all(bins_dist, pattern = "\\[|\\]") %>%
stringr::str_split_fixed(pattern = ",", n = 2) %>%
base::apply(X = ., MARGIN = 2, FUN = base::as.numeric)
if(fn == "mean"){
out <- base::rowMeans(mtr)
} else if(fn == "max"){
out <- MatrixGenerics::rowMaxs(mtr)
} else if(fn == "min"){
out <- MatrixGenerics::rowMins(mtr)
}
return(out)
}
#' @title Extract distance units
#'
#' @description Extracts unit of distance input.
#'
#' @inherit is_dist params details
#'
#' @return Character vector of the same length as `input`. If `input` is numeric,
#' the extracted unit will be *px*.
#'
#' @examples
#'
#' library(SPATA2)
#'
#' dist_vals <- c("2mm", "2.3mm")
#'
#' extrat_unit(dist_vals)
#'
#' pixels <- c(2,5, 500)
#'
#' extract_unit(pixels)
#'
#' @export
#'
extract_unit <- function(input){
is_spatial_measure(input = input, error = TRUE)
if(base::is.character(input) | is_numeric_input(input)){
out <- stringr::str_extract(input, pattern = regex_unit)
no_units <-
!stringr::str_detect(out, pattern = regex_unit)|
base::is.na(out)
out[no_units] <- "px"
} else {
unit_attr <- base::attr(input, which = "units")
if(base::length(unit_attr$numerator) == 2){
out <- stringr::str_c(unit_attr$numerator[1], "2", sep = "")
} else {
out <- unit_attr$numerator
}
out <- base::rep(out, base::length(input))
}
return(out)
}
#' @title Extract distance value
#'
#' @description Extracts distance value of distance input.
#'
#' @inherit is_dist params details
#'
#' @return Numeric value.
#'
#' @export
#'
#' @examples
#'
#' library(SPATA2)
#'
#' dist_vals <- c("2mm", "2.3mm")
#'
#' extrat_unit(dist_vals)
#'
#' pixels <- c(2,5, 500)
#'
#' extract_unit(pixels)
extract_value <- function(input){
# regex works for area and distance values
stringr::str_remove(input, pattern = regex_unit) %>%
base::as.numeric()
}
#' Extract var names from filter expression
#'
#' This function takes a list of quosures representing logical expressions and
#' returns the variable names used in these expressions.
#'
#' @param filter_expr A list of quosures representing logical expressions.
#'
#' @return A character vector containing the unique variable names used in the expressions.
#'
#' @keywords internal
extract_var_names <- function(filter_expr) {
all_vars <- function(expr) {
if (rlang::is_symbol(expr)) {
return(as.character(expr))
} else if (rlang::is_call(expr)) {
return(unique(unlist(lapply(expr[-1], all_vars))))
} else {
return(NULL)
}
}
var_names <- lapply(filter_expr, function(expr) {
all_vars(rlang::quo_get_expr(expr))
})
var_names <- unique(unlist(var_names))
return(var_names)
}
# Example usage:
test_fn <- function(x, ...) {
filter_expr <- rlang::enquos(...)
return(extract_var_names(filter_expr))
}
# Test call
test_fn(x = "something", GFAP > 0.5 & bayes_space %in% c("1", "2"))
# Expected output: [1] "GFAP" "bayes_space"
# expand ------------------------------------------------------------------
#' @keywords internal
expand_image_range <- function(range,
expand_with,
object,
ref_axis,
limits = NULL){
if(base::length(expand_with) == 1){
expand_with <- base::rep(expand_with, 2)
}
# handle exclam input
if(base::any(is_exclam(expand_with))){
abs_axes_length <-
stringr::str_remove(string = expand_with, pattern = "!$") %>%
base::unique()
if(!base::all(is_dist_pixel(abs_axes_length))){
abs_axes_length <- as_pixel(input = abs_axes_length, object = object, add_attr = FALSE)
}
abs_axes_length <- base::as.numeric(abs_axes_length)
center <- base::mean(range)
out1 <- center - abs_axes_length/2
out2 <- center + abs_axes_length/2
if(base::is.numeric(limits)){
if(out1 < limits[1]){
warning(
glue::glue(
"Min. of image {ref_axis} is {out1} due to `expand` but must not be lower than {limit}px. Returning {limit}px.",
out1 = base::round(out1, digits = 5) %>% stringr::str_c(., "px"),
limit = limits[1]
)
)
out1 <- limits[1]
}
if(out2 > limits[2]){
warning(
glue::glue(
"Max. of image {ref_axis} is {out2} due to `expand` but must not be higher than {limit}px. Returning {limit}px.",
out2 = base::round(out2, digits = 5) %>% stringr::str_c(., "px"),
limit = limits[2]
)
)
out2 <- limits[2]
}
}
# handle normal input
} else {
out1 <-
expand_image_side(
side = 1,
range = range,
expand_with = expand_with[1],
object = object,
ref_axis = ref_axis,
limit = limits[1]
)
out2 <-
expand_image_side(
side = 2,
range = range,
expand_with = expand_with[2],
object = object,
ref_axis = ref_axis,
limit = limits[2]
)
}
out <- c(out1, out2)
return(out)
}
#' @keywords internal
expand_image_side <- function(expand_with,
range,
side = c(1,2),
object,
ref_axis,
limit = NULL){
if(is_dist(expand_with)){ # expand in absolute measures
expand_abs <- as_pixel(expand_with, object = object, add_attr = FALSE)
if(side == 1){
out <- range[side] - expand_abs
} else if(side == 2){
out <- range[side] + expand_abs
}
} else { # expand in relative measures from the center
rdist <- range[2]-range[1]
rmean <- base::mean(range)
expand_perc <-
stringr::str_remove(expand_with, pattern = "%") %>%
base::as.numeric() %>%
base::abs()
expand_fct <- (expand_perc/100) + 1
expand_abs <- (rdist/2)*expand_fct
if(side == 1){
out <- rmean - expand_abs
} else if(side == 2){
out <- rmean + expand_abs
}
}
if(base::is.numeric(limit)){
if(side == 1 & out < limit){
warning(
glue::glue(
"Min.of image {ref_axis} is {out} but must not be lower than {limit}px. Returning {limit}px.",
out = base::round(out, digits = 5) %>% stringr::str_c(., "px")
)
)
out <- limit
} else if(side == 2 & out > limit){
warning(
glue::glue(
"Max. of image {ref_axis} is {out} but must not be higher than {limit}px. Returning {limit}px.",
out = base::round(out, digits = 5) %>% stringr::str_c(., "px")
)
)
out <- limit
}
}
return(out)
}
#' @title Expand the outline of spatial annotations
#'
#' @description Expands or shrinks the outer outline of a spatial annotation.
#'
#' @param id Character value. The ID of the spatial annotation of interest.
#' @param expand Distance measure with which to expand the border. Negative
#' values shrink the outline.
#' @param new_id Character value or `FALSE`. If character, the resulting
#' spatial annotation is stored under a new ID.
#' @inherit argument_dummy params
#' @inherit update_dummy return
#'
#' @seealso [`smoothSpatialAnnotation()`], [`shiftSpatialAnnotation()`], [`SpatialAnnotation`]
#'
#' @export
#'
#' @examples
#'
#' library(SPATA2)
#' library(tidyverse)
#'
#' data("example_data")
#'
#' object <- loadExampleObject("UKF275T")
#'
#' plotImage(object) + ggpLayerSpatAnnOutline(object, ids = "vessel1", line_color = "red")
#' plotSpatialAnnotations(object, "vessel1")
#'
#' object <- expandSpatialAnnotation(object, id = "vessel1", expand = "50um", new_id = "vessel1_exp")
#'
#' plotSpatialAnnotations(object, ids = c("vessel1", "vessel1_exp"))
#'
expandSpatialAnnotation <- function(object,
id,
expand,
new_id = FALSE,
overwrite = FALSE){
if(base::is.character(new_id)){
confuns::check_none_of(
input = new_id,
against = getSpatAnnIds(object),
ref.against = "present spatial annotation IDs",
overwrite = TRUE
)
}
spat_ann <-
getSpatialAnnotation(object, id = id, add_image = FALSE)
outline_df <-
getSpatAnnOutlineDf(object, ids = id, outer = TRUE, inner = FALSE)
isf <- getScaleFactor(object, fct_name = "image")
expand <- as_pixel(input = expand, object = object)
outer_df_new <-
dplyr::select(spat_ann@area$outer, x, y) %>%
buffer_area(df = ., buffer = expand) %>%
dplyr::mutate(x_orig = x / {{isf}}, y_orig = y / {{isf}}) %>%
dplyr::select(-x, -y)
spat_ann@area$outer <- outer_df_new
if(base::is.character(new_id)){
spat_ann@id <- new_id
}
object <- setSpatialAnnotation(object, spat_ann = spat_ann)
returnSpataObject(object)
}
#' Extract Row and Column Variables for VisiumHD Barcodes
#'
#' This function extracts row and column information from VisiumHD barcodes in a provided dataframe.
#'
#' @param coords_df A dataframe containing VisiumHD barcodes.
#' @param name_bcs The column name where the barcodes are stored (default is "barcodes").
#' @param name_row The name to assign to the row variable (default is "row").
#' @param name_col The name to assign to the column variable (default is "col").
#'
#' @return A dataframe with added row and column information.
#' @keywords internal
#' @export
extract_row_col_vars_visiumHD <- function(coords_df,
name_bcs = "barcodes",
name_row = "row",
name_col = "col"){
sym <- rlang::sym
# test if barcodes are valid
bcs_valid <- stringr::str_detect(coords_df[[name_bcs]], pattern = regexes$visiumHD_barcode)
all_valid <- all(bcs_valid)
if(!all_valid){
warning("There are barcodes that do not fit the regular expression regexes$visiumHD_barcode. Consider to check row/col assignment.")
}
# extract data
coords_df <-
dplyr::group_by(coords_df, !!sym(name_bcs)) %>%
dplyr::mutate(
{{name_row}} := as.numeric(stringr::str_extract(!!sym(name_bcs), pattern = regexes$visiumHD_barcode_row)),
{{name_col}} := as.numeric(stringr::str_extract(!!sym(name_bcs), pattern = regexes$visiumHD_barcode_col))
) %>%
dplyr::ungroup()
return(coords_df)
}
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.