From 854a87aeb80097ae3d11d9e71c2830924ab22d51 Mon Sep 17 00:00:00 2001 From: "Fukuda, Hiroaki" Date: Thu, 23 Oct 2025 16:43:20 -0400 Subject: [PATCH 1/6] Add `digits_km_curves` argument so that users can control the display --- R/prepare_hr_forestly.R | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/R/prepare_hr_forestly.R b/R/prepare_hr_forestly.R index c7d3a9d..5ed2f88 100644 --- a/R/prepare_hr_forestly.R +++ b/R/prepare_hr_forestly.R @@ -27,6 +27,8 @@ #' Use "all" to include the result for overall population (e.g., "all;age;gender"). #' @param km_curves A semicolon-separated string of subgroups for which KM curves should be plotted. #' The parameters should be defined at value levels for subgroups. +#' @param digits_km_curves A numeric value specifying the number of digits +#' for the survival probability in KM curves. #' @param arm_levels A vector of character specifying the levels of arms, starting with the reference arm. #' #' @return An metadata with HR per subgroup along with its KM plotting data @@ -49,6 +51,7 @@ prepare_hr_forestly <- function(meta = NULL, endpoint = NULL, subgroup = NULL, km_curves = NULL, + digits_km_curves = 2, arm_levels = NULL) { # obtain population/observation variables pop_var <- metalite::collect_adam_mapping(meta, population)$var @@ -208,6 +211,7 @@ prepare_hr_forestly <- function(meta = NULL, survival::survfit(survival::Surv(time, event) ~ treatment, data = data_sub, conf.type = "log-log") |> km_extract() |> dplyr::mutate( + surv = round(surv, digits_km_curves), endpoint = endpt_label, subgroup = km_curve_val, text = paste0(endpoint, ": ", surv, "\n", "Number of participants at risk: ", n.risk) From e0ddd3d4746801ecce4b1e1196bbb096c72461f2 Mon Sep 17 00:00:00 2001 From: "Fukuda, Hiroaki" Date: Thu, 23 Oct 2025 16:44:07 -0400 Subject: [PATCH 2/6] Add legend for the forest plot --- R/format_hr_forestly.R | 18 +++++++++++++----- inst/js/sparkline.js | 3 ++- man/format_hr_forestly.Rd | 4 ++-- man/hr_forestly.Rd | 4 ++-- man/prepare_hr_forestly.Rd | 4 ++++ 5 files changed, 23 insertions(+), 10 deletions(-) diff --git a/R/format_hr_forestly.R b/R/format_hr_forestly.R index d5f456e..7509982 100644 --- a/R/format_hr_forestly.R +++ b/R/format_hr_forestly.R @@ -62,11 +62,11 @@ format_hr_forestly <- function(outdata, display = c("n", "event", "fig_hr"), digits = 2, width_subgroup = 50, - width_fig = 320, + width_fig = 360, width_n = 40, width_event = 40, width_hr = 40, - footer_space = 90, + footer_space = 150, hr_range = NULL, color = NULL, hr_label = "Treatment <- Favor -> Placebo") { @@ -154,15 +154,23 @@ format_hr_forestly <- function(outdata, # Function to create Axis js_hr_fig_footer <- sparkline_point_js( - tbl = data.frame(x = 1), - x = "x", + tbl = tbl, + x = names(outdata$hr_est)[1:n_group1], + # tbl = data.frame(x = 1), + # x = "x", y = -1, type = "footer", xlab = hr_label, xlim = fig_hr_range, height = footer_space, width = width_fig, - legend = FALSE, + # legend = FALSE, + color = fig_hr_color, + legend = TRUE, + legend_label = outdata$group[2:n_group], + legend_title = "", + legend_position = -2, + legend_type = "point", margin = c(footer_space - 20, 20, 0, 0, 0) ) diff --git a/inst/js/sparkline.js b/inst/js/sparkline.js index e62eb27..3a96ccc 100644 --- a/inst/js/sparkline.js +++ b/inst/js/sparkline.js @@ -106,7 +106,8 @@ function(cell, state) { "orientation": "h", "xanchor": "center", "x": 0.5, - "y": legend_position + "y": legend_position, + "yref": "container" } }, "config": { diff --git a/man/format_hr_forestly.Rd b/man/format_hr_forestly.Rd index 84bbdfc..632856c 100644 --- a/man/format_hr_forestly.Rd +++ b/man/format_hr_forestly.Rd @@ -9,11 +9,11 @@ format_hr_forestly( display = c("n", "event", "fig_hr"), digits = 2, width_subgroup = 50, - width_fig = 320, + width_fig = 360, width_n = 40, width_event = 40, width_hr = 40, - footer_space = 90, + footer_space = 150, hr_range = NULL, color = NULL, hr_label = "Treatment <- Favor -> Placebo" diff --git a/man/hr_forestly.Rd b/man/hr_forestly.Rd index 9f4e14e..4531fab 100644 --- a/man/hr_forestly.Rd +++ b/man/hr_forestly.Rd @@ -9,7 +9,7 @@ hr_forestly( time_unit = c("days", "weeks", "months", "years"), y_label_kmplot = "Survival Probability", width = 1000, - height_kmoplot = 400, + height_kmplot = 400, height_at_risk = 200, max_page = NULL ) @@ -25,7 +25,7 @@ Default is "Survival Probability".} \item{width}{A numeric value of width of the entire plot in pixels. Default is 1000.} -\item{height_kmoplot}{A numeric value of height of the KM plot in pixels. Default is 400.} +\item{height_kmplot}{A numeric value of height of the KM plot in pixels. Default is 400.} \item{height_at_risk}{A numeric value of height of the at-risk table in pixels. Default is 200.} diff --git a/man/prepare_hr_forestly.Rd b/man/prepare_hr_forestly.Rd index a3d3268..5514226 100644 --- a/man/prepare_hr_forestly.Rd +++ b/man/prepare_hr_forestly.Rd @@ -11,6 +11,7 @@ prepare_hr_forestly( endpoint = NULL, subgroup = NULL, km_curves = NULL, + digits_km_curves = 2, arm_levels = NULL ) } @@ -30,6 +31,9 @@ Use "all" to include the result for overall population (e.g., "all;age;gender"). \item{km_curves}{A semicolon-separated string of subgroups for which KM curves should be plotted. The parameters should be defined at value levels for subgroups.} +\item{digits_km_curves}{A numeric value specifying the number of digits +for the survival probability in KM curves.} + \item{arm_levels}{A vector of character specifying the levels of arms, starting with the reference arm.} } \value{ From 75a28e4e636f0d253ffda6ef1dc7d3c06f37bc57 Mon Sep 17 00:00:00 2001 From: "Fukuda, Hiroaki" Date: Thu, 23 Oct 2025 16:44:20 -0400 Subject: [PATCH 3/6] Fix the typo --- R/hr_forestly.R | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/R/hr_forestly.R b/R/hr_forestly.R index 028b76f..3e77f57 100644 --- a/R/hr_forestly.R +++ b/R/hr_forestly.R @@ -24,7 +24,7 @@ #' @param y_label_kmplot A string specifying the y-axis label of the KM plot. #' Default is "Survival Probability". #' @param width A numeric value of width of the entire plot in pixels. Default is 1000. -#' @param height_kmoplot A numeric value of height of the KM plot in pixels. Default is 400. +#' @param height_kmplot A numeric value of height of the KM plot in pixels. Default is 400. #' @param height_at_risk A numeric value of height of the at-risk table in pixels. #' Default is 200. #' @param max_page A numeric value of maximum number of subgroups to display per page. @@ -48,7 +48,7 @@ hr_forestly <- function(outdata, time_unit = c("days", "weeks", "months", "years"), y_label_kmplot = "Survival Probability", width = 1000, - height_kmoplot = 400, + height_kmplot = 400, height_at_risk = 200, max_page = NULL) { time_unit <- match.arg(time_unit, choices = time_unit) @@ -166,7 +166,7 @@ hr_forestly <- function(outdata, htmltools::div( htmltools::tagList( - ggplotly(km_plot, tooltip = c("text"), dynamicTicks = FALSE, height = height_kmoplot) %>% + ggplotly(km_plot, tooltip = c("text"), dynamicTicks = FALSE, height = height_kmplot) %>% highlight(on = "plotly_click", off = "plotly_doubleclick") %>% add_trace( data = cnr_details, From 5a2c64e1ed602e22f489eb2a06fd09719608a4cb Mon Sep 17 00:00:00 2001 From: "Fukuda, Hiroaki" Date: Fri, 24 Oct 2025 10:20:06 -0400 Subject: [PATCH 4/6] Aligne bar order with table and clean code --- R/format_hr_forestly.R | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/R/format_hr_forestly.R b/R/format_hr_forestly.R index 7509982..4ffa781 100644 --- a/R/format_hr_forestly.R +++ b/R/format_hr_forestly.R @@ -144,7 +144,7 @@ format_hr_forestly <- function(outdata, x = names(outdata$hr_est)[1:n_group1], x_lower = names(outdata$hr_ci_lower)[1:n_group1], x_upper = names(outdata$hr_ci_upper)[1:n_group1], - y = 1:n_group1, + y = rev(1:n_group1), xlim = fig_hr_range, color = fig_hr_color, width = width_fig, @@ -156,15 +156,12 @@ format_hr_forestly <- function(outdata, js_hr_fig_footer <- sparkline_point_js( tbl = tbl, x = names(outdata$hr_est)[1:n_group1], - # tbl = data.frame(x = 1), - # x = "x", y = -1, type = "footer", xlab = hr_label, xlim = fig_hr_range, height = footer_space, width = width_fig, - # legend = FALSE, color = fig_hr_color, legend = TRUE, legend_label = outdata$group[2:n_group], From 2d5424de60669e24bfb6a25511e59a29200b5d5d Mon Sep 17 00:00:00 2001 From: "Fukuda, Hiroaki" Date: Fri, 24 Oct 2025 13:31:21 -0400 Subject: [PATCH 5/6] Move `digits_km_curves` to `format_hr_forestly` and rename `digits` to distinguish --- R/format_hr_forestly.R | 25 ++++++++++++++++++------- R/prepare_hr_forestly.R | 7 +------ man/format_hr_forestly.Rd | 8 ++++++-- man/prepare_hr_forestly.Rd | 4 ---- 4 files changed, 25 insertions(+), 19 deletions(-) diff --git a/R/format_hr_forestly.R b/R/format_hr_forestly.R index 4ffa781..4349950 100644 --- a/R/format_hr_forestly.R +++ b/R/format_hr_forestly.R @@ -26,7 +26,7 @@ #' - `event`: Number of events in a comparison. #' - `hr`: Hazard ratio estimate in a comparison. #' - `fig_hr`: Hazard ratio figure in a comparison. -#' @param digits A numeric value specifying the number of digits to +#' @param digits_hr A numeric value specifying the number of digits to #' display for hazard ratios and confidence intervals. Default is 2. #' @param width_subgroup A numeric value specifying the width of #' the subgroup column in pixels. @@ -36,6 +36,8 @@ #' @param width_event A numeric value specifying the width of #' the "event" column in pixels. #' @param width_hr A numeric value specifying the width of the hazard ratio column in pixels. +#' @param digits_km_curves A numeric value specifying the number of digits to display +#' for the survival probability in KM curves. #' @param footer_space A numeric value specifying the space for the footer in pixels. #' @param hr_range A numeric vector of lower and upper limit of x-axis #' for the hazard ratio figure. @@ -60,12 +62,13 @@ #' format_hr_forestly() format_hr_forestly <- function(outdata, display = c("n", "event", "fig_hr"), - digits = 2, + digits_hr = 2, width_subgroup = 50, width_fig = 360, width_n = 40, width_event = 40, width_hr = 40, + digits_km_curves = 2, footer_space = 150, hr_range = NULL, color = NULL, @@ -105,9 +108,9 @@ format_hr_forestly <- function(outdata, tbl <- data.frame( outdata$n, outdata$event[1:n_group1], - round(outdata$hr_est[1:n_group1], digits = digits), - round(outdata$hr_ci_lower[1:n_group1], digits = digits), - round(outdata$hr_ci_upper[1:n_group1], digits = digits), + round(outdata$hr_est[1:n_group1], digits = digits_hr), + round(outdata$hr_ci_lower[1:n_group1], digits = digits_hr), + round(outdata$hr_ci_upper[1:n_group1], digits = digits_hr), hr_fig = NA ) col_names <- sapply(2:n_group, function(x) { @@ -137,7 +140,7 @@ format_hr_forestly <- function(outdata, fig_hr_color <- color[2:n_group] iter <- 1:ncol(outdata$hr_est[1:n_group1]) - 1 - text <- glue::glue("x[{iter}] + '(' + x_lower[{iter}] + ', ' + x_upper[{iter}] + ')'") + text <- glue::glue("x[{iter}] + ' (' + x_lower[{iter}] + ', ' + x_upper[{iter}] + ')'") js_hr_fig_cell <- sparkline_point_js( tbl = tbl, type = "cell", @@ -236,7 +239,7 @@ format_hr_forestly <- function(outdata, header = "HR", minWidth = width_hr, show = display_hr, - format = reactable::colFormat(digits = digits) + format = reactable::colFormat(digits = digits_hr) ) } ) @@ -284,6 +287,13 @@ format_hr_forestly <- function(outdata, return(x) }) + # Update km_data to round + km_data <- outdata$km_data |> + dplyr::mutate( + surv = round(surv, digits_km_curves), + text = paste0(endpoint, ": ", formatC(surv, format = "f", digits = digits_km_curves), "\n", "Number of participants at risk: ", n.risk) + ) + # Create outdata outdata$tbl <- tbl outdata$reactable_columns <- columns @@ -291,6 +301,7 @@ format_hr_forestly <- function(outdata, outdata$display <- display outdata$fig_hr_color <- fig_hr_color outdata$color <- color + outdata$km_data <- km_data outdata } diff --git a/R/prepare_hr_forestly.R b/R/prepare_hr_forestly.R index 5ed2f88..9248b52 100644 --- a/R/prepare_hr_forestly.R +++ b/R/prepare_hr_forestly.R @@ -27,8 +27,6 @@ #' Use "all" to include the result for overall population (e.g., "all;age;gender"). #' @param km_curves A semicolon-separated string of subgroups for which KM curves should be plotted. #' The parameters should be defined at value levels for subgroups. -#' @param digits_km_curves A numeric value specifying the number of digits -#' for the survival probability in KM curves. #' @param arm_levels A vector of character specifying the levels of arms, starting with the reference arm. #' #' @return An metadata with HR per subgroup along with its KM plotting data @@ -51,7 +49,6 @@ prepare_hr_forestly <- function(meta = NULL, endpoint = NULL, subgroup = NULL, km_curves = NULL, - digits_km_curves = 2, arm_levels = NULL) { # obtain population/observation variables pop_var <- metalite::collect_adam_mapping(meta, population)$var @@ -211,10 +208,8 @@ prepare_hr_forestly <- function(meta = NULL, survival::survfit(survival::Surv(time, event) ~ treatment, data = data_sub, conf.type = "log-log") |> km_extract() |> dplyr::mutate( - surv = round(surv, digits_km_curves), endpoint = endpt_label, - subgroup = km_curve_val, - text = paste0(endpoint, ": ", surv, "\n", "Number of participants at risk: ", n.risk) + subgroup = km_curve_val ) }) km_tbl_new <- do.call(rbind, km_tbl_new) diff --git a/man/format_hr_forestly.Rd b/man/format_hr_forestly.Rd index 632856c..a873f04 100644 --- a/man/format_hr_forestly.Rd +++ b/man/format_hr_forestly.Rd @@ -7,12 +7,13 @@ format_hr_forestly( outdata, display = c("n", "event", "fig_hr"), - digits = 2, + digits_hr = 2, width_subgroup = 50, width_fig = 360, width_n = 40, width_event = 40, width_hr = 40, + digits_km_curves = 2, footer_space = 150, hr_range = NULL, color = NULL, @@ -32,7 +33,7 @@ Default is c("n", "event", "fig_hr"). \item \code{fig_hr}: Hazard ratio figure in a comparison. }} -\item{digits}{A numeric value specifying the number of digits to +\item{digits_hr}{A numeric value specifying the number of digits to display for hazard ratios and confidence intervals. Default is 2.} \item{width_subgroup}{A numeric value specifying the width of @@ -48,6 +49,9 @@ the "event" column in pixels.} \item{width_hr}{A numeric value specifying the width of the hazard ratio column in pixels.} +\item{digits_km_curves}{A numeric value specifying the number of digits to display +for the survival probability in KM curves.} + \item{footer_space}{A numeric value specifying the space for the footer in pixels.} \item{hr_range}{A numeric vector of lower and upper limit of x-axis diff --git a/man/prepare_hr_forestly.Rd b/man/prepare_hr_forestly.Rd index 5514226..a3d3268 100644 --- a/man/prepare_hr_forestly.Rd +++ b/man/prepare_hr_forestly.Rd @@ -11,7 +11,6 @@ prepare_hr_forestly( endpoint = NULL, subgroup = NULL, km_curves = NULL, - digits_km_curves = 2, arm_levels = NULL ) } @@ -31,9 +30,6 @@ Use "all" to include the result for overall population (e.g., "all;age;gender"). \item{km_curves}{A semicolon-separated string of subgroups for which KM curves should be plotted. The parameters should be defined at value levels for subgroups.} -\item{digits_km_curves}{A numeric value specifying the number of digits -for the survival probability in KM curves.} - \item{arm_levels}{A vector of character specifying the levels of arms, starting with the reference arm.} } \value{ From 4e377a885ea39476832fed58165b2a361e8736a4 Mon Sep 17 00:00:00 2001 From: "Fukuda, Hiroaki" Date: Tue, 28 Oct 2025 11:41:57 -0400 Subject: [PATCH 6/6] Rename `digits_km_surves` to `digits_surv` for clarification --- R/format_hr_forestly.R | 8 ++++---- man/format_hr_forestly.Rd | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/R/format_hr_forestly.R b/R/format_hr_forestly.R index 4349950..542f3f4 100644 --- a/R/format_hr_forestly.R +++ b/R/format_hr_forestly.R @@ -36,7 +36,7 @@ #' @param width_event A numeric value specifying the width of #' the "event" column in pixels. #' @param width_hr A numeric value specifying the width of the hazard ratio column in pixels. -#' @param digits_km_curves A numeric value specifying the number of digits to display +#' @param digits_surv A numeric value specifying the number of digits to display #' for the survival probability in KM curves. #' @param footer_space A numeric value specifying the space for the footer in pixels. #' @param hr_range A numeric vector of lower and upper limit of x-axis @@ -68,7 +68,7 @@ format_hr_forestly <- function(outdata, width_n = 40, width_event = 40, width_hr = 40, - digits_km_curves = 2, + digits_surv = 2, footer_space = 150, hr_range = NULL, color = NULL, @@ -290,8 +290,8 @@ format_hr_forestly <- function(outdata, # Update km_data to round km_data <- outdata$km_data |> dplyr::mutate( - surv = round(surv, digits_km_curves), - text = paste0(endpoint, ": ", formatC(surv, format = "f", digits = digits_km_curves), "\n", "Number of participants at risk: ", n.risk) + surv = round(surv, digits_surv), + text = paste0(endpoint, ": ", formatC(surv, format = "f", digits = digits_surv), "\n", "Number of participants at risk: ", n.risk) ) # Create outdata diff --git a/man/format_hr_forestly.Rd b/man/format_hr_forestly.Rd index a873f04..181ad99 100644 --- a/man/format_hr_forestly.Rd +++ b/man/format_hr_forestly.Rd @@ -13,7 +13,7 @@ format_hr_forestly( width_n = 40, width_event = 40, width_hr = 40, - digits_km_curves = 2, + digits_surv = 2, footer_space = 150, hr_range = NULL, color = NULL, @@ -49,7 +49,7 @@ the "event" column in pixels.} \item{width_hr}{A numeric value specifying the width of the hazard ratio column in pixels.} -\item{digits_km_curves}{A numeric value specifying the number of digits to display +\item{digits_surv}{A numeric value specifying the number of digits to display for the survival probability in KM curves.} \item{footer_space}{A numeric value specifying the space for the footer in pixels.}