Nothing
# tests/testthat/test-rate-map.R
.rate_map_skip_if_missing_deps <- function() {
testthat::skip_if_not_installed("ape")
testthat::skip_if_not_installed("phytools")
testthat::skip_if_not_installed("future")
testthat::skip_if_not_installed("future.apply")
testthat::skip_if_not_installed("progressr")
}
.rate_map_fixture <- function() {
set.seed(20260521)
tr <- ape::rtree(8)
base <- phytools::paintSubTree(
tree = ape::as.phylo(tr),
node = ape::Ntip(tr) + 1L,
state = "0"
)
shifted_a <- phytools::paintSubTree(
tree = base,
node = ape::Ntip(base) + 2L,
state = "1"
)
shifted_b <- phytools::paintSubTree(
tree = base,
node = ape::Ntip(base) + 3L,
state = "1"
)
list(base = base, shifted_a = shifted_a, shifted_b = shifted_b)
}
.rate_map_fit <- function(tree, param = c("0" = 0.1, "1" = 0.5)) {
list(
variables = list(tree = tree),
param = param
)
}
.rate_map_eval_no_error <- function(expr) {
expr <- substitute(expr)
env <- parent.frame()
value <- NULL
testthat::expect_error(value <- eval(expr, env), NA)
value
}
.rate_map_with_pdf <- function(expr) {
expr <- substitute(expr)
env <- parent.frame()
path <- tempfile(fileext = ".pdf")
grDevices::pdf(path)
on.exit(grDevices::dev.off(), add = TRUE)
eval(expr, env)
}
.rate_map_two_tip <- function(edge_length = c(1, 1), maps = NULL) {
tr <- ape::read.tree(text = "(a:1,b:1);")
tr$edge.length <- edge_length
if (is.null(maps)) {
maps <- lapply(edge_length, function(len) c("0" = len))
}
tr$maps <- maps
tr$mapped.edge <- .rateMap_make_mapped_edge(tr$edge, tr$maps)
class(tr) <- c("simmap", "phylo")
tr
}
.rate_map_state_fit <- function(rates, edge_length = 1) {
tr <- ape::stree(length(rates), type = "star")
tr$edge.length <- rep(edge_length, nrow(tr$edge))
states <- paste0("s", seq_len(nrow(tr$edge)))
tr$maps <- lapply(states, function(state) stats::setNames(edge_length, state))
tr$mapped.edge <- .rateMap_make_mapped_edge(tr$edge, tr$maps)
class(tr) <- c("simmap", "phylo")
.rate_map_fit(tr, stats::setNames(rates, states))
}
test_that("rateMap summarizes small synthetic stochastic-map fits", {
.rate_map_skip_if_missing_deps()
fx <- .rate_map_fixture()
fits <- list(
.rate_map_fit(fx$shifted_a, c("0" = 0.10, "1" = 0.50)),
.rate_map_fit(fx$shifted_b, c("0" = 0.20, "1" = 0.80))
)
out <- rateMap(
fits,
progress = FALSE,
control = rateMapControl(res = 8)
)
testthat::expect_s3_class(out, "rateMap")
testthat::expect_s3_class(out$tree, "simmap")
testthat::expect_equal(out$summary, "branch")
testthat::expect_equal(out$color_mode, "category")
testthat::expect_true(out$log)
testthat::expect_s3_class(out$rate_categories, "data.frame")
testthat::expect_true(all(c(
"n_branches",
"value_mean",
"value_median",
"value_min",
"value_max",
"value_sd",
"total_branch_length"
) %in% names(out$rate_categories)))
testthat::expect_length(out$lims, 2)
testthat::expect_true(is.data.frame(out$intervals))
testthat::expect_true(all(c(
"edge",
"parent",
"child",
"depth_start",
"depth_end",
"interval_length",
"value",
"color_bin",
"rate_flag_source",
"rate_category"
) %in% names(out$intervals)))
testthat::expect_equal(out$ncolors, 256L)
testthat::expect_equal(out$rate_flag_source, "value")
testthat::expect_true(all(out$intervals$rate_flag_source == "value"))
testthat::expect_equal(out$n_fits, 2L)
})
test_that("rateMap auto-detects bifrost_search-style objects", {
.rate_map_skip_if_missing_deps()
fx <- .rate_map_fixture()
fit <- structure(
list(
tree_no_uncertainty_untransformed = fx$shifted_a,
model_no_uncertainty = list(param = c("0" = 0.25, "1" = 0.75))
),
class = c("bifrost_search", "list")
)
out <- rateMap(
list(fit, fit),
progress = FALSE,
control = rateMapControl(res = 4)
)
testthat::expect_s3_class(out, "rateMap")
testthat::expect_equal(out$n_fits, 2L)
testthat::expect_true(out$log)
testthat::expect_equal(range(out$intervals$value), out$lims)
})
test_that("rateMap validates mapped state and parameter compatibility", {
.rate_map_skip_if_missing_deps()
fx <- .rate_map_fixture()
testthat::expect_error(
rateMap(
list(list(param = c("0" = 0.1))),
progress = FALSE
),
"mapped simmap"
)
testthat::expect_error(
rateMap(
list(list(variables = list(tree = fx$base))),
progress = FALSE
),
"named numeric"
)
testthat::expect_error(
rateMap(
list(.rate_map_fit(fx$shifted_a, c("0" = 0.1))),
progress = FALSE
),
"missing rate parameters"
)
testthat::expect_error(
rateMap(
list(.rate_map_fit(fx$shifted_a, c("0" = 0.1, "1" = 0))),
progress = FALSE
),
"non-positive"
)
testthat::expect_error(
rateMap(
list(.rate_map_fit(fx$shifted_a, c("0" = 0.1, "1" = -0.5))),
progress = FALSE
),
"strictly positive"
)
testthat::expect_error(
rateMap(
list(.rate_map_fit(fx$shifted_a, c("0" = 0.1, "1" = 0))),
log = FALSE,
progress = FALSE
),
"strictly positive"
)
testthat::expect_error(
rateMap(
list(.rate_map_fit(fx$shifted_a, c("0" = 0.1, "1" = -0.5))),
log = FALSE,
progress = FALSE
),
"strictly positive"
)
below_one <- rateMap(
list(.rate_map_state_fit(c(0.1, 0.2))),
log = TRUE,
progress = FALSE
)
testthat::expect_true(all(below_one$intervals$value < 0))
testthat::expect_error(
rateMap(
list(.rate_map_fit(fx$shifted_a, c("0" = 0.1, "1" = Inf))),
progress = FALSE
),
"non-finite"
)
})
test_that("rateMap errors on no-shift NA params by default and can omit them", {
.rate_map_skip_if_missing_deps()
fx <- .rate_map_fixture()
invalid <- .rate_map_fit(fx$base, NA_real_)
valid <- .rate_map_fit(fx$shifted_a, c("0" = 0.1, "1" = 0.5))
testthat::expect_error(
rateMap(list(invalid), progress = FALSE),
"named numeric parameter"
)
testthat::expect_error(
rateMap(
list(invalid),
progress = FALSE,
control = rateMapControl(na_action = "omit")
),
"No fits remain"
)
out <- rateMap(
list(invalid, valid),
progress = FALSE,
control = rateMapControl(res = 4, na_action = "omit")
)
testthat::expect_equal(out$n_fits, 1L)
testthat::expect_equal(out$omitted, 1L)
})
test_that("rateMap supports all default extraction shapes", {
.rate_map_skip_if_missing_deps()
fx <- .rate_map_fixture()
mvgls_stub <- structure(
list(corrSt = list(phy = fx$base), param = c("0" = 0.2)),
class = "mvgls"
)
wrapped_mvgls <- list(model = mvgls_stub)
bifrost_fit <- structure(
list(
tree_no_uncertainty_untransformed = fx$base,
model_no_uncertainty = list(param = c("0" = 0.4))
),
class = c("bifrost_search", "list")
)
out <- rateMap(
list(mvgls_stub, wrapped_mvgls, bifrost_fit),
summary = "branch",
log = FALSE,
progress = FALSE
)
testthat::expect_equal(out$n_fits, 3L)
testthat::expect_equal(out$weight_mode, "equal")
testthat::expect_true(all(abs(out$intervals$value - mean(c(0.2, 0.2, 0.4))) < 1e-12))
transformed_only <- structure(
list(
tree_no_uncertainty_transformed = fx$base,
model_no_uncertainty = list(param = c("0" = 0.4))
),
class = c("bifrost_search", "list")
)
testthat::expect_error(
rateMap(list(transformed_only), progress = FALSE),
"tree_no_uncertainty_untransformed"
)
transformed_override <- rateMap(
list(transformed_only),
summary = "branch",
log = FALSE,
progress = FALSE,
control = rateMapControl(
tree_fun = function(x) x$tree_no_uncertainty_transformed
)
)
testthat::expect_s3_class(transformed_override, "rateMap")
testthat::expect_equal(transformed_override$n_fits, 1L)
testthat::expect_true(all(abs(transformed_override$intervals$value - 0.4) < 1e-12))
omitted_tree <- rateMap(
list(transformed_only, bifrost_fit),
summary = "branch",
log = FALSE,
progress = FALSE,
control = rateMapControl(na_action = "omit")
)
testthat::expect_equal(omitted_tree$n_fits, 1L)
testthat::expect_equal(omitted_tree$omitted, 1L)
testthat::expect_true(all(abs(omitted_tree$intervals$value - 0.4) < 1e-12))
})
test_that("rateMap accepts a single fitted object and plot() draws rateMap objects", {
.rate_map_skip_if_missing_deps()
fx <- .rate_map_fixture()
scratch_fit <- .rate_map_fit(fx$base, c("0" = 0.2))
scratch_out <- rateMap(
scratch_fit,
progress = FALSE
)
testthat::expect_s3_class(scratch_out, "rateMap")
testthat::expect_equal(scratch_out$n_fits, 1L)
testthat::expect_equal(scratch_out$summary, "branch")
testthat::expect_true(scratch_out$log)
bifrost_fit <- structure(
list(
tree_no_uncertainty_untransformed = fx$base,
model_no_uncertainty = list(param = c("0" = 0.3))
),
class = c("bifrost_search", "list")
)
bifrost_out <- rateMap(
bifrost_fit,
progress = FALSE
)
testthat::expect_equal(bifrost_out$n_fits, 1L)
testthat::expect_true(bifrost_out$log)
testthat::expect_equal(bifrost_out$intervals$value, rep(log(0.3), nrow(fx$base$edge)))
bifrost_view <- rateMap(
bifrost_fit,
uncertainty = TRUE,
summary = "branch",
progress = FALSE
)
drawn <- .rate_map_with_pdf({
.rate_map_eval_no_error(plot(
bifrost_view,
legend = FALSE,
hold = FALSE,
palette = "Viridis",
reverse_palette = TRUE,
color_mode = "category",
n_categories = 2,
category_bin_method = "equal",
category_breaks = c(-2, 0),
category_labels = "single"
))
})
testthat::expect_s3_class(drawn, "rateMap")
testthat::expect_equal(drawn$n_fits, 1L)
testthat::expect_equal(drawn$category_labels, "single")
testthat::expect_true(drawn$uncertainty)
testthat::expect_error(.plot_rate_map(bifrost_fit, legend = FALSE), "rateMap")
})
test_that("rateMap validates top-level arguments and tree checks", {
.rate_map_skip_if_missing_deps()
fx <- .rate_map_fixture()
fit <- .rate_map_fit(fx$base, c("0" = 1))
testthat::expect_error(rateMap(NULL), "non-empty list")
testthat::expect_error(rateMapControl(res = 0), "res")
testthat::expect_error(rateMap(list(fit), workers = 0), "workers")
testthat::expect_error(rateMap(list(fit), summary = "node"), "'arg' should be")
testthat::expect_error(rateMap(list(fit), uncertainty = NA), "uncertainty")
testthat::expect_error(rateMap(list(fit), value_summary = "mode"), "'arg' should be")
testthat::expect_error(rateMapControl(quantile_probs = c(0.9, 0.1)), "quantile_probs")
testthat::expect_error(rateMapControl(highest_density_interval_prob = 0), "highest_density_interval_prob")
testthat::expect_error(
rateMap(list(fit), unsupported_arg = TRUE, progress = FALSE),
"unused argument"
)
testthat::expect_error(rateMapControl(check = "branch"), "check")
testthat::expect_error(rateMapControl(tree_fun = 1), "tree_fun")
testthat::expect_error(rateMapControl(param_fun = 1), "param_fun")
testthat::expect_error(rateMap(list(fit), control = list(bogus = TRUE)), "Unsupported rateMapControl")
testthat::expect_error(rateMap(list(fit), control = list(TRUE)), "named list")
testthat::expect_error(rateMap(list(fit), control = 1), "control")
testthat::expect_error(rateMap(list(fit), control = NULL, progress = FALSE), "control")
testthat::expect_error(
rateMap(list(fit), target_tree = list(), progress = FALSE),
"target_tree"
)
changed <- fx$base
changed$edge.length[1L] <- changed$edge.length[1L] * 2
testthat::expect_error(
rateMap(
list(fit, .rate_map_fit(changed, c("0" = 1))),
progress = FALSE
),
"do not match"
)
phylo_with_maps <- fx$base
class(phylo_with_maps) <- "phylo"
out <- rateMap(
list(.rate_map_fit(phylo_with_maps, c("0" = 1))),
summary = "branch",
progress = FALSE
)
testthat::expect_s3_class(out, "rateMap")
})
test_that("rateMap projects same-topology branch-length variation onto a target tree", {
.rate_map_skip_if_missing_deps()
target <- .rate_map_two_tip(edge_length = c(1, 1))
edge_a <- which(target$edge[, 2L] == match("a", target$tip.label))
edge_b <- which(target$edge[, 2L] == match("b", target$tip.label))
sampled <- target
sampled$edge.length[edge_a] <- 2
sampled$edge.length[edge_b] <- 0.5
sampled$maps[[edge_a]] <- c("0" = 1, "1" = 1)
sampled$maps[[edge_b]] <- c("1" = 0.5)
sampled$mapped.edge <- .rateMap_make_mapped_edge(sampled$edge, sampled$maps)
generic_target <- ape::as.phylo(target)
generic_target$edge.length <- c(0.75, 1.25)
testthat::expect_error(
rateMap(
list(.rate_map_fit(target, c("0" = 1, "1" = 3)), .rate_map_fit(sampled, c("0" = 1, "1" = 3))),
summary = "branch",
progress = FALSE
),
"do not match"
)
branch_out <- rateMap(
list(.rate_map_fit(sampled, c("0" = 1, "1" = 3))),
target_tree = generic_target,
summary = "branch",
log = FALSE,
progress = FALSE,
control = list(check = "topology")
)
testthat::expect_equal(branch_out$target, "user")
testthat::expect_equal(branch_out$check, "topology")
testthat::expect_equal(branch_out$tree$edge.length, generic_target$edge.length)
testthat::expect_equal(branch_out$intervals$value[branch_out$intervals$edge == edge_a], 2)
testthat::expect_equal(branch_out$intervals$value[branch_out$intervals$edge == edge_b], 3)
interval_out <- rateMap(
list(.rate_map_fit(sampled, c("0" = 1, "1" = 3))),
target_tree = ape::as.phylo(target),
summary = "interval",
log = FALSE,
progress = FALSE,
control = list(check = "topology", res = 2)
)
edge_a_rows <- interval_out$intervals[interval_out$intervals$edge == edge_a, ]
testthat::expect_equal(edge_a_rows$interval_length, c(0.5, 0.5))
testthat::expect_equal(edge_a_rows$value, c(1, 3))
testthat::expect_equal(
as.numeric(rowSums(interval_out$tree$mapped.edge)),
target$edge.length,
tolerance = 1e-10
)
permuted <- sampled
ord <- rev(seq_len(nrow(permuted$edge)))
permuted$edge <- permuted$edge[ord, , drop = FALSE]
permuted$edge.length <- permuted$edge.length[ord]
permuted$maps <- permuted$maps[ord]
permuted$mapped.edge <- .rateMap_make_mapped_edge(permuted$edge, permuted$maps)
permuted_out <- rateMap(
list(.rate_map_fit(permuted, c("0" = 1, "1" = 3))),
target_tree = ape::as.phylo(target),
summary = "branch",
log = FALSE,
progress = FALSE,
control = list(check = FALSE)
)
testthat::expect_equal(permuted_out$check, "none")
testthat::expect_equal(permuted_out$intervals$value[permuted_out$intervals$edge == edge_a], 2)
testthat::expect_length(permuted_out$clade_key, nrow(target$edge))
testthat::expect_true("clade_key" %in% names(permuted_out$intervals))
testthat::expect_equal(dim(permuted_out$edge_matches), c(nrow(target$edge), 1L))
testthat::expect_equal(colnames(permuted_out$edge_matches), "fit_1")
testthat::expect_equal(
permuted_out$clade_key[permuted_out$intervals$edge],
permuted_out$intervals$clade_key
)
mcc_out <- rateMap(
list(.rate_map_fit(sampled, c("0" = 1, "1" = 3)), .rate_map_fit(permuted, c("0" = 1, "1" = 3))),
summary = "branch",
log = FALSE,
progress = FALSE,
control = list(target = "mcc", check = "topology")
)
testthat::expect_equal(mcc_out$target, "mcc")
testthat::expect_equal(mcc_out$tree$edge.length, sampled$edge.length)
bad_target <- ape::read.tree(text = "(a:1,c:1);")
testthat::expect_error(
rateMap(
list(.rate_map_fit(sampled, c("0" = 1, "1" = 3))),
target_tree = bad_target,
summary = "branch",
progress = FALSE,
control = list(check = "topology")
),
"topology"
)
testthat::expect_error(
rateMap(
list(.rate_map_fit(sampled, c("0" = 1, "1" = 3))),
target_tree = bad_target,
summary = "branch",
progress = FALSE,
control = list(check = FALSE)
),
"missing one or more target-tree branches"
)
})
test_that("rateMap mapped.edge row sums match edge lengths", {
.rate_map_skip_if_missing_deps()
fx <- .rate_map_fixture()
out <- rateMap(
list(.rate_map_fit(fx$shifted_a), .rate_map_fit(fx$shifted_a)),
progress = FALSE,
control = rateMapControl(res = 10)
)
testthat::expect_equal(
as.numeric(rowSums(out$tree$mapped.edge)),
out$tree$edge.length,
tolerance = 1e-10
)
})
test_that("rateMap computes whole-branch summaries without splitting branches", {
.rate_map_skip_if_missing_deps()
fx <- .rate_map_fixture()
out <- rateMap(
list(
.rate_map_fit(fx$base, c("0" = 0.1)),
.rate_map_fit(fx$base, c("0" = 0.5))
),
summary = "branch",
weights = c(1, 3),
log = FALSE,
progress = FALSE
)
testthat::expect_equal(out$summary, "branch")
testthat::expect_equal(nrow(out$intervals), nrow(fx$base$edge))
testthat::expect_equal(out$intervals$interval_length, out$tree$edge.length)
testthat::expect_equal(out$weights, c(0.25, 0.75))
testthat::expect_equal(out$weight_mode, "custom")
testthat::expect_true(all(abs(out$intervals$value - 0.4) < 1e-12))
testthat::expect_true(all(vapply(out$tree$maps, length, integer(1)) == 1L))
})
test_that("rateMap floor flags near-zero branch rates without changing values", {
.rate_map_skip_if_missing_deps()
default_no_rule_out <- rateMap(
list(.rate_map_state_fit(c(0.001, 1, 2))),
summary = "branch",
log = FALSE,
progress = FALSE,
control = rateMapControl(
rate_flags = rateMapRateFlags()
)
)
testthat::expect_true(default_no_rule_out$rate_diagnostics$enabled)
testthat::expect_equal(default_no_rule_out$rate_diagnostics$method, "none")
testthat::expect_equal(default_no_rule_out$rate_diagnostics$n_near_zero, 0L)
testthat::expect_equal(default_no_rule_out$rate_diagnostics$full_fold_range, 2000)
testthat::expect_false("near-zero" %in% default_no_rule_out$rate_categories$rate_category)
default_no_rule_print <- utils::capture.output(print(default_no_rule_out))
testthat::expect_true(any(grepl(
"rate flags: 0 near-zero, 0 high-outlier \\(method: none\\)",
default_no_rule_print
)))
floor_out <- rateMap(
list(.rate_map_state_fit(c(0.001, 0.005, 1, 2))),
summary = "branch",
log = FALSE,
progress = FALSE,
control = rateMapControl(
rate_flags = rateMapRateFlags(
zero_floor = 0.01,
zero_color = "grey60"
)
)
)
testthat::expect_equal(floor_out$intervals$value, c(0.001, 0.005, 1, 2))
testthat::expect_equal(
floor_out$intervals$rate_flag,
c("near-zero", "near-zero", "regular", "regular")
)
testthat::expect_equal(
floor_out$intervals$rate_category,
c("near-zero", "near-zero", "1", "2")
)
testthat::expect_equal(floor_out$rate_categories$rate_category[1L], "near-zero")
testthat::expect_equal(floor_out$rate_categories$color[1L], "grey60")
testthat::expect_equal(floor_out$rate_diagnostics$n_near_zero, 2L)
testthat::expect_equal(floor_out$rate_diagnostics$n_high_outlier, 0L)
testthat::expect_equal(floor_out$rate_diagnostics$full_fold_range, 2000)
testthat::expect_equal(floor_out$rate_diagnostics$regular_fold_range, 2)
testthat::expect_equal(.rateMap_category_lims(floor_out), c(0.001, 2))
testthat::expect_equal(
.rateMap_category_marker_values(floor_out)["near-zero"],
c("near-zero" = 0.01)
)
testthat::expect_true(is.na(.rateMap_rate_marker_to_value(NA_real_, log = FALSE)))
testthat::expect_true(is.na(.rateMap_rate_marker_to_value(0, log = TRUE)))
floor_print <- utils::capture.output(print(floor_out))
testthat::expect_true(any(grepl("rate flags: 2 near-zero", floor_print)))
testthat::expect_true(any(grepl("near-zero floor:", floor_print)))
palette_out <- rateMapView(
floor_out,
palette = c("blue", "red"),
color_mode = "category"
)
regular_category_rows <- palette_out$rate_categories$rate_category != "near-zero"
testthat::expect_equal(
unname(palette_out$rate_categories$color[regular_category_rows]),
grDevices::colorRampPalette(c("blue", "red"))(2)
)
log_floor_out <- rateMap(
list(.rate_map_state_fit(c(1e-10, 1e-5, 1e-4))),
summary = "branch",
log = TRUE,
progress = FALSE,
control = rateMapControl(
rate_flags = rateMapRateFlags(method = "floor", zero_floor = 1e-8)
)
)
testthat::expect_equal(
.rateMap_category_marker_values(log_floor_out)["near-zero"],
c("near-zero" = log(1e-8))
)
plot_file <- tempfile(fileext = ".png")
grDevices::png(plot_file)
on.exit(if (grDevices::dev.cur() > 1L) grDevices::dev.off(), add = TRUE)
plot(floor_out, legend = 1, show_tip_labels = FALSE)
grDevices::dev.off()
finite_floor_out <- rateMap(
list(.rate_map_state_fit(c(0.001, 1, 2))),
summary = "branch",
log = FALSE,
progress = FALSE,
control = rateMapControl(
rate_flags = rateMapRateFlags(method = "floor", zero_floor = 0.01)
)
)
finite_floor_print <- utils::capture.output(print(finite_floor_out))
testthat::expect_true(any(grepl("fold range: 2000 full, 2 regular", finite_floor_print)))
all_floor_out <- rateMap(
list(.rate_map_state_fit(c(0.001, 0.005))),
summary = "branch",
log = FALSE,
progress = FALSE,
control = rateMapControl(
rate_flags = rateMapRateFlags(method = "floor", zero_floor = 0.01)
)
)
testthat::expect_equal(unique(all_floor_out$intervals$rate_category), "near-zero")
testthat::expect_true(is.na(all_floor_out$rate_diagnostics$regular_fold_range))
testthat::expect_equal(nrow(all_floor_out$rate_categories), 1L)
})
test_that("rateMap rate flags support tail clustering, disabled, and interval-mode behavior", {
.rate_map_skip_if_missing_deps()
cluster_rates <- exp(c(
-24, -22, -20,
-17, -16.5, -16, -15.5, -15, -14.5, -14, -13.5, -13, -12.5, -12
))
cluster_out <- rateMap(
list(.rate_map_state_fit(cluster_rates)),
summary = "branch",
log = FALSE,
progress = FALSE,
control = rateMapControl(
rate_flags = rateMapRateFlags(method = "tail_cluster")
)
)
testthat::expect_equal(cluster_out$rate_diagnostics$n_near_zero, 3L)
testthat::expect_equal(cluster_out$rate_diagnostics$zero_cluster_n_tail, 3L)
testthat::expect_equal(cluster_out$rate_diagnostics$zero_cluster_n_regular, 11L)
testthat::expect_true(is.finite(cluster_out$rate_diagnostics$zero_cluster_log_gap))
testthat::expect_gt(cluster_out$rate_diagnostics$zero_cluster_log_gap, 0)
testthat::expect_gt(
cluster_out$rate_diagnostics$zero_cluster_cutoff_rate,
max(cluster_rates[1:3])
)
testthat::expect_lt(
cluster_out$rate_diagnostics$zero_cluster_cutoff_rate,
min(cluster_rates[-(1:3)])
)
testthat::expect_true(all(cluster_out$intervals$is_near_zero[1:3]))
testthat::expect_false(any(cluster_out$intervals$is_near_zero[-(1:3)]))
testthat::expect_equal(
.rateMap_category_marker_values(cluster_out)["near-zero"],
c("near-zero" = cluster_out$rate_diagnostics$zero_cluster_cutoff_rate)
)
no_cluster_out <- rateMap(
list(.rate_map_state_fit(exp(seq(-10, -4, length.out = 14)))),
summary = "branch",
log = FALSE,
progress = FALSE,
control = rateMapControl(
rate_flags = rateMapRateFlags(method = "tail_cluster")
)
)
testthat::expect_equal(no_cluster_out$rate_diagnostics$n_near_zero, 0L)
testthat::expect_true(is.na(no_cluster_out$rate_diagnostics$zero_cluster_cutoff_rate))
too_small_cluster_out <- rateMap(
list(.rate_map_state_fit(exp(c(-20, -19, -10, -9)))),
summary = "branch",
log = FALSE,
progress = FALSE,
control = rateMapControl(
rate_flags = rateMapRateFlags(method = "tail_cluster")
)
)
testthat::expect_equal(too_small_cluster_out$rate_diagnostics$n_near_zero, 0L)
testthat::expect_equal(too_small_cluster_out$rate_diagnostics$zero_cluster_n_tail, 0L)
testthat::expect_equal(too_small_cluster_out$rate_diagnostics$zero_cluster_n_regular, 4L)
high_cluster_out <- rateMap(
list(.rate_map_state_fit(exp(c(
-16, -15.5, -15, -14.5, -14, -13.5, -13, -12.5, -12, -11.5, -11,
-8, -6, -4
)))),
summary = "branch",
log = FALSE,
progress = FALSE,
control = rateMapControl(
rate_flags = rateMapRateFlags(
near_zero = FALSE,
high_outlier = TRUE,
method = "tail_cluster"
)
)
)
testthat::expect_equal(high_cluster_out$rate_diagnostics$n_high_outlier, 3L)
testthat::expect_equal(high_cluster_out$rate_diagnostics$high_cluster_n_tail, 3L)
testthat::expect_true(all(utils::tail(high_cluster_out$intervals$is_high_outlier, 3)))
testthat::expect_equal(
.rateMap_category_marker_values(high_cluster_out)["high-outlier"],
c("high-outlier" = exp(-9.5))
)
plot_file <- tempfile(fileext = ".png")
grDevices::png(plot_file)
on.exit(if (grDevices::dev.cur() > 1L) grDevices::dev.off(), add = TRUE)
plot(
high_cluster_out,
legend = 1,
show_tip_labels = FALSE,
xlim = rev(range(phytools::nodeHeights(high_cluster_out$tree)))
)
grDevices::dev.off()
disabled <- rateMap(
list(.rate_map_state_fit(c(1e-9, 1, 2))),
summary = "branch",
log = FALSE,
progress = FALSE,
control = rateMapControl(rate_flags = NULL)
)
testthat::expect_false("rate_flag" %in% names(disabled$intervals))
testthat::expect_false(disabled$rate_diagnostics$enabled)
testthat::expect_equal(disabled$rate_diagnostics$reason, "rate flagging is disabled")
disabled_view <- rateMapView(disabled, color_mode = "category")
testthat::expect_false(disabled_view$rate_diagnostics$enabled)
disabled_print <- utils::capture.output(print(disabled))
testthat::expect_false(any(grepl("rate flags:", disabled_print)))
interval_out <- rateMap(
list(.rate_map_state_fit(c(1e-9, 1, 2))),
summary = "interval",
log = FALSE,
progress = FALSE,
control = rateMapControl(
res = 2,
rate_flags = rateMapRateFlags(method = "tail_cluster")
)
)
testthat::expect_false("rate_flag" %in% names(interval_out$intervals))
testthat::expect_false(interval_out$rate_diagnostics$enabled)
testthat::expect_equal(
interval_out$rate_diagnostics$reason,
"rate flags are only computed for branch summaries"
)
})
test_that("rateMapView can color by discrete rate categories", {
.rate_map_skip_if_missing_deps()
tr <- .rate_map_two_tip(
edge_length = c(1, 1),
maps = list(c("0" = 1), c("1" = 1))
)
fit <- .rate_map_fit(tr, c("0" = 1, "1" = 4))
base <- rateMap(
list(fit),
summary = "branch",
log = FALSE,
progress = FALSE
)
out <- rateMapView(
base,
color_mode = "category",
n_categories = 4,
palette = c("blue", "red")
)
testthat::expect_equal(out$color_mode, "category")
testthat::expect_equal(out$category_labels, c("1", "4"))
testthat::expect_equal(out$rate_categories$value, c(1, 4))
testthat::expect_equal(out$rate_categories$n_branches, c(1L, 1L))
testthat::expect_equal(out$rate_categories$value_mean, c(1, 4))
testthat::expect_equal(out$rate_categories$value_median, c(1, 4))
testthat::expect_equal(out$rate_categories$value_min, c(1, 4))
testthat::expect_equal(out$rate_categories$value_max, c(1, 4))
testthat::expect_true(all(is.na(out$rate_categories$value_sd)))
testthat::expect_equal(out$rate_categories$total_branch_length, c(1, 1))
testthat::expect_equal(names(out$cols), c("1", "4"))
testthat::expect_equal(length(out$cols), nrow(out$rate_categories))
testthat::expect_equal(out$intervals$rate_category, c("1", "4"))
testthat::expect_equal(
unname(unlist(lapply(out$tree$maps, names), use.names = FALSE)),
c("1", "4")
)
custom <- rateMapView(
base,
color_mode = "category",
category_breaks = c(0, 2, 5),
category_labels = c("slow", "fast")
)
testthat::expect_equal(custom$category_labels, c("slow", "fast"))
testthat::expect_equal(custom$intervals$rate_category, c("slow", "fast"))
testthat::expect_equal(custom$rate_categories$lower, c(0, 2))
testthat::expect_equal(custom$rate_categories$upper, c(2, 5))
testthat::expect_equal(length(custom$cols), nrow(custom$rate_categories))
empty_bin <- rateMapView(
base,
color_mode = "category",
category_breaks = c(0, 2, 3, 5),
category_labels = c("slow", "middle", "fast")
)
testthat::expect_equal(empty_bin$rate_categories$n_branches, c(1L, 0L, 1L))
testthat::expect_equal(empty_bin$rate_categories$value_mean, c(1, NA, 4))
testthat::expect_equal(empty_bin$rate_categories$value_median, c(1, NA, 4))
testthat::expect_equal(empty_bin$rate_categories$value_min, c(1, NA, 4))
testthat::expect_equal(empty_bin$rate_categories$value_max, c(1, NA, 4))
testthat::expect_true(all(is.na(empty_bin$rate_categories$value_sd)))
testthat::expect_equal(empty_bin$rate_categories$total_branch_length, c(1, 0, 1))
equal_binned <- rateMapView(
base,
color_mode = "category",
n_categories = 1,
category_bin_method = "equal"
)
testthat::expect_equal(equal_binned$category_bin_method, "equal")
testthat::expect_equal(equal_binned$category_breaks, c(1, 4))
testthat::expect_equal(equal_binned$category_labels, "1 to 4")
testthat::expect_equal(equal_binned$rate_categories$n_branches, 2L)
testthat::expect_equal(equal_binned$rate_categories$value_mean, 2.5)
testthat::expect_equal(equal_binned$rate_categories$value_median, 2.5)
testthat::expect_equal(equal_binned$rate_categories$value_min, 1)
testthat::expect_equal(equal_binned$rate_categories$value_max, 4)
testthat::expect_equal(equal_binned$rate_categories$value_sd, stats::sd(c(1, 4)))
testthat::expect_equal(equal_binned$rate_categories$total_branch_length, 2)
near_constant <- rateMap(
list(.rate_map_state_fit(c(1, 1 + 1e-12))),
summary = "branch",
log = FALSE,
progress = FALSE
)
near_constant <- rateMapView(
near_constant,
color_mode = "category",
category_breaks = c(0, 2),
category_labels = "one"
)
testthat::expect_equal(near_constant$rate_categories$n_branches, 2L)
testthat::expect_equal(near_constant$rate_categories$value_sd, 0)
continuous_three <- rateMapView(
base,
color_mode = "continuous",
ncolors = 3
)
testthat::expect_equal(continuous_three$color_mode, "continuous")
testthat::expect_length(continuous_three$cols, 3)
testthat::expect_equal(continuous_three$ncolors, 3L)
testthat::expect_null(continuous_three$rate_categories)
continuous_default <- rateMapView(base, color_mode = "continuous")
testthat::expect_equal(continuous_default$ncolors, 256L)
testthat::expect_length(continuous_default$cols, 256)
old_base <- base
old_base$ncolors <- NULL
old_continuous <- rateMapView(old_base, color_mode = "continuous")
testthat::expect_equal(old_continuous$ncolors, 256L)
testthat::expect_length(old_continuous$cols, 256)
category_again <- rateMapView(continuous_three, color_mode = "category")
testthat::expect_equal(category_again$ncolors, 3L)
interval_base <- rateMap(
list(fit),
summary = "interval",
log = FALSE,
progress = FALSE,
control = rateMapControl(res = 2)
)
testthat::expect_false("n_branches" %in% names(interval_base$rate_categories))
many <- .rateMap_resolve_categories(1:10, n_categories = 3)
testthat::expect_equal(many$breaks, c(0, 5, 10))
testthat::expect_equal(many$labels, c("0 to 5", "5 to 10"))
testthat::expect_equal(many$index, c(1L, 1L, 1L, 1L, 2L, 2L, 2L, 2L, 2L, 2L))
equal_width <- .rateMap_resolve_categories(
1:10,
n_categories = 3,
category_bin_method = "equal"
)
testthat::expect_equal(equal_width$breaks, c(1, 4, 7, 10))
testthat::expect_equal(equal_width$labels, c("1 to 4", "4 to 7", "7 to 10"))
testthat::expect_equal(
equal_width$index,
c(1L, 1L, 1L, 2L, 2L, 2L, 3L, 3L, 3L, 3L)
)
auto_breaks <- .rateMap_resolve_categories(
c(1, 4),
n_categories = 2,
category_breaks = c(0, 2, 5)
)
testthat::expect_equal(auto_breaks$labels, c("0 to 2", "2 to 5"))
testthat::expect_equal(auto_breaks$index, c(1L, 2L))
testthat::expect_error(
.rateMap_resolve_categories(c(NA_real_, Inf), n_categories = 2),
"finite rate categories"
)
testthat::expect_error(
.rateMap_build_color_map(
values_by_edge = list(c(1, NA_real_), 2),
ncolors = 4,
palette = "YlOrRd",
reverse_palette = FALSE,
color_mode = "category",
n_categories = 2
),
"must all be finite"
)
testthat::expect_error(rateMapView(list()), "rateMap")
testthat::expect_error(
rateMapView(base, color_mode = "continuous", ncolors = 1),
"ncolors"
)
testthat::expect_error(
rateMapView(
base,
color_mode = "category",
category_bin_method = "quantile"
),
"'arg' should be"
)
testthat::expect_error(
rateMapView(
base,
color_mode = "category",
category_breaks = c(2, 1)
),
"category_breaks"
)
testthat::expect_error(
rateMapView(
base,
color_mode = "category",
category_breaks = c(2, 3)
),
"cover"
)
testthat::expect_error(
rateMapView(
base,
color_mode = "category",
category_breaks = c(0, 2, 5),
category_labels = c("same", "same")
),
"unique"
)
})
test_that("rateMap computes optional uncertainty summaries", {
.rate_map_skip_if_missing_deps()
fx <- .rate_map_fixture()
fits <- list(
.rate_map_fit(fx$base, c("0" = 1)),
.rate_map_fit(fx$base, c("0" = 3))
)
out <- rateMap(
fits,
summary = "branch",
uncertainty = TRUE,
log = FALSE,
progress = FALSE
)
testthat::expect_true(out$uncertainty)
testthat::expect_equal(out$value_summary, "mean")
testthat::expect_length(out$run_values, nrow(fx$base$edge))
testthat::expect_equal(dim(out$run_values[[1L]]), c(1L, 2L))
testthat::expect_true(all(c(
"mean", "median", "sd", "q025", "q975", "highest_density_interval_low", "highest_density_interval_high",
"ci_width", "highest_density_interval_width", "cv", "n"
) %in% names(out$intervals)))
testthat::expect_equal(out$intervals$value, out$intervals$mean)
testthat::expect_true(all(abs(out$intervals$mean - 2) < 1e-12))
testthat::expect_true(all(abs(out$intervals$median - 2) < 1e-12))
testthat::expect_true(all(abs(out$intervals$sd - sqrt(2)) < 1e-12))
testthat::expect_true(all(abs(out$intervals$q025 - 1.05) < 1e-12))
testthat::expect_true(all(abs(out$intervals$q975 - 2.95) < 1e-12))
testthat::expect_true(all(abs(out$intervals$highest_density_interval_low - 1) < 1e-12))
testthat::expect_true(all(abs(out$intervals$highest_density_interval_high - 3) < 1e-12))
testthat::expect_true(all(abs(out$intervals$ci_width - 1.9) < 1e-12))
testthat::expect_true(all(abs(out$intervals$highest_density_interval_width - 2) < 1e-12))
testthat::expect_true(all(abs(out$intervals$cv - sqrt(2) / 2) < 1e-12))
testthat::expect_true(all(out$intervals$n == 2L))
testthat::expect_equal(
.rateMap_add_derived_uncertainty(data.frame(mean = 1)),
data.frame(mean = 1)
)
sd_map <- .rateMap_recolor(out, "sd")
testthat::expect_equal(sd_map$plot_value, "sd")
testthat::expect_true(diff(sd_map$lims) > 0)
single_fit <- rateMap(
list(.rate_map_fit(fx$base, c("0" = 1))),
summary = "branch",
uncertainty = TRUE,
log = FALSE,
progress = FALSE
)
testthat::expect_error(
rateMapView(single_fit, value = "sd"),
"contains no finite values"
)
mixed_cv <- rateMap(
list(
.rate_map_state_fit(c(1, 2)),
.rate_map_state_fit(c(1, 4))
),
summary = "branch",
uncertainty = TRUE,
log = TRUE,
progress = FALSE
)
testthat::expect_true(any(is.na(mixed_cv$intervals$cv)))
testthat::expect_true(any(is.finite(mixed_cv$intervals$cv)))
testthat::expect_error(
rateMapView(mixed_cv, value = "cv", color_mode = "category"),
"contains non-finite values"
)
testthat::expect_error(
rateMapView(mixed_cv, value = "cv", color_mode = "continuous"),
"contains non-finite values"
)
flagged_uncertainty <- rateMap(
list(
.rate_map_state_fit(c(1e-9, 1, 2)),
.rate_map_state_fit(c(1e-9, 1.2, 3))
),
summary = "branch",
uncertainty = TRUE,
log = FALSE,
progress = FALSE,
control = rateMapControl(
rate_flags = rateMapRateFlags(method = "floor", zero_floor = 1e-8)
)
)
flagged_sd <- rateMapView(flagged_uncertainty, value = "sd", color_mode = "category")
testthat::expect_equal(flagged_uncertainty$rate_diagnostics$n_near_zero, 1L)
testthat::expect_equal(flagged_sd$rate_diagnostics$n_near_zero, 1L)
testthat::expect_equal(flagged_uncertainty$rate_flag_source, "value")
testthat::expect_equal(flagged_sd$rate_flag_source, "value")
testthat::expect_true(all(flagged_sd$intervals$rate_flag_source == "value"))
testthat::expect_true(flagged_sd$intervals$is_near_zero[1L])
testthat::expect_false("near-zero" %in% flagged_sd$intervals$rate_category)
median_out <- rateMap(
list(
.rate_map_fit(fx$base, c("0" = 1)),
.rate_map_fit(fx$base, c("0" = 5)),
.rate_map_fit(fx$base, c("0" = 9))
),
summary = "branch",
value_summary = "median",
log = FALSE,
progress = FALSE
)
testthat::expect_false(median_out$uncertainty)
testthat::expect_null(median_out$run_values)
testthat::expect_equal(median_out$value_summary, "median")
testthat::expect_true(all(abs(median_out$intervals$value - 5) < 1e-12))
weighted <- rateMap(
fits,
summary = "branch",
weights = c(1, 3),
uncertainty = TRUE,
value_summary = "median",
log = FALSE,
progress = FALSE
)
testthat::expect_equal(weighted$weights, c(0.25, 0.75))
testthat::expect_true(all(abs(weighted$intervals$mean - 2.5) < 1e-12))
testthat::expect_true(all(abs(weighted$intervals$value - 3) < 1e-12))
testthat::expect_true(all(abs(weighted$intervals$median - 3) < 1e-12))
})
test_that("rateMap handles valid log transforms and multi-segment branch maps", {
.rate_map_skip_if_missing_deps()
fx <- .rate_map_fixture()
segmented <- fx$base
edge_len <- segmented$edge.length[1L]
segmented$maps[[1L]] <- c("0" = edge_len / 2, "1" = edge_len / 2)
segmented$mapped.edge <- .rateMap_make_mapped_edge(segmented$edge, segmented$maps)
out <- rateMap(
list(.rate_map_fit(segmented, c("0" = exp(1), "1" = exp(3)))),
summary = "branch",
progress = FALSE
)
testthat::expect_equal(out$summary, "branch")
testthat::expect_true(out$log)
testthat::expect_true(any(abs(out$intervals$value - 2) < 1e-12))
})
test_that("rateMap handles zero-length mapped branches", {
.rate_map_skip_if_missing_deps()
fx <- .rate_map_fixture()
zero_branch <- fx$base
zero_branch$edge.length[1L] <- 0
zero_branch$maps[[1L]] <- c("0" = 0)
zero_branch$mapped.edge <- .rateMap_make_mapped_edge(zero_branch$edge, zero_branch$maps)
out <- rateMap(
list(.rate_map_fit(zero_branch, c("0" = 1))),
summary = "branch",
log = FALSE,
progress = FALSE
)
testthat::expect_equal(out$intervals$interval_length[1L], 0)
testthat::expect_equal(out$intervals$value[1L], 1)
})
test_that("rateMap supports IC weights for comparable bifrost_search objects", {
.rate_map_skip_if_missing_deps()
fx <- .rate_map_fixture()
make_search <- function(rate, ic, family = "GIC") {
structure(
list(
tree_no_uncertainty_untransformed = fx$base,
model_no_uncertainty = list(param = c("0" = rate)),
optimal_ic = ic,
IC_used = family
),
class = c("bifrost_search", "list")
)
}
fit_a <- make_search(10, 100)
fit_b <- make_search(20, 102)
expected_weights <- exp(-0.5 * c(0, 2))
expected_weights <- expected_weights / sum(expected_weights)
out <- rateMap(
list(fit_a, fit_b),
summary = "branch",
weights = "ic",
log = FALSE,
progress = FALSE
)
testthat::expect_equal(out$weight_mode, "ic")
testthat::expect_equal(out$weights, expected_weights, tolerance = 1e-12)
testthat::expect_equal(out$weight_table$ic, c(100, 102))
testthat::expect_equal(out$weight_table$IC_used, c("GIC", "GIC"))
testthat::expect_true(all(abs(out$intervals$value - sum(expected_weights * c(10, 20))) < 1e-12))
testthat::expect_error(
rateMap(
list(fit_a, make_search(20, 102, "BIC")),
weights = "ic",
progress = FALSE
),
"same non-missing 'IC_used'"
)
no_family <- fit_a
no_family$IC_used <- NULL
testthat::expect_error(
rateMap(
list(fit_a, no_family),
weights = "ic",
progress = FALSE
),
"same non-missing 'IC_used'"
)
missing_ic <- fit_a
missing_ic$optimal_ic <- NA_real_
testthat::expect_error(
rateMap(
list(fit_a, missing_ic),
weights = "ic",
progress = FALSE
),
"finite 'optimal_ic'"
)
missing_ic_field <- fit_a
missing_ic_field$optimal_ic <- NULL
testthat::expect_error(
rateMap(
list(fit_a, missing_ic_field),
weights = "ic",
progress = FALSE
),
"finite 'optimal_ic'"
)
testthat::expect_error(
rateMap(
list(.rate_map_fit(fx$base, c("0" = 1))),
weights = "ic",
progress = FALSE
),
"finite 'optimal_ic'"
)
})
test_that("rateMap validates custom fit weights", {
.rate_map_skip_if_missing_deps()
fx <- .rate_map_fixture()
fits <- list(
.rate_map_fit(fx$base, c("0" = 1)),
.rate_map_fit(fx$base, c("0" = 3))
)
out <- rateMap(
fits,
summary = "branch",
weights = c(2, 2),
log = FALSE,
progress = FALSE
)
testthat::expect_equal(out$weight_mode, "custom")
testthat::expect_equal(out$weights, c(0.5, 0.5))
testthat::expect_true(all(abs(out$intervals$value - 2) < 1e-12))
testthat::expect_error(
rateMap(fits, weights = c(1, -1), progress = FALSE),
"non-negative"
)
testthat::expect_error(
rateMap(fits, weights = c(0, 0), progress = FALSE),
"positive"
)
testthat::expect_error(
rateMap(fits, weights = c(1, 2, 3), progress = FALSE),
"length"
)
testthat::expect_error(
rateMap(fits, weights = c(1, NA), progress = FALSE),
"finite numeric"
)
invalid <- .rate_map_fit(fx$base, NA_real_)
out_omit <- rateMap(
list(invalid, fits[[1]], fits[[2]]),
summary = "branch",
weights = c(100, 1, 3),
progress = FALSE,
control = rateMapControl(na_action = "omit")
)
testthat::expect_equal(out_omit$weights, c(0.25, 0.75))
out_omit_used_weights <- rateMap(
list(invalid, fits[[1]], fits[[2]]),
summary = "branch",
weights = c(1, 3),
progress = FALSE,
control = rateMapControl(na_action = "omit")
)
testthat::expect_equal(out_omit_used_weights$weights, c(0.25, 0.75))
})
test_that("rateMap palette resolution handles named palettes, ramps, and functions", {
.rate_map_skip_if_missing_deps()
vir <- .rateMap_colors(5, "Viridis")
vir_rev <- .rateMap_colors(5, "Viridis", reverse_palette = TRUE)
testthat::expect_equal(vir_rev, rev(vir))
ramp <- .rateMap_colors(6, c("black", "white"))
ramp_rev <- .rateMap_colors(6, c("black", "white"), reverse_palette = TRUE)
testthat::expect_equal(ramp_rev, rev(ramp))
fun_cols <- .rateMap_colors(4, function(n) grDevices::hcl.colors(n, "Inferno"))
testthat::expect_length(fun_cols, 4)
testthat::expect_type(fun_cols, "character")
resized <- .rateMap_colors(4, function(n) c("black", "white"))
testthat::expect_length(resized, 4)
testthat::expect_error(.rateMap_colors(3, 1:3), "palette")
testthat::expect_error(.rateMap_colors(3, function(n) "black"), "at least two")
})
test_that("rateMap display option helpers validate labels, dots, and legends", {
.rate_map_skip_if_missing_deps()
testthat::expect_error(
.rateMap_validate_dots(list(TRUE), allowed = "x"),
"must be named"
)
testthat::expect_null(.rateMap_validate_dots(list(x = TRUE), allowed = "x"))
testthat::expect_equal(.rateMap_order_state_names(c("b", "a")), c("a", "b"))
testthat::expect_error(.rateMap_normalize_color_options(ncolors = 1), "ncolors")
testthat::expect_true(.rateMap_show_legend(0.1))
testthat::expect_false(.rateMap_show_legend(FALSE))
testthat::expect_equal(.rateMap_legend_digits(c(1e-9, 1e-5)), 11L)
testthat::expect_equal(.rateMap_legend_digits(c(-10, 10)), 3L)
testthat::expect_equal(.rateMap_legend_digits(c(NA_real_, 1)), 3L)
testthat::expect_equal(.rateMap_legend_digits(c(0, 0)), 3L)
testthat::expect_equal(.rateMap_format_rate(1e-9, c(1e-9, 1e-5)), "0.000000001")
testthat::expect_error(.rateMap_validate_n_categories(NA_real_), "n_categories")
testthat::expect_error(.rateMap_category_labels(c("a", NA), 2, TRUE), "non-missing")
testthat::expect_equal(
.rateMap_category_labels(c("a", "a"), 2, FALSE),
c("a", "a_1")
)
})
test_that("rateMap rate flag controls normalize defaults and reject invalid settings", {
.rate_map_skip_if_missing_deps()
testthat::expect_equal(rateMapRateFlags()$method, "none")
testthat::expect_false(rateMapRateFlags()$near_zero)
testthat::expect_false(rateMapRateFlags()$high_outlier)
flag_control <- rateMapRateFlags(zero_floor = 1e-8)
testthat::expect_s3_class(flag_control, "rateMap_rate_flags")
testthat::expect_equal(flag_control$method, "floor")
testthat::expect_true(flag_control$near_zero)
testthat::expect_false(flag_control$high_outlier)
testthat::expect_false(rateMapRateFlags(
method = "floor",
zero_floor = 1e-8,
high_outlier = TRUE
)$high_outlier)
tail_control <- rateMapRateFlags(method = "tail_cluster", high_outlier = TRUE)
testthat::expect_true(tail_control$near_zero)
testthat::expect_true(tail_control$high_outlier)
testthat::expect_equal(
rateMapControl(rate_flags = list(zero_floor = 1e-8))$rate_flags$method,
"floor"
)
testthat::expect_true(rateMapControl(rate_flags = list(zero_floor = 1e-8))$rate_flags$near_zero)
testthat::expect_equal(
rateMapControl(rate_flags = list(method = "none"))$rate_flags$method,
"none"
)
testthat::expect_false(rateMapControl(rate_flags = list(method = "none"))$rate_flags$near_zero)
testthat::expect_error(rateMapRateFlags(near_zero = NA), "near_zero")
testthat::expect_error(rateMapRateFlags(high_outlier = NA), "high_outlier")
testthat::expect_error(rateMapRateFlags(method = TRUE), "method")
testthat::expect_error(rateMapRateFlags(method = "floor"), "zero_floor")
testthat::expect_error(
rateMapRateFlags(method = "tail_cluster", zero_floor = 1e-8),
"zero_floor"
)
testthat::expect_error(rateMapRateFlags(method = "none", zero_floor = 1e-8), "zero_floor")
testthat::expect_error(rateMapRateFlags(zero_floor = -1), "zero_floor")
testthat::expect_error(rateMapRateFlags(cluster_min_log_gap = 0), "cluster_min_log_gap")
testthat::expect_error(
rateMapRateFlags(cluster_min_fold_reduction = 1),
"cluster_min_fold_reduction"
)
testthat::expect_error(
rateMapRateFlags(cluster_max_tail_fraction = 0.75),
"cluster_max_tail_fraction"
)
testthat::expect_error(rateMapRateFlags(cluster_min_flagged = 0), "cluster_min_flagged")
testthat::expect_error(rateMapRateFlags(cluster_min_regular = 0), "cluster_min_regular")
testthat::expect_error(rateMapRateFlags(zero_label = "same", high_label = "same"), "unique")
testthat::expect_error(rateMapRateFlags(zero_color = ""), "color")
testthat::expect_error(rateMapControl(rate_flags = TRUE), "rate_flags")
testthat::expect_error(rateMapControl(rate_flags = list(TRUE)), "rate_flags")
testthat::expect_error(rateMapControl(rate_flags = list(nope = TRUE)), "Unsupported")
})
test_that("rateMap category limits and legend breaks handle edge cases", {
.rate_map_skip_if_missing_deps()
testthat::expect_equal(
.rateMap_category_lims(list(rate_categories = NULL, lims = c(0, 1))),
c(0, 1)
)
testthat::expect_equal(
.rateMap_category_lims(list(
rate_categories = data.frame(value = c(1, 4)),
lims = c(0, 5)
)),
c(1, 4)
)
testthat::expect_equal(
.rateMap_category_lims(list(
rate_categories = data.frame(lower = 1, upper = 1, value = 1),
lims = c(0.99, 1.01)
)),
c(0.99, 1.01)
)
fisher_breaks <- c(-14.22, -13.69, -13.21, -12.91, -12.57, -11.40, -10.57)
testthat::expect_equal(
.rateMap_category_legend_breaks(fisher_breaks, 6L),
fisher_breaks
)
xs <- .rateMap_category_legend_x(fisher_breaks, 0, 1)
testthat::expect_equal(diff(xs), diff(fisher_breaks) / diff(range(fisher_breaks)))
leftward_xs <- .rateMap_category_legend_x(fisher_breaks, 0, 1, "leftwards")
testthat::expect_equal(abs(diff(leftward_xs)), diff(xs))
testthat::expect_equal(leftward_xs[c(1L, length(leftward_xs))], c(1, 0))
testthat::expect_null(.rateMap_category_legend_breaks("not numeric", 1L))
testthat::expect_null(.rateMap_category_legend_breaks(c(0, 1), "two"))
testthat::expect_null(.rateMap_category_legend_breaks(c(0, 1), c(1L, 2L)))
testthat::expect_null(.rateMap_category_legend_breaks(c(0, 1), NA_real_))
testthat::expect_null(.rateMap_category_legend_breaks(c(0, 1), 0L))
testthat::expect_null(.rateMap_category_legend_breaks(c(0, 1, 2), 2.2))
testthat::expect_null(.rateMap_category_legend_breaks(c(1, 4), 2L))
testthat::expect_null(.rateMap_category_legend_breaks(c(0, NA_real_, 1), 2L))
testthat::expect_null(.rateMap_category_legend_breaks(c(0, 2, 2), 2L))
testthat::expect_null(.rateMap_add_category_legend(list(rate_categories = NULL)))
})
test_that("rateMap branch-value and weighted summary helpers handle missing values", {
.rate_map_skip_if_missing_deps()
testthat::expect_equal(
.rateMap_map_value(c("0" = 1), c("0" = 7), start = 2, end = 3),
7
)
testthat::expect_equal(
.rateMap_weighted_mean(c(NA, 4), c(1, 3)),
4
)
testthat::expect_true(is.na(.rateMap_weighted_mean(c(NA, Inf), c(1, 1))))
testthat::expect_true(is.na(.rateMap_weighted_sd(c(1, NA), c(1, 1))))
testthat::expect_equal(
.rateMap_weighted_quantile(c(NA, Inf), c(1, 1), c(0.25, 0.75)),
c(NA_real_, NA_real_)
)
testthat::expect_equal(
.rateMap_weighted_quantile(c(4, NA), c(1, 1), c(0.25, 0.75)),
c(4, 4)
)
testthat::expect_equal(
.rateMap_weighted_quantile(c(1, 3), c(1, 3), c(0, 1)),
c(1, 3)
)
testthat::expect_equal(
.rateMap_highest_density_interval(c(NA, Inf), c(1, 1), 0.95),
c(NA_real_, NA_real_)
)
testthat::expect_equal(
.rateMap_highest_density_interval(c(4, NA), c(1, 1), 0.95),
c(4, 4)
)
testthat::expect_equal(
.rateMap_highest_density_interval(c(3, 1, 2, NA), c(1, 1, 1, 1), 0.5),
c(1, 2)
)
testthat::expect_equal(
.rateMap_highest_density_interval(c(1, 2, 100), c(0.49, 0.49, 0.02), 0.9),
c(1, 2)
)
testthat::expect_equal(
.rateMap_highest_density_interval(c(1, 2, 3), c(1, 1, 1), 1),
c(1, 3)
)
testthat::expect_equal(
.rateMap_row_means(matrix(c(1, NA, 3, 5), nrow = 2, byrow = TRUE), c(0.25, 0.75)),
c(1, 4.5)
)
})
test_that("rateMap uses progress/workers and plot() draws separately", {
.rate_map_skip_if_missing_deps()
fx <- .rate_map_fixture()
.rate_map_with_pdf({
graphics::plot.new()
graphics::plot.window(xlim = c(0, 1), ylim = c(0, 1))
testthat::expect_equal(
.rateMap_category_legend_label_index(c("0", "1"), c(0, 1), 1),
c(1L, 2L)
)
testthat::expect_equal(
.rateMap_category_legend_label_index(c("0", "1", "2"), c(0, 0.5, 1), 0.5),
1:3
)
testthat::expect_equal(
.rateMap_category_legend_label_index(
c("long left label", "long middle label", "long right label"),
c(0, 0.01, 0.02),
2
),
c(1L, 3L)
)
testthat::expect_null(.rateMap_add_category_legend(
list(
rate_categories = data.frame(lower = 1, upper = 1, value = 1),
cols = c("1" = "red"),
title = "one category",
lims = c(0.99, 1.01)
),
legend = 0.5,
x_pos = 0.2,
y_pos = 0.2
))
testthat::expect_null(.rateMap_add_category_legend(
list(
rate_categories = data.frame(
lower = c(0, 2),
upper = c(2, 5),
value = c(NA_real_, NA_real_)
),
cols = c(slow = "red", fast = "blue"),
category_breaks = c(0, 2, 5),
title = "custom categories",
lims = c(0, 5)
),
legend = 0.5,
x_pos = 0.2,
y_pos = 0.3
))
out <- .rate_map_eval_no_error(rateMap(
list(.rate_map_fit(fx$base, c("0" = 1))),
summary = "branch",
progress = TRUE,
workers = 1,
control = rateMapControl(future_strategy = "multisession")
))
testthat::expect_s3_class(out, "rateMap")
.rate_map_eval_no_error(plot(out, legend = FALSE, hold = FALSE))
})
})
test_that("plot.rateMap preserves active coordinates without leaking plot styles", {
.rate_map_skip_if_missing_deps()
fx <- .rate_map_fixture()
out <- rateMap(
list(.rate_map_fit(fx$shifted_a), .rate_map_fit(fx$shifted_b)),
progress = FALSE,
control = rateMapControl(res = 4)
)
for (layout in c("fan", "arc")) {
.rate_map_with_pdf({
graphics::par(
mar = c(4.1, 3.2, 2.3, 1.4),
fg = "navy",
col = "magenta",
xpd = NA,
mgp = c(2.5, 0.75, 0)
)
before_usr <- graphics::par("usr")
before_style <- graphics::par(c("col", "fg", "xpd", "mgp"))
drawn <- plot(
out,
type = layout,
outline = TRUE,
legend = FALSE,
show_tip_labels = FALSE,
hold = FALSE
)
after_usr <- graphics::par("usr")
after_style <- graphics::par(c("col", "fg", "xpd", "mgp"))
plot_env <- get(".PlotPhyloEnv", envir = asNamespace("ape"))
last_plot <- get("last_plot.phylo", envir = plot_env)
nodes_inside_plot <-
last_plot$xx >= after_usr[1L] &
last_plot$xx <= after_usr[2L] &
last_plot$yy >= after_usr[3L] &
last_plot$yy <= after_usr[4L]
testthat::expect_s3_class(drawn, "rateMap")
testthat::expect_false(identical(after_usr, before_usr))
testthat::expect_true(all(nodes_inside_plot))
testthat::expect_identical(after_style, before_style)
})
}
})
test_that("plot.rateMap supports shift-node overlays on its active tree", {
.rate_map_skip_if_missing_deps()
fx <- .rate_map_fixture()
out <- rateMap(
list(.rate_map_fit(fx$shifted_a), .rate_map_fit(fx$shifted_b)),
progress = FALSE,
control = rateMapControl(res = 4)
)
marks <- shift_node_marks(data.frame(
node = ape::Ntip(out$tree) + 2L,
rate_change = "increase",
child_state = "1",
age = 1,
percentage_change = 100
))
.rate_map_with_pdf({
plot(
out,
type = "arc",
outline = TRUE,
legend = FALSE,
show_tip_labels = FALSE,
hold = FALSE
)
tree_usr <- graphics::par("usr")
testthat::expect_no_error(plot(
marks,
rate_changes = "increase",
show_low_support = FALSE,
show_legend = FALSE
))
testthat::expect_identical(graphics::par("usr"), tree_usr)
})
})
test_that("plot.rateMap restores graphical parameters after plotting errors", {
.rate_map_skip_if_missing_deps()
fx <- .rate_map_fixture()
out <- rateMap(
list(.rate_map_fit(fx$shifted_a), .rate_map_fit(fx$shifted_b)),
progress = FALSE,
control = rateMapControl(res = 4)
)
testthat::expect_error(
.plot_rate_map(out, type = "arc", arc_height = Inf),
"'arc_height' must be a finite numeric scalar for arc plots",
fixed = TRUE
)
.rate_map_with_pdf({
graphics::par(
mar = c(4.1, 3.2, 2.3, 1.4),
fg = "navy",
col = "magenta",
xpd = NA,
mgp = c(2.5, 0.75, 0)
)
before <- graphics::par(no.readonly = TRUE)
testthat::expect_error(plot(
out,
type = "arc",
outline = TRUE,
xlim = "invalid",
legend = FALSE,
show_tip_labels = FALSE,
hold = FALSE
))
testthat::expect_identical(graphics::par(no.readonly = TRUE), before)
})
.rate_map_with_pdf({
graphics::par(
mar = c(4.1, 3.2, 2.3, 1.4),
fg = "navy",
col = "magenta",
xpd = NA,
mgp = c(2.5, 0.75, 0)
)
before <- graphics::par(no.readonly = TRUE)
testthat::expect_error(
plot(
out,
type = "arc",
outline = TRUE,
arc_height = "invalid",
legend = FALSE,
show_tip_labels = FALSE,
hold = FALSE
),
"'arc_height' must be a finite numeric scalar for arc plots",
fixed = TRUE
)
testthat::expect_identical(graphics::par(no.readonly = TRUE), before)
})
})
test_that("plot.rateMap never writes getYmult in the global environment", {
.rate_map_skip_if_missing_deps()
global <- .GlobalEnv
had_getYmult <- exists("getYmult", envir = global, inherits = FALSE)
was_active <- had_getYmult && bindingIsActive("getYmult", global)
old_getYmult <- if (was_active) {
activeBindingFunction("getYmult", global)
} else if (had_getYmult) {
get("getYmult", envir = global, inherits = FALSE)
} else {
NULL
}
on.exit({
if (exists("getYmult", envir = global, inherits = FALSE)) {
rm("getYmult", envir = global)
}
if (had_getYmult) {
if (was_active) {
makeActiveBinding("getYmult", old_getYmult, global)
} else {
assign("getYmult", old_getYmult, envir = global)
}
}
}, add = TRUE)
if (had_getYmult) {
rm("getYmult", envir = global)
}
writes <- 0L
makeActiveBinding("getYmult", function(value) {
if (!missing(value)) {
writes <<- writes + 1L
stop("plot.rateMap attempted to write global getYmult")
}
function() 1
}, global)
fx <- .rate_map_fixture()
out <- rateMap(
list(.rate_map_fit(fx$shifted_a), .rate_map_fit(fx$shifted_b)),
progress = FALSE,
control = rateMapControl(res = 4)
)
for (layout in c("arc", "fan")) {
drawn <- .rate_map_with_pdf(.rate_map_eval_no_error(plot(
out,
type = layout,
legend = FALSE,
show_tip_labels = FALSE,
hold = FALSE
)))
testthat::expect_s3_class(drawn, "rateMap")
}
testthat::expect_equal(writes, 0L)
})
test_that("plot.rateMap preserves an existing global getYmult binding", {
.rate_map_skip_if_missing_deps()
global <- .GlobalEnv
had_getYmult <- exists("getYmult", envir = global, inherits = FALSE)
old_getYmult <- if (had_getYmult) {
get("getYmult", envir = global, inherits = FALSE)
} else {
NULL
}
on.exit({
if (exists("getYmult", envir = global, inherits = FALSE)) {
rm("getYmult", envir = global)
}
if (had_getYmult) {
assign("getYmult", old_getYmult, envir = global)
}
}, add = TRUE)
if (exists("getYmult", envir = global, inherits = FALSE)) {
rm("getYmult", envir = global)
}
sentinel <- structure("sentinel", class = "rateMap_getYmult_sentinel")
assign("getYmult", sentinel, envir = global)
fx <- .rate_map_fixture()
out <- rateMap(
list(.rate_map_fit(fx$shifted_a), .rate_map_fit(fx$shifted_b)),
progress = FALSE,
control = rateMapControl(res = 4)
)
.rate_map_with_pdf(.rate_map_eval_no_error(plot(
out,
type = "arc",
legend = FALSE,
show_tip_labels = FALSE,
hold = FALSE
)))
testthat::expect_identical(
get("getYmult", envir = global, inherits = FALSE),
sentinel
)
testthat::expect_error(.rate_map_with_pdf(plot(
out,
type = "arc",
arc_height = "invalid",
legend = FALSE,
hold = FALSE
)))
testthat::expect_identical(
get("getYmult", envir = global, inherits = FALSE),
sentinel
)
})
test_that("plot.rateMap errors do not create global getYmult state", {
.rate_map_skip_if_missing_deps()
global <- .GlobalEnv
had_getYmult <- exists("getYmult", envir = global, inherits = FALSE)
old_getYmult <- if (had_getYmult) {
get("getYmult", envir = global, inherits = FALSE)
} else {
NULL
}
on.exit({
if (exists("getYmult", envir = global, inherits = FALSE)) {
rm("getYmult", envir = global)
}
if (had_getYmult) {
assign("getYmult", old_getYmult, envir = global)
}
}, add = TRUE)
if (exists("getYmult", envir = global, inherits = FALSE)) {
rm("getYmult", envir = global)
}
fx <- .rate_map_fixture()
out <- rateMap(
list(.rate_map_fit(fx$shifted_a), .rate_map_fit(fx$shifted_b)),
progress = FALSE,
control = rateMapControl(res = 4)
)
testthat::expect_error(.rate_map_with_pdf(plot(
out,
type = "arc",
arc_height = "invalid",
legend = FALSE,
hold = FALSE
)))
testthat::expect_false(exists("getYmult", envir = global, inherits = FALSE))
})
test_that("plot.rateMap draws rate maps on a graphics device", {
.rate_map_skip_if_missing_deps()
fx <- .rate_map_fixture()
out <- rateMap(
list(.rate_map_fit(fx$shifted_a), .rate_map_fit(fx$shifted_b)),
progress = FALSE,
control = rateMapControl(res = 4)
)
binned_like <- out
binned_like$color_mode <- "category"
binned_like$n_categories <- 2L
binned_like$category_breaks <- c(-3, -1, 0)
binned_like$category_labels <- c("low", "high")
binned_like$rate_categories <- data.frame(
color_bin = 1:2,
rate_category = c("low", "high"),
lower = c(-3, -1),
upper = c(-1, 0),
value = c(NA_real_, NA_real_),
color = c("black", "white"),
stringsAsFactors = FALSE
)
binned_recolored <- .rateMap_recolor(binned_like, "value")
testthat::expect_equal(binned_recolored$category_labels, c("low", "high"))
drawn <- .rate_map_with_pdf({
.rate_map_eval_no_error(plot(
out,
type = "arc",
show_tip_labels = FALSE,
legend = FALSE,
hold = FALSE
))
})
testthat::expect_s3_class(drawn, "rateMap")
testthat::expect_error(.plot_rate_map(list()), "rateMap")
})
test_that("plot.rateMap covers phylogram, fan, legend, outline, and S3 paths", {
.rate_map_skip_if_missing_deps()
fx <- .rate_map_fixture()
out <- rateMap(
list(.rate_map_fit(fx$shifted_a), .rate_map_fit(fx$shifted_b)),
uncertainty = TRUE,
progress = FALSE,
control = rateMapControl(res = 4)
)
path <- tempfile(fileext = ".pdf")
grDevices::pdf(path)
on.exit(grDevices::dev.off(), add = TRUE)
sd_drawn <- .rate_map_eval_no_error(plot(
out,
value = "sd",
palette = c("white", "black"),
reverse_palette = TRUE,
color_mode = "continuous",
type = "arc",
legend = FALSE,
hold = FALSE
))
testthat::expect_equal(sd_drawn$plot_value, "sd")
testthat::expect_equal(sd_drawn$intervals$value, sd_drawn$intervals$sd)
testthat::expect_equal(
sd_drawn$cols,
stats::setNames(
.rateMap_colors(out$ncolors, c("white", "black"), reverse_palette = TRUE),
as.character(seq_len(out$ncolors))
)
)
testthat::expect_equal(sd_drawn$ncolors, out$ncolors)
testthat::expect_equal(
as.numeric(rowSums(sd_drawn$tree$mapped.edge)),
sd_drawn$tree$edge.length,
tolerance = 1e-10
)
default_recolored <- .rate_map_eval_no_error(plot(
out,
palette = c("navy", "gold"),
legend = FALSE,
hold = FALSE
))
testthat::expect_equal(default_recolored$plot_value, "value")
testthat::expect_equal(default_recolored$intervals$value, out$intervals$value)
category_drawn <- .rate_map_eval_no_error(plot(
out,
color_mode = "category",
n_categories = 3,
category_bin_method = "equal",
type = "phylogram",
legend = TRUE,
hold = FALSE
))
testthat::expect_equal(category_drawn$color_mode, "category")
testthat::expect_equal(category_drawn$category_bin_method, "equal")
testthat::expect_true("rate_category" %in% names(category_drawn$intervals))
testthat::expect_s3_class(category_drawn$rate_categories, "data.frame")
continuous_again <- plot(
category_drawn,
color_mode = "continuous",
legend = FALSE,
hold = FALSE
)
testthat::expect_equal(continuous_again$color_mode, "continuous")
testthat::expect_false("rate_category" %in% names(continuous_again$intervals))
testthat::expect_equal(continuous_again$ncolors, out$ncolors)
testthat::expect_length(continuous_again$cols, out$ncolors)
continuous_out <- rateMapView(
rateMap(
list(.rate_map_fit(fx$shifted_a), .rate_map_fit(fx$shifted_b)),
progress = FALSE,
control = rateMapControl(res = 4)
),
color_mode = "continuous"
)
testthat::expect_equal(continuous_out$ncolors, 256L)
testthat::expect_length(continuous_out$cols, 256)
highest_density_recolored <- .rateMap_recolor(out, "highest_density_interval_width")
testthat::expect_equal(
highest_density_recolored$title,
"95% highest-density interval width (log rate)"
)
raw_out <- rateMap(
list(.rate_map_fit(fx$shifted_a), .rate_map_fit(fx$shifted_b)),
uncertainty = TRUE,
log = FALSE,
progress = FALSE,
control = rateMapControl(res = 4)
)
raw_highest_density_recolored <- .rateMap_recolor(raw_out, "highest_density_interval_width")
testthat::expect_equal(
raw_highest_density_recolored$title,
"95% highest-density interval width"
)
.rate_map_eval_no_error(plot(
continuous_out,
type = "phylogram",
legend = 0.2,
hold = FALSE
))
.rate_map_eval_no_error(plot(
continuous_out,
type = "arc",
legend = 0.2,
hold = FALSE
))
.rate_map_eval_no_error(plot(
continuous_out,
type = "fan",
outline = TRUE,
legend = 0.2,
hold = FALSE
))
testthat::expect_error(plot(out, value = "missing", legend = FALSE), "not a column")
testthat::expect_error(plot(out, value = "clade_key", legend = FALSE), "numeric column")
testthat::expect_error(plot(out, value = NA_character_, legend = FALSE), "single non-empty")
testthat::expect_error(plot(out, pallete = "Viridis"), "Unsupported argument")
testthat::expect_error(plot(out, legend = FALSE, legend_digits = -1), "legend_digits")
testthat::expect_error(plot(out, legend = FALSE, n_categories = 0), "n_categories")
testthat::expect_error(
plot(
out,
color_mode = "category",
category_breaks = c(0, 0.01),
legend = FALSE
),
"cover"
)
.rate_map_eval_no_error(plot(out, type = "arc", legend = TRUE, hold = FALSE))
.rate_map_eval_no_error(plot(out, type = "fan", legend = TRUE, hold = FALSE))
testthat::expect_message(
plot(
out,
type = "phylogram",
outline = TRUE,
legend = 1e9,
fsize = 0.5,
ftype = "i",
lwd = c(1, 2, 3),
hold = TRUE
),
"legend scale"
)
.rate_map_eval_no_error(plot(
out,
type = "phylogram",
outline = TRUE,
offset = 0.1,
direction = "leftwards",
xlim = c(1, 0),
legend = 0.1,
tip_fsize = 0.4,
legend_fsize = 0.6,
hold = FALSE
))
.rate_map_eval_no_error(plot(
out,
type = "fan",
outline = TRUE,
legend = 0.2,
fsize = c(0.4, 0.5),
hold = FALSE
))
printed <- utils::capture.output(print(out))
testthat::expect_true(any(grepl("rateMap object", printed)))
testthat::expect_true(any(grepl("uncertainty: TRUE", printed)))
testthat::expect_error(print.rateMap(list()), "rateMap")
.rate_map_eval_no_error(plot(
out,
value = "sd",
type = "arc",
outline = TRUE,
legend = 0.2,
show_tip_labels = FALSE,
hold = FALSE
))
})
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.