The LBT03 template is the result of a junction between the analysis of AVAL at baseline and CHG at visit time. AVAL is summarized for baseline visits and and CHG is summarized for post-baseline visits.
A: Drug X B: Placebo C: Combination
Analysis Visit (N=134) (N=134) (N=132)
—————————————————————————————————————————————————————————————
BASELINE
n 134 134 132
Mean (SD) 9.06 (0.93) 8.99 (0.98) 8.98 (0.89)
Median 9.07 8.92 8.96
Min - Max 6.21 - 11.87 6.23 - 11.63 6.24 - 11.18
WEEK 1 DAY 8
n 134 0 132
Mean (SD) -0.05 (1.38) NA -0.02 (1.30)
Median -0.17 NA 0.02
Min - Max -3.56 - 3.48 NA -3.28 - 3.33
WEEK 2 DAY 15
n 134 134 132
Mean (SD) -0.19 (1.47) 0.01 (1.45) 0.15 (1.25)
Median -0.27 -0.00 0.15
Min - Max -4.53 - 4.45 -3.79 - 3.43 -2.92 - 3.28
WEEK 3 DAY 22
n 134 134 132
Mean (SD) 0.03 (1.38) -0.02 (1.49) 0.02 (1.34)
Median 0.15 -0.04 0.20
Min - Max -3.95 - 2.99 -4.28 - 4.24 -2.76 - 3.26
WEEK 4 DAY 29
n 134 134 132
Mean (SD) -0.26 (1.45) 0.05 (1.24) -0.01 (1.17)
Median -0.37 0.10 -0.06
Min - Max -3.74 - 4.15 -3.34 - 3.71 -3.06 - 3.22
WEEK 5 DAY 36
n 134 134 132
Mean (SD) -0.02 (1.50) 0.07 (1.34) 0.03 (1.27)
Median 0.01 0.15 0.05
Min - Max -4.15 - 3.96 -3.50 - 3.53 -3.63 - 4.78
Experimental use!
WebR is a tool allowing you to run R code in the web browser. Modify the code below and click run to see the results. Alternatively, copy the code and click here to open WebR in a new tab.
In the final step, a new variable is derived from AVISIT that can specify the method of estimation of the evaluated change.
adlb_f <- adlb_f %>%mutate(AVISIT_header =recode(AVISIT,"BASELINE"="BASELINE","WEEK 1 DAY 8"="WEEK 1 DAY 8 value minus baseline","WEEK 2 DAY 15"="WEEK 2 DAY 15 value minus baseline","WEEK 3 DAY 22"="WEEK 3 DAY 22 value minus baseline","WEEK 4 DAY 29"="WEEK 4 DAY 29 value minus baseline","WEEK 5 DAY 36"="WEEK 5 DAY 36 value minus baseline"))# Define the split functionsplit_fun <- drop_split_levelslyt <-basic_table(show_colcounts =TRUE) %>%split_cols_by("ARM") %>%split_rows_by("AVISIT_header",split_fun = split_fun,label_pos ="topleft",split_label =obj_label(adlb_f$AVISIT) ) %>%summarize_change("CHG",variables =list(value ="AVAL", baseline_flag ="ABLFLL"),na.rm =TRUE )result <-build_table(lyt = lyt,df = adlb_f,alt_counts_df = adsl)result
A: Drug X B: Placebo C: Combination
Analysis Visit (N=134) (N=134) (N=132)
—————————————————————————————————————————————————————————————————————————————————
BASELINE
n 134 134 132
Mean (SD) 9.06 (0.93) 8.99 (0.98) 8.98 (0.89)
Median 9.07 8.92 8.96
Min - Max 6.21 - 11.87 6.23 - 11.63 6.24 - 11.18
WEEK 1 DAY 8 value minus baseline
n 134 0 132
Mean (SD) -0.05 (1.38) NA -0.02 (1.30)
Median -0.17 NA 0.02
Min - Max -3.56 - 3.48 NA -3.28 - 3.33
WEEK 2 DAY 15 value minus baseline
n 134 134 132
Mean (SD) -0.19 (1.47) 0.01 (1.45) 0.15 (1.25)
Median -0.27 -0.00 0.15
Min - Max -4.53 - 4.45 -3.79 - 3.43 -2.92 - 3.28
WEEK 3 DAY 22 value minus baseline
n 134 134 132
Mean (SD) 0.03 (1.38) -0.02 (1.49) 0.02 (1.34)
Median 0.15 -0.04 0.20
Min - Max -3.95 - 2.99 -4.28 - 4.24 -2.76 - 3.26
WEEK 4 DAY 29 value minus baseline
n 134 134 132
Mean (SD) -0.26 (1.45) 0.05 (1.24) -0.01 (1.17)
Median -0.37 0.10 -0.06
Min - Max -3.74 - 4.15 -3.34 - 3.71 -3.06 - 3.22
WEEK 5 DAY 36 value minus baseline
n 134 134 132
Mean (SD) -0.02 (1.50) 0.07 (1.34) 0.03 (1.27)
Median 0.01 0.15 0.05
Min - Max -4.15 - 3.96 -3.50 - 3.53 -3.63 - 4.78
Experimental use!
WebR is a tool allowing you to run R code in the web browser. Modify the code below and click run to see the results. Alternatively, copy the code and click here to open WebR in a new tab.
For illustration purposes, this example focuses on “C-Reactive Protein Measurement” starting from baseline, while excluding visit at week 1 for subjects who were randomized to the placebo group.
Code
library(dplyr)library(tern)adsl <- random.cdisc.data::cadsladlb <- random.cdisc.data::cadlb# Ensure character variables are converted to factors and empty strings and NAs are explicit missing levels.adsl <-df_explicit_na(adsl)adlb <-df_explicit_na(adlb)saved_labels <-var_labels(adlb)adlb_f <- adlb %>%filter( PARAM =="C-Reactive Protein Measurement",!(ARM =="B: Placebo"& AVISIT =="WEEK 1 DAY 8"), AVISIT !="SCREENING" ) %>% dplyr::mutate(AVISIT =droplevels(AVISIT),ABLFLL = ABLFL =="Y" )var_labels(adlb_f) <-c(saved_labels, "")
Here, we pre-process and manually define the variable “Baseline or Absolute Change from Baseline”.
Code
library(teal.modules.clinical)## Data reproducible codedata <-teal_data()data <-within(data, { ADSL <-df_explicit_na(random.cdisc.data::cadsl) ADLB <-df_explicit_na(random.cdisc.data::cadlb) %>%filter(!(ARM =="B: Placebo"& AVISIT =="WEEK 1 DAY 8"), AVISIT !="SCREENING" ) %>%mutate(AVISIT =droplevels(AVISIT),ABLFLL = ABLFL =="Y",AVISIT_header =recode(AVISIT,"BASELINE"="BASELINE","WEEK 1 DAY 8"="WEEK 1 DAY 8 value minus baseline","WEEK 2 DAY 15"="WEEK 2 DAY 15 value minus baseline","WEEK 3 DAY 22"="WEEK 3 DAY 22 value minus baseline","WEEK 4 DAY 29"="WEEK 4 DAY 29 value minus baseline","WEEK 5 DAY 36"="WEEK 5 DAY 36 value minus baseline" ) ) %>%group_by(USUBJID, PARAM) %>%mutate(AVAL_CHG = AVAL - (!ABLFLL) *sum(AVAL * ABLFLL) ) %>%ungroup() %>%col_relabel(AVAL_CHG ="Baseline or Absolute Change from Baseline",ABLFLL ="Baseline Flag (TRUE/FALSE)",AVISIT_header ="Analysis Visit" )})datanames <-c("ADSL", "ADLB")datanames(data) <- datanamesjoin_keys(data) <- default_cdisc_join_keys[datanames]## Reusable Configuration For ModulesADSL <- data[["ADSL"]]ADLB <- data[["ADLB"]]## Setup Appapp <-init(data = data,modules =modules(tm_t_summary_by(label ="Laboratory Test Results Change from Baseline by Visit",dataname ="ADLB",arm_var =choices_selected(choices =variable_choices(ADSL, c("ARM", "ARMCD")),selected ="ARM" ),by_vars =choices_selected(# note: order matters here. If `PARAM` is first, the split will be first by `PARAM`and then by `AVISIT`choices =variable_choices(ADLB, c("PARAM", "AVISIT_header")),selected =c("PARAM", "AVISIT_header") ),summarize_vars =choices_selected(choices =variable_choices(ADLB, c("AVAL", "CHG", "AVAL_CHG")),selected =c("AVAL_CHG") ),useNA ="ifany",paramcd =choices_selected(choices =value_choices(ADLB, "PARAMCD", "PARAM"),selected ="CRP" ) ) ),filter =teal_slices(teal_slice("ADLB", "AVAL", selected =NULL)))shinyApp(app$ui, app$server)
Experimental use!
shinylive allow you to modify to run shiny application entirely in the web browser. Modify the code below and click re-run the app to see the results. The performance is slighly worse and some of the features (e.g. downloading) might not work at all.
#| standalone: true#| viewerHeight: 800#| editorHeight: 200#| components: [viewer, editor]#| layout: vertical# -- WEBR HELPERS --options(webr_pkg_repos = c("r-universe" = "https://pharmaverse.r-universe.dev", getOption("webr_pkg_repos")))# -- APP CODE --library(teal.modules.clinical)## Data reproducible codedata <- teal_data()data <- within(data, { ADSL <- df_explicit_na(random.cdisc.data::cadsl) ADLB <- df_explicit_na(random.cdisc.data::cadlb) %>% filter( !(ARM == "B: Placebo" & AVISIT == "WEEK 1 DAY 8"), AVISIT != "SCREENING" ) %>% mutate( AVISIT = droplevels(AVISIT), ABLFLL = ABLFL == "Y", AVISIT_header = recode(AVISIT, "BASELINE" = "BASELINE", "WEEK 1 DAY 8" = "WEEK 1 DAY 8 value minus baseline", "WEEK 2 DAY 15" = "WEEK 2 DAY 15 value minus baseline", "WEEK 3 DAY 22" = "WEEK 3 DAY 22 value minus baseline", "WEEK 4 DAY 29" = "WEEK 4 DAY 29 value minus baseline", "WEEK 5 DAY 36" = "WEEK 5 DAY 36 value minus baseline" ) ) %>% group_by(USUBJID, PARAM) %>% mutate( AVAL_CHG = AVAL - (!ABLFLL) * sum(AVAL * ABLFLL) ) %>% ungroup() %>% col_relabel( AVAL_CHG = "Baseline or Absolute Change from Baseline", ABLFLL = "Baseline Flag (TRUE/FALSE)", AVISIT_header = "Analysis Visit" )})datanames <- c("ADSL", "ADLB")datanames(data) <- datanamesjoin_keys(data) <- default_cdisc_join_keys[datanames]## Reusable Configuration For ModulesADSL <- data[["ADSL"]]ADLB <- data[["ADLB"]]## Setup Appapp <- init( data = data, modules = modules( tm_t_summary_by( label = "Laboratory Test Results Change from Baseline by Visit", dataname = "ADLB", arm_var = choices_selected( choices = variable_choices(ADSL, c("ARM", "ARMCD")), selected = "ARM" ), by_vars = choices_selected( # note: order matters here. If `PARAM` is first, the split will be first by `PARAM`and then by `AVISIT` choices = variable_choices(ADLB, c("PARAM", "AVISIT_header")), selected = c("PARAM", "AVISIT_header") ), summarize_vars = choices_selected( choices = variable_choices(ADLB, c("AVAL", "CHG", "AVAL_CHG")), selected = c("AVAL_CHG") ), useNA = "ifany", paramcd = choices_selected( choices = value_choices(ADLB, "PARAMCD", "PARAM"), selected = "CRP" ) ) ), filter = teal_slices(teal_slice("ADLB", "AVAL", selected = NULL)))shinyApp(app$ui, app$server)