From 368eb72894d9d6bae9970935a374a6e8a8f7c28c Mon Sep 17 00:00:00 2001
From: Melkiades <davide.garolini@roche.com>
Date: Mon, 4 Nov 2024 13:18:03 +0100
Subject: [PATCH 01/17] rework of summarize_change

---
 NEWS.md                                |   3 +
 R/summarize_change.R                   | 166 +++++++++++++++++++------
 R/utils_default_stats_formats_labels.R |  18 +--
 3 files changed, 137 insertions(+), 50 deletions(-)

diff --git a/NEWS.md b/NEWS.md
index ce82541bb6..16957a5146 100644
--- a/NEWS.md
+++ b/NEWS.md
@@ -10,6 +10,9 @@
 * Updated the `table_font_size` parameter of `g_lineplot()` to control the size of all text in the annotation table, including labels.
 * Added `as_list` parameter to `g_lineplot()` to allow users to return the line plot and annotation table elements as a list instead of stacked for more complex customization.
 
+### Miscellaneous
+* Reverted deprecation of quick getters for `summary_formats` and `summary_labels`. Added disclaimer about underlying use of `get_stats`.
+
 ### Bug Fixes
 * Fixed bug in `a_summary()` causing non-unique `row_name` values to occur when multiple statistics are selected for count variables.
 
diff --git a/R/summarize_change.R b/R/summarize_change.R
index bf76ca7424..60c6c96510 100644
--- a/R/summarize_change.R
+++ b/R/summarize_change.R
@@ -29,11 +29,13 @@ NULL
 #'   an error will be thrown.
 #'
 #' @keywords internal
