## ----setup, include=FALSE-----------------------------------------------------
is_check_env <- nzchar(Sys.getenv("_R_CHECK_PACKAGE_NAME_"))
.vig_tmp_root <- file.path(tempdir(), "ddesonn-vig-s1-s2")
dir.create(.vig_tmp_root, recursive = TRUE, showWarnings = FALSE)
options(DDESONN_OUTPUT_ROOT = .vig_tmp_root)
Sys.setenv(DDESONN_ARTIFACTS_ROOT = .vig_tmp_root)
# ============================================================
# FILE: vignettes/plot-controls_scenario1-2_single-run_scenarioA.Rmd
# FULL WORKING — DDESONN Plot Controls — Scenario 1 & 2 — Single Run: Scenario A
#
# GOAL:
# - Demonstrate TWO supported user-facing interfaces for plot control:
# (1) Scenario 1: training_overrides knobs (minimal integration)
# (2) Scenario 2: plot_controls umbrella (recommended)
#
# IMPORTANT (binary eval):
# - To emit BOTH confusion matrix heatmaps (fixed + tuned),
# users must set:
# accuracy_plot = TRUE
# accuracy_plot_mode = "both"
#
# IMPORTANT (performance/relevance):
# - This vignette uses the *current* naming shown in your branch:
# plot_controls$performance_relevance
# and Scenario 1 uses the same key so the bridge can map it.
# - No "boxplot" naming anywhere in config.
# ============================================================
# ============================================================
# FIX: VIGNETTE PARSE-SAFE opts_chunk$set
# ============================================================
# knitr options (SINGLE consolidated set)
# ============================================================
knitr::opts_chunk$set(
echo = TRUE,
message = FALSE,
warning = FALSE,
fig.width = 6.5,
fig.height = 4,
dpi = 96,
fig.retina = 1,
out.width = "85%",
fig.path = file.path(.vig_tmp_root, "figures", ""),
cache.path = file.path(.vig_tmp_root, "cache", "")
)
# ============================================================
# FIX: VIGNETTE-SAFE LOAD (no devtools::load_all)
# ============================================================
if (!requireNamespace("DDESONN", quietly = TRUE)) {
stop(
"DDESONN must be installed to build this vignette. ",
"Run: install.packages('DDESONN') (or your install flow) then rebuild vignettes.",
call. = FALSE
)
}
library(DDESONN)
## ============================================================
## SECTION: Recommended knitr figure options (consistency)
## ============================================================
## For consistent ggplot title sizing across HTML/PDF output,
## keep these chunk options stable:
## - fig.width / fig.height set explicit device size (inches).
## - fig.retina controls display scaling (avoid implicit CSS).
## - out.width affects HTML scaling; keep constant across plots.
# ============================================================
# Output roots for vignette artifacts
# - Keep artifact paths short and outside vignette *_files trees.
# - Disable persistent plot saving during R CMD check.
# ============================================================
.dd_out_root <- file.path(.vig_tmp_root, "outputs")
out1 <- file.path(.dd_out_root, "DDESONN_plots_scenarioA_s1")
out2 <- file.path(.dd_out_root, "DDESONN_plots_scenarioA_s2")
if (!is_check_env) {
dir.create(out1, recursive = TRUE, showWarnings = FALSE)
dir.create(out2, recursive = TRUE, showWarnings = FALSE)
}
# Make package helpers resolve to a short temp root.
options(DDESONN_OUTPUT_ROOT = if (is_check_env) .vig_tmp_root else out1)
Sys.setenv(DDESONN_ARTIFACTS_ROOT = if (is_check_env) .vig_tmp_root else out1)
# ============================================================
# Helper: include_saved_plots()
# - Uses knitr::image_uri() to embed PNGs as data: URIs
# ============================================================
include_saved_plots <- function(output_root, header) {
plot_dir <- ddesonn_plots_dir(output_root)
if (!dir.exists(plot_dir)) {
return(knitr::asis_output(
paste0("\n\n[plot-controls:scenarioA] plots dir does not exist: ", plot_dir, "\n\n")
))
}
pngs <- list.files(plot_dir, pattern = "\\.png$", recursive = TRUE, full.names = TRUE)
pngs <- pngs[nzchar(pngs)]
pngs <- pngs[order(pngs)]
if (!length(pngs)) {
return(knitr::asis_output(
paste0("\n\n[plot-controls:scenarioA] no PNGs found under: ", plot_dir, "\n\n")
))
}
out <- character()
out <- c(out, paste0("\n\n## ", header, "\n\n"))
for (p in pngs) {
uri <- knitr::image_uri(p)
out <- c(out, paste0('
\n\n'))
out <- c(out, "
\n\n")
}
knitr::asis_output(paste(out, collapse = ""))
}
## What “both heatmaps” means (binary EvaluatePredictionsReport)
## (unchanged text section)
set.seed(111)
ext_dir <- system.file("extdata", package = "DDESONN")
if (!nzchar(ext_dir)) stop("Could not find DDESONN extdata folder.", call. = FALSE)
hf_path <- file.path(ext_dir, "heart_failure_clinical_records.csv")
if (!file.exists(hf_path)) {
csvs <- list.files(ext_dir, pattern = "\\.csv$", full.names = TRUE)
if (!length(csvs)) stop("No .csv files found in extdata.", call. = FALSE)
hf_path <- csvs[[1]]
}
df <- read.csv(hf_path)
target_col <- if ("DEATH_EVENT" %in% names(df)) {
"DEATH_EVENT"
} else {
cand <- names(df)[vapply(df, function(col) {
v <- suppressWarnings(as.numeric(col))
if (all(is.na(v))) return(FALSE)
u <- unique(v[is.finite(v)])
length(u) <= 2 && all(sort(u) %in% c(0, 1))
}, logical(1))]
if (!length(cand)) stop("Could not infer a binary target column.", call. = FALSE)
cand[[1]]
}
y_all <- matrix(as.integer(df[[target_col]]), ncol = 1)
x_df <- df[, setdiff(names(df), target_col), drop = FALSE]
x_all <- as.matrix(x_df)
storage.mode(x_all) <- "double"
n <- nrow(x_all)
idx <- sample.int(n)
n_train <- floor(0.70 * n)
n_valid <- floor(0.15 * n)
i_tr <- idx[1:n_train]
i_va <- idx[(n_train + 1):(n_train + n_valid)]
i_te <- idx[(n_train + n_valid + 1):n]
x_train <- x_all[i_tr, , drop = FALSE]
y_train <- y_all[i_tr, , drop = FALSE]
x_valid <- x_all[i_va, , drop = FALSE]
y_valid <- y_all[i_va, , drop = FALSE]
x_test <- x_all[i_te, , drop = FALSE]
y_test <- y_all[i_te, , drop = FALSE]
# Scale train-only (no leakage)
x_train_s <- scale(x_train)
ctr <- attr(x_train_s, "scaled:center")
scl <- attr(x_train_s, "scaled:scale")
scl[!is.finite(scl) | scl == 0] <- 1
x_valid_s <- sweep(sweep(x_valid, 2, ctr, "-"), 2, scl, "/")
x_test_s <- sweep(sweep(x_test, 2, ctr, "-"), 2, scl, "/")
mx <- suppressWarnings(max(abs(x_train_s)))
if (!is.finite(mx) || mx == 0) mx <- 1
x_train <- x_train_s / mx
x_valid <- x_valid_s / mx
x_test <- x_test_s / mx
cat(sprintf("[split] train=%d valid=%d test=%d\n", nrow(x_train), nrow(x_valid), nrow(x_test)))
## ----scenarioA_s1_plots, results="asis", echo=FALSE---------------------------
options(DDESONN_OUTPUT_ROOT = if (is_check_env) .vig_tmp_root else out1)
Sys.setenv(DDESONN_ARTIFACTS_ROOT = if (is_check_env) .vig_tmp_root else out1)
res_scenarioA_s1 <- tryCatch(
ddesonn_run(
x = x_train,
y = y_train,
classification_mode = "binary",
hidden_sizes = c(64, 32),
seeds = 1L,
do_ensemble = FALSE,
validation = list(x = x_valid, y = y_valid),
test = list(x = x_test, y = y_test),
training_overrides = list(
init_method = "he",
optimizer = "adagrad",
lr = 0.125,
lambda = 0.00028,
activation_functions = list(relu, relu, sigmoid),
dropout_rates = list(0.10),
loss_type = "CrossEntropy",
validation_metrics = TRUE,
num_epochs = 360,
final_summary_decimals = 6L,
per_epoch_plots = list(
saveEnabled = !is_check_env,
loss_curve = TRUE,
probe_plots = TRUE,
verbose = TRUE
),
# ============================================================
# SECTION: performance_relevance (Scenario 1)
# - This key is bridged into plot_controls$performance_relevance
# ============================================================
performance_relevance = list(
saveEnabled = !is_check_env,
viewAllPlots = FALSE,
performance_high_mean_plots = TRUE,
performance_low_mean_plots = TRUE,
relevance_high_mean_plots = TRUE,
relevance_low_mean_plots = TRUE,
verbose = TRUE
),
evaluate_predictions_report_plots = list(
accuracy_plot = TRUE,
accuracy_plot_mode = "both",
plot_roc = TRUE,
plot_pr = TRUE,
show_auprc = TRUE,
viewAllPlots = FALSE,
verbose = TRUE
)
)
),
error = function(e) {
cat("\n================ DDESONN ERROR — Scenario 1 | Scenario A =================\n")
cat(conditionMessage(e), "\n\n")
cat("-------------- TRACEBACK -----------------------\n")
traceback(2)
cat("================================================\n\n")
stop(e)
}
)
if (!is_check_env) include_saved_plots(out1, "Scenario 1 — Saved plots")
## ----scenarioA_s2_run, donttest=TRUE------------------------------------------
options(DDESONN_OUTPUT_ROOT = if (is_check_env) .vig_tmp_root else out2)
Sys.setenv(DDESONN_ARTIFACTS_ROOT = if (is_check_env) .vig_tmp_root else out2)
res_scenarioA_s2 <- ddesonn_run(
x = x_train,
y = y_train,
classification_mode = "binary",
hidden_sizes = c(64, 32),
seeds = 1L,
do_ensemble = FALSE,
validation = list(x = x_valid, y = y_valid),
test = list(x = x_test, y = y_test),
training_overrides = list(
init_method = "he",
optimizer = "adagrad",
lr = 0.125,
lambda = 0.00028,
activation_functions = list(relu, relu, sigmoid),
dropout_rates = list(0.10),
loss_type = "CrossEntropy",
validation_metrics = TRUE,
num_epochs = 1,
final_summary_decimals = 6L
),
plot_controls = list(
per_epoch = list(
saveEnabled = !is_check_env,
loss_curve = TRUE,
probe_plots = TRUE,
verbose = TRUE
),
# ============================================================
# SECTION: performance_relevance (Scenario 2)
# ============================================================
performance_relevance = list(
saveEnabled = !is_check_env,
viewAllPlots = FALSE,
performance_high_mean_plots = TRUE,
performance_low_mean_plots = TRUE,
relevance_high_mean_plots = TRUE,
relevance_low_mean_plots = TRUE,
verbose = TRUE
),
evaluate_report = list(
accuracy_plot = TRUE,
accuracy_plot_mode = "both",
plot_roc = TRUE,
plot_pr = TRUE,
show_auprc = TRUE,
viewAllPlots = FALSE,
verbose = TRUE
)
)
)
## ----scenarioA_s2_plots, results="asis", echo=FALSE---------------------------
if (!is_check_env) include_saved_plots(out2, "Scenario 2 — Saved plots")