diff --git a/.gitignore b/.gitignore index f7e7e96156..9e15e1d9d2 100644 --- a/.gitignore +++ b/.gitignore @@ -3,12 +3,10 @@ .RData .Ruserdata .DS_Store -InputVads.Rdata -t_ae_ctc_SE.out -t_ae_ctc_ATEZOREL_SENBX.out inst/doc docs temp *.bak .Renviron .Rprofile +.vscode diff --git a/DESCRIPTION b/DESCRIPTION index 4eba8c7331..793577e930 100755 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -80,6 +80,7 @@ Collate: 'egt05_qtcat.R' 'ext01.R' 'gen_args.R' + 'kmg01.R' 'lbt01.R' 'lbt04.R' 'lbt05.R' diff --git a/NAMESPACE b/NAMESPACE index 8938454292..4cf4c66b9d 100755 --- a/NAMESPACE +++ b/NAMESPACE @@ -54,6 +54,7 @@ export(aet10_1_pre) export(args_ls) export(assert_all_tablenames) export(assert_colnames) +export(assert_only_one_paramcd) export(chevron_g) export(chevron_l) export(chevron_t) @@ -150,6 +151,10 @@ export(get_preprocess) export(gg_list) export(grob_list) export(h_format_dec) +export(kmg01_1) +export(kmg01_1_main) +export(kmg01_1_post) +export(kmg01_1_pre) export(lbt01_1) export(lbt01_1_lyt) export(lbt01_1_main) diff --git a/R/ael01_nollt.R b/R/ael01_nollt.R index 8232d2ab25..eae52cf646 100644 --- a/R/ael01_nollt.R +++ b/R/ael01_nollt.R @@ -99,7 +99,9 @@ ael01_nollt_1_post <- function(tlg, ...) { #' @export #' #' @examples -#' run(ael01_nollt_1, syn_data, new_lbls = list(AETERM = "Investigator-Specified\n Adverse Event Term")) +#' run(ael01_nollt_1, syn_data, new_lbls = list( +#' AETERM = "Investigator-Specified\n Adverse Event Term" +#' )) ael01_nollt_1 <- chevron_l( main = ael01_nollt_1_main, preprocess = ael01_nollt_1_pre, diff --git a/R/assertions.R b/R/assertions.R index d203a2299d..aa0efefac0 100644 --- a/R/assertions.R +++ b/R/assertions.R @@ -167,3 +167,18 @@ assert_subset_suggest <- function(x, choices) { stop(msg, call. = FALSE) } + + +#' Check to have only one PARAMCD in the analysis dataset +#' @param param_val value of PARAMCD +#' @export +assert_only_one_paramcd <- function(param_val) { + unique_param_val <- unique(param_val) + if (length(unique_param_val) > 1) { + stop(paste0( + "More than one parameters:", + toString(unique_param_val), + ", only one suppose to have." + )) + } +} diff --git a/R/kmg01.R b/R/kmg01.R new file mode 100644 index 0000000000..df9107be34 --- /dev/null +++ b/R/kmg01.R @@ -0,0 +1,137 @@ +# kmg01_1 ---- + +#' @describeIn kmg01_1 Main TLG Function +#' +#' @details +#' * No overall value. +#' +#' @inheritParams gen_args +#' @param dataset (`string`) the name of a table in the `adam_db` object. +#' @param x_name (`string`) the name of the x-axis. +#' @param y_name (`string`) the name of the x-axis. +#' @param show_statis (`flag`) should the summary statistic table be displayed. +#' @param show_censor (`flag`) should the censor flag be displayed. +#' @param pval_method (`string`) should the censor flag be displayed. +#' @param ties (`string`) should the censor flag be displayed. +#' @param conf_level (`numeric`) should the censor flag be displayed. +#' @param position_coxph (`numeric`) x and y positions for plotting survival::coxph() model. +#' @param position_surv_med (`numeric`) x and y positions for plotting annotation table estimating +#' median survival time per group. +#' @param line_col (`list`) describing the colors to use for the lines or a named `list` +#' associating values of `arm_var` with color names. +#' +#' @note +#' * `adam_db` object must contain the table specified by `dataset` with the columns specified by `arm_var`. +#' +#' @return a list of `ggplot` objects. +#' @export +kmg01_1_main <- function(adam_db, + dataset = "adtte", + arm_var = "ARM", + x_name = "Time (Days)", + y_name = "Survival Probability", + show_statis = TRUE, + show_censor = TRUE, + pval_method = "wald", + ties = "exact", + conf_level = 0.95, + position_coxph = c(0, 0.05), + position_surv_med = c(0.9, 0.9), + line_col = as.list(nestcolor::color_palette()), + ...) { + anl <- adam_db[[dataset]] + assert_colnames(anl, c("PARAMCD", "is_event", arm_var)) + assert_only_one_paramcd(anl$PARAMCD) + checkmate::assert_string(x_name) + checkmate::assert_string(y_name) + checkmate::assert_flag(show_statis) + checkmate::assert_flag(show_censor) + + line_col <- unlist(line_col) + checkmate::assert_character(line_col, null.ok = TRUE) + + assert_colnames(anl, "AVAL") + variables <- list(tte = "AVAL", is_event = "is_event", arm = arm_var) + + + if (!is.null(names(line_col))) { + color_lvl <- sort(unique(anl[[arm_var]])) + col <- line_col[as.character(color_lvl)] + + if (anyNA(col)) { + missing_col <- setdiff(color_lvl, names(col)) + stop(paste("Missing color matching for", toString(missing_col))) + } + + col <- unname(col) + } else { + col <- line_col + } + + g_km( + df = anl, + variables = variables, + censor_show = show_censor, + xlab = x_name, + ylab = y_name, + annot_surv_med = !show_statis, + annot_coxph = show_statis, + control_coxph_pw = control_coxph(pval_method = pval_method, ties = ties, conf_level = conf_level), + position_coxph = position_coxph, + position_surv_med = position_surv_med + ) +} + +#' @describeIn kmg01_1 Preprocessing +#' +#' @inheritParams kmg01_1_main +#' +#' @export +kmg01_1_pre <- function(adam_db, dataset = "adtte", ...) { + assert_all_tablenames(adam_db, c("adsl", dataset)) + assert_colnames(adam_db[[dataset]], "CNSR") + + adam_db[[dataset]] <- adam_db[[dataset]] %>% + mutate(is_event = .data$CNSR == 0) + + adam_db +} + +#' @describeIn kmg01_1 Postprocessing +#' +#' @inheritParams gen_args +#' +#' @export +kmg01_1_post <- function(tlg, ...) { + tlg +} + +# `kmg01_1` Pipeline ---- + +#' `KMG01` Kaplan-Meier Plot 1. +#' +#' +#' @include chevron_tlg-S4class.R +#' @export +#' +#' @examples +#' library(dplyr) +#' library(dunlin) +#' +#' col <- list( +#' "A: Drug X" = "black", +#' "B: Placebo" = "blue", +#' "C: Combination" = "gray" +#' ) +#' +#' syn_data2 <- log_filter(syn_data, PARAMCD == "OS", "adtte") +#' run(kmg01_1, syn_data2, dataset = "adtte", line_col = col) +#' +#' syn_data3 <- log_filter(syn_data, PARAMCD == "AEREPTTE", "adaette") +#' run(kmg01_1, syn_data3, dataset = "adaette") +kmg01_1 <- chevron_g( + main = kmg01_1_main, + preproces = kmg01_1_pre, + postprocess = kmg01_1_post, + adam_datasets = c("adsl") +) diff --git a/_pkgdown.yaml b/_pkgdown.yaml index 0559d10157..a6ea263d11 100755 --- a/_pkgdown.yaml +++ b/_pkgdown.yaml @@ -80,6 +80,7 @@ reference: - egt05_qtcat_1 - ext01_1 - ext01_2 + - kmg01_1 - lbt01_1 - lbt04_1 - lbt05_1 @@ -108,6 +109,7 @@ reference: - h_format_dec - gg_list - grob_list + - assert_only_one_paramcd - title: Non-exported Documented Functions for Packagage Developers contents: diff --git a/inst/WORDLIST b/inst/WORDLIST index 24c5211873..d92ee080d4 100755 --- a/inst/WORDLIST +++ b/inst/WORDLIST @@ -2,22 +2,21 @@ ADEG ADaM AESI CTCAE -gg -gg_list Hoffmann +Kaplan NCI PARAMCD Postprocessing -postprocessing -preprocess Pre Repo -SSO +Rua TLG TLGs +coxph +de funder +postprocessing pre +preprocess repo reproducibility -de -Rua diff --git a/man/ael01_nollt_1.Rd b/man/ael01_nollt_1.Rd index 4f9c4b84bb..a319fe9d92 100644 --- a/man/ael01_nollt_1.Rd +++ b/man/ael01_nollt_1.Rd @@ -85,6 +85,8 @@ strings to the new labels to apply to the named variables. Set to \code{NULL} to } } \examples{ -run(ael01_nollt_1, syn_data, new_lbls = list(AETERM = "Investigator-Specified\n Adverse Event Term")) +run(ael01_nollt_1, syn_data, new_lbls = list( + AETERM = "Investigator-Specified\n Adverse Event Term" +)) } \keyword{datasets} diff --git a/man/assert_only_one_paramcd.Rd b/man/assert_only_one_paramcd.Rd new file mode 100644 index 0000000000..474266247b --- /dev/null +++ b/man/assert_only_one_paramcd.Rd @@ -0,0 +1,14 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/assertions.R +\name{assert_only_one_paramcd} +\alias{assert_only_one_paramcd} +\title{Check to have only one PARAMCD in the analysis dataset} +\usage{ +assert_only_one_paramcd(param_val) +} +\arguments{ +\item{param_val}{value of PARAMCD} +} +\description{ +Check to have only one PARAMCD in the analysis dataset +} diff --git a/man/kmg01_1.Rd b/man/kmg01_1.Rd new file mode 100644 index 0000000000..2f2acfcbc1 --- /dev/null +++ b/man/kmg01_1.Rd @@ -0,0 +1,111 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/kmg01.R +\docType{data} +\name{kmg01_1_main} +\alias{kmg01_1_main} +\alias{kmg01_1_pre} +\alias{kmg01_1_post} +\alias{kmg01_1} +\title{\code{KMG01} Kaplan-Meier Plot 1.} +\format{ +An object of class \code{chevron_g} of length 1. +} +\usage{ +kmg01_1_main( + adam_db, + dataset = "adtte", + arm_var = "ARM", + x_name = "Time (Days)", + y_name = "Survival Probability", + show_statis = TRUE, + show_censor = TRUE, + pval_method = "wald", + ties = "exact", + conf_level = 0.95, + position_coxph = c(0, 0.05), + position_surv_med = c(0.9, 0.9), + line_col = as.list(nestcolor::color_palette()), + ... +) + +kmg01_1_pre(adam_db, dataset = "adtte", ...) + +kmg01_1_post(tlg, ...) + +kmg01_1 +} +\arguments{ +\item{adam_db}{(\code{list} of \code{data.frames}) object containing the \code{ADaM} datasets} + +\item{dataset}{(\code{string}) the name of a table in the \code{adam_db} object.} + +\item{arm_var}{(\code{string}) variable used for column splitting} + +\item{x_name}{(\code{string}) the name of the x-axis.} + +\item{y_name}{(\code{string}) the name of the x-axis.} + +\item{show_statis}{(\code{flag}) should the summary statistic table be displayed.} + +\item{show_censor}{(\code{flag}) should the censor flag be displayed.} + +\item{pval_method}{(\code{string}) should the censor flag be displayed.} + +\item{ties}{(\code{string}) should the censor flag be displayed.} + +\item{conf_level}{(\code{numeric}) should the censor flag be displayed.} + +\item{position_coxph}{(\code{numeric}) x and y positions for plotting survival::coxph() model.} + +\item{position_surv_med}{(\code{numeric}) x and y positions for plotting annotation table estimating +median survival time per group.} + +\item{line_col}{(\code{list}) describing the colors to use for the lines or a named \code{list} +associating values of \code{arm_var} with color names.} + +\item{...}{not used.} + +\item{tlg}{(\code{TableTree}, \code{Listing} or \code{ggplot}) object typically produced by a \code{main} function.} +} +\value{ +a list of \code{ggplot} objects. +} +\description{ +\code{KMG01} Kaplan-Meier Plot 1. +} +\details{ +\itemize{ +\item No overall value. +} +} +\section{Functions}{ +\itemize{ +\item \code{kmg01_1_main()}: Main TLG Function + +\item \code{kmg01_1_pre()}: Preprocessing + +\item \code{kmg01_1_post()}: Postprocessing + +}} +\note{ +\itemize{ +\item \code{adam_db} object must contain the table specified by \code{dataset} with the columns specified by \code{arm_var}. +} +} +\examples{ +library(dplyr) +library(dunlin) + +col <- list( + "A: Drug X" = "black", + "B: Placebo" = "blue", + "C: Combination" = "gray" +) + +syn_data2 <- log_filter(syn_data, PARAMCD == "OS", "adtte") +run(kmg01_1, syn_data2, dataset = "adtte", line_col = col) + +syn_data3 <- log_filter(syn_data, PARAMCD == "AEREPTTE", "adaette") +run(kmg01_1, syn_data3, dataset = "adaette") +} +\keyword{datasets} diff --git a/tests/testthat/test-kmg01.R b/tests/testthat/test-kmg01.R new file mode 100644 index 0000000000..d7cf44d46e --- /dev/null +++ b/tests/testthat/test-kmg01.R @@ -0,0 +1,41 @@ +test_that("kmg01_1 works as expected", { + filter_data <- dunlin::log_filter(syn_data, PARAMCD == "OS", "adtte") + pre_data <- expect_silent(kmg01_1_pre(filter_data, dataset = "adtte")) + raw_res <- expect_silent(kmg01_1_main(pre_data, dataset = "adtte")) + checkmate::assert_true(grid::is.grob(raw_res)) +}) + +test_that("kmg01_1 works as expected with custom color set", { + col <- list( + "A: Drug X" = "black", + "B: Placebo" = "blue", + "C: Combination" = "gray" + ) + + filter_data <- dunlin::log_filter(syn_data, PARAMCD == "OS", "adtte") + res <- expect_silent(run(kmg01_1, filter_data, dataset = "adtte", line_col = col)) + checkmate::assert_true(grid::is.grob(res)) + res <- expect_silent(run(kmg01_1, filter_data, dataset = "adtte", line_col = unname(col))) + checkmate::assert_true(grid::is.grob(res)) +}) + +test_that("kmg01_1 works if change pvalue, ties and conf level", { + filter_data <- dunlin::log_filter(syn_data, PARAMCD == "OS", "adtte") + res <- expect_silent(run(kmg01_1, filter_data, + dataset = "adtte", + pval_method = "log-rank", + ties = "efron", + conf_level = 0.99 + )) + checkmate::assert_true(grid::is.grob(res)) +}) + + +test_that("kmg01_1 works if change annotation position", { + filter_data <- dunlin::log_filter(syn_data, PARAMCD == "OS", "adtte") + res <- expect_silent(run(kmg01_1, filter_data, + dataset = "adtte", show_statis = FALSE, + position_coxph = c(0.4, 0.5), position_surv_med = c(1, 0.7) + )) + checkmate::assert_true(grid::is.grob(res)) +})