-s_change_from_baseline <- function(df,
-                                   .var,
-                                   variables,
-                                   na.rm = TRUE, # nolint
-                                   ...) {
+s_change_from_baseline <- function(df, ...) {
+  # s_summary should get na.rm
+  args_list <- list(...)
+  .var <- args_list[[".var"]]
+  variables <- args_list[["variables"]]
+  na.rm <- args_list[["na.rm"]]
+
   checkmate::assert_numeric(df[[variables$value]])
   checkmate::assert_numeric(df[[.var]])
   checkmate::assert_logical(df[[variables$baseline_flag]])
@@ -48,7 +50,7 @@ s_change_from_baseline <- function(df,
   if (is.logical(combined) && identical(length(combined), 0L)) {
     combined <- numeric(0)
   }
-  s_summary(combined, na.rm = na.rm, ...)
+  s_summary(combined, ...)
 }
 
 #' @describeIn summarize_change Formatted analysis function which is used as `afun` in `summarize_change()`.
@@ -57,26 +59,48 @@ s_change_from_baseline <- function(df,
 #' * `a_change_from_baseline()` returns the corresponding list with formatted [rtables::CellValue()].
 #'
 #' @keywords internal
-a_change_from_baseline <- make_afun(
-  s_change_from_baseline,
-  .formats = c(
-    n = "xx",
-    mean_sd = "xx.xx (xx.xx)",
-    mean_se = "xx.xx (xx.xx)",
-    median = "xx.xx",
-    range = "xx.xx - xx.xx",
-    mean_ci = "(xx.xx, xx.xx)",
-    median_ci = "(xx.xx, xx.xx)",
-    mean_pval = "xx.xx"
-  ),
-  .labels = c(
-    mean_sd = "Mean (SD)",
-    mean_se = "Mean (SE)",
-    median = "Median",
-    range = "Min - Max"
+a_change_from_baseline <- function(df,
+                                   # .ref_group = NULL,
+                                   # .in_ref_col = FALSE,
+                                   # variables, # comes from ...
+                                   # na.rm = TRUE, # comes from ...
+                                   ...,
+                                   .stats = NULL,
+                                   .formats = NULL,
+                                   .labels = NULL,
+                                   .indent_mods = NULL,
+                                   na_str = default_na_str()) {
+
+  # Adding automatically extra parameters to the statistic function (see ?rtables::additional_fun_params)
+  extra_afun_params <- names(get_additional_analysis_fun_parameters(add_alt_df = FALSE))
+  x_stats <- do.call(
+    s_change_from_baseline,
+    args = c(
+      df = list(df),
+      retrieve_extra_afun_params(extra_afun_params),
+      list(...)
+    )
   )
-)
 
+  # Fill in with formatting defaults if needed
+  .stats <- get_stats("analyze_vars_numeric", stats_in = .stats)
+  .formats <- get_formats_from_stats(.stats, .formats)
+  .indent_mods <- get_indents_from_stats(.stats, .indent_mods)
+
+  lbls <- get_labels_from_stats(.stats, .labels)
+
+  # Auto format handling
+  .formats <- apply_auto_formatting(.formats, x_stats, .df_row, .var)
+
+  in_rows(
+    .list = x_stats[.stats],
+    .formats = .formats,
+    .names = names(.labels),
+    .labels = .labels,
+    .indent_mods = .indent_mods,
+    .format_na_strs = na_str
+  )
+}
 #' @describeIn summarize_change Layout-creating function which can take statistics function arguments
 #'   and additional format arguments. This function is a wrapper for [rtables::analyze()].
 #'
@@ -119,31 +143,97 @@ a_change_from_baseline <- make_afun(
 summarize_change <- function(lyt,
                              vars,
                              variables,
+                             var_labels = vars,
                              na_str = default_na_str(),
+                             na_rm = TRUE,
                              nested = TRUE,
-                             ...,
+                             show_labels = "default",
                              table_names = vars,
+                             section_div = NA_character_,
+                             ...,
                              .stats = c("n", "mean_sd", "median", "range"),
-                             .formats = NULL,
-                             .labels = NULL,
+                             .formats = c(
+                               n = "xx",
+                               mean_sd = "xx.xx (xx.xx)",
+                               mean_se = "xx.xx (xx.xx)",
+                               median = "xx.xx",
+                               range = "xx.xx - xx.xx",
+                               mean_ci = "(xx.xx, xx.xx)",
+                               median_ci = "(xx.xx, xx.xx)",
+                               mean_pval = "xx.xx"
+                             ),
+                             .labels = c(
+                               mean_sd = "Mean (SD)",
+                               mean_se = "Mean (SE)",
+                               median = "Median",
+                               range = "Min - Max"
+                             ),
                              .indent_mods = NULL) {
-  extra_args <- list(variables = variables, ...)
+  checkmate::assert_string(vars)
 
-  afun <- make_afun(
-    a_change_from_baseline,
-    .stats = .stats,
-    .formats = .formats,
-    .labels = .labels,
-    .indent_mods = .indent_mods
+  # Extra args must contain .stats,.formats, .labels, .indent_mods - firsta analysis level
+  extra_args <- list(".stats" = .stats)
+  if (!is.null(.formats)) extra_args[[".formats"]] <- .formats
+  if (!is.null(.labels)) extra_args[[".labels"]] <- .labels
+  if (!is.null(.indent_mods)) extra_args[[".indent_mods"]] <- .indent_mods
+
+  # Adding additional arguments to the analysis function (depends on the specific call)
+  extra_args <- c(extra_args, "variables" = list(variables), "na.rm" = na_rm, ...)
+
+  # Adding all additional information from layout to analysis functions (see ?rtables::additional_fun_params)
+  formals(a_change_from_baseline) <- c(
+    formals(a_change_from_baseline),
+    get_additional_analysis_fun_parameters()
   )
 
+  # Main analysis call - Nothing with .* -> these should be dedicated to the analysis function
   analyze(
-    lyt,
-    vars,
-    afun = afun,
+    lyt = lyt,
+    vars = vars,
+    var_labels = var_labels,
+    afun = a_change_from_baseline,
     na_str = na_str,
     nested = nested,
     extra_args = extra_args,
-    table_names = table_names
+    inclNAs = TRUE,
+    show_labels = show_labels,
+    table_names = table_names,
+    section_div = section_div
+  )
+}
+
+retrieve_extra_afun_params <- function(extra_afun_params) {
+  out <- list()
+  for (extra_param in extra_afun_params) {
+    out <- c(out, list(get(extra_param, envir = parent.frame())))
+  }
+  setNames(out, extra_afun_params)
+}
+
+# @param ... additional arguments for the lower level functions. Important additional parameters, useful to
+#   modify behavior of analysis and summary functions are listed in [rtables::additional_fun_params].
+get_additional_analysis_fun_parameters <- function(add_alt_df = FALSE) {
+  out_list <- list(
+    .N_col = integer(),
+    .N_total = integer(),
+    .N_row = integer(),
+    .df_row = data.frame(),
+    .var = character(),
+    .ref_group = character(),
+    .ref_full = vector(mode = "numeric"),
+    .in_ref_col = logical(),
+    .spl_context = data.frame(),
+    .all_col_exprs = vector(mode = "expression"),
+    .all_col_counts = vector(mode = "integer")
   )
+
+  if (isTRUE(add_alt_df)) {
+    out_list <- c(
+      out_list,
+      .alt_df_row = data.frame(),
+      .alt_df = data.frame(),
+    )
+  }
+
+  out_list
 }
diff --git a/R/utils_default_stats_formats_labels.R b/R/utils_default_stats_formats_labels.R
index bd3871b4b8..c5be1c3ad7 100644
--- a/R/utils_default_stats_formats_labels.R
+++ b/R/utils_default_stats_formats_labels.R
@@ -496,9 +496,7 @@ tern_default_labels <- c(
   rate_ratio = "Adjusted Rate Ratio"
 )
 
-# To deprecate ---------
-
-#' @describeIn default_stats_formats_labels `r lifecycle::badge("deprecated")`
+#' @describeIn default_stats_formats_labels `r lifecycle::badge("stable")`
 #'   Quick function to retrieve default formats for summary statistics:
 #'   [analyze_vars()] and [analyze_vars_in_cols()] principally.
 #'
@@ -513,20 +511,20 @@ tern_default_labels <- c(
 #'
 #' @export
 summary_formats <- function(type = "numeric", include_pval = FALSE) {
-  lifecycle::deprecate_warn(
-    "0.9.6", "summary_formats()",
-    details = 'Use get_formats_from_stats(get_stats("analyze_vars_numeric", add_pval = include_pval)) instead'
-  )
   met_grp <- paste0(c("analyze_vars", type), collapse = "_")
   get_formats_from_stats(get_stats(met_grp, add_pval = include_pval))
 }
 
-#' @describeIn default_stats_formats_labels `r lifecycle::badge("deprecated")`
+#' @describeIn default_stats_formats_labels `r lifecycle::badge("stable")`
 #'   Quick function to retrieve default labels for summary statistics.
 #'   Returns labels of descriptive statistics which are understood by `rtables`. Similar to `summary_formats`.
 #'
 #' @param include_pval (`flag`)\cr same as the `add_pval` argument in [get_stats()].
 #'
+#' @details
+#' `summary_*` quick getter for labels or formats uses `get_stats` and `get_labels_from_stats` or `get_formats_from_stats`
+#' respectively to retrieve relevant information.
+#'
 #' @return
 #' * `summary_labels` returns a named `vector` of default statistic labels for the given data type.
 #'
@@ -536,10 +534,6 @@ summary_formats <- function(type = "numeric", include_pval = FALSE) {
 #'
 #' @export
 summary_labels <- function(type = "numeric", include_pval = FALSE) {
-  lifecycle::deprecate_warn(
-    "0.9.6", "summary_formats()",
-    details = 'Use get_labels_from_stats(get_stats("analyze_vars_numeric", add_pval = include_pval)) instead'
-  )
   met_grp <- paste0(c("analyze_vars", type), collapse = "_")
   get_labels_from_stats(get_stats(met_grp, add_pval = include_pval))
 }

From a5b6df9b5341a4393481d6433028884625c45676 Mon Sep 17 00:00:00 2001
From: Melkiades <davide.garolini@roche.com>
Date: Mon, 4 Nov 2024 16:06:51 +0100
Subject: [PATCH 02/17] fixes and vignette

---
 NEWS.md                             |  11 +--
 R/summarize_change.R                |  56 ++-----------
 R/utils_rtables.R                   |  65 +++++++++++++++
 man/default_stats_formats_labels.Rd |   7 +-
 man/summarize_change.Rd             |  39 ++++++---
 vignettes/tern_functions_guide.Rmd  | 123 ++++++++++++++++++++++++++++
 6 files changed, 233 insertions(+), 68 deletions(-)
 create mode 100644 vignettes/tern_functions_guide.Rmd

diff --git a/NEWS.md b/NEWS.md
index 16957a5146..2bd50bbe93 100644
--- a/NEWS.md
+++ b/NEWS.md
@@ -4,18 +4,19 @@
 * Added the `denom` parameter to `s_count_cumulative()`, `s_count_missed_doses()`, and `s_count_occurrences_by_grade()`.
 * Added `"N_row"` as an optional input to `denom` in `s_count_occurrences()`.
 * Refactored `a_count_occurrences_by_grade()`, `a_count_patients_with_event()`, and `a_count_patients_with_flags()` to no longer use `make_afun()`.
-
-### Enhancements
 * Added `rel_height_plot` parameter to `g_lineplot()` to control the line plot height relative to annotation table height.
 * Updated the `table_font_size` parameter of `g_lineplot()` to control the size of all text in the annotation table, including labels.
 * Added `as_list` parameter to `g_lineplot()` to allow users to return the line plot and annotation table elements as a list instead of stacked for more complex customization.
-
-### Miscellaneous
-* Reverted deprecation of quick getters for `summary_formats` and `summary_labels`. Added disclaimer about underlying use of `get_stats`.
+* Refactored `summarize_change()` to work without `make_afun()` and access all additional function parameter.
+* Added vignette "Unerstanding `tern` functions" for future reference.
 
 ### Bug Fixes
 * Fixed bug in `a_summary()` causing non-unique `row_name` values to occur when multiple statistics are selected for count variables.
 
+### Miscellaneous
+* Reverted deprecation of quick getters for `summary_formats()` and `summary_labels()`. Added disclaimer about underlying use of `get_stats`.
+* Corrected handling of extra arguments and `NA` for `summarize_change()`.
+
 # tern 0.9.6
 
 ### Enhancements
diff --git a/R/summarize_change.R b/R/summarize_change.R
index 60c6c96510..4ddf7c229b 100644
--- a/R/summarize_change.R
+++ b/R/summarize_change.R
@@ -34,7 +34,6 @@ s_change_from_baseline <- function(df, ...) {
   args_list <- list(...)
   .var <- args_list[[".var"]]
   variables <- args_list[["variables"]]
-  na.rm <- args_list[["na.rm"]]
 
   checkmate::assert_numeric(df[[variables$value]])
   checkmate::assert_numeric(df[[.var]])
@@ -60,17 +59,11 @@ s_change_from_baseline <- function(df, ...) {
 #'
 #' @keywords internal
 a_change_from_baseline <- function(df,
-                                   # .ref_group = NULL,
-                                   # .in_ref_col = FALSE,
-                                   # variables, # comes from ...
-                                   # na.rm = TRUE, # comes from ...
                                    ...,
                                    .stats = NULL,
                                    .formats = NULL,
                                    .labels = NULL,
-                                   .indent_mods = NULL,
-                                   na_str = default_na_str()) {
-
+                                   .indent_mods = NULL) {
   # Adding automatically extra parameters to the statistic function (see ?rtables::additional_fun_params)
   extra_afun_params <- names(get_additional_analysis_fun_parameters(add_alt_df = FALSE))
   x_stats <- do.call(
@@ -85,10 +78,9 @@ a_change_from_baseline <- function(df,
   # Fill in with formatting defaults if needed
   .stats <- get_stats("analyze_vars_numeric", stats_in = .stats)
   .formats <- get_formats_from_stats(.stats, .formats)
+  .labels <- get_labels_from_stats(.stats, .labels)
   .indent_mods <- get_indents_from_stats(.stats, .indent_mods)
 
-  lbls <- get_labels_from_stats(.stats, .labels)
-
   # Auto format handling
   .formats <- apply_auto_formatting(.formats, x_stats, .df_row, .var)
 
@@ -97,8 +89,8 @@ a_change_from_baseline <- function(df,
     .formats = .formats,
     .names = names(.labels),
     .labels = .labels,
-    .indent_mods = .indent_mods,
-    .format_na_strs = na_str
+    .indent_mods = .indent_mods
+    # .format_na_strs = na_str # set above level
   )
 }
 #' @describeIn summarize_change Layout-creating function which can take statistics function arguments
@@ -178,7 +170,7 @@ summarize_change <- function(lyt,
   if (!is.null(.indent_mods)) extra_args[[".indent_mods"]] <- .indent_mods
 
   # Adding additional arguments to the analysis function (depends on the specific call)
-  extra_args <- c(extra_args, "variables" = list(variables), "na.rm" = na_rm, ...)
+  extra_args <- c(extra_args, "variables" = list(variables), ...)
 
   # Adding all additional information from layout to analysis functions (see ?rtables::additional_fun_params)
   formals(a_change_from_baseline) <- c(
@@ -195,45 +187,9 @@ summarize_change <- function(lyt,
     na_str = na_str,
     nested = nested,
     extra_args = extra_args,
-    inclNAs = TRUE,
+    inclNAs = na_rm, # adds na.rm = TRUE to the analysis function
     show_labels = show_labels,
     table_names = table_names,
     section_div = section_div
   )
 }
-
-retrieve_extra_afun_params <- function(extra_afun_params) {
-  out <- list()
-  for (extra_param in extra_afun_params) {
-    out <- c(out, list(get(extra_param, envir = parent.frame())))
-  }
-  setNames(out, extra_afun_params)
-}
-
-# @param ... additional arguments for the lower level functions. Important additional parameters, useful to
-#   modify behavior of analysis and summary functions are listed in [rtables::additional_fun_params].
-get_additional_analysis_fun_parameters <- function(add_alt_df = FALSE) {
-  out_list <- list(
-    .N_col = integer(),
-    .N_total = integer(),
-    .N_row = integer(),
-    .df_row = data.frame(),
-    .var = character(),
-    .ref_group = character(),
-    .ref_full = vector(mode = "numeric"),
-    .in_ref_col = logical(),
-    .spl_context = data.frame(),
-    .all_col_exprs = vector(mode = "expression"),
-    .all_col_counts = vector(mode = "integer")
-  )
-
-  if (isTRUE(add_alt_df)) {
-    out_list <- c(
-      out_list,
-      .alt_df_row = data.frame(),
-      .alt_df = data.frame(),
-    )
-  }
-
-  out_list
-}
diff --git a/R/utils_rtables.R b/R/utils_rtables.R
index 61dd4b5f3e..01912a3e08 100644
--- a/R/utils_rtables.R
+++ b/R/utils_rtables.R
@@ -467,3 +467,68 @@ set_default_na_str <- function(na_str) {
   checkmate::assert_character(na_str, len = 1, null.ok = TRUE)
   options("tern_default_na_str" = na_str)
 }
+
+
+#' Utilities to handle extra arguments in analysis functions
+#'
+#' @description `r lifecycle::badge("stable")`
+#' Important additional parameters, useful to modify behavior of analysis and summary
+#' functions are listed in [rtables::additional_fun_params]. With these utility functions
+#' we can retrieve a curated list of these parameters from the environment, and pass them
+#' to the analysis functions with dedicated `...`; notice that the final `s_*` function
+#' will get them through argument matching.
+#'
+#' @param extra_afun_params (`list`)\cr list of additional parameters (`character`) to be
+#'   retrieved from the environment. Curated list is present in [rtables::additional_fun_params].
+#' @param add_alt_df (`logical`)\cr if `TRUE`, the function will also add `.alt_df` and `.alt_df_row`
+#'   parameters.
+#'
+#' @name util_handling_additional_fun_params
+NULL
+
+#' @describeIn util_handling_additional_fun_params Retrieve additional parameters from the environment.
+#'
+#' @return
+#' * `retrieve_extra_afun_params` returns a list of the values of the parameters in the environment.
+#'
+#' @keywords internal
+retrieve_extra_afun_params <- function(extra_afun_params) {
+  out <- list()
+  for (extra_param in extra_afun_params) {
+    out <- c(out, list(get(extra_param, envir = parent.frame())))
+  }
+  setNames(out, extra_afun_params)
+}
+
+#' @describeIn util_handling_additional_fun_params Curated list of additional parameters for
+#'   analysis functions. Please check [rtables::additional_fun_params] for precise descriptions.
+#'
+#' @return
+#' * `get_additional_analysis_fun_parameters` returns a list of additional parameters.
+#'
+#' @keywords internal
+get_additional_analysis_fun_parameters <- function(add_alt_df = FALSE) {
+  out_list <- list(
+    .N_col = integer(),
+    .N_total = integer(),
+    .N_row = integer(),
+    .df_row = data.frame(),
+    .var = character(),
+    .ref_group = character(),
+    .ref_full = vector(mode = "numeric"),
+    .in_ref_col = logical(),
+    .spl_context = data.frame(),
+    .all_col_exprs = vector(mode = "expression"),
+    .all_col_counts = vector(mode = "integer")
+  )
+
+  if (isTRUE(add_alt_df)) {
+    out_list <- c(
+      out_list,
+      .alt_df_row = data.frame(),
+      .alt_df = data.frame(),
+    )
+  }
+
+  out_list
+}
diff --git a/man/default_stats_formats_labels.Rd b/man/default_stats_formats_labels.Rd
index 228288a6f8..f0d99ea86f 100644
--- a/man/default_stats_formats_labels.Rd
+++ b/man/default_stats_formats_labels.Rd
@@ -120,6 +120,9 @@ seen in \code{\link[=analyze_vars]{analyze_vars()}}. See notes to understand why
 }
 \details{
 Current choices for \code{type} are \code{counts} and \code{numeric} for \code{\link[=analyze_vars]{analyze_vars()}} and affect \code{get_stats()}.
+
+\verb{summary_*} quick getter for labels or formats uses \code{get_stats} and \code{get_labels_from_stats} or \code{get_formats_from_stats}
+respectively to retrieve relevant information.
 }
 \section{Functions}{
 \itemize{
@@ -142,11 +145,11 @@ It defaults to 0L for all values.
 
 \item \code{tern_default_labels}: Named \code{character} vector of default labels for \code{tern}.
 
-\item \code{summary_formats()}: \ifelse{html}{\href{https://lifecycle.r-lib.org/articles/stages.html#deprecated}{\figure{lifecycle-deprecated.svg}{options: alt='[Deprecated]'}}}{\strong{[Deprecated]}}
+\item \code{summary_formats()}: \ifelse{html}{\href{https://lifecycle.r-lib.org/articles/stages.html#stable}{\figure{lifecycle-stable.svg}{options: alt='[Stable]'}}}{\strong{[Stable]}}
 Quick function to retrieve default formats for summary statistics:
 \code{\link[=analyze_vars]{analyze_vars()}} and \code{\link[=analyze_vars_in_cols]{analyze_vars_in_cols()}} principally.
 
-\item \code{summary_labels()}: \ifelse{html}{\href{https://lifecycle.r-lib.org/articles/stages.html#deprecated}{\figure{lifecycle-deprecated.svg}{options: alt='[Deprecated]'}}}{\strong{[Deprecated]}}
+\item \code{summary_labels()}: \ifelse{html}{\href{https://lifecycle.r-lib.org/articles/stages.html#stable}{\figure{lifecycle-stable.svg}{options: alt='[Stable]'}}}{\strong{[Stable]}}
 Quick function to retrieve default labels for summary statistics.
 Returns labels of descriptive statistics which are understood by \code{rtables}. Similar to \code{summary_formats}.
 
diff --git a/man/summarize_change.Rd b/man/summarize_change.Rd
index 40b05f423c..c74cdbdc30 100644
--- a/man/summarize_change.Rd
+++ b/man/summarize_change.Rd
@@ -10,19 +10,34 @@ summarize_change(
   lyt,
   vars,
   variables,
+  var_labels = vars,
   na_str = default_na_str(),
+  na_rm = TRUE,
   nested = TRUE,
-  ...,
+  show_labels = "default",
   table_names = vars,
+  section_div = NA_character_,
+  ...,
   .stats = c("n", "mean_sd", "median", "range"),
-  .formats = NULL,
-  .labels = NULL,
+  .formats = c(n = "xx", mean_sd = "xx.xx (xx.xx)", mean_se = "xx.xx (xx.xx)", median =
+    "xx.xx", range = "xx.xx - xx.xx", mean_ci = "(xx.xx, xx.xx)", median_ci =
+    "(xx.xx, xx.xx)", mean_pval = "xx.xx"),
+  .labels = c(mean_sd = "Mean (SD)", mean_se = "Mean (SE)", median = "Median", range =
+    "Min - Max"),
   .indent_mods = NULL
 )
 
-s_change_from_baseline(df, .var, variables, na.rm = TRUE, ...)
+s_change_from_baseline(df, ...)
 
-a_change_from_baseline(df, .var, variables, na.rm = TRUE, ...)
+a_change_from_baseline(
+  df,
+  ...,
+  .stats = NULL,
+  .formats = NULL,
+  .labels = NULL,
+  .indent_mods = NULL,
+  na_str = default_na_str()
+)
 }
 \arguments{
 \item{lyt}{(\code{PreDataTableLayouts})\cr layout that analyses will be added to.}
@@ -31,17 +46,24 @@ a_change_from_baseline(df, .var, variables, na.rm = TRUE, ...)
 
 \item{variables}{(named \code{list} of \code{string})\cr list of additional analysis variables.}
 
+\item{var_labels}{(\code{character})\cr variable labels.}
+
 \item{na_str}{(\code{string})\cr string used to replace all \code{NA} or empty values in the output.}
 
 \item{nested}{(\code{flag})\cr whether this layout instruction should be applied within the existing layout structure _if
 possible (\code{TRUE}, the default) or as a new top-level element (\code{FALSE}). Ignored if it would nest a split.
 underneath analyses, which is not allowed.}
 
-\item{...}{additional arguments for the lower level functions.}
+\item{show_labels}{(\code{string})\cr label visibility: one of "default", "visible" and "hidden".}
 
 \item{table_names}{(\code{character})\cr this can be customized in the case that the same \code{vars} are analyzed multiple
 times, to avoid warnings from \code{rtables}.}
 
+\item{section_div}{(\code{string})\cr string which should be repeated as a section divider after each group
+defined by this split instruction, or \code{NA_character_} (the default) for no section divider.}
+
+\item{...}{additional arguments for the lower level functions.}
+
 \item{.stats}{(\code{character})\cr statistics to select for the table.
 
 Options are: \verb{'n', 'sum', 'mean', 'sd', 'se', 'mean_sd', 'mean_se', 'mean_ci', 'mean_sei', 'mean_sdi', 'mean_pval', 'median', 'mad', 'median_ci', 'quantiles', 'iqr', 'range', 'min', 'max', 'median_range', 'cv', 'geom_mean', 'geom_mean_ci', 'geom_cv'}}
@@ -55,11 +77,6 @@ information on the \code{"auto"} setting.}
 unmodified default behavior. Can be negative.}
 
 \item{df}{(\code{data.frame})\cr data set containing all analysis variables.}
-
-\item{.var}{(\code{string})\cr single variable name that is passed by \code{rtables} when requested
-by a statistics function.}
-
-\item{na.rm}{(\code{flag})\cr whether \code{NA} values should be removed from \code{x} prior to analysis.}
 }
 \value{
 \itemize{
diff --git a/vignettes/tern_functions_guide.Rmd b/vignettes/tern_functions_guide.Rmd
new file mode 100644
index 0000000000..7921550dba
--- /dev/null
+++ b/vignettes/tern_functions_guide.Rmd
@@ -0,0 +1,123 @@
+---
+title: "Understanding `tern` functions"
+date: "2024-11-04"
+output:
+    rmarkdown::html_document:
+        theme: "spacelab"
+        highlight: "kate"
+        toc: true
+        toc_float: true
+vignette: >
+    %\VignetteIndexEntry{Understanding `tern` functions}
+    %\VignetteEngine{knitr::rmarkdown}
+    %\VignetteEncoding{UTF-8}
+editor_options:
+    markdown: 
+        wrap: 72
+---
+
+```{r, include = FALSE}
+knitr::opts_chunk$set(
+  collapse = TRUE,
+  comment = "#>"
+)
+```
+
+## Understanding `tern` functions
+
+Every function in the `tern` package is designed to have a certain structure that can cooperate well with every user's need, while maintaining a consistent and predictable behavior. This document will guide you through an example function in the package, explaining the purpose of many of its building blocks and how they can be used.
+
+As we recently worked on it we will consider `summarize_change()` as an example. This function is used to calculate the change from a baseline value for a given variable. A realistic example can be found in [LBT03](https://insightsengineering.github.io/tlg-catalog/stable/tables/lab-results/lbt03.html) from the TLG-catalog.
+
+`summarize_change()` is the main function that is available to the user. You can find lists of these functions in `?tern::analyze_functions`. All of these are build around `rtables::analyze()` function, which is the core analysis function in `rtables`. All these wrapper functions call specific analysis functions (always written as `a_*`) that are meant to handle the statistic functions (always written as `s_*`) and format the results with the `rtables::in_row()` function. We can summarize this structure as follows:
+
+`summarize_change()` (1)-> `a_change_from_baseline()` (2)-> [`s_change_from_baseline()` + `rtables::in_row()`]
+
+The main questions that may arise are:
+
+1. Handling of `NA`.
+2. Handling of formats.
+3. Additional statistics (WIP).
+
+Data set and library loading.
+```{r}
+library(dplyr)
+
+## Fabricate dataset
+dta_test <- data.frame(
+  USUBJID = rep(1:6, each = 3),
+  AVISIT = rep(paste0("V", 1:3), 6),
+  ARM = rep(LETTERS[1:3], rep(6, 3)),
+  AVAL = c(9:1, rep(NA, 9))
+) %>%
+  mutate(ABLFLL = AVISIT == "V1") %>%
+  group_by(USUBJID) %>%
+  mutate(
+    BLVAL = AVAL[ABLFLL],
+    CHG = AVAL - BLVAL
+  ) %>%
+  ungroup()
+```
+
+Classic use of `summarize_change()`.
+```{r}
+fix_layout <- basic_table() %>%
+  split_cols_by("ARM") %>%
+  split_rows_by("AVISIT")
+
+
+# na_rm = TRUE
+fix_layout %>%
+  summarize_change("CHG", variables = list(value = "AVAL", baseline_flag = "ABLFLL")) %>%
+  build_table(dta_test) %>%
+  print()
+
+# na_rm = FALSE
+fix_layout %>%
+  summarize_change("CHG", variables = list(value = "AVAL", baseline_flag = "ABLFLL"), na_rm = FALSE) %>%
+  build_table(dta_test) %>%
+  print()
+
+# changing the NA string (it is done on all levels)
+fix_layout %>%
+  summarize_change("CHG", variables = list(value = "AVAL", baseline_flag = "ABLFLL"), na_str = "my_na") %>%
+  build_table(dta_test) %>%
+  print()
+
+```
+
+`.formats`, `.labels`, and `.indent_mods` depend on the names of `.stats`. Here is how you can change the default formatting.
+
+```{r}
+# changing n count format and label and indentation
+fix_layout %>%
+  summarize_change("CHG", variables = list(value = "AVAL", baseline_flag = "ABLFLL"), 
+                   .stats = c("n", "mean"), # reducing the number of stats for visual appreciation
+                   .formats = c(n = "xx.xx"),
+                   .labels = c(n = "NnNn"),
+                   .indent_mods = c(n = 5), na_str = "nA") %>%
+  build_table(dta_test) %>%
+  print()
+```
+What if I want something special for the format?
+
+```{r}
+# changing n count format and label and indentation
+fix_layout %>%
+  summarize_change("CHG", variables = list(value = "AVAL", baseline_flag = "ABLFLL"), 
+                   .stats = c("n", "mean"), # reducing the number of stats for visual appreciation
+                   .formats = c(n = function(x, ...) as.character(x * 100))) %>% # Note you need ...!!!
+  build_table(dta_test) %>%
+  print()
+```
+
+Adding a custom statistic (WIP)
+
+
+## For Developers
+
+In all of these layers there are specific parameters that need to be available, and, while `rtables` has multiple way to handle formatting and `NA` values, we had to decide how to correctly handle these and additional extra arguments. We follow the following scheme:
+
+Level 1: `summarize_change()`: all parameters without a starting dot `.*` are used or added to `extra_args`. Specifically, here we solve `NA` values by using `inclNAs` option in `rtables::analyze()`. This will add to `...` `na.rm = inclNAs`. Also `na_str` is here set. We may want to be statistic dependend in the future, but we still need to think how to accomplish that. We add the `rtables::additional_fun_params` to the analysis function so to make them available as `...` in the next level.
+
+Level 2: `a_change_from_baseline()`: all parameters starting with a dot `.` are used. Mainly `.stats`, `.formats`, `.labels`, and `.indent_mods` are used. We also add `extra_afun_params` to the `...` list for the statistical function. Notice the handling for additional parameters in the `do.call()` function.

From 241e9a561422396c0240e42cffddb4627995eec7 Mon Sep 17 00:00:00 2001
From: Melkiades <davide.garolini@roche.com>
Date: Mon, 4 Nov 2024 16:12:14 +0100
Subject: [PATCH 03/17] trial

---
 R/summarize_change.R | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/R/summarize_change.R b/R/summarize_change.R
index 4ddf7c229b..dbcef02b29 100644
--- a/R/summarize_change.R
+++ b/R/summarize_change.R
@@ -107,7 +107,7 @@ a_change_from_baseline <- function(df,
 #' @examples
 #' library(dplyr)
 #'
-#' ## Fabricate dataset
+#' # Fabricate dataset
 #' dta_test <- data.frame(
 #'   USUBJID = rep(1:6, each = 3),
 #'   AVISIT = rep(paste0("V", 1:3), 6),

From 61f61c932916dae3b2e364231b651cca9d534fd5 Mon Sep 17 00:00:00 2001
From: shajoezhu <sha.joe.zhu@gmail.com>
Date: Tue, 5 Nov 2024 10:55:58 +0800
Subject: [PATCH 04/17] Empty-Commit


From b56920db27adeb1d5d6554773903f837574553dc Mon Sep 17 00:00:00 2001
From: Melkiades <davide.garolini@roche.com>
Date: Tue, 5 Nov 2024 09:20:44 +0100
Subject: [PATCH 05/17] fix vignette

---
 vignettes/tern_functions_guide.Rmd | 1 +
 1 file changed, 1 insertion(+)

diff --git a/vignettes/tern_functions_guide.Rmd b/vignettes/tern_functions_guide.Rmd
index 7921550dba..7adbabbf33 100644
--- a/vignettes/tern_functions_guide.Rmd
+++ b/vignettes/tern_functions_guide.Rmd
@@ -42,6 +42,7 @@ The main questions that may arise are:
 Data set and library loading.
 ```{r}
 library(dplyr)
+library(tern)
 
 ## Fabricate dataset
 dta_test <- data.frame(

From 8386dd9a6618b464f511454c100d7e727739b534 Mon Sep 17 00:00:00 2001
From: shajoezhu <sha.joe.zhu@gmail.com>
Date: Tue, 5 Nov 2024 17:10:56 +0800
Subject: [PATCH 06/17] Empty-Commit


From 3090db7110d95a8cd02c6f1c592fa26be6a53e05 Mon Sep 17 00:00:00 2001
From: github-actions <41898282+github-actions[bot]@users.noreply.github.com>
Date: Tue, 5 Nov 2024 09:13:18 +0000
Subject: [PATCH 07/17] [skip style] [skip vbump] Restyle files

---
 vignettes/tern_functions_guide.Rmd | 21 ++++++++++++---------
 1 file changed, 12 insertions(+), 9 deletions(-)

diff --git a/vignettes/tern_functions_guide.Rmd b/vignettes/tern_functions_guide.Rmd
index 7adbabbf33..f5a6f33c02 100644
--- a/vignettes/tern_functions_guide.Rmd
+++ b/vignettes/tern_functions_guide.Rmd
@@ -84,7 +84,6 @@ fix_layout %>%
   summarize_change("CHG", variables = list(value = "AVAL", baseline_flag = "ABLFLL"), na_str = "my_na") %>%
   build_table(dta_test) %>%
   print()
-
 ```
 
 `.formats`, `.labels`, and `.indent_mods` depend on the names of `.stats`. Here is how you can change the default formatting.
@@ -92,11 +91,13 @@ fix_layout %>%
 ```{r}
 # changing n count format and label and indentation
 fix_layout %>%
-  summarize_change("CHG", variables = list(value = "AVAL", baseline_flag = "ABLFLL"), 
-                   .stats = c("n", "mean"), # reducing the number of stats for visual appreciation
-                   .formats = c(n = "xx.xx"),
-                   .labels = c(n = "NnNn"),
-                   .indent_mods = c(n = 5), na_str = "nA") %>%
+  summarize_change("CHG",
+    variables = list(value = "AVAL", baseline_flag = "ABLFLL"),
+    .stats = c("n", "mean"), # reducing the number of stats for visual appreciation
+    .formats = c(n = "xx.xx"),
+    .labels = c(n = "NnNn"),
+    .indent_mods = c(n = 5), na_str = "nA"
+  ) %>%
   build_table(dta_test) %>%
   print()
 ```
@@ -105,9 +106,11 @@ What if I want something special for the format?
 ```{r}
 # changing n count format and label and indentation
 fix_layout %>%
-  summarize_change("CHG", variables = list(value = "AVAL", baseline_flag = "ABLFLL"), 
-                   .stats = c("n", "mean"), # reducing the number of stats for visual appreciation
-                   .formats = c(n = function(x, ...) as.character(x * 100))) %>% # Note you need ...!!!
+  summarize_change("CHG",
+    variables = list(value = "AVAL", baseline_flag = "ABLFLL"),
+    .stats = c("n", "mean"), # reducing the number of stats for visual appreciation
+    .formats = c(n = function(x, ...) as.character(x * 100))
+  ) %>% # Note you need ...!!!
   build_table(dta_test) %>%
   print()
 ```

From d97263170081a59693a3f72a97a9f604ddf287ee Mon Sep 17 00:00:00 2001
From: Melkiades <davide.garolini@roche.com>
Date: Tue, 5 Nov 2024 11:30:20 +0100
Subject: [PATCH 08/17] final fixes

---
 R/summarize_change.R                       | 18 +++++---
 R/utils_default_stats_formats_labels.R     | 50 +++++++++++++++++++++
 man/summarize_change.Rd                    |  5 +--
 man/util_handling_additional_fun_params.Rd | 45 +++++++++++++++++++
 tests/testthat/test-summarize_change.R     | 51 ++++++++++++++++++++++
 vignettes/tern_functions_guide.Rmd         | 11 ++++-
 6 files changed, 170 insertions(+), 10 deletions(-)
 create mode 100644 man/util_handling_additional_fun_params.Rd

diff --git a/R/summarize_change.R b/R/summarize_change.R
index dbcef02b29..54c462b2cf 100644
--- a/R/summarize_change.R
+++ b/R/summarize_change.R
@@ -64,11 +64,18 @@ a_change_from_baseline <- function(df,
                                    .formats = NULL,
                                    .labels = NULL,
                                    .indent_mods = NULL) {
+
+  # Check if there are user-defined functions
+  default_and_custom_stats_list <- .split_default_from_custom_stats(.stats)
+  .stats <- default_and_custom_stats_list$default_stats
+  custom_stat_functions <- default_and_custom_stats_list$custom_stats
+
   # Adding automatically extra parameters to the statistic function (see ?rtables::additional_fun_params)
   extra_afun_params <- names(get_additional_analysis_fun_parameters(add_alt_df = FALSE))
-  x_stats <- do.call(
-    s_change_from_baseline,
-    args = c(
+  x_stats <- .apply_stat_functions(
+    default_stat_fnc = s_change_from_baseline,
+    custom_stat_fnc_list = custom_stat_functions,
+    args_list = c(
       df = list(df),
       retrieve_extra_afun_params(extra_afun_params),
       list(...)
@@ -93,6 +100,7 @@ a_change_from_baseline <- function(df,
     # .format_na_strs = na_str # set above level
   )
 }
+
 #' @describeIn summarize_change Layout-creating function which can take statistics function arguments
 #'   and additional format arguments. This function is a wrapper for [rtables::analyze()].
 #'
@@ -161,9 +169,7 @@ summarize_change <- function(lyt,
                                range = "Min - Max"
                              ),
                              .indent_mods = NULL) {
-  checkmate::assert_string(vars)
-
-  # Extra args must contain .stats,.formats, .labels, .indent_mods - firsta analysis level
+  # Extra args must contain .stats, .formats, .labels, .indent_mods - sent to the analysis level
   extra_args <- list(".stats" = .stats)
   if (!is.null(.formats)) extra_args[[".formats"]] <- .formats
   if (!is.null(.labels)) extra_args[[".labels"]] <- .labels
diff --git a/R/utils_default_stats_formats_labels.R b/R/utils_default_stats_formats_labels.R
index c5be1c3ad7..0546cc3e02 100644
--- a/R/utils_default_stats_formats_labels.R
+++ b/R/utils_default_stats_formats_labels.R
@@ -121,6 +121,56 @@ get_stats <- function(method_groups = "analyze_vars_numeric", stats_in = NULL, a
   out
 }
 
+# Utility function used to separate custom stats (user-defined functions) from defaults
+.split_default_from_custom_stats <- function(stats_in) {
+  out <- list(default_stats = NULL, custom_stats = NULL)
+  if (is.list(stats_in)) {
+    is_custom_fnc <- sapply(stats_in, is.function)
+    out[["custom_stats"]] <- stats_in[is_custom_fnc]
+    out[["default_stats"]] <- unlist(stats_in[!is_custom_fnc])
+  } else {
+    out[["default_stats"]] <- stats_in
+  }
+
+  out
+}
+
+# Utility function to apply statistical functions
+.apply_stat_functions <- function(default_stat_fnc, custom_stat_fnc_list, args_list) {
+  # Default checks
+  checkmate::assert_function(default_stat_fnc)
+  checkmate::assert_list(custom_stat_fnc_list, types = "function", null.ok = TRUE)
+  checkmate::assert_list(args_list)
+
+  # Checking custom stats have same formals
+  if (!is.null(custom_stat_fnc_list)) {
+    fundamental_call_to_data <- names(formals(default_stat_fnc))[[1]]
+    for (fnc in custom_stat_fnc_list) {
+      if (!identical(names(formals(fnc))[[1]], fundamental_call_to_data)) {
+        stop(
+          "The first parameter of a custom statistical function needs to be the same (it can be `df` or `x`) ",
+          "as the default statistical function. In this case your custom function has ", names(formals(fnc))[[1]],
+          " as first parameter, while the default function has ", fundamental_call_to_data, "."
+        )
+      }
+      if (!any(names(formals(fnc)) == "...")) {
+        stop(
+          "The custom statistical function needs to have `...` as a parameter to accept additional arguments. ",
+          "In this case your custom function does not have `...`."
+        )
+      }
+    }
+  }
+
+  # Merging
+  stat_fnc_list <- c(default_stat_fnc, custom_stat_fnc_list)
+
+  # Applying
+  out <- unlist(lapply(stat_fnc_list, function(fnc) do.call(fnc, args = args_list)), recursive = FALSE)
+
+  out
+}
+
 #' @describeIn default_stats_formats_labels Get formats corresponding to a list of statistics.
 #'   To check available defaults see `tern::tern_default_formats` list.
 #'
diff --git a/man/summarize_change.Rd b/man/summarize_change.Rd
index c74cdbdc30..b37cdd761c 100644
--- a/man/summarize_change.Rd
+++ b/man/summarize_change.Rd
@@ -35,8 +35,7 @@ a_change_from_baseline(
   .stats = NULL,
   .formats = NULL,
   .labels = NULL,
-  .indent_mods = NULL,
-  na_str = default_na_str()
+  .indent_mods = NULL
 )
 }
 \arguments{
@@ -125,7 +124,7 @@ an error will be thrown.
 \examples{
 library(dplyr)
 
-## Fabricate dataset
+# Fabricate dataset
 dta_test <- data.frame(
   USUBJID = rep(1:6, each = 3),
   AVISIT = rep(paste0("V", 1:3), 6),
diff --git a/man/util_handling_additional_fun_params.Rd b/man/util_handling_additional_fun_params.Rd
new file mode 100644
index 0000000000..2a2f6adccb
--- /dev/null
+++ b/man/util_handling_additional_fun_params.Rd
@@ -0,0 +1,45 @@
+% Generated by roxygen2: do not edit by hand
+% Please edit documentation in R/utils_rtables.R
+\name{util_handling_additional_fun_params}
+\alias{util_handling_additional_fun_params}
+\alias{retrieve_extra_afun_params}
+\alias{get_additional_analysis_fun_parameters}
+\title{Utilities to handle extra arguments in analysis functions}
+\usage{
+retrieve_extra_afun_params(extra_afun_params)
+
+get_additional_analysis_fun_parameters(add_alt_df = FALSE)
+}
+\arguments{
+\item{extra_afun_params}{(\code{list})\cr list of additional parameters (\code{character}) to be
+retrieved from the environment. Curated list is present in \link[rtables:additional_fun_params]{rtables::additional_fun_params}.}
+
+\item{add_alt_df}{(\code{logical})\cr if \code{TRUE}, the function will also add \code{.alt_df} and \code{.alt_df_row}
+parameters.}
+}
+\value{
+\itemize{
+\item \code{retrieve_extra_afun_params} returns a list of the values of the parameters in the environment.
+}
+
+\itemize{
+\item \code{get_additional_analysis_fun_parameters} returns a list of additional parameters.
+}
+}
+\description{
+\ifelse{html}{\href{https://lifecycle.r-lib.org/articles/stages.html#stable}{\figure{lifecycle-stable.svg}{options: alt='[Stable]'}}}{\strong{[Stable]}}
+Important additional parameters, useful to modify behavior of analysis and summary
+functions are listed in \link[rtables:additional_fun_params]{rtables::additional_fun_params}. With these utility functions
+we can retrieve a curated list of these parameters from the environment, and pass them
+to the analysis functions with dedicated \code{...}; notice that the final \verb{s_*} function
+will get them through argument matching.
+}
+\section{Functions}{
+\itemize{
+\item \code{retrieve_extra_afun_params()}: Retrieve additional parameters from the environment.
+
+\item \code{get_additional_analysis_fun_parameters()}: Curated list of additional parameters for
+analysis functions. Please check \link[rtables:additional_fun_params]{rtables::additional_fun_params} for precise descriptions.
+
+}}
+\keyword{internal}
diff --git a/tests/testthat/test-summarize_change.R b/tests/testthat/test-summarize_change.R
index 4c8d13a92e..ae5db43dd9 100644
--- a/tests/testthat/test-summarize_change.R
+++ b/tests/testthat/test-summarize_change.R
@@ -77,3 +77,54 @@ testthat::test_that("summarize_change works as expected", {
   res <- testthat::expect_silent(result)
   testthat::expect_snapshot(res)
 })
+
+
+testthat::test_that("summarize_change works with custom statistical functions", {
+  dta_test <- data.frame(
+    USUBJID = rep(1:6, each = 3),
+    AVISIT = rep(paste0("V", 1:3), 6),
+    AVAL = c(9:1, rep(NA, 9))
+  ) %>%
+    dplyr::mutate(
+      ABLFLL = AVISIT == "V1"
+    ) %>%
+    dplyr::group_by(USUBJID) %>%
+    dplyr::mutate(
+      BLVAL = AVAL[ABLFLL],
+      CHG = AVAL - BLVAL
+    ) %>%
+    dplyr::ungroup()
+
+  testthat::expect_error(
+    basic_table() %>%
+      split_rows_by("AVISIT") %>%
+      summarize_change(
+        "CHG",
+        variables = list(value = "AVAL", baseline_flag = "ABLFLL"),
+        .stats = c("n", "my_stat" = function(x) mean(x))
+      ) %>%
+      build_table(dta_test),
+    "custom function has x as first parameter, while the default function has df"
+  )
+  testthat::expect_error(
+    basic_table() %>%
+      split_rows_by("AVISIT") %>%
+      summarize_change(
+        "CHG",
+        variables = list(value = "AVAL", baseline_flag = "ABLFLL"),
+        .stats = c("n", "my_stat" = function(df) mean(df$AVAL))
+      ) %>%
+      build_table(dta_test),
+    "The custom statistical function needs to have "
+  )
+
+  result <- basic_table() %>%
+    split_rows_by("AVISIT") %>%
+    summarize_change(
+      "CHG",
+      variables = list(value = "AVAL", baseline_flag = "ABLFLL"),
+      .stats = c("n", "my_stat" = function(df, ...) mean(df$AVISIT, na.rm = TRUE))
+    ) %>%
+    build_table(dta_test)
+
+})
diff --git a/vignettes/tern_functions_guide.Rmd b/vignettes/tern_functions_guide.Rmd
index 7adbabbf33..72896745f0 100644
--- a/vignettes/tern_functions_guide.Rmd
+++ b/vignettes/tern_functions_guide.Rmd
@@ -112,7 +112,16 @@ fix_layout %>%
   print()
 ```
 
-Adding a custom statistic (WIP)
+Adding a custom statistic:
+```{r}
+# changing n count format and label and indentation
+fix_layout %>%
+  summarize_change("CHG", variables = list(value = "AVAL", baseline_flag = "ABLFLL"), 
+                   .stats = c("n", "mean", "arg" = function(x, ...) mean(x)),
+                   .formats = c(n = function(x, ...) as.character(x * 100))) %>% # Note you need ...!!!
+  build_table(dta_test) %>%
+  print()
+```
 
 
 ## For Developers

From 1241ac4ce545a1eb424247d3ad8f6880226cd86f Mon Sep 17 00:00:00 2001
From: Melkiades <davide.garolini@roche.com>
Date: Tue, 5 Nov 2024 11:36:35 +0100
Subject: [PATCH 09/17] style

---
 R/summarize_change.R                   | 1 -
 tests/testthat/test-summarize_change.R | 1 -
 vignettes/tern_functions_guide.Rmd     | 8 +++++---
 3 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/R/summarize_change.R b/R/summarize_change.R
index 54c462b2cf..2f9fc8240b 100644
--- a/R/summarize_change.R
+++ b/R/summarize_change.R
@@ -64,7 +64,6 @@ a_change_from_baseline <- function(df,
                                    .formats = NULL,
                                    .labels = NULL,
                                    .indent_mods = NULL) {
-
   # Check if there are user-defined functions
   default_and_custom_stats_list <- .split_default_from_custom_stats(.stats)
   .stats <- default_and_custom_stats_list$default_stats
diff --git a/tests/testthat/test-summarize_change.R b/tests/testthat/test-summarize_change.R
index ae5db43dd9..2b3b457a81 100644
--- a/tests/testthat/test-summarize_change.R
+++ b/tests/testthat/test-summarize_change.R
@@ -126,5 +126,4 @@ testthat::test_that("summarize_change works with custom statistical functions",
       .stats = c("n", "my_stat" = function(df, ...) mean(df$AVISIT, na.rm = TRUE))
     ) %>%
     build_table(dta_test)
-
 })
diff --git a/vignettes/tern_functions_guide.Rmd b/vignettes/tern_functions_guide.Rmd
index c1fddf5c28..532530aa51 100644
--- a/vignettes/tern_functions_guide.Rmd
+++ b/vignettes/tern_functions_guide.Rmd
@@ -119,9 +119,11 @@ Adding a custom statistic:
 ```{r}
 # changing n count format and label and indentation
 fix_layout %>%
-  summarize_change("CHG", variables = list(value = "AVAL", baseline_flag = "ABLFLL"), 
-                   .stats = c("n", "mean", "arg" = function(x, ...) mean(x)),
-                   .formats = c(n = function(x, ...) as.character(x * 100))) %>% # Note you need ...!!!
+  summarize_change("CHG",
+    variables = list(value = "AVAL", baseline_flag = "ABLFLL"),
+    .stats = c("n", "mean", "arg" = function(x, ...) mean(x)),
+    .formats = c(n = function(x, ...) as.character(x * 100))
+  ) %>% # Note you need ...!!!
   build_table(dta_test) %>%
   print()
 ```

From 513686c6a14733b0c19ca542d48835bc5ff71f89 Mon Sep 17 00:00:00 2001
From: Melkiades <davide.garolini@roche.com>
Date: Tue, 5 Nov 2024 11:56:22 +0100
Subject: [PATCH 10/17] lintr

---
 R/summarize_change.R                   | 1 -
 R/utils_default_stats_formats_labels.R | 6 +++---
 R/utils_rtables.R                      | 2 +-
 vignettes/tern_functions_guide.Rmd     | 4 ++--
 4 files changed, 6 insertions(+), 7 deletions(-)

diff --git a/R/summarize_change.R b/R/summarize_change.R
index 2f9fc8240b..6cca7d36e9 100644
--- a/R/summarize_change.R
+++ b/R/summarize_change.R
@@ -96,7 +96,6 @@ a_change_from_baseline <- function(df,
     .names = names(.labels),
     .labels = .labels,
     .indent_mods = .indent_mods
-    # .format_na_strs = na_str # set above level
   )
 }
 
diff --git a/R/utils_default_stats_formats_labels.R b/R/utils_default_stats_formats_labels.R
index 0546cc3e02..606571c2e1 100644
--- a/R/utils_default_stats_formats_labels.R
+++ b/R/utils_default_stats_formats_labels.R
@@ -122,7 +122,7 @@ get_stats <- function(method_groups = "analyze_vars_numeric", stats_in = NULL, a
 }
 
 # Utility function used to separate custom stats (user-defined functions) from defaults
-.split_default_from_custom_stats <- function(stats_in) {
+.split_std_from_custom_stats <- function(stats_in) {
   out <- list(default_stats = NULL, custom_stats = NULL)
   if (is.list(stats_in)) {
     is_custom_fnc <- sapply(stats_in, is.function)
@@ -572,8 +572,8 @@ summary_formats <- function(type = "numeric", include_pval = FALSE) {
 #' @param include_pval (`flag`)\cr same as the `add_pval` argument in [get_stats()].
 #'
 #' @details
-#' `summary_*` quick getter for labels or formats uses `get_stats` and `get_labels_from_stats` or `get_formats_from_stats`
-#' respectively to retrieve relevant information.
+#' `summary_*` quick getter for labels or formats uses `get_stats` and `get_labels_from_stats` or
+#' `get_formats_from_stats` respectively to retrieve relevant information.
 #'
 #' @return
 #' * `summary_labels` returns a named `vector` of default statistic labels for the given data type.
diff --git a/R/utils_rtables.R b/R/utils_rtables.R
index 01912a3e08..0853ed9bb8 100644
--- a/R/utils_rtables.R
+++ b/R/utils_rtables.R
@@ -507,7 +507,7 @@ retrieve_extra_afun_params <- function(extra_afun_params) {
 #' * `get_additional_analysis_fun_parameters` returns a list of additional parameters.
 #'
 #' @keywords internal
-get_additional_analysis_fun_parameters <- function(add_alt_df = FALSE) {
+get_additional_afun_params <- function(add_alt_df = FALSE) {
   out_list <- list(
     .N_col = integer(),
     .N_total = integer(),
diff --git a/vignettes/tern_functions_guide.Rmd b/vignettes/tern_functions_guide.Rmd
index 532530aa51..200d1764fc 100644
--- a/vignettes/tern_functions_guide.Rmd
+++ b/vignettes/tern_functions_guide.Rmd
@@ -67,13 +67,13 @@ fix_layout <- basic_table() %>%
   split_rows_by("AVISIT")
 
 
-# na_rm = TRUE
+# NA: na_rm = TRUE
 fix_layout %>%
   summarize_change("CHG", variables = list(value = "AVAL", baseline_flag = "ABLFLL")) %>%
   build_table(dta_test) %>%
   print()
 
-# na_rm = FALSE
+# NA: na_rm = FALSE
 fix_layout %>%
   summarize_change("CHG", variables = list(value = "AVAL", baseline_flag = "ABLFLL"), na_rm = FALSE) %>%
   build_table(dta_test) %>%

From 9f3afad96ffc2046b28641f319fd395109f19bfd Mon Sep 17 00:00:00 2001
From: Melkiades <davide.garolini@roche.com>
Date: Tue, 5 Nov 2024 16:03:01 +0100
Subject: [PATCH 11/17] fix

---
 R/summarize_change.R                      | 10 +++++++---
 R/utils_default_stats_formats_labels.R    |  3 ++-
 tests/testthat/_snaps/summarize_change.md | 17 +++++++++++++++++
 tests/testthat/test-summarize_change.R    | 10 +++++++++-
 vignettes/tern_functions_guide.Rmd        | 20 ++++++++++++--------
 5 files changed, 47 insertions(+), 13 deletions(-)

diff --git a/R/summarize_change.R b/R/summarize_change.R
index 6cca7d36e9..e6fd1d5fd7 100644
--- a/R/summarize_change.R
+++ b/R/summarize_change.R
@@ -70,7 +70,7 @@ a_change_from_baseline <- function(df,
   custom_stat_functions <- default_and_custom_stats_list$custom_stats
 
   # Adding automatically extra parameters to the statistic function (see ?rtables::additional_fun_params)
-  extra_afun_params <- names(get_additional_analysis_fun_parameters(add_alt_df = FALSE))
+  extra_afun_params <- names(list(...)$.additional_fun_parameters)
   x_stats <- .apply_stat_functions(
     default_stat_fnc = s_change_from_baseline,
     custom_stat_fnc_list = custom_stat_functions,
@@ -82,7 +82,10 @@ a_change_from_baseline <- function(df,
   )
 
   # Fill in with formatting defaults if needed
-  .stats <- get_stats("analyze_vars_numeric", stats_in = .stats)
+  .stats <- c(
+    get_stats("analyze_vars_numeric", stats_in = .stats),
+    names(custom_stat_functions) # Additional stats from custom functions
+  )
   .formats <- get_formats_from_stats(.stats, .formats)
   .labels <- get_labels_from_stats(.stats, .labels)
   .indent_mods <- get_indents_from_stats(.stats, .indent_mods)
@@ -177,9 +180,10 @@ summarize_change <- function(lyt,
   extra_args <- c(extra_args, "variables" = list(variables), ...)
 
   # Adding all additional information from layout to analysis functions (see ?rtables::additional_fun_params)
+  extra_args[[".additional_fun_parameters"]] <- get_additional_analysis_fun_parameters(add_alt_df = FALSE)
   formals(a_change_from_baseline) <- c(
     formals(a_change_from_baseline),
-    get_additional_analysis_fun_parameters()
+    extra_args[[".additional_fun_parameters"]]
   )
 
   # Main analysis call - Nothing with .* -> these should be dedicated to the analysis function
diff --git a/R/utils_default_stats_formats_labels.R b/R/utils_default_stats_formats_labels.R
index 606571c2e1..2b47ca88c6 100644
--- a/R/utils_default_stats_formats_labels.R
+++ b/R/utils_default_stats_formats_labels.R
@@ -126,6 +126,7 @@ get_stats <- function(method_groups = "analyze_vars_numeric", stats_in = NULL, a
   out <- list(default_stats = NULL, custom_stats = NULL)
   if (is.list(stats_in)) {
     is_custom_fnc <- sapply(stats_in, is.function)
+    checkmate::assert_list(stats_in[is_custom_fnc], types = "function", names = "named")
     out[["custom_stats"]] <- stats_in[is_custom_fnc]
     out[["default_stats"]] <- unlist(stats_in[!is_custom_fnc])
   } else {
@@ -139,7 +140,7 @@ get_stats <- function(method_groups = "analyze_vars_numeric", stats_in = NULL, a
 .apply_stat_functions <- function(default_stat_fnc, custom_stat_fnc_list, args_list) {
   # Default checks
   checkmate::assert_function(default_stat_fnc)
-  checkmate::assert_list(custom_stat_fnc_list, types = "function", null.ok = TRUE)
+  checkmate::assert_list(custom_stat_fnc_list, types = "function", null.ok = TRUE, names = "named")
   checkmate::assert_list(args_list)
 
   # Checking custom stats have same formals
diff --git a/tests/testthat/_snaps/summarize_change.md b/tests/testthat/_snaps/summarize_change.md
index b0e8774d89..9752712464 100644
--- a/tests/testthat/_snaps/summarize_change.md
+++ b/tests/testthat/_snaps/summarize_change.md
@@ -499,3 +499,20 @@
         Median          -2.00    
         Min - Max   -2.00 - -2.00
 
+# summarize_change works with custom statistical functions
+
+    Code
+      res
+    Output
+                  all obs
+      ———————————————————
+      V1                 
+        n            3   
+        my_stat    1.00  
+      V2                 
+        n            3   
+        my_stat    0.83  
+      V3                 
+        n            3   
+        my_stat    0.67  
+
diff --git a/tests/testthat/test-summarize_change.R b/tests/testthat/test-summarize_change.R
index 2b3b457a81..adf60ffc68 100644
--- a/tests/testthat/test-summarize_change.R
+++ b/tests/testthat/test-summarize_change.R
@@ -123,7 +123,15 @@ testthat::test_that("summarize_change works with custom statistical functions",
     summarize_change(
       "CHG",
       variables = list(value = "AVAL", baseline_flag = "ABLFLL"),
-      .stats = c("n", "my_stat" = function(df, ...) mean(df$AVISIT, na.rm = TRUE))
+      .stats = c("n", "my_stat" = function(df, ...) {
+        a <- mean(df$AVAL, na.rm = TRUE)
+        b <- list(...)$.N_row
+        a / b
+      }),
+      .formats = c("my_stat" = function(x, ...) sprintf("%.2f", x))
     ) %>%
     build_table(dta_test)
+
+  res <- testthat::expect_silent(result)
+  testthat::expect_snapshot(res)
 })
diff --git a/vignettes/tern_functions_guide.Rmd b/vignettes/tern_functions_guide.Rmd
index 200d1764fc..929c106ff2 100644
--- a/vignettes/tern_functions_guide.Rmd
+++ b/vignettes/tern_functions_guide.Rmd
@@ -115,17 +115,21 @@ fix_layout %>%
   print()
 ```
 
-Adding a custom statistic:
+Adding a custom statistic (and custom format):
 ```{r}
 # changing n count format and label and indentation
 fix_layout %>%
-  summarize_change("CHG",
-    variables = list(value = "AVAL", baseline_flag = "ABLFLL"),
-    .stats = c("n", "mean", "arg" = function(x, ...) mean(x)),
-    .formats = c(n = function(x, ...) as.character(x * 100))
-  ) %>% # Note you need ...!!!
-  build_table(dta_test) %>%
-  print()
+    summarize_change(
+      "CHG",
+      variables = list(value = "AVAL", baseline_flag = "ABLFLL"),
+      .stats = c("n", "my_stat" = function(df, ...) {
+        a <- mean(df$AVAL, na.rm = TRUE)
+        b <- list(...)$.N_row # It has access at all `?rtables::additional_fun_params`
+        a / b
+      }),
+      .formats = c("my_stat" = function(x, ...) sprintf("%.2f", x))
+    ) %>%
+    build_table(dta_test)
 ```
 
 

From 383ccc2f2d45ffa10085435af1103c90d6f3d151 Mon Sep 17 00:00:00 2001
From: github-actions <41898282+github-actions[bot]@users.noreply.github.com>
Date: Tue, 5 Nov 2024 15:05:38 +0000
Subject: [PATCH 12/17] [skip style] [skip vbump] Restyle files

---
 vignettes/tern_functions_guide.Rmd | 22 +++++++++++-----------
 1 file changed, 11 insertions(+), 11 deletions(-)

diff --git a/vignettes/tern_functions_guide.Rmd b/vignettes/tern_functions_guide.Rmd
index 929c106ff2..9ca00049cf 100644
--- a/vignettes/tern_functions_guide.Rmd
+++ b/vignettes/tern_functions_guide.Rmd
@@ -119,17 +119,17 @@ Adding a custom statistic (and custom format):
 ```{r}
 # changing n count format and label and indentation
 fix_layout %>%
-    summarize_change(
-      "CHG",
-      variables = list(value = "AVAL", baseline_flag = "ABLFLL"),
-      .stats = c("n", "my_stat" = function(df, ...) {
-        a <- mean(df$AVAL, na.rm = TRUE)
-        b <- list(...)$.N_row # It has access at all `?rtables::additional_fun_params`
-        a / b
-      }),
-      .formats = c("my_stat" = function(x, ...) sprintf("%.2f", x))
-    ) %>%
-    build_table(dta_test)
+  summarize_change(
+    "CHG",
+    variables = list(value = "AVAL", baseline_flag = "ABLFLL"),
+    .stats = c("n", "my_stat" = function(df, ...) {
+      a <- mean(df$AVAL, na.rm = TRUE)
+      b <- list(...)$.N_row # It has access at all `?rtables::additional_fun_params`
+      a / b
+    }),
+    .formats = c("my_stat" = function(x, ...) sprintf("%.2f", x))
+  ) %>%
+  build_table(dta_test)
 ```
 
 

From e4ccb5313bfd9954d522f79004b7d766baf416e9 Mon Sep 17 00:00:00 2001
From: Melkiades <davide.garolini@roche.com>
Date: Tue, 5 Nov 2024 17:05:28 +0100
Subject: [PATCH 13/17] fix spelling

---
 NEWS.md                                    |  4 ++--
 R/utils_default_stats_formats_labels.R     |  2 +-
 man/default_stats_formats_labels.Rd        |  4 ++--
 man/util_handling_additional_fun_params.Rd |  6 +++---
 vignettes/tern_functions_guide.Rmd         | 10 +++++-----
 5 files changed, 13 insertions(+), 13 deletions(-)

diff --git a/NEWS.md b/NEWS.md
index 2bd50bbe93..64aedc63d6 100644
--- a/NEWS.md
+++ b/NEWS.md
@@ -8,13 +8,13 @@
 * Updated the `table_font_size` parameter of `g_lineplot()` to control the size of all text in the annotation table, including labels.
 * Added `as_list` parameter to `g_lineplot()` to allow users to return the line plot and annotation table elements as a list instead of stacked for more complex customization.
 * Refactored `summarize_change()` to work without `make_afun()` and access all additional function parameter.
-* Added vignette "Unerstanding `tern` functions" for future reference.
+* Added vignette "Understanding `tern` functions" for future reference.
 
 ### Bug Fixes
 * Fixed bug in `a_summary()` causing non-unique `row_name` values to occur when multiple statistics are selected for count variables.
 
 ### Miscellaneous
-* Reverted deprecation of quick getters for `summary_formats()` and `summary_labels()`. Added disclaimer about underlying use of `get_stats`.
+* Reverted deprecation of quick get functions `summary_formats()` and `summary_labels()`. Added disclaimer about underlying use of `get_stats`.
 * Corrected handling of extra arguments and `NA` for `summarize_change()`.
 
 # tern 0.9.6
diff --git a/R/utils_default_stats_formats_labels.R b/R/utils_default_stats_formats_labels.R
index 2b47ca88c6..b97acf4a08 100644
--- a/R/utils_default_stats_formats_labels.R
+++ b/R/utils_default_stats_formats_labels.R
@@ -573,7 +573,7 @@ summary_formats <- function(type = "numeric", include_pval = FALSE) {
 #' @param include_pval (`flag`)\cr same as the `add_pval` argument in [get_stats()].
 #'
 #' @details
-#' `summary_*` quick getter for labels or formats uses `get_stats` and `get_labels_from_stats` or
+#' `summary_*` quick get functions for labels or formats uses `get_stats` and `get_labels_from_stats` or
 #' `get_formats_from_stats` respectively to retrieve relevant information.
 #'
 #' @return
diff --git a/man/default_stats_formats_labels.Rd b/man/default_stats_formats_labels.Rd
index f0d99ea86f..3fbcad8fad 100644
--- a/man/default_stats_formats_labels.Rd
+++ b/man/default_stats_formats_labels.Rd
@@ -121,8 +121,8 @@ seen in \code{\link[=analyze_vars]{analyze_vars()}}. See notes to understand why
 \details{
 Current choices for \code{type} are \code{counts} and \code{numeric} for \code{\link[=analyze_vars]{analyze_vars()}} and affect \code{get_stats()}.
 
-\verb{summary_*} quick getter for labels or formats uses \code{get_stats} and \code{get_labels_from_stats} or \code{get_formats_from_stats}
-respectively to retrieve relevant information.
+\verb{summary_*} quick get functions for labels or formats uses \code{get_stats} and \code{get_labels_from_stats} or
+\code{get_formats_from_stats} respectively to retrieve relevant information.
 }
 \section{Functions}{
 \itemize{
diff --git a/man/util_handling_additional_fun_params.Rd b/man/util_handling_additional_fun_params.Rd
index 2a2f6adccb..c3106bbf32 100644
--- a/man/util_handling_additional_fun_params.Rd
+++ b/man/util_handling_additional_fun_params.Rd
@@ -3,12 +3,12 @@
 \name{util_handling_additional_fun_params}
 \alias{util_handling_additional_fun_params}
 \alias{retrieve_extra_afun_params}
-\alias{get_additional_analysis_fun_parameters}
+\alias{get_additional_afun_params}
 \title{Utilities to handle extra arguments in analysis functions}
 \usage{
 retrieve_extra_afun_params(extra_afun_params)
 
-get_additional_analysis_fun_parameters(add_alt_df = FALSE)
+get_additional_afun_params(add_alt_df = FALSE)
 }
 \arguments{
 \item{extra_afun_params}{(\code{list})\cr list of additional parameters (\code{character}) to be
@@ -38,7 +38,7 @@ will get them through argument matching.
 \itemize{
 \item \code{retrieve_extra_afun_params()}: Retrieve additional parameters from the environment.
 
-\item \code{get_additional_analysis_fun_parameters()}: Curated list of additional parameters for
+\item \code{get_additional_afun_params()}: Curated list of additional parameters for
 analysis functions. Please check \link[rtables:additional_fun_params]{rtables::additional_fun_params} for precise descriptions.
 
 }}
diff --git a/vignettes/tern_functions_guide.Rmd b/vignettes/tern_functions_guide.Rmd
index 929c106ff2..fab846e963 100644
--- a/vignettes/tern_functions_guide.Rmd
+++ b/vignettes/tern_functions_guide.Rmd
@@ -27,7 +27,7 @@ knitr::opts_chunk$set(
 
 Every function in the `tern` package is designed to have a certain structure that can cooperate well with every user's need, while maintaining a consistent and predictable behavior. This document will guide you through an example function in the package, explaining the purpose of many of its building blocks and how they can be used.
 
-As we recently worked on it we will consider `summarize_change()` as an example. This function is used to calculate the change from a baseline value for a given variable. A realistic example can be found in [LBT03](https://insightsengineering.github.io/tlg-catalog/stable/tables/lab-results/lbt03.html) from the TLG-catalog.
+As we recently worked on it we will consider `summarize_change()` as an example. This function is used to calculate the change from a baseline value for a given variable. A realistic example can be found in [`LBT03`](https://insightsengineering.github.io/tlg-catalog/stable/tables/lab-results/lbt03.html) from the TLG-catalog.
 
 `summarize_change()` is the main function that is available to the user. You can find lists of these functions in `?tern::analyze_functions`. All of these are build around `rtables::analyze()` function, which is the core analysis function in `rtables`. All these wrapper functions call specific analysis functions (always written as `a_*`) that are meant to handle the statistic functions (always written as `s_*`) and format the results with the `rtables::in_row()` function. We can summarize this structure as follows:
 
@@ -37,7 +37,7 @@ The main questions that may arise are:
 
 1. Handling of `NA`.
 2. Handling of formats.
-3. Additional statistics (WIP).
+3. Additional statistics.
 
 Data set and library loading.
 ```{r}
@@ -67,13 +67,13 @@ fix_layout <- basic_table() %>%
   split_rows_by("AVISIT")
 
 
-# NA: na_rm = TRUE
+# Dealing with NAs: na_rm = TRUE
 fix_layout %>%
   summarize_change("CHG", variables = list(value = "AVAL", baseline_flag = "ABLFLL")) %>%
   build_table(dta_test) %>%
   print()
 
-# NA: na_rm = FALSE
+# Dealing with NAs: na_rm = FALSE
 fix_layout %>%
   summarize_change("CHG", variables = list(value = "AVAL", baseline_flag = "ABLFLL"), na_rm = FALSE) %>%
   build_table(dta_test) %>%
@@ -137,6 +137,6 @@ fix_layout %>%
 
 In all of these layers there are specific parameters that need to be available, and, while `rtables` has multiple way to handle formatting and `NA` values, we had to decide how to correctly handle these and additional extra arguments. We follow the following scheme:
 
-Level 1: `summarize_change()`: all parameters without a starting dot `.*` are used or added to `extra_args`. Specifically, here we solve `NA` values by using `inclNAs` option in `rtables::analyze()`. This will add to `...` `na.rm = inclNAs`. Also `na_str` is here set. We may want to be statistic dependend in the future, but we still need to think how to accomplish that. We add the `rtables::additional_fun_params` to the analysis function so to make them available as `...` in the next level.
+Level 1: `summarize_change()`: all parameters without a starting dot `.*` are used or added to `extra_args`. Specifically, here we solve `NA` values by using `inclNAs` option in `rtables::analyze()`. This will add to `...` `na.rm = inclNAs`. Also `na_str` is here set. We may want to be statistic dependent in the future, but we still need to think how to accomplish that. We add the `rtables::additional_fun_params` to the analysis function so to make them available as `...` in the next level.
 
 Level 2: `a_change_from_baseline()`: all parameters starting with a dot `.` are used. Mainly `.stats`, `.formats`, `.labels`, and `.indent_mods` are used. We also add `extra_afun_params` to the `...` list for the statistical function. Notice the handling for additional parameters in the `do.call()` function.

From c8a7e4276b303bbdf42b95690905a04eb1b5875d Mon Sep 17 00:00:00 2001
From: Melkiades <davide.garolini@roche.com>
Date: Wed, 6 Nov 2024 11:39:27 +0100
Subject: [PATCH 14/17] fixes

---
 R/summarize_change.R                       | 4 ++--
 R/utils_rtables.R                          | 2 +-
 man/util_handling_additional_fun_params.Rd | 2 +-
 3 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/R/summarize_change.R b/R/summarize_change.R
index e6fd1d5fd7..46187031c2 100644
--- a/R/summarize_change.R
+++ b/R/summarize_change.R
@@ -65,7 +65,7 @@ a_change_from_baseline <- function(df,
                                    .labels = NULL,
                                    .indent_mods = NULL) {
   # Check if there are user-defined functions
-  default_and_custom_stats_list <- .split_default_from_custom_stats(.stats)
+  default_and_custom_stats_list <- .split_std_from_custom_stats(.stats)
   .stats <- default_and_custom_stats_list$default_stats
   custom_stat_functions <- default_and_custom_stats_list$custom_stats
 
@@ -180,7 +180,7 @@ summarize_change <- function(lyt,
   extra_args <- c(extra_args, "variables" = list(variables), ...)
 
   # Adding all additional information from layout to analysis functions (see ?rtables::additional_fun_params)
-  extra_args[[".additional_fun_parameters"]] <- get_additional_analysis_fun_parameters(add_alt_df = FALSE)
+  extra_args[[".additional_fun_parameters"]] <- get_additional_afun_params(add_alt_df = FALSE)
   formals(a_change_from_baseline) <- c(
     formals(a_change_from_baseline),
     extra_args[[".additional_fun_parameters"]]
diff --git a/R/utils_rtables.R b/R/utils_rtables.R
index 0853ed9bb8..039a226b80 100644
--- a/R/utils_rtables.R
+++ b/R/utils_rtables.R
@@ -504,7 +504,7 @@ retrieve_extra_afun_params <- function(extra_afun_params) {
 #'   analysis functions. Please check [rtables::additional_fun_params] for precise descriptions.
 #'
 #' @return
-#' * `get_additional_analysis_fun_parameters` returns a list of additional parameters.
+#' * `get_additional_afun_params` returns a list of additional parameters.
 #'
 #' @keywords internal
 get_additional_afun_params <- function(add_alt_df = FALSE) {
diff --git a/man/util_handling_additional_fun_params.Rd b/man/util_handling_additional_fun_params.Rd
index c3106bbf32..ce95abe6dc 100644
--- a/man/util_handling_additional_fun_params.Rd
+++ b/man/util_handling_additional_fun_params.Rd
@@ -23,7 +23,7 @@ parameters.}
 }
 
 \itemize{
-\item \code{get_additional_analysis_fun_parameters} returns a list of additional parameters.
+\item \code{get_additional_afun_params} returns a list of additional parameters.
 }
 }
 \description{

From bba677822d77275a5f51256b77fd3ab20688d48f Mon Sep 17 00:00:00 2001
From: Melkiades <davide.garolini@roche.com>
Date: Wed, 6 Nov 2024 11:57:27 +0100
Subject: [PATCH 15/17] last fix

---
 tests/testthat/test-utils_default_stats_formats_labels.R | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/tests/testthat/test-utils_default_stats_formats_labels.R b/tests/testthat/test-utils_default_stats_formats_labels.R
index f040eb0ef2..8c2b8bb712 100644
--- a/tests/testthat/test-utils_default_stats_formats_labels.R
+++ b/tests/testthat/test-utils_default_stats_formats_labels.R
@@ -212,11 +212,11 @@ testthat::test_that("summary_formats works as expected", {
 })
 
 testthat::test_that("summary_labels works as expected", {
-  testthat::expect_warning(result <- summary_labels())
+  result <- summary_labels()
   res <- testthat::expect_silent(result)
   testthat::expect_snapshot(res)
 
-  testthat::expect_warning(result <- summary_labels(type = "counts", include_pval = TRUE))
+  result <- summary_labels(type = "counts", include_pval = TRUE)
   res <- testthat::expect_silent(result)
   testthat::expect_snapshot(res)
 })

From f3324d0206efe053e5cd7a2f838b2ac2072094c8 Mon Sep 17 00:00:00 2001
From: Melkiades <davide.garolini@roche.com>
Date: Wed, 6 Nov 2024 16:56:27 +0100
Subject: [PATCH 16/17] forgot

---
 tests/testthat/test-utils_default_stats_formats_labels.R | 7 ++-----
 1 file changed, 2 insertions(+), 5 deletions(-)

diff --git a/tests/testthat/test-utils_default_stats_formats_labels.R b/tests/testthat/test-utils_default_stats_formats_labels.R
index 8c2b8bb712..9583faac18 100644
--- a/tests/testthat/test-utils_default_stats_formats_labels.R
+++ b/tests/testthat/test-utils_default_stats_formats_labels.R
@@ -199,14 +199,11 @@ testthat::test_that("labels_use_control works as expected", {
 })
 
 testthat::test_that("summary_formats works as expected", {
-  testthat::expect_warning(
-    result <- summary_formats() %>%
-      unlist() # More compact fruition
-  )
+  result <- summary_formats() %>% unlist() # More compact fruition
   res <- testthat::expect_silent(result)
   testthat::expect_snapshot(res)
 
-  testthat::expect_warning(result <- summary_formats(type = "counts", include_pval = TRUE))
+  result <- summary_formats(type = "counts", include_pval = TRUE)
   testthat::expect_true(all(result[c("n", "count", "n_blq")] == "xx."))
   testthat::expect_identical(result[["pval_counts"]], "x.xxxx | (<0.0001)")
 })

From 4f3b5fd232a6314e81689f00f0cb83d5f5d23904 Mon Sep 17 00:00:00 2001
From: Melkiades <davide.garolini@roche.com>
Date: Thu, 7 Nov 2024 20:04:18 +0100
Subject: [PATCH 17/17] Fix last note

---
 R/summarize_change.R | 13 ++++++++++---
 R/utils_rtables.R    |  2 +-
 2 files changed, 11 insertions(+), 4 deletions(-)

diff --git a/R/summarize_change.R b/R/summarize_change.R
index 46187031c2..832d8647b1 100644
--- a/R/summarize_change.R
+++ b/R/summarize_change.R
@@ -70,13 +70,15 @@ a_change_from_baseline <- function(df,
   custom_stat_functions <- default_and_custom_stats_list$custom_stats
 
   # Adding automatically extra parameters to the statistic function (see ?rtables::additional_fun_params)
-  extra_afun_params <- names(list(...)$.additional_fun_parameters)
+  extra_afun_params <- retrieve_extra_afun_params(
+    names(list(...)$.additional_fun_parameters)
+  )
   x_stats <- .apply_stat_functions(
     default_stat_fnc = s_change_from_baseline,
     custom_stat_fnc_list = custom_stat_functions,
     args_list = c(
       df = list(df),
-      retrieve_extra_afun_params(extra_afun_params),
+      extra_afun_params,
       list(...)
     )
   )
@@ -91,7 +93,12 @@ a_change_from_baseline <- function(df,
   .indent_mods <- get_indents_from_stats(.stats, .indent_mods)
 
   # Auto format handling
-  .formats <- apply_auto_formatting(.formats, x_stats, .df_row, .var)
+  .formats <- apply_auto_formatting(
+    .formats,
+    x_stats,
+    extra_afun_params$.df_row,
+    extra_afun_params$.var
+  )
 
   in_rows(
     .list = x_stats[.stats],
diff --git a/R/utils_rtables.R b/R/utils_rtables.R
index 039a226b80..26c45543db 100644
--- a/R/utils_rtables.R
+++ b/R/utils_rtables.R
@@ -526,7 +526,7 @@ get_additional_afun_params <- function(add_alt_df = FALSE) {
     out_list <- c(
       out_list,
       .alt_df_row = data.frame(),
-      .alt_df = data.frame(),
+      .alt_df = data.frame()
     )
   }