Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add decorators to all TMC modules #1371

Closed
36 tasks done
gogonzo opened this issue Oct 9, 2024 · 1 comment
Closed
36 tasks done

Add decorators to all TMC modules #1371

gogonzo opened this issue Oct 9, 2024 · 1 comment
Assignees
Labels

Comments

@gogonzo
Copy link
Contributor

gogonzo commented Oct 9, 2024

Blocked by #1368

  • Assign yourself to a single module by adding your name next to the item.
  • add the decorator functionality to the module and update relevant documentation by including the decorator
  • Keep consistent output names - table, listing, graph
  • PR link should be added next to the item
  • once merged ✔️ the item

Items:

Part 1

Moved from part 2 to part 1

Part 2

Moved from part 1

@gogonzo gogonzo added this to the Decorate modules' output milestone Oct 9, 2024
@gogonzo gogonzo added the core label Oct 9, 2024
m7pr added a commit to insightsengineering/teal.modules.clinical that referenced this issue Nov 28, 2024
Part of insightsengineering/teal#1371

WIP

<details>
<summary> Example with decorator </summary>

```r
devtools::load_all("../teal")
devtools::load_all(".")
library(nestcolor)

data <- teal_data()
data <- within(data, {
  ADSL <- tmc_ex_adsl
  ADLB <- tmc_ex_adlb
})
join_keys(data) <- default_cdisc_join_keys[names(data)]

ADSL <- data[["ADSL"]]
ADLB <- data[["ADLB"]]

caption_decorator <- function(default_caption = "I am a good decorator", .var_to_replace = "plot") {
  teal_transform_module(
    label = "Caption",
    ui = function(id) shiny::textInput(shiny::NS(id, "footnote"), "Footnote", value = default_caption),
    server = make_teal_transform_server(
      substitute({
        .var_to_replace <- .var_to_replace + ggplot2::labs(caption = footnote)
      }, env = list(.var_to_replace = as.name(.var_to_replace)))
    )
  )
}



app <- init(
  data = data,
  modules = modules(
    tm_g_ci(
      label = "Confidence Interval Plot",
      x_var = data_extract_spec(
        dataname = "ADSL",
        select = select_spec(
          choices = c("ARMCD", "BMRKR2"),
          selected = c("ARMCD"),
          multiple = FALSE,
          fixed = FALSE
        )
      ),
      y_var = data_extract_spec(
        dataname = "ADLB",
        filter = list(
          filter_spec(
            vars = "PARAMCD",
            choices = levels(ADLB$PARAMCD),
            selected = levels(ADLB$PARAMCD)[1],
            multiple = FALSE,
            label = "Select lab:"
          ),
          filter_spec(
            vars = "AVISIT",
            choices = levels(ADLB$AVISIT),
            selected = levels(ADLB$AVISIT)[1],
            multiple = FALSE,
            label = "Select visit:"
          )
        ),
        select = select_spec(
          label = "Analyzed Value",
          choices = c("AVAL", "CHG"),
          selected = "AVAL",
          multiple = FALSE,
          fixed = FALSE
        )
      ),
      color = data_extract_spec(
        dataname = "ADSL",
        select = select_spec(
          label = "Color by variable",
          choices = c("SEX", "STRATA1", "STRATA2"),
          selected = c("STRATA1"),
          multiple = FALSE,
          fixed = FALSE
        )
      ),
      decorators = list(caption_decorator(.var_to_replace = "plot"))
    )
  )
)
shinyApp(app$ui, app$server)
```

</details>

---------

Co-authored-by: Marcin <[email protected]>
Co-authored-by: m7pr <[email protected]>
m7pr added a commit to insightsengineering/teal.modules.clinical that referenced this issue Nov 28, 2024
Part of insightsengineering/teal#1371

This module also returns a plot from `cowplot`, and I am not sure if the
example I got works well (I am not that familiar with it).

<details>
<summary>Draft of an example</summary>

````r
devtools::load_all("../teal.reporter")
devtools::load_all("../teal")
devtools::load_all(".")
library(nestcolor)
library(dplyr)

caption_decorator <- function(annotation = "I am a good decorator", var_to_decorate = "plot") {
  teal_transform_module(
    label = "Annotation",
    ui = function(id) shiny::textInput(shiny::NS(id, "annotation"), "Annotation", value = annotation),
    server = make_teal_transform_server(
      substitute({
        var_to_decorate <- cowplot::add_sub(var_to_decorate, annotation)
      }, env = list(var_to_decorate = as.name(var_to_decorate)))
    )
  )
}

data <- teal_data()
data <- within(data, {
  ADSL <- tmc_ex_adsl
  ADRS <- tmc_ex_adrs %>%
    mutate(AVALC = d_onco_rsp_label(AVALC) %>%
             with_label("Character Result/Finding")) %>%
    filter(PARAMCD != "OVRINV" | AVISIT == "FOLLOW UP")
})
join_keys(data) <- default_cdisc_join_keys[names(data)]

ADSL <- data[["ADSL"]]
ADRS <- data[["ADRS"]]

arm_ref_comp <- list(
  ARM = list(
    ref = "B: Placebo",
    comp = c("A: Drug X", "C: Combination")
  ),
  ARMCD = list(
    ref = "ARM B",
    comp = c("ARM A", "ARM C")
  )
)

app <- init(
  data = data,
  modules = modules(
    tm_g_forest_rsp(
      label = "Forest Response",
      dataname = "ADRS",
      arm_var = choices_selected(
        variable_choices(ADSL, c("ARM", "ARMCD")),
        "ARMCD"
      ),
      arm_ref_comp = arm_ref_comp,
      paramcd = choices_selected(
        value_choices(ADRS, "PARAMCD", "PARAM"),
        "INVET"
      ),
      subgroup_var = choices_selected(
        variable_choices(ADSL, names(ADSL)),
        c("BMRKR2", "SEX")
      ),
      strata_var = choices_selected(
        variable_choices(ADSL, c("STRATA1", "STRATA2")),
        "STRATA2"
      ),
      plot_height = c(600L, 200L, 2000L),
      default_responses = list(
        BESRSPI = list(
          rsp = c("Stable Disease (SD)", "Not Evaluable (NE)"),
          levels = c(
            "Complete Response (CR)", "Partial Response (PR)", "Stable Disease (SD)",
            "Progressive Disease (PD)", "Not Evaluable (NE)"
          )
        ),
        INVET = list(
          rsp = c("Complete Response (CR)", "Partial Response (PR)"),
          levels = c(
            "Complete Response (CR)", "Not Evaluable (NE)", "Partial Response (PR)",
            "Progressive Disease (PD)", "Stable Disease (SD)"
          )
        ),
        OVRINV = list(
          rsp = c("Progressive Disease (PD)", "Stable Disease (SD)"),
          levels = c("Progressive Disease (PD)", "Stable Disease (SD)", "Not Evaluable (NE)")
        )
      ),
      decorators = list(caption_decorator())
    )
  )
)
shinyApp(app$ui, app$server)


```

</details>

---------

Co-authored-by: Marcin <[email protected]>
Co-authored-by: m7pr <[email protected]>
m7pr added a commit to insightsengineering/teal.modules.clinical that referenced this issue Nov 28, 2024
Part of insightsengineering/teal#1371

<details><summary> Working Example </summary>

```r
devtools::load_all("../teal.reporter")
devtools::load_all("../teal")
devtools::load_all(".")
library(nestcolor)
library(dplyr)

caption_decorator <- function(annotation = "I am a good decorator", var_to_decorate = "plot") {
  teal_transform_module(
    label = "Annotation",
    ui = function(id) shiny::textInput(shiny::NS(id, "annotation"), "Annotation", value = annotation),
    server = make_teal_transform_server(
      substitute({
        var_to_decorate <- cowplot::add_sub(var_to_decorate, annotation)
      }, env = list(var_to_decorate = as.name(var_to_decorate)))
    )
  )
}

data <- teal_data()
data <- within(data, {
  ADSL <- tmc_ex_adsl
  ADTTE <- tmc_ex_adtte
  ADSL$RACE <- droplevels(ADSL$RACE) %>% with_label("Race")
})
join_keys(data) <- default_cdisc_join_keys[names(data)]

ADSL <- data[["ADSL"]]
ADTTE <- data[["ADTTE"]]

arm_ref_comp <- list(
  ARM = list(
    ref = "B: Placebo",
    comp = c("A: Drug X", "C: Combination")
  ),
  ARMCD = list(
    ref = "ARM B",
    comp = c("ARM A", "ARM C")
  )
)

app <- init(
  data = data,
  modules = modules(
    tm_g_forest_tte(
      label = "Forest Survival",
      dataname = "ADTTE",
      arm_var = choices_selected(
        variable_choices(ADSL, c("ARM", "ARMCD")),
        "ARMCD"
      ),
      arm_ref_comp = arm_ref_comp,
      paramcd = choices_selected(
        value_choices(ADTTE, "PARAMCD", "PARAM"),
        "OS"
      ),
      subgroup_var = choices_selected(
        variable_choices(ADSL, names(ADSL)),
        c("BMRKR2", "SEX")
      ),
      strata_var = choices_selected(
        variable_choices(ADSL, c("STRATA1", "STRATA2")),
        "STRATA2"
      ),
      decorators = list(caption_decorator())
    )
  )
)
shinyApp(app$ui, app$server)


```

</details>
m7pr added a commit to insightsengineering/teal.modules.clinical that referenced this issue Nov 28, 2024
Part of insightsengineering/teal#1371

Alternative to
#1259

<details><summary> Working Example </summary>

```r
devtools::load_all("../teal.reporter")
devtools::load_all("../teal")
devtools::load_all(".")

insert_rrow_decorator <- function(default_caption = "I am a good new row", .var_to_replace = "table") {
  teal_transform_module(
    label = "New row",
    ui = function(id) shiny::textInput(shiny::NS(id, "new_row"), "New row", value = default_caption),
    server = make_teal_transform_server(
      substitute({
        .var_to_replace <- rtables::insert_rrow(.var_to_replace, rtables::rrow(new_row))
      }, env = list(.var_to_replace = as.name(.var_to_replace)))
    )
  )
}

library(dplyr)

data <- teal_data()
data <- within(data, {
  ADSL <- tmc_ex_adsl
  ADQS <- tmc_ex_adqs %>%
    filter(ABLFL != "Y" & ABLFL2 != "Y") %>%
    mutate(
      AVISIT = as.factor(AVISIT),
      AVISITN = rank(AVISITN) %>%
        as.factor() %>%
        as.numeric() %>%
        as.factor(),
      AVALBIN = AVAL < 50 # Just as an example to get a binary endpoint.
    ) %>%
    droplevels()
})
join_keys(data) <- default_cdisc_join_keys[names(data)]

app <- init(
  data = data,
  modules = modules(
    tm_a_gee(
      label = "GEE",
      dataname = "ADQS",
      aval_var = choices_selected("AVALBIN", fixed = TRUE),
      id_var = choices_selected(c("USUBJID", "SUBJID"), "USUBJID"),
      arm_var = choices_selected(c("ARM", "ARMCD"), "ARM"),
      visit_var = choices_selected(c("AVISIT", "AVISITN"), "AVISIT"),
      paramcd = choices_selected(
        choices = value_choices(data[["ADQS"]], "PARAMCD", "PARAM"),
        selected = "FKSI-FWB"
      ),
      cov_var = choices_selected(c("BASE", "AGE", "SEX", "BASE:AVISIT"), NULL),
      decorators = list(insert_rrow_decorator("Hello world", "table"))
    )
  )
)
if (interactive()) {
  shinyApp(app$ui, app$server)
}


```

</details>
m7pr added a commit to insightsengineering/teal.modules.clinical that referenced this issue Nov 28, 2024
Part of insightsengineering/teal#1371

<details><summary> Working Example </summary>

```r

devtools::load_all("../teal")
devtools::load_all(".")

library(nestcolor)
library(dplyr)

data <- teal_data()
data <- within(data, {
  ADSL <- tmc_ex_adsl %>%
    slice(1:20) %>%
    df_explicit_na()
  ADLB <- tmc_ex_adlb %>%
    filter(USUBJID %in% ADSL$USUBJID) %>%
    df_explicit_na() %>%
    filter(AVISIT != "SCREENING")
})
join_keys(data) <- default_cdisc_join_keys[names(data)]

ADSL <- data[["ADSL"]]
ADLB <- data[["ADLB"]]

caption_decorator <- function(default_caption = "I am a good decorator", .var_to_replace = "plot") {
  teal_transform_module(
    label = "Caption",
    ui = function(id) shiny::textInput(shiny::NS(id, "footnote"), "Footnote", value = default_caption),
    server = make_teal_transform_server(
      substitute({
        .var_to_replace <- .var_to_replace + ggplot2::labs(caption = footnote)
      }, env = list(.var_to_replace = as.name(.var_to_replace)))
    )
  )
}

app <- init(
  data = data,
  modules = modules(
    tm_g_ipp(
      label = "Individual Patient Plot",
      dataname = "ADLB",
      arm_var = choices_selected(
        value_choices(ADLB, "ARMCD"),
        "ARM A"
      ),
      paramcd = choices_selected(
        value_choices(ADLB, "PARAMCD"),
        "ALT"
      ),
      aval_var = choices_selected(
        variable_choices(ADLB, c("AVAL", "CHG")),
        "AVAL"
      ),
      avalu_var = choices_selected(
        variable_choices(ADLB, c("AVALU")),
        "AVALU",
        fixed = TRUE
      ),
      id_var = choices_selected(
        variable_choices(ADLB, c("USUBJID")),
        "USUBJID",
        fixed = TRUE
      ),
      visit_var = choices_selected(
        variable_choices(ADLB, c("AVISIT")),
        "AVISIT"
      ),
      baseline_var = choices_selected(
        variable_choices(ADLB, c("BASE")),
        "BASE",
        fixed = TRUE
      ),
      add_baseline_hline = FALSE,
      separate_by_obs = FALSE,
      decorators = list(caption_decorator(.var_to_replace = "plot"))
    )
  )
)
if (interactive()) {
  shinyApp(app$ui, app$server)
}

```

</details>
m7pr added a commit to insightsengineering/teal.modules.clinical that referenced this issue Nov 29, 2024
Part of insightsengineering/teal#1371

<details>
<summary>Example using cowplot::add_sub with ggplot2</summary>

```r
devtools::load_all("../teal.modules.general")
devtools::load_all("../teal.reporter")
devtools::load_all("../teal")
devtools::load_all(".")
library(nestcolor)
library(dplyr)

data <- teal_data()
data <- within(data, {
  ADAE <- tmc_ex_adae
  ADSL <- tmc_ex_adsl %>%
    filter(USUBJID %in% ADAE$USUBJID)
  ADCM <- tmc_ex_adcm %>%
    mutate(
      CMSTDY = case_when(
        CMCAT == "medcl B" ~ 20,
        CMCAT == "medcl C" ~ 150,
        TRUE ~ 1
      ) %>% with_label("Study Day of Start of Medication"),
      CMENDY = case_when(
        CMCAT == "medcl B" ~ 700,
        CMCAT == "medcl C" ~ 1000,
        TRUE ~ 500
      ) %>% with_label("Study Day of End of Medication"),
      CMASTDTM = ASTDTM,
      CMAENDTM = AENDTM
    )
})

join_keys(data) <- default_cdisc_join_keys[c("ADSL", "ADAE", "ADCM")]
adcm_keys <- c("STUDYID", "USUBJID", "ASTDTM", "CMSEQ", "ATC1", "ATC2", "ATC3", "ATC4")
join_keys(data)["ADCM", "ADCM"] <- adcm_keys
join_keys(data)["ADAE", "ADCM"] <- c("STUDYID", "USUBJID")


caption_decorator <- function(annotation = "I am a good decorator", var_to_decorate = "plot") {
  teal_transform_module(
    label = "Annotation",
    ui = function(id) shiny::textInput(shiny::NS(id, "annotation"), "Annotation", value = annotation),
    server = make_teal_transform_server(
      substitute({
        var_to_decorate <- cowplot::add_sub(var_to_decorate, annotation)
      }, env = list(var_to_decorate = as.name(var_to_decorate)))
    )
  )
}


app <- init(
  data = data,
  modules = modules(
    tm_g_pp_patient_timeline(
      label = "Patient Timeline",
      dataname_adae = "ADAE",
      dataname_adcm = "ADCM",
      parentname = "ADSL",
      patient_col = "USUBJID",
      plot_height = c(600L, 200L, 2000L),
      cmdecod = choices_selected(
        choices = variable_choices(data[["ADCM"]], "CMDECOD"),
        selected = "CMDECOD",
      ),
      aeterm = choices_selected(
        choices = variable_choices(data[["ADAE"]], "AETERM"),
        selected = c("AETERM")
      ),
      aetime_start = choices_selected(
        choices = variable_choices(data[["ADAE"]], "ASTDTM"),
        selected = c("ASTDTM")
      ),
      aetime_end = choices_selected(
        choices = variable_choices(data[["ADAE"]], "AENDTM"),
        selected = c("AENDTM")
      ),
      dstime_start = choices_selected(
        choices = variable_choices(data[["ADCM"]], "CMASTDTM"),
        selected = c("CMASTDTM")
      ),
      dstime_end = choices_selected(
        choices = variable_choices(data[["ADCM"]], "CMAENDTM"),
        selected = c("CMAENDTM")
      ),
      aerelday_start = choices_selected(
        choices = variable_choices(data[["ADAE"]], "ASTDY"),
        selected = c("ASTDY")
      ),
      aerelday_end = choices_selected(
        choices = variable_choices(data[["ADAE"]], "AENDY"),
        selected = c("AENDY")
      ),
      dsrelday_start = choices_selected(
        choices = variable_choices(data[["ADCM"]], "ASTDY"),
        selected = c("ASTDY")
      ),
      dsrelday_end = choices_selected(
        choices = variable_choices(data[["ADCM"]], "AENDY"),
        selected = c("AENDY")
      ),
      decorators = list(caption_decorator())
    )
  )
)
shinyApp(app$ui, app$server)
```

</details>

---------

Co-authored-by: m7pr <[email protected]>
m7pr added a commit to insightsengineering/teal.modules.clinical that referenced this issue Nov 29, 2024
Part of insightsengineering/teal#1371

<details><summary> Working Example </summary>

```r
devtools::load_all("../teal.reporter")
devtools::load_all("../teal")
devtools::load_all(".")

library(nestcolor)
library(dplyr)

data <- teal_data()
data <- within(data, {
  ADCM <- tmc_ex_adcm
  ADSL <- tmc_ex_adsl %>% filter(USUBJID %in% ADCM$USUBJID)
  ADCM$CMASTDTM <- ADCM$ASTDTM
  ADCM$CMAENDTM <- ADCM$AENDTM
})

join_keys(data) <- default_cdisc_join_keys[c("ADSL", "ADCM")]
adcm_keys <- c("STUDYID", "USUBJID", "ASTDTM", "CMSEQ", "ATC1", "ATC2", "ATC3", "ATC4")
join_keys(data)["ADCM", "ADCM"] <- adcm_keys

ADSL <- data[["ADSL"]]
ADCM <- data[["ADCM"]]

caption_decorator <- function(default_caption = "I am a good decorator", .var_to_replace = "plot") {
  teal_transform_module(
    label = "Caption",
    ui = function(id) shiny::textInput(shiny::NS(id, "footnote"), "Footnote", value = default_caption),
    server = make_teal_transform_server(
      substitute({
        .var_to_replace <- .var_to_replace + ggplot2::labs(caption = footnote)
      }, env = list(.var_to_replace = as.name(.var_to_replace)))
    )
  )
}

head_decorator <- function(default_value = 6, .var_to_replace = "object") {
  teal_transform_module(
    label = "Head",
    ui = function(id) shiny::numericInput(shiny::NS(id, "n"), "N rows", value = default_value),
    server = make_teal_transform_server(
      substitute({
        .var_to_replace <- utils::head(.var_to_replace, n = n)
      }, env = list(.var_to_replace = as.name(.var_to_replace)))
    )
  )
}

app <- init(
  data = data,
  modules = modules(
    tm_g_pp_therapy(
      label = "Therapy",
      dataname = "ADCM",
      parentname = "ADSL",
      patient_col = "USUBJID",
      plot_height = c(600L, 200L, 2000L),
      atirel = choices_selected(
        choices = variable_choices(ADCM, "ATIREL"),
        selected = c("ATIREL")
      ),
      cmdecod = choices_selected(
        choices = variable_choices(ADCM, "CMDECOD"),
        selected = "CMDECOD"
      ),
      cmindc = choices_selected(
        choices = variable_choices(ADCM, "CMINDC"),
        selected = "CMINDC"
      ),
      cmdose = choices_selected(
        choices = variable_choices(ADCM, "CMDOSE"),
        selected = "CMDOSE"
      ),
      cmtrt = choices_selected(
        choices = variable_choices(ADCM, "CMTRT"),
        selected = "CMTRT"
      ),
      cmdosu = choices_selected(
        choices = variable_choices(ADCM, "CMDOSU"),
        selected = c("CMDOSU")
      ),
      cmroute = choices_selected(
        choices = variable_choices(ADCM, "CMROUTE"),
        selected = "CMROUTE"
      ),
      cmdosfrq = choices_selected(
        choices = variable_choices(ADCM, "CMDOSFRQ"),
        selected = "CMDOSFRQ"
      ),
      cmstdy = choices_selected(
        choices = variable_choices(ADCM, "ASTDY"),
        selected = "ASTDY"
      ),
      cmendy = choices_selected(
        choices = variable_choices(ADCM, "AENDY"),
        selected = "AENDY"
      ),
      decorators = list(plot = caption_decorator('Marcin', 'plot'), table = head_decorator(2, 'table'))
    )
  )
)
if (interactive()) {
  shinyApp(app$ui, app$server)
}
```

</details>
m7pr added a commit to insightsengineering/teal.modules.clinical that referenced this issue Nov 29, 2024
Part of insightsengineering/teal#1371

<details><summary> Working Example </summary>

```r
devtools::load_all("../teal")
devtools::load_all(".")

library(nestcolor)

data <- teal_data()
data <- within(data, {
  ADSL <- tmc_ex_adsl
  ADVS <- tmc_ex_advs
})
join_keys(data) <- default_cdisc_join_keys[names(data)]

ADSL <- data[["ADSL"]]
ADVS <- data[["ADVS"]]

change_theme_decorator <- function(default_check = TRUE, .var_to_replace = "plot") {
  teal_transform_module(
    label = "Theme",
    server = make_teal_transform_server(
      substitute({
        .var_to_replace <- .var_to_replace + ggplot2::theme_void()
      }, 
      env = list(.var_to_replace = as.name(.var_to_replace))
      )
    )
  )
}

app <- init(
  data = data,
  modules = modules(
    tm_g_pp_vitals(
      label = "Vitals",
      dataname = "ADVS",
      parentname = "ADSL",
      patient_col = "USUBJID",
      plot_height = c(600L, 200L, 2000L),
      paramcd = choices_selected(
        choices = variable_choices(ADVS, "PARAMCD"),
        selected = "PARAMCD"
      ),
      xaxis = choices_selected(
        choices = variable_choices(ADVS, "ADY"),
        selected = "ADY"
      ),
      aval_var = choices_selected(
        choices = variable_choices(ADVS, "AVAL"),
        selected = "AVAL"
      )#,
      #decorators = list(plot = change_theme_decorator(TRUE, "plot"))
    )
  )
)
if (interactive()) {
  shinyApp(app$ui, app$server)
}devtools::load_all("../teal")
devtools::load_all(".")

library(nestcolor)
library(dplyr)
library(forcats)

data <- teal_data()
data <- within(data, {
  ADSL <- tmc_ex_adsl
  ADLB <- tmc_ex_adlb %>%
    mutate(AVISIT == fct_reorder(AVISIT, AVISITN, min))
})
join_keys(data) <- default_cdisc_join_keys[names(data)]

ADSL <- data[["ADSL"]]
ADLB <- data[["ADLB"]]

change_theme_decorator <- function(default_check = TRUE, .var_to_replace = "plot") {
  teal_transform_module(
    label = "Theme",
    server = make_teal_transform_server(
      substitute({
        .var_to_replace <- .var_to_replace + ggplot2::theme_void()
      }, 
      env = list(.var_to_replace = as.name(.var_to_replace))
      )
    )
  )
}

app <- init(
  data = data,
  modules = modules(
    tm_g_lineplot(
      label = "Line Plot",
      dataname = "ADLB",
      strata = choices_selected(
        variable_choices(ADSL, c("ARM", "ARMCD", "ACTARMCD")),
        "ARM"
      ),
      y = choices_selected(
        variable_choices(ADLB, c("AVAL", "BASE", "CHG", "PCHG")),
        "AVAL"
      ),
      param = choices_selected(
        value_choices(ADLB, "PARAMCD", "PARAM"),
        "ALT"
      ),
      decorators = list(plot = change_theme_decorator(TRUE, "plot"))
    )
  )
)
if (interactive()) {
  shinyApp(app$ui, app$server)
}
```

</details>

---------

Co-authored-by: André Veríssimo <[email protected]>
m7pr added a commit to insightsengineering/teal.modules.clinical that referenced this issue Nov 29, 2024
Part of insightsengineering/teal#1371

<details><summary> Working Example </summary>

```r
devtools::load_all("../teal")
devtools::load_all(".")

insert_rrow_decorator <- function(default_caption = "I am a good new row", .var_to_replace = "table") {
  teal_transform_module(
    label = "New row",
    ui = function(id) shiny::textInput(shiny::NS(id, "new_row"), "New row", value = default_caption),
    server = make_teal_transform_server(
      substitute({
        .var_to_replace <- rtables::insert_rrow(.var_to_replace, rtables::rrow(new_row))
      }, env = list(.var_to_replace = as.name(.var_to_replace)))
    )
  )
}

library(dplyr)

data <- teal_data()
data <- within(data, {
  ADSL <- tmc_ex_adsl
  ADLB <- tmc_ex_adlb %>%
    mutate(
      ONTRTFL = case_when(
        AVISIT %in% c("SCREENING", "BASELINE") ~ "",
        TRUE ~ "Y"
      ) %>% with_label("On Treatment Record Flag")
    )
})
join_keys(data) <- default_cdisc_join_keys[names(data)]

ADSL <- data[["ADSL"]]
ADLB <- data[["ADLB"]]

app <- init(
  data = data,
  modules = modules(
    tm_t_abnormality(
      label = "Abnormality Table",
      dataname = "ADLB",
      arm_var = choices_selected(
        choices = variable_choices(ADSL, subset = c("ARM", "ARMCD")),
        selected = "ARM"
      ),
      add_total = FALSE,
      by_vars = choices_selected(
        choices = variable_choices(ADLB, subset = c("LBCAT", "PARAM", "AVISIT")),
        selected = c("LBCAT", "PARAM"),
        keep_order = TRUE
      ),
      baseline_var = choices_selected(
        variable_choices(ADLB, subset = "BNRIND"),
        selected = "BNRIND", fixed = TRUE
      ),
      grade = choices_selected(
        choices = variable_choices(ADLB, subset = "ANRIND"),
        selected = "ANRIND",
        fixed = TRUE
      ),
      abnormal = list(low = "LOW", high = "HIGH"),
      exclude_base_abn = FALSE,
      decorators = list(insert_rrow_decorator("I am a good new row"))
    )
  )
)
if (interactive()) {
  shinyApp(app$ui, app$server)
}

```

</details>

---------

Co-authored-by: Lluís Revilla <[email protected]>
Co-authored-by: André Veríssimo <[email protected]>
m7pr added a commit to insightsengineering/teal.modules.clinical that referenced this issue Dec 9, 2024
Part of insightsengineering/teal#1371

<details><summary> Working Example </summary>

```r
pkgload::load_all("../teal.modules.clinical", export_all = FALSE)

library(nestcolor)
library(dplyr)

data <- teal_data()
data <- within(data, {
  ADAE <- tmc_ex_adae
  ADSL <- tmc_ex_adsl %>%
    filter(USUBJID %in% ADAE$USUBJID)

  ADAE$ASTDY <- structure(
    as.double(ADAE$ASTDY, unit = attr(ADAE$ASTDY, "units", exact = TRUE)),
    label = attr(ADAE$ASTDY, "label", exact = TRUE)
  )
})
join_keys(data) <- default_cdisc_join_keys[names(data)]

ADSL <- data[["ADSL"]]
ADAE <- data[["ADAE"]]

caption_decorator <- function(default_caption = "I am a good decorator", .var_to_replace = "plot") {
  teal_transform_module(
    label = "Caption",
    ui = function(id) shiny::textInput(shiny::NS(id, "footnote"), "Footnote", value = default_caption),
    server = make_teal_transform_server(
      substitute({
        .var_to_replace <- .var_to_replace + ggplot2::labs(caption = footnote)
      }, env = list(.var_to_replace = as.name(.var_to_replace)))
    )
  )
}

head_decorator <- function(default_value = 6, .var_to_replace = "object") {
  teal_transform_module(
    label = "Head",
    ui = function(id) shiny::numericInput(shiny::NS(id, "n"), "N rows", value = default_value),
    server = make_teal_transform_server(
      substitute({
        .var_to_replace <- utils::head(.var_to_replace, n = n)
      }, env = list(.var_to_replace = as.name(.var_to_replace)))
    )
  )
}

app <- init(
  data = data,
  modules = modules(
    tm_g_pp_adverse_events(
      label = "Adverse Events",
      dataname = "ADAE",
      parentname = "ADSL",
      patient_col = "USUBJID",
      plot_height = c(600L, 200L, 2000L),
      aeterm = choices_selected(
        choices = variable_choices(ADAE, "AETERM"),
        selected = "AETERM"
      ),
      tox_grade = choices_selected(
        choices = variable_choices(ADAE, "AETOXGR"),
        selected = "AETOXGR"
      ),
      causality = choices_selected(
        choices = variable_choices(ADAE, "AEREL"),
        selected = "AEREL"
      ),
      outcome = choices_selected(
        choices = variable_choices(ADAE, "AEOUT"),
        selected = "AEOUT"
      ),
      action = choices_selected(
        choices = variable_choices(ADAE, "AEACN"),
        selected = "AEACN"
      ),
      time = choices_selected(
        choices = variable_choices(ADAE, "ASTDY"),
        selected = "ASTDY"
      ),
      decod = NULL,
      decorators = list(plot = caption_decorator('Marcin', 'plot'), table = head_decorator(2, 'table'))
    )
  )
) |> shiny::runApp()

```

</details>

---------

Signed-off-by: Marcin <[email protected]>
Co-authored-by: André Veríssimo <[email protected]>
llrs-roche pushed a commit to insightsengineering/teal.modules.clinical that referenced this issue Dec 9, 2024
Part of insightsengineering/teal#1371

<details>
<summary>Working example</summary>

```r
pkgload::load_all("../teal.modules.clinical", export_all = FALSE)
# Example below

rlisting_footer <- function(default_footer = "I am a good footer", .var_to_replace = "table_listing") {
  teal_transform_module(
    label = "New row",
    ui = function(id) shiny::textInput(shiny::NS(id, "footer"), "footer", value = default_footer),
    server = make_teal_transform_server(
      substitute({
        rlistings::main_footer(.var_to_replace) <- footer
      }, env = list(.var_to_replace = as.name(.var_to_replace)))
    )
  )
}

data <- teal_data()
data <- within(data, {
  ADSL <- tmc_ex_adsl
  ADMH <- tmc_ex_admh
})
join_keys(data) <- default_cdisc_join_keys[names(data)]

ADSL <- data[["ADSL"]]
ADMH <- data[["ADMH"]]

app <- init(
  data = data,
  modules = modules(
    tm_t_pp_medical_history(
      label = "Medical History",
      dataname = "ADMH",
      parentname = "ADSL",
      patient_col = "USUBJID",
      mhterm = choices_selected(
        choices = variable_choices(ADMH, c("MHTERM")),
        selected = "MHTERM"
      ),
      mhbodsys = choices_selected(
        choices = variable_choices(ADMH, "MHBODSYS"),
        selected = "MHBODSYS"
      ),
      mhdistat = choices_selected(
        choices = variable_choices(ADMH, "MHDISTAT"),
        selected = "MHDISTAT"
      ),
      decorators = list(insert_rrow_decorator())
    )
  )
) |> shiny::runApp()
```

</details>

---------

Co-authored-by: Marcin <[email protected]>
averissimo added a commit to insightsengineering/teal.modules.clinical that referenced this issue Dec 10, 2024
Part of insightsengineering/teal#1371

<details>
<summary>Working example</summary>

```r
pkgload::load_all("../teal.modules.clinical", export_all = FALSE)
# Example below

insert_rrow_decorator <- function(default_caption = "I am a good new row", .var_to_replace = "table") {
  teal_transform_module(
    label = "New row",
    ui = function(id) shiny::textInput(shiny::NS(id, "new_row"), "New row", value = default_caption),
    server = make_teal_transform_server(
      substitute({
        .var_to_replace <- rtables::insert_rrow(.var_to_replace, rtables::rrow(new_row))
      }, env = list(.var_to_replace = as.name(.var_to_replace)))
    )
  )
}

library(dplyr)

data <- teal_data()
data <- within(data, {
  ADSL <- tmc_ex_adsl
  ADRS <- tmc_ex_adrs %>%
    filter(PARAMCD %in% c("BESRSPI", "INVET"))
})
join_keys(data) <- default_cdisc_join_keys[names(data)]

ADSL <- data[["ADSL"]]
ADRS <- data[["ADRS"]]

arm_ref_comp <- list(
  ACTARMCD = list(
    ref = "ARM B",
    comp = c("ARM A", "ARM C")
  ),
  ARM = list(
    ref = "B: Placebo",
    comp = c("A: Drug X", "C: Combination")
  )
)

init(
  data = data,
  modules = modules(
    tm_t_logistic(
      label = "Logistic Regression",
      dataname = "ADRS",
      arm_var = choices_selected(
        choices = variable_choices(ADRS, c("ARM", "ARMCD")),
        selected = "ARM"
      ),
      arm_ref_comp = arm_ref_comp,
      paramcd = choices_selected(
        choices = value_choices(ADRS, "PARAMCD", "PARAM"),
        selected = "BESRSPI"
      ),
      cov_var = choices_selected(
        choices = c("SEX", "AGE", "BMRKR1", "BMRKR2"),
        selected = "SEX"
      ),
      decorators = list(insert_rrow_decorator())
    )
  )
) |> shiny::runApp()
```

</details>
averissimo added a commit to insightsengineering/teal.modules.clinical that referenced this issue Dec 10, 2024
Part of insightsengineering/teal#1371

<details>
<summary>Working example</summary>

```r
pkgload::load_all("../teal.modules.clinical", export_all = FALSE)
# Example below

insert_rrow_decorator <- function(default_caption = "I am a good new row", .var_to_replace = "table") {
  teal_transform_module(
    label = "New row",
    ui = function(id) shiny::textInput(shiny::NS(id, "new_row"), "New row", value = default_caption),
    server = make_teal_transform_server(
      substitute({
        .var_to_replace <- rtables::insert_rrow(.var_to_replace, rtables::rrow(new_row))
      }, env = list(.var_to_replace = as.name(.var_to_replace)))
    )
  )
}

# Preparation of the test case - use `EOSDY` and `DCSREAS` variables to demonstrate missing data.
data <- teal_data()
data <- within(data, {
  ADSL <- tmc_ex_adsl
  ADSL$EOSDY[1] <- NA_integer_
})
join_keys(data) <- default_cdisc_join_keys[names(data)]

ADSL <- data[["ADSL"]]

app <- init(
  data = data,
  modules = modules(
    tm_t_summary(
      label = "Demographic Table",
      dataname = "ADSL",
      arm_var = choices_selected(c("ARM", "ARMCD"), "ARM"),
      add_total = TRUE,
      summarize_vars = choices_selected(
        c("SEX", "RACE", "BMRKR2", "EOSDY", "DCSREAS", "AGE"),
        c("SEX", "RACE")
      ),
      useNA = "ifany",
      decorators = list(insert_rrow_decorator())
    )
  )
) |> shiny::runApp()
```

</details>

---------

Co-authored-by: Marcin <[email protected]>
averissimo added a commit to insightsengineering/teal.modules.clinical that referenced this issue Dec 10, 2024
Part of insightsengineering/teal#1371

<details>
<summary>Working example</summary>

```r
pkgload::load_all("../teal.modules.clinical", export_all = FALSE)
# Example below

insert_rrow_decorator <- function(default_caption = "I am a good new row", .var_to_replace = "table") {
  teal_transform_module(
    label = "New row",
    ui = function(id) shiny::textInput(shiny::NS(id, "new_row"), "New row", value = default_caption),
    server = make_teal_transform_server(
      substitute({
        .var_to_replace <- rtables::insert_rrow(.var_to_replace, rtables::rrow(new_row))
      }, env = list(.var_to_replace = as.name(.var_to_replace)))
    )
  )
}

data <- teal_data()
data <- within(data, {
  ADSL <- tmc_ex_adsl
  ADAE <- tmc_ex_adae

  .names_baskets <- grep("^(SMQ|CQ).*NAM$", names(ADAE), value = TRUE)
  .names_scopes <- grep("^SMQ.*SC$", names(ADAE), value = TRUE)

  .cs_baskets <- choices_selected(
    choices = variable_choices(ADAE, subset = .names_baskets),
    selected = .names_baskets
  )

  .cs_scopes <- choices_selected(
    choices = variable_choices(ADAE, subset = .names_scopes),
    selected = .names_scopes,
    fixed = TRUE
  )
})
join_keys(data) <- default_cdisc_join_keys[names(data)]

app <- init(
  data = data,
  modules = modules(
    tm_t_smq(
      label = "Adverse Events by SMQ Table",
      dataname = "ADAE",
      arm_var = choices_selected(
        choices = variable_choices(data[["ADSL"]], subset = c("ARM", "SEX")),
        selected = "ARM"
      ),
      add_total = FALSE,
      baskets = data[[".cs_baskets"]],
      scopes = data[[".cs_scopes"]],
      llt = choices_selected(
        choices = variable_choices(data[["ADAE"]], subset = c("AEDECOD")),
        selected = "AEDECOD"
      ),
      decorators = list(insert_rrow_decorator())
    )
  )
) |> shiny::runApp()
```

</details>

---------

Co-authored-by: Marcin <[email protected]>
averissimo added a commit to insightsengineering/teal.modules.clinical that referenced this issue Dec 10, 2024
Part of insightsengineering/teal#1371

<details>
<summary>Working example</summary>

```r
pkgload::load_all("../teal.modules.clinical", export_all = FALSE)
# Example below

insert_rrow_decorator <- function(default_caption = "I am a good new row", .var_to_replace = "table") {
  teal_transform_module(
    label = "New row",
    ui = function(id) shiny::textInput(shiny::NS(id, "new_row"), "New row", value = default_caption),
    server = make_teal_transform_server(
      substitute({
        .var_to_replace <- rtables::insert_rrow(.var_to_replace, rtables::rrow(new_row))
      }, env = list(.var_to_replace = as.name(.var_to_replace)))
    )
  )
}

data <- teal_data()
data <- within(data, {
  ADSL <- tmc_ex_adsl
  ADLB <- tmc_ex_adlb
})
join_keys(data) <- default_cdisc_join_keys[names(data)]

ADSL <- data[["ADSL"]]
ADLB <- data[["ADLB"]]

init(
  data = data,
  modules = modules(
    tm_t_shift_by_grade(
      label = "Grade Laboratory Abnormality Table",
      dataname = "ADLB",
      arm_var = choices_selected(
        choices = variable_choices(ADSL, subset = c("ARM", "ARMCD")),
        selected = "ARM"
      ),
      paramcd = choices_selected(
        choices = value_choices(ADLB, "PARAMCD", "PARAM"),
        selected = "ALT"
      ),
      worst_flag_var = choices_selected(
        choices = variable_choices(ADLB, subset = c("WGRLOVFL", "WGRLOFL", "WGRHIVFL", "WGRHIFL")),
        selected = c("WGRLOVFL")
      ),
      worst_flag_indicator = choices_selected(
        value_choices(ADLB, "WGRLOVFL"),
        selected = "Y", fixed = TRUE
      ),
      anl_toxgrade_var = choices_selected(
        choices = variable_choices(ADLB, subset = c("ATOXGR")),
        selected = c("ATOXGR"),
        fixed = TRUE
      ),
      base_toxgrade_var = choices_selected(
        choices = variable_choices(ADLB, subset = c("BTOXGR")),
        selected = c("BTOXGR"),
        fixed = TRUE
      ),
      add_total = FALSE,
      decorators = list(insert_rrow_decorator())
    )
  ),
  filter = teal_slices(teal_slice("ADSL", "SAFFL", selected = "Y"))
) |> shiny::runApp()
```

</details>

---------

Co-authored-by: Marcin <[email protected]>
averissimo added a commit to insightsengineering/teal.modules.clinical that referenced this issue Dec 10, 2024
Part of insightsengineering/teal#1371

<details>
<summary>Working example</summary>

```r
pkgload::load_all("../teal.modules.clinical", export_all = FALSE)
# Example below

insert_rrow_decorator <- function(default_caption = "I am a good new row", .var_to_replace = "table") {
  teal_transform_module(
    label = "New row",
    ui = function(id) shiny::textInput(shiny::NS(id, "new_row"), "New row", value = default_caption),
    server = make_teal_transform_server(
      substitute({
        .var_to_replace <- rtables::insert_rrow(.var_to_replace, rtables::rrow(new_row))
      }, env = list(.var_to_replace = as.name(.var_to_replace)))
    )
  )
}

data <- teal_data()
data <- within(data, {
  ADSL <- tmc_ex_adsl
  ADLB <- tmc_ex_adlb
})
join_keys(data) <- default_cdisc_join_keys[names(data)]

ADSL <- data[["ADSL"]]
ADLB <- data[["ADLB"]]

app <- init(
  data = data,
  modules = modules(
    tm_t_summary_by(
      label = "Summary by Row Groups Table",
      dataname = "ADLB",
      arm_var = choices_selected(
        choices = variable_choices(ADSL, c("ARM", "ARMCD")),
        selected = "ARM"
      ),
      add_total = TRUE,
      by_vars = choices_selected(
        choices = variable_choices(ADLB, c("PARAM", "AVISIT")),
        selected = c("AVISIT")
      ),
      summarize_vars = choices_selected(
        choices = variable_choices(ADLB, c("AVAL", "CHG")),
        selected = c("AVAL")
      ),
      useNA = "ifany",
      paramcd = choices_selected(
        choices = value_choices(ADLB, "PARAMCD", "PARAM"),
        selected = "ALT"
      ),
      decorators = list(insert_rrow_decorator())
    )
  )
) |> shiny::runApp()
```

</details>

---------

Co-authored-by: Marcin <[email protected]>
averissimo added a commit to insightsengineering/teal.modules.clinical that referenced this issue Dec 10, 2024
Part of insightsengineering/teal#1371

<details>
<summary>Working example</summary>

```r
pkgload::load_all("../teal.modules.clinical", export_all = FALSE)
# Example below

insert_rrow_decorator <- function(default_caption = "I am a good new row", .var_to_replace = "table") {
  teal_transform_module(
    label = "New row",
    ui = function(id) shiny::textInput(shiny::NS(id, "new_row"), "New row", value = default_caption),
    server = make_teal_transform_server(
      substitute({
        .var_to_replace <- rtables::insert_rrow(.var_to_replace, rtables::rrow(new_row))
      }, env = list(.var_to_replace = as.name(.var_to_replace)))
    )
  )
}

data <- teal_data()
data <- within(data, {
  ADSL <- tmc_ex_adsl
  ADEG <- tmc_ex_adeg
})
join_keys(data) <- default_cdisc_join_keys[names(data)]

ADSL <- data[["ADSL"]]
ADEG <- data[["ADEG"]]

init(
  data = data,
  modules = modules(
    tm_t_shift_by_arm(
      label = "Shift by Arm Table",
      dataname = "ADEG",
      arm_var = choices_selected(
        variable_choices(ADSL, subset = c("ARM", "ARMCD")),
        selected = "ARM"
      ),
      paramcd = choices_selected(
        value_choices(ADEG, "PARAMCD"),
        selected = "HR"
      ),
      visit_var = choices_selected(
        value_choices(ADEG, "AVISIT"),
        selected = "POST-BASELINE MINIMUM"
      ),
      aval_var = choices_selected(
        variable_choices(ADEG, subset = "ANRIND"),
        selected = "ANRIND",
        fixed = TRUE
      ),
      baseline_var = choices_selected(
        variable_choices(ADEG, subset = "BNRIND"),
        selected = "BNRIND",
        fixed = TRUE
      ),
      useNA = "ifany",
      decorators = list(insert_rrow_decorator())
    )
  )
) |> shiny::runApp()
```

</details>
averissimo added a commit to insightsengineering/teal.modules.clinical that referenced this issue Dec 10, 2024
Part of insightsengineering/teal#1371

<details>
<summary>Working example</summary>

```r
pkgload::load_all("../teal.modules.clinical", export_all = FALSE)
# Example below

insert_rrow_decorator <- function(default_caption = "I am a good new row", .var_to_replace = "table") {
  teal_transform_module(
    label = "New row",
    ui = function(id) shiny::textInput(shiny::NS(id, "new_row"), "New row", value = default_caption),
    server = make_teal_transform_server(
      substitute({
        .var_to_replace <- rtables::insert_rrow(.var_to_replace, rtables::rrow(new_row))
      }, env = list(.var_to_replace = as.name(.var_to_replace)))
    )
  )
}

data <- teal_data()
data <- within(data, {
  ADSL <- tmc_ex_adsl
  ADEG <- tmc_ex_adeg
})
join_keys(data) <- default_cdisc_join_keys[names(data)]

ADSL <- data[["ADSL"]]
ADEG <- data[["ADEG"]]

init(
  data = data,
  modules = modules(
    tm_t_shift_by_arm_by_worst(
      label = "Shift by Arm Table",
      dataname = "ADEG",
      arm_var = choices_selected(
        variable_choices(ADSL, subset = c("ARM", "ARMCD")),
        selected = "ARM"
      ),
      paramcd = choices_selected(
        value_choices(ADEG, "PARAMCD"),
        selected = "ECGINTP"
      ),
      worst_flag_var = choices_selected(
        variable_choices(ADEG, c("WORS02FL", "WORS01FL")),
        selected = "WORS02FL"
      ),
      worst_flag = choices_selected(
        value_choices(ADEG, "WORS02FL"),
        selected = "Y",
        fixed = TRUE
      ),
      aval_var = choices_selected(
        variable_choices(ADEG, c("AVALC", "ANRIND")),
        selected = "AVALC"
      ),
      baseline_var = choices_selected(
        variable_choices(ADEG, c("BASEC", "BNRIND")),
        selected = "BASEC"
      ),
      useNA = "ifany",
      decorators = list(insert_rrow_decorator())
    )
  )
) |> shiny::runApp()
```

</details>

---------

Co-authored-by: Marcin <[email protected]>
llrs-roche added a commit to insightsengineering/teal.modules.clinical that referenced this issue Dec 11, 2024
Part of insightsengineering/teal#1371

<details>
<summary>Example with decorator</summary>

```r
devtools::load_all("../teal")
devtools::load_all("../tern")
devtools::load_all(".")

insert_rrow_decorator <- function(default_caption = "I am a good new row", .var_to_replace = "table") {
  teal_transform_module(
    label = "New row",
    ui = function(id) shiny::textInput(shiny::NS(id, "new_row"), "New row", value = default_caption),
    server = make_teal_transform_server(
      substitute({
        .var_to_replace <- rtables::insert_rrow(.var_to_replace, rtables::rrow(new_row))
      }, env = list(.var_to_replace = as.name(.var_to_replace)))
    )
  )
}
library(dplyr)

data <- teal_data()
data <- within(data, {
  ADSL <- tmc_ex_adsl
  ADEX <- tmc_ex_adex
  
  set.seed(1, kind = "Mersenne-Twister")
  .labels <- col_labels(ADEX, fill = FALSE)
  ADEX <- ADEX %>%
    distinct(USUBJID, .keep_all = TRUE) %>%
    mutate(
      PARAMCD = "TDURD",
      PARAM = "Overall duration (days)",
      AVAL = sample(x = seq(1, 200), size = n(), replace = TRUE),
      AVALU = "Days"
    ) %>%
    bind_rows(ADEX)
  col_labels(ADEX) <- .labels
})
join_keys(data) <- default_cdisc_join_keys[names(data)]

app <- init(
  data = data,
  modules = modules(
    tm_t_exposure(
      label = "Duration of Exposure Table",
      dataname = "ADEX",
      paramcd = choices_selected(
        choices = value_choices(data[["ADEX"]], "PARAMCD", "PARAM"),
        selected = "TDURD"
      ),
      col_by_var = choices_selected(
        choices = variable_choices(data[["ADEX"]], subset = c("SEX", "ARM")),
        selected = "SEX"
      ),
      row_by_var = choices_selected(
        choices = variable_choices(data[["ADEX"]], subset = c("RACE", "REGION1", "STRATA1", "SEX")),
        selected = "RACE"
      ),
      parcat = choices_selected(
        choices = value_choices(data[["ADEX"]], "PARCAT2"),
        selected = "Drug A"
      ),
      add_total = FALSE,
      decorators = list(insert_rrow_decorator())
    )
  ),
  filter = teal_slices(teal_slice("ADSL", "SAFFL", selected = "Y"))
)
shinyApp(app$ui, app$server)
```

</details>

Note: I placed the decorated right above some options to add additional
columns and rows.
Perhaps we need to review where to place it. I would group these three
options in a single panel

---------

Signed-off-by: Lluís Revilla <[email protected]>
Co-authored-by: André Veríssimo <[email protected]>
averissimo added a commit to insightsengineering/teal.modules.clinical that referenced this issue Dec 11, 2024
Part of insightsengineering/teal#1371

<details>
<summary>Working example</summary>

```r
pkgload::load_all("../teal.modules.clinical", export_all = FALSE)
# Example below

rlisting_footer <- function(default_footer = "I am a good footer", .var_to_replace = "table") {
  teal_transform_module(
    label = "New row",
    ui = function(id) shiny::textInput(shiny::NS(id, "footer"), "footer", value = default_footer),
    server = make_teal_transform_server(
      substitute({
        rlistings::main_footer(.var_to_replace) <- footer
      }, env = list(.var_to_replace = as.name(.var_to_replace)))
    )
  )
}

dt_decorator <- function(.color1 = "#f9f9f9", .color2 = "#f0f0f0", .var_to_replace = "table") {
  teal_transform_module(
    label = "Table color",
    ui = function(id) {
      selectInput(
        NS(id, "style"),
        "Table Style",
        choices = c("Default", "Color1", "Color2"),
        selected = "Default"
      )
    },
    server = function(id, data) {
      moduleServer(id, function(input, output, session) {
        logger::log_info("🔵 Table row color called to action!", namespace = "teal.modules.general")
        reactive({
          req(data(), input$style)
          logger::log_info("changing the Table row color '{input$style}'", namespace = "teal.modules.general")
          teal.code::eval_code(data(), substitute({
            .var_to_replace <- switch(
              style,
              "Color1" = DT::formatStyle(
                .var_to_replace,
                columns = attr(.var_to_replace$x, "colnames")[-1],
                target = "row",
                backgroundColor = .color1
              ),
              "Color2" = DT::formatStyle(
                .var_to_replace,
                columns = attr(.var_to_replace$x, "colnames")[-1],
                target = "row",
                backgroundColor = .color2
              ),
              .var_to_replace
            )
          }, env = list(
            style = input$style,
            .var_to_replace = as.name(.var_to_replace),
            .color1 = .color1,
            .color2 = .color2
          )))
        })
      })
    }
  )
}

data <- teal_data()
data <- within(data, {
  ADSL <- tmc_ex_adsl
  ADLB <- tmc_ex_adlb
})
join_keys(data) <- default_cdisc_join_keys[names(data)]

ADSL <- data[["ADSL"]]
ADLB <- data[["ADLB"]]

init(
  data = data,
  modules = modules(
    tm_t_pp_laboratory(
      label = "Vitals",
      dataname = "ADLB",
      patient_col = "USUBJID",
      paramcd = choices_selected(
        choices = variable_choices(ADLB, "PARAMCD"),
        selected = "PARAMCD"
      ),
      param = choices_selected(
        choices = variable_choices(ADLB, "PARAM"),
        selected = "PARAM"
      ),
      timepoints = choices_selected(
        choices = variable_choices(ADLB, "ADY"),
        selected = "ADY"
      ),
      anrind = choices_selected(
        choices = variable_choices(ADLB, "ANRIND"),
        selected = "ANRIND"
      ),
      aval_var = choices_selected(
        choices = variable_choices(ADLB, "AVAL"),
        selected = "AVAL"
      ),
      avalu_var = choices_selected(
        choices = variable_choices(ADLB, "AVALU"),
        selected = "AVALU"
      ),
      decorators = list(
        table_listing = rlisting_footer()
      )
    )
  )
) |> shiny::runApp()
```

</details>
averissimo added a commit to insightsengineering/teal.modules.clinical that referenced this issue Dec 11, 2024
Part of insightsengineering/teal#1371

<details>
<summary>Working example</summary>

```r
# Load packages
pkgload::load_all("../teal.modules.clinical", export_all = FALSE)
# Example below

insert_rlisting_footer_decorator <- function(default_caption = "I am a good new footer", .var_to_replace = "table") {
  teal_transform_module(
    label = "New row",
    ui = function(id) shiny::textInput(shiny::NS(id, "new_footer"), "New footer", value = default_caption),
    server = make_teal_transform_server(
      substitute({
        rlistings::main_footer(.var_to_replace) <- new_footer
      }, env = list(.var_to_replace = as.name(.var_to_replace)))
    )
  )
}

data <- teal_data()
data <- within(data, {
  ADSL <- tmc_ex_adsl
})
join_keys(data) <- default_cdisc_join_keys[names(data)]

ADSL <- data[["ADSL"]]

init(
  data = data,
  modules = modules(
    tm_t_pp_basic_info(
      label = "Basic Info",
      dataname = "ADSL",
      patient_col = "USUBJID",
      vars = choices_selected(choices = variable_choices(ADSL), selected = c("ARM", "AGE", "SEX", "COUNTRY", "RACE", "EOSSTT")),
      decorators = list(
        table = insert_rlisting_footer_decorator(.var_to_replace = "table")
      )
    )
  )
) |> shiny::runApp()
```

</details>
averissimo added a commit to insightsengineering/teal.modules.clinical that referenced this issue Dec 11, 2024
Part of insightsengineering/teal#1371

<details>
<summary>Working example</summary>

```r
# Load packages
pkgload::load_all("../teal.modules.clinical", export_all = FALSE)
# Example below

rlisting_footer <- function(default_footer = "I am a good footer", .var_to_replace = "table_listing") {
  teal_transform_module(
    label = "New row",
    ui = function(id) shiny::textInput(shiny::NS(id, "footer"), "footer", value = default_footer),
    server = make_teal_transform_server(
      substitute({
        rlistings::main_footer(.var_to_replace) <- footer
      }, env = list(.var_to_replace = as.name(.var_to_replace)))
    )
  )
}

library(dplyr)
data <- teal_data()
data <- within(data, {
  ADCM <- tmc_ex_adcm
  ADSL <- tmc_ex_adsl %>% filter(USUBJID %in% ADCM$USUBJID)
  ADCM$CMASTDTM <- ADCM$ASTDTM
  ADCM$CMAENDTM <- ADCM$AENDTM
})
join_keys(data) <- default_cdisc_join_keys[names(data)]
adcm_keys <- c("STUDYID", "USUBJID", "ASTDTM", "CMSEQ", "ATC1", "ATC2", "ATC3", "ATC4")
join_keys(data)["ADCM", "ADCM"] <- adcm_keys

ADSL <- data[["ADSL"]]
ADCM <- data[["ADCM"]]

init(
  data = data,
  modules = modules(
    tm_t_pp_prior_medication(
      label = "Prior Medication",
      dataname = "ADCM",
      parentname = "ADSL",
      patient_col = "USUBJID",
      atirel = choices_selected(
        choices = variable_choices(ADCM, "ATIREL"),
        selected = "ATIREL"
      ),
      cmdecod = choices_selected(
        choices = variable_choices(ADCM, "CMDECOD"),
        selected = "CMDECOD"
      ),
      cmindc = choices_selected(
        choices = variable_choices(ADCM, "CMINDC"),
        selected = "CMINDC"
      ),
      cmstdy = choices_selected(
        choices = variable_choices(ADCM, "ASTDY"),
        selected = "ASTDY"
      ),
      decorators = list(
        table = rlisting_footer(.var_to_replace = "table")
      )
    )
  )
) |> shiny::runApp()
```

</details>
llrs-roche added a commit to insightsengineering/teal.modules.clinical that referenced this issue Dec 11, 2024
Part of insightsengineering/teal#1371

<details>
<summary>Example with decorators</summary>

```r
load_all("../teal")
load_all(".")
library(dplyr)

data <- teal_data()
data <- within(data, {
  ADSL <- tmc_ex_adsl
  .lbls_adae <- col_labels(tmc_ex_adae)
  ADAE <- tmc_ex_adae %>%
    mutate_if(is.character, as.factor) #' be certain of having factors
  col_labels(ADAE) <- .lbls_adae
})
join_keys(data) <- default_cdisc_join_keys[names(data)]

ADSL <- data[["ADSL"]]
ADAE <- data[["ADAE"]]

insert_rrow_decorator <- function(default_caption = "I am a good new row", .var_to_replace = "table") {
  teal_transform_module(
    label = "New row",
    ui = function(id) shiny::textInput(shiny::NS(id, "new_row"), "New row", value = default_caption),
    server = make_teal_transform_server(
      substitute({
        .var_to_replace <- rtables::insert_rrow(.var_to_replace, rtables::rrow(new_row))
      }, env = list(.var_to_replace = as.name(.var_to_replace)))
    )
  )
}

app <- init(
  data = data,
  modules = modules(
    tm_t_events_by_grade(
      label = "Adverse Events by Grade Table",
      dataname = "ADAE",
      arm_var = choices_selected(c("ARM", "ARMCD"), "ARM"),
      llt = choices_selected(
        choices = variable_choices(ADAE, c("AETERM", "AEDECOD")),
        selected = c("AEDECOD")
      ),
      hlt = choices_selected(
        choices = variable_choices(ADAE, c("AEBODSYS", "AESOC")),
        selected = "AEBODSYS"
      ),
      grade = choices_selected(
        choices = variable_choices(ADAE, c("AETOXGR", "AESEV")),
        selected = "AETOXGR"
      ),
      decorators = list(insert_rrow_decorator())
    )
  )
)
shinyApp(app$ui, app$server)

```

</details>

---------

Signed-off-by: Lluís Revilla <[email protected]>
Co-authored-by: André Veríssimo <[email protected]>
Co-authored-by: Marcin <[email protected]>
averissimo added a commit to insightsengineering/teal.modules.clinical that referenced this issue Dec 12, 2024
Part of insightsengineering/teal#1371

<details>
<summary>Working example</summary>

```r
# Load packages
pkgload::load_all("../teal.modules.clinical", export_all = FALSE)
# Example below

insert_rrow_decorator <- function(default_caption = "I am a good new row", .var_to_replace = "table") {
  teal_transform_module(
    label = "New row",
    ui = function(id) shiny::textInput(shiny::NS(id, "new_row"), "New row", value = default_caption),
    server = make_teal_transform_server(
      substitute({
        .var_to_replace <- rtables::insert_rrow(.var_to_replace, rtables::rrow(new_row))
      }, env = list(.var_to_replace = as.name(.var_to_replace)))
    )
  )
}

add_title_decorator <- function(default_check = TRUE, .var_to_replace = "plot") {
  teal_transform_module(
    label = "Theme",
    ui = function(id) shiny::checkboxInput(NS(id, "flag"), "Add title?", TRUE),
    server = make_teal_transform_server(
      substitute({
        if (flag) .var_to_replace <-
            .var_to_replace + ggplot2::ggtitle("Title added by decorator")
      },
      env = list(.var_to_replace = as.name(.var_to_replace))
      )
    )
  )
}

library(dplyr)

arm_ref_comp <- list(
  ARMCD = list(
    ref = "ARM B",
    comp = c("ARM A", "ARM C")
  )
)

data <- teal_data()
data <- within(data, {
  ADSL <- tmc_ex_adsl
  ADQS <- tmc_ex_adqs %>%
    filter(ABLFL != "Y" & ABLFL2 != "Y") %>%
    filter(AVISIT %in% c("WEEK 1 DAY 8", "WEEK 2 DAY 15", "WEEK 3 DAY 22")) %>%
    mutate(
      AVISIT = as.factor(AVISIT),
      AVISITN = rank(AVISITN) %>%
        as.factor() %>%
        as.numeric() %>%
        as.factor() #' making consecutive numeric factor
    )
})
join_keys(data) <- default_cdisc_join_keys[names(data)]

init(
  data = data,
  modules = modules(
    tm_a_mmrm(
      label = "MMRM",
      dataname = "ADQS",
      aval_var = choices_selected(c("AVAL", "CHG"), "AVAL"),
      id_var = choices_selected(c("USUBJID", "SUBJID"), "USUBJID"),
      arm_var = choices_selected(c("ARM", "ARMCD"), "ARM"),
      visit_var = choices_selected(c("AVISIT", "AVISITN"), "AVISIT"),
      arm_ref_comp = arm_ref_comp,
      paramcd = choices_selected(
        choices = value_choices(data[["ADQS"]], "PARAMCD", "PARAM"),
        selected = "FKSI-FWB"
      ),
      cov_var = choices_selected(c("BASE", "AGE", "SEX", "BASE:AVISIT"), NULL),
      decorators = list(
        lsmeans_table = insert_rrow_decorator("A", .var_to_replace = "lsmeans_table")
        , lsmeans_plot = add_title_decorator("B", .var_to_replace = "lsmeans_plot")
        , covariance_table = insert_rrow_decorator("C", .var_to_replace = "covariance_table")
        , fixed_effects_table = insert_rrow_decorator("D", .var_to_replace = "fixed_effects_table")
        , diagnostic_table = insert_rrow_decorator(.var_to_replace = "diagnostic_table")
        , diagnostic_plot = add_title_decorator(.var_to_replace = "diagnostic_plot")
      )
    )
  )
) |> shiny::runApp()
```

</details>

---------

Co-authored-by: Marcin <[email protected]>
averissimo added a commit to insightsengineering/teal.modules.clinical that referenced this issue Dec 16, 2024
Part of insightsengineering/teal#1371

### Example app with all modules / decorators

<details>
<summary>Example app</summary>

```r
# Load packages
pkgload::load_all("../teal.modules.clinical", export_all = FALSE)

# Decorators ------------------------------------------------------------------
insert_rrow_decorator <- function(default_caption = "I am a good new row", .var_to_replace = "table") {
  teal_transform_module(
    label = "New rtables row",
    ui = function(id) shiny::textInput(shiny::NS(id, "new_row"), "New row", value = default_caption),
    server = make_teal_transform_server(
      substitute({
        .var_to_replace <- rtables::insert_rrow(.var_to_replace, rtables::rrow(new_row))
      }, env = list(.var_to_replace = as.name(.var_to_replace)))
    )
  )
}
add_title_decorator <- function(default_check = TRUE, .var_to_replace = "plot") {
  teal_transform_module(
    label = "Title",
    ui = function(id) shiny::checkboxInput(NS(id, "flag"), "Add title?", TRUE),
    server = make_teal_transform_server(
      substitute({
        if (flag) .var_to_replace <-
            .var_to_replace + ggplot2::ggtitle("Title added by decorator")
      },
      env = list(.var_to_replace = as.name(.var_to_replace))
      )
    )
  )
}
caption_decorator <- function(default_caption = "I am a good decorator", .var_to_replace = "plot") {
  teal_transform_module(
    label = "Caption",
    ui = function(id) shiny::textInput(shiny::NS(id, "footnote"), "Footnote", value = default_caption),
    server = make_teal_transform_server(
      substitute({
        .var_to_replace <- .var_to_replace + ggplot2::labs(caption = footnote)
      }, env = list(.var_to_replace = as.name(.var_to_replace)))
    )
  )
}
change_theme_decorator <- function(default_check = TRUE, .var_to_replace = "plot") {
  teal_transform_module(
    label = "Theme",
    ui = function(id) shiny::checkboxInput(NS(id, "flag"), "Apply dark theme?", TRUE),
    server = make_teal_transform_server(
      substitute({
        if (flag) .var_to_replace <- .var_to_replace + ggplot2::theme_dark()
      },
      env = list(.var_to_replace = as.name(.var_to_replace))
      )
    )
  )
}
add_cowplot_title_decorator <- function(default_check = TRUE, .var_to_replace = "plot") {
  teal_transform_module(
    label = "Cowplot title",
    ui = function(id) shiny::checkboxInput(NS(id, "flag"), "Add title?", TRUE),
    server = make_teal_transform_server(
      substitute({
        if (flag) .var_to_replace <-
            .var_to_replace +
            ggplot2::ggtitle("Title added by decorator") +
            cowplot::theme_cowplot()
      },
      env = list(.var_to_replace = as.name(.var_to_replace))
      )
    )
  )
}
rlisting_footer <- function(default_footer = "I am a good footer", .var_to_replace = "table_listing") {
  teal_transform_module(
    label = "New row",
    ui = function(id) shiny::textInput(shiny::NS(id, "footer"), "footer", value = default_footer),
    server = make_teal_transform_server(
      substitute({
        rlistings::main_footer(.var_to_replace) <- footer
      }, env = list(.var_to_replace = as.name(.var_to_replace)))
    )
  )
}

# End of decorators -----------------------------------------------------------

library(dplyr)

# arm_ref_comp <- list(ARMCD = list(ref = "ARM B", comp = c("ARM A", "ARM C")))

arm_ref_comp <- list(
  ACTARMCD = list(ref = "ARM B", comp = c("ARM A", "ARM C")),
  ARM = list(ref = "B: Placebo", comp = c("A: Drug X", "C: Combination"))
)

data <- within(teal_data(), {
  ADSL <- tmc_ex_adsl |>
    mutate(ITTFL = factor("Y") |> with_label("Intent-To-Treat Population Flag")) |>
    mutate(DTHFL = case_when(!is.na(DTHDT) ~ "Y", TRUE ~ "") |> with_label("Subject Death Flag"))

  ADAE <- tmc_ex_adae |>
    filter(!((AETOXGR == 1) & (AESEV == "MILD") & (ARM == "A: Drug X")))

  ADAE$ASTDY <- structure(
    as.double(ADAE$ASTDY, unit = attr(ADAE$ASTDY, "units", exact = TRUE)),
    label = attr(ADAE$ASTDY, "label", exact = TRUE)
  )

  .lbls_adae <- col_labels(tmc_ex_adae)
  ADAE <- tmc_ex_adae %>%
    mutate_if(is.character, as.factor) #' be certain of having factors
  col_labels(ADAE) <- .lbls_adae

  ADTTE <- tmc_ex_adtte

  ADLB <- tmc_ex_adlb |>
    mutate(AVISIT == forcats::fct_reorder(AVISIT, AVISITN, min)) |>
    mutate(
      ONTRTFL = case_when(
        AVISIT %in% c("SCREENING", "BASELINE") ~ "",
        TRUE ~ "Y"
      ) |> with_label("On Treatment Record Flag")
    )

  ADVS <- tmc_ex_advs

  ADRS <- tmc_ex_adrs |>
    mutate(
      AVALC = d_onco_rsp_label(AVALC) |>
        with_label("Character Result/Finding")
    ) |>
    filter(PARAMCD != "OVRINV" | AVISIT == "FOLLOW UP") |>
    filter(PARAMCD %in% c("BESRSPI", "INVET"))

  ADAETTE <- tmc_ex_adaette %>%
    filter(PARAMCD %in% c("AETTE1", "AETTE2", "AETTE3")) %>%
    mutate(is_event = CNSR == 0) %>%
    mutate(n_events = as.integer(is_event))

  .add_event_flags <- function(dat) {
    dat <- dat %>%
      mutate(
        TMPFL_SER = AESER == "Y",
        TMPFL_REL = AEREL == "Y",
        TMPFL_GR5 = AETOXGR == "5",
        TMP_SMQ01 = !is.na(SMQ01NAM),
        TMP_SMQ02 = !is.na(SMQ02NAM),
        TMP_CQ01 = !is.na(CQ01NAM)
      )
    column_labels <- list(
      TMPFL_SER = "Serious AE",
      TMPFL_REL = "Related AE",
      TMPFL_GR5 = "Grade 5 AE",
      TMP_SMQ01 = aesi_label(dat[["SMQ01NAM"]], dat[["SMQ01SC"]]),
      TMP_SMQ02 = aesi_label("Y.9.9.9.9/Z.9.9.9.9 AESI"),
      TMP_CQ01 = aesi_label(dat[["CQ01NAM"]])
    )
    col_labels(dat)[names(column_labels)] <- as.character(column_labels)
    dat
  }

  ADEX <- tmc_ex_adex

  set.seed(1, kind = "Mersenne-Twister")
  .labels <- col_labels(ADEX, fill = FALSE)
  ADEX <- ADEX %>%
    distinct(USUBJID, .keep_all = TRUE) %>%
    mutate(
      PARAMCD = "TDURD",
      PARAM = "Overall duration (days)",
      AVAL = sample(x = seq(1, 200), size = n(), replace = TRUE),
      AVALU = "Days"
    ) %>%
    bind_rows(ADEX)
  col_labels(ADEX) <- .labels

  ADCM <- tmc_ex_adcm

  ADMH <- tmc_ex_admh

  ADCM$CMASTDTM <- ADCM$ASTDTM
  ADCM$CMAENDTM <- ADCM$AENDTM

  ADEG <- tmc_ex_adeg

  # smq
  .names_baskets <- grep("^(SMQ|CQ).*NAM$", names(ADAE), value = TRUE)
  .names_scopes <- grep("^SMQ.*SC$", names(ADAE), value = TRUE)

  .cs_baskets <- choices_selected(
    choices = variable_choices(ADAE, subset = .names_baskets),
    selected = .names_baskets
  )

  .cs_scopes <- choices_selected(
    choices = variable_choices(ADAE, subset = .names_scopes),
    selected = .names_scopes,
    fixed = TRUE
  )

  # summary
  ADSL$EOSDY[1] <- NA_integer_
})
join_keys(data) <- default_cdisc_join_keys[names(data)]
adcm_keys <- c("STUDYID", "USUBJID", "ASTDTM", "CMSEQ", "ATC1", "ATC2", "ATC3", "ATC4")
join_keys(data)["ADCM", "ADCM"] <- adcm_keys

# Use in choices selected -----------------------------------------------------

ADSL <- data[["ADSL"]]
ADQS <- data[["ADQS"]]
ADAE <- data[["ADAE"]]
ADTTE <- data[["ADTTE"]]
ADLB <- data[["ADLB"]]
ADAE <- data[["ADAE"]]
ADVS <- data[["ADVS"]]
ADRS <- data[["ADRS"]]
ADAETTE <- data[["ADAETTE"]]
ADEX <- data[["ADEX"]]
ADCM <- data[["ADCM"]]
ADMH <- data[["ADMH"]]
ADEG <- data[["ADEG"]]

# Init ------------------------------------------------------------------------

init(
  data = data,
  modules = modules(
    # -------------------------------------------------------------------------
    tm_t_summary_by(
      label = "Summary by Row Groups Table",
      dataname = "ADLB",
      arm_var = choices_selected(
        choices = variable_choices(ADSL, c("ARM", "ARMCD")),
        selected = "ARM"
      ),
      add_total = TRUE,
      by_vars = choices_selected(
        choices = variable_choices(ADLB, c("PARAM", "AVISIT")),
        selected = c("AVISIT")
      ),
      summarize_vars = choices_selected(
        choices = variable_choices(ADLB, c("AVAL", "CHG")),
        selected = c("AVAL")
      ),
      useNA = "ifany",
      paramcd = choices_selected(
        choices = value_choices(ADLB, "PARAMCD", "PARAM"),
        selected = "ALT"
      ),
      decorators = list(insert_rrow_decorator())
    ),
    # -------------------------------------------------------------------------
    tm_t_smq(
      label = "Adverse Events by SMQ Table",
      dataname = "ADAE",
      arm_var = choices_selected(
        choices = variable_choices(data[["ADSL"]], subset = c("ARM", "SEX")),
        selected = "ARM"
      ),
      add_total = FALSE,
      baskets = data[[".cs_baskets"]],
      scopes = data[[".cs_scopes"]],
      llt = choices_selected(
        choices = variable_choices(data[["ADAE"]], subset = c("AEDECOD")),
        selected = "AEDECOD"
      ),
      decorators = list(insert_rrow_decorator())
    ),
    # -------------------------------------------------------------------------
    tm_t_shift_by_grade(
      label = "Grade Laboratory Abnormality Table",
      dataname = "ADLB",
      arm_var = choices_selected(
        choices = variable_choices(ADSL, subset = c("ARM", "ARMCD")),
        selected = "ARM"
      ),
      paramcd = choices_selected(
        choices = value_choices(ADLB, "PARAMCD", "PARAM"),
        selected = "ALT"
      ),
      worst_flag_var = choices_selected(
        choices = variable_choices(ADLB, subset = c("WGRLOVFL", "WGRLOFL", "WGRHIVFL", "WGRHIFL")),
        selected = c("WGRLOVFL")
      ),
      worst_flag_indicator = choices_selected(
        value_choices(ADLB, "WGRLOVFL"),
        selected = "Y", fixed = TRUE
      ),
      anl_toxgrade_var = choices_selected(
        choices = variable_choices(ADLB, subset = c("ATOXGR")),
        selected = c("ATOXGR"),
        fixed = TRUE
      ),
      base_toxgrade_var = choices_selected(
        choices = variable_choices(ADLB, subset = c("BTOXGR")),
        selected = c("BTOXGR"),
        fixed = TRUE
      ),
      add_total = FALSE,
      decorators = list(insert_rrow_decorator())
    ),
    # -------------------------------------------------------------------------
    tm_t_shift_by_arm(
      label = "Shift by Arm Table",
      dataname = "ADEG",
      arm_var = choices_selected(
        variable_choices(ADSL, subset = c("ARM", "ARMCD")),
        selected = "ARM"
      ),
      paramcd = choices_selected(
        value_choices(ADEG, "PARAMCD"),
        selected = "HR"
      ),
      visit_var = choices_selected(
        value_choices(ADEG, "AVISIT"),
        selected = "POST-BASELINE MINIMUM"
      ),
      aval_var = choices_selected(
        variable_choices(ADEG, subset = "ANRIND"),
        selected = "ANRIND",
        fixed = TRUE
      ),
      baseline_var = choices_selected(
        variable_choices(ADEG, subset = "BNRIND"),
        selected = "BNRIND",
        fixed = TRUE
      ),
      useNA = "ifany",
      decorators = list(insert_rrow_decorator())
    ),
    # -------------------------------------------------------------------------
    tm_t_shift_by_arm_by_worst(
      label = "Shift by Arm Table (by worst)",
      dataname = "ADEG",
      arm_var = choices_selected(
        variable_choices(ADSL, subset = c("ARM", "ARMCD")),
        selected = "ARM"
      ),
      paramcd = choices_selected(
        value_choices(ADEG, "PARAMCD"),
        selected = "ECGINTP"
      ),
      worst_flag_var = choices_selected(
        variable_choices(ADEG, c("WORS02FL", "WORS01FL")),
        selected = "WORS02FL"
      ),
      worst_flag = choices_selected(
        value_choices(ADEG, "WORS02FL"),
        selected = "Y",
        fixed = TRUE
      ),
      aval_var = choices_selected(
        variable_choices(ADEG, c("AVALC", "ANRIND")),
        selected = "AVALC"
      ),
      baseline_var = choices_selected(
        variable_choices(ADEG, c("BASEC", "BNRIND")),
        selected = "BASEC"
      ),
      useNA = "ifany",
      decorators = list(insert_rrow_decorator())
    ),
    # -------------------------------------------------------------------------
    tm_t_pp_prior_medication(
      label = "Prior Medication",
      dataname = "ADCM",
      parentname = "ADSL",
      patient_col = "USUBJID",
      atirel = choices_selected(
        choices = variable_choices(ADCM, "ATIREL"),
        selected = "ATIREL"
      ),
      cmdecod = choices_selected(
        choices = variable_choices(ADCM, "CMDECOD"),
        selected = "CMDECOD"
      ),
      cmindc = choices_selected(
        choices = variable_choices(ADCM, "CMINDC"),
        selected = "CMINDC"
      ),
      cmstdy = choices_selected(
        choices = variable_choices(ADCM, "ASTDY"),
        selected = "ASTDY"
      ),
      decorators = list(
        table = rlisting_footer(.var_to_replace = "table")
      )
    ),
    # -------------------------------------------------------------------------
    tm_t_pp_medical_history(
      label = "Medical History",
      dataname = "ADMH",
      parentname = "ADSL",
      patient_col = "USUBJID",
      mhterm = choices_selected(
        choices = variable_choices(ADMH, c("MHTERM")),
        selected = "MHTERM"
      ),
      mhbodsys = choices_selected(
        choices = variable_choices(ADMH, "MHBODSYS"),
        selected = "MHBODSYS"
      ),
      mhdistat = choices_selected(
        choices = variable_choices(ADMH, "MHDISTAT"),
        selected = "MHDISTAT"
      ),
      decorators = list(insert_rrow_decorator())
    ),
    # -------------------------------------------------------------------------
    tm_t_pp_laboratory(
      label = "Vitals",
      dataname = "ADLB",
      patient_col = "USUBJID",
      paramcd = choices_selected(
        choices = variable_choices(ADLB, "PARAMCD"),
        selected = "PARAMCD"
      ),
      param = choices_selected(
        choices = variable_choices(ADLB, "PARAM"),
        selected = "PARAM"
      ),
      timepoints = choices_selected(
        choices = variable_choices(ADLB, "ADY"),
        selected = "ADY"
      ),
      anrind = choices_selected(
        choices = variable_choices(ADLB, "ANRIND"),
        selected = "ANRIND"
      ),
      aval_var = choices_selected(
        choices = variable_choices(ADLB, "AVAL"),
        selected = "AVAL"
      ),
      avalu_var = choices_selected(
        choices = variable_choices(ADLB, "AVALU"),
        selected = "AVALU"
      ),
      decorators = list(table = rlisting_footer(.var_to_replace = "table"))
    ),
    # -------------------------------------------------------------------------
    tm_t_pp_basic_info(
      label = "Basic Info",
      dataname = "ADSL",
      patient_col = "USUBJID",
      vars = choices_selected(choices = variable_choices(ADSL), selected = c("ARM", "AGE", "SEX", "COUNTRY", "RACE", "EOSSTT"))
      , decorators = list(
        table = rlisting_footer(.var_to_replace = "table")
      )
    ),
    # -------------------------------------------------------------------------
    tm_t_mult_events(
      label = "Concomitant Medications by Medication Class and Preferred Name",
      dataname = "ADCM",
      arm_var = choices_selected(c("ARM", "ARMCD"), "ARM"),
      seq_var = choices_selected("CMSEQ", selected = "CMSEQ", fixed = TRUE),
      hlt = choices_selected(
        choices = variable_choices(ADCM, c("ATC1", "ATC2", "ATC3", "ATC4")),
        selected = c("ATC1", "ATC2", "ATC3", "ATC4")
      ),
      llt = choices_selected(choices = variable_choices(ADCM, c("CMDECOD")), selected = c("CMDECOD")),
      add_total = TRUE,
      event_type = "treatment",
      decorators = list(insert_rrow_decorator())
    ),
    # -------------------------------------------------------------------------
    tm_t_logistic(
      label = "Logistic Regression",
      dataname = "ADRS",
      arm_var = choices_selected(
        choices = variable_choices(ADRS, c("ARM", "ARMCD")),
        selected = "ARM"
      ),
      arm_ref_comp = arm_ref_comp,
      paramcd = choices_selected(
        choices = value_choices(ADRS, "PARAMCD", "PARAM"),
        selected = "BESRSPI"
      ),
      cov_var = choices_selected(
        choices = c("SEX", "AGE", "BMRKR1", "BMRKR2"),
        selected = "SEX"
      ),
      decorators = list(insert_rrow_decorator())
    ),
    # -------------------------------------------------------------------------
    tm_t_exposure(
      label = "Duration of Exposure Table",
      dataname = "ADEX",
      paramcd = choices_selected(
        choices = value_choices(data[["ADEX"]], "PARAMCD", "PARAM"),
        selected = "TDURD"
      ),
      col_by_var = choices_selected(
        choices = variable_choices(data[["ADEX"]], subset = c("SEX", "ARM")),
        selected = "SEX"
      ),
      row_by_var = choices_selected(
        choices = variable_choices(data[["ADEX"]], subset = c("RACE", "REGION1", "STRATA1", "SEX")),
        selected = "RACE"
      ),
      parcat = choices_selected(
        choices = value_choices(data[["ADEX"]], "PARCAT2"),
        selected = "Drug A"
      ),
      add_total = FALSE,
      decorators = list(insert_rrow_decorator())
    ),
    # -------------------------------------------------------------------------
    tm_t_events(
      label = "Adverse Event Table",
      dataname = "ADAE",
      arm_var = choices_selected(c("ARM", "ARMCD"), "ARM"),
      llt = choices_selected(
        choices = variable_choices(ADAE, c("AETERM", "AEDECOD")),
        selected = c("AEDECOD")
      ),
      hlt = choices_selected(
        choices = variable_choices(ADAE, c("AEBODSYS", "AESOC")),
        selected = "AEBODSYS"
      ),
      add_total = TRUE,
      event_type = "adverse event",
      decorators = list(insert_rrow_decorator())
    ),
    # -------------------------------------------------------------------------
    tm_t_events_patyear(
      label = "AE Rate Adjusted for Patient-Years At Risk Table",
      dataname = "ADAETTE",
      arm_var = choices_selected(
        choices = variable_choices(ADSL, c("ARM", "ARMCD")),
        selected = "ARMCD"
      ),
      add_total = TRUE,
      events_var = choices_selected(
        choices = variable_choices(ADAETTE, "n_events"),
        selected = "n_events",
        fixed = TRUE
      ),
      paramcd = choices_selected(
        choices = value_choices(ADAETTE, "PARAMCD", "PARAM"),
        selected = "AETTE1"
      ),
      decorators = list(insert_rrow_decorator())
    ),
    # -------------------------------------------------------------------------
    tm_t_events_by_grade(
      label = "Adverse Events by Grade Table",
      dataname = "ADAE",
      arm_var = choices_selected(c("ARM", "ARMCD"), "ARM"),
      llt = choices_selected(
        choices = variable_choices(ADAE, c("AETERM", "AEDECOD")),
        selected = c("AEDECOD")
      ),
      hlt = choices_selected(
        choices = variable_choices(ADAE, c("AEBODSYS", "AESOC")),
        selected = "AEBODSYS"
      ),
      grade = choices_selected(
        choices = variable_choices(ADAE, c("AETOXGR", "AESEV")),
        selected = "AETOXGR"
      ),
      decorators = list(insert_rrow_decorator())
    ),
    # -------------------------------------------------------------------------
    tm_t_coxreg(
      label = "Cox Reg.",
      dataname = "ADTTE",
      arm_var = choices_selected(c("ARM", "ARMCD", "ACTARMCD"), "ARM"),
      arm_ref_comp = arm_ref_comp,
      paramcd = choices_selected(
        value_choices(ADTTE, "PARAMCD", "PARAM"), "OS"
      ),
      strata_var = choices_selected(
        c("COUNTRY", "STRATA1", "STRATA2"), "STRATA1"
      ),
      cov_var = choices_selected(
        c("AGE", "BMRKR1", "BMRKR2", "REGION1"), "AGE"
      ),
      multivariate = TRUE,
      decorators = list(insert_rrow_decorator())
    ),
    # -------------------------------------------------------------------------
    tm_t_abnormality(
      label = "Abnormality Table",
      dataname = "ADLB",
      arm_var = choices_selected(
        choices = variable_choices(ADSL, subset = c("ARM", "ARMCD")),
        selected = "ARM"
      ),
      add_total = FALSE,
      by_vars = choices_selected(
        choices = variable_choices(ADLB, subset = c("LBCAT", "PARAM", "AVISIT")),
        selected = c("LBCAT", "PARAM"),
        keep_order = TRUE
      ),
      baseline_var = choices_selected(
        variable_choices(ADLB, subset = "BNRIND"),
        selected = "BNRIND", fixed = TRUE
      ),
      grade = choices_selected(
        choices = variable_choices(ADLB, subset = "ANRIND"),
        selected = "ANRIND",
        fixed = TRUE
      ),
      abnormal = list(low = "LOW", high = "HIGH"),
      exclude_base_abn = FALSE,
      decorators = list(insert_rrow_decorator("I am a good new row"))
    ),
    # -------------------------------------------------------------------------
    tm_g_pp_vitals(
      label = "Vitals",
      dataname = "ADVS",
      parentname = "ADSL",
      patient_col = "USUBJID",
      plot_height = c(600L, 200L, 2000L),
      paramcd = choices_selected(
        choices = variable_choices(ADVS, "PARAMCD"),
        selected = "PARAMCD"
      ),
      xaxis = choices_selected(
        choices = variable_choices(ADVS, "ADY"),
        selected = "ADY"
      ),
      aval_var = choices_selected(
        choices = variable_choices(ADVS, "AVAL"),
        selected = "AVAL"
      ),
      decorators = list(plot = add_title_decorator("plot"))
    ),
    # -------------------------------------------------------------------------
    tm_g_pp_adverse_events(
      label = "Adverse Events",
      dataname = "ADAE",
      parentname = "ADSL",
      patient_col = "USUBJID",
      plot_height = c(600L, 200L, 2000L),
      aeterm = choices_selected(
        choices = variable_choices(ADAE, "AETERM"),
        selected = "AETERM"
      ),
      tox_grade = choices_selected(
        choices = variable_choices(ADAE, "AETOXGR"),
        selected = "AETOXGR"
      ),
      causality = choices_selected(
        choices = variable_choices(ADAE, "AEREL"),
        selected = "AEREL"
      ),
      outcome = choices_selected(
        choices = variable_choices(ADAE, "AEOUT"),
        selected = "AEOUT"
      ),
      action = choices_selected(
        choices = variable_choices(ADAE, "AEACN"),
        selected = "AEACN"
      ),
      time = choices_selected(
        choices = variable_choices(ADAE, "ASTDY"),
        selected = "ASTDY"
      ),
      decod = NULL,
      decorators = list(
        plot = caption_decorator('I am a good caption', 'plot'),
        table = rlisting_footer(.var_to_replace = 'table')
      )
    ),
    # -------------------------------------------------------------------------
    tm_g_lineplot(
      label = "Line Plot",
      dataname = "ADLB",
      strata = choices_selected(
        variable_choices(ADSL, c("ARM", "ARMCD", "ACTARMCD")),
        "ARM"
      ),
      y = choices_selected(
        variable_choices(ADLB, c("AVAL", "BASE", "CHG", "PCHG")),
        "AVAL"
      ),
      param = choices_selected(
        value_choices(ADLB, "PARAMCD", "PARAM"),
        "ALT"
      ),
      decorators = list(add_cowplot_title_decorator("plot"))
    ),
    # -------------------------------------------------------------------------
    tm_g_km(
      label = "Kaplan-Meier Plot",
      dataname = "ADTTE",
      arm_var = choices_selected(
        variable_choices(ADSL, c("ARM", "ARMCD", "ACTARMCD")),
        "ARM"
      ),
      paramcd = choices_selected(
        value_choices(ADTTE, "PARAMCD", "PARAM"),
        "OS"
      ),
      arm_ref_comp = arm_ref_comp,
      strata_var = choices_selected(
        variable_choices(ADSL, c("SEX", "BMRKR2")),
        "SEX"
      ),
      facet_var = choices_selected(
        variable_choices(ADSL, c("SEX", "BMRKR2")),
        NULL
      ),
      decorators = list(plot = add_cowplot_title_decorator(TRUE, "plot"))
    ),
    # -------------------------------------------------------------------------
    tm_g_barchart_simple(
      label = "ADAE Analysis",
      x = data_extract_spec(
        dataname = "ADSL",
        select = select_spec(
          choices = variable_choices(
            ADSL,
            c(
              "ARM", "ACTARM", "SEX",
              "RACE", "ITTFL", "SAFFL", "STRATA2"
            )
          ),
          selected = "ACTARM",
          multiple = FALSE
        )
      ),
      fill = list(
        data_extract_spec(
          dataname = "ADSL",
          select = select_spec(
            choices = variable_choices(
              ADSL,
              c(
                "ARM", "ACTARM", "SEX",
                "RACE", "ITTFL", "SAFFL", "STRATA2"
              )
            ),
            selected = "SEX",
            multiple = FALSE
          )
        ),
        data_extract_spec(
          dataname = "ADAE",
          select = select_spec(
            choices = variable_choices(ADAE, c("AETOXGR", "AESEV", "AESER")),
            selected = NULL,
            multiple = FALSE
          )
        )
      ),
      x_facet = list(
        data_extract_spec(
          dataname = "ADAE",
          select = select_spec(
            choices = variable_choices(ADAE, c("AETOXGR", "AESEV", "AESER")),
            selected = "AETOXGR",
            multiple = FALSE
          )
        ),
        data_extract_spec(
          dataname = "ADSL",
          select = select_spec(
            choices = variable_choices(
              ADSL,
              c(
                "ARM", "ACTARM", "SEX",
                "RACE", "ITTFL", "SAFFL", "STRATA2"
              )
            ),
            selected = NULL,
            multiple = FALSE
          )
        )
      ),
      y_facet = list(
        data_extract_spec(
          dataname = "ADAE",
          select = select_spec(
            choices = variable_choices(ADAE, c("AETOXGR", "AESEV", "AESER")),
            selected = "AESEV",
            multiple = FALSE
          )
        ),
        data_extract_spec(
          dataname = "ADSL",
          select = select_spec(
            choices = variable_choices(
              ADSL,
              c(
                "ARM", "ACTARM", "SEX",
                "RACE", "ITTFL", "SAFFL", "STRATA2"
              )
            ),
            selected = NULL,
            multiple = FALSE
          )
        )
      ),
      decorators = list(plot = caption_decorator('The best', 'plot'))
    )
  )
) |> shiny::runApp()

```

</details>    

<details>
<summary>Second App</summary>

```r
# Load packages
pkgload::load_all("../teal.modules.clinical", export_all = FALSE)
# Example below

insert_rrow_decorator <- function(default_caption = "I am a good new row", .var_to_replace = "table") {
  teal_transform_module(
    label = "New row",
    ui = function(id) shiny::textInput(shiny::NS(id, "new_row"), "New row", value = default_caption),
    server = make_teal_transform_server(
      substitute({
        .var_to_replace <- rtables::insert_rrow(.var_to_replace, rtables::rrow(new_row))
      }, env = list(.var_to_replace = as.name(.var_to_replace)))
    )
  )
}

# Preparation of the test case - use `EOSDY` and `DCSREAS` variables to demonstrate missing data.
data <- teal_data()
data <- within(data, {
  ADSL <- tmc_ex_adsl |>
    mutate(
      DTHFL = case_when(
        !is.na(DTHDT) ~ "Y",
        TRUE ~ ""
      ) %>% with_label("Subject Death Flag")
    )
  ADSL$EOSDY[1] <- NA_integer_

  ADAE <- tmc_ex_adae

  .add_event_flags <- function(dat) {
    dat <- dat %>%
      mutate(
        TMPFL_SER = AESER == "Y",
        TMPFL_REL = AEREL == "Y",
        TMPFL_GR5 = AETOXGR == "5",
        TMP_SMQ01 = !is.na(SMQ01NAM),
        TMP_SMQ02 = !is.na(SMQ02NAM),
        TMP_CQ01 = !is.na(CQ01NAM)
      )
    column_labels <- list(
      TMPFL_SER = "Serious AE",
      TMPFL_REL = "Related AE",
      TMPFL_GR5 = "Grade 5 AE",
      TMP_SMQ01 = aesi_label(dat[["SMQ01NAM"]], dat[["SMQ01SC"]]),
      TMP_SMQ02 = aesi_label("Y.9.9.9.9/Z.9.9.9.9 AESI"),
      TMP_CQ01 = aesi_label(dat[["CQ01NAM"]])
    )
    col_labels(dat)[names(column_labels)] <- as.character(column_labels)
    dat
  }

  #' Generating user-defined event flags.
  ADAE <- ADAE %>% .add_event_flags()

  .ae_anl_vars <- names(ADAE)[startsWith(names(ADAE), "TMPFL_")]
  .aesi_vars <- names(ADAE)[startsWith(names(ADAE), "TMP_")]

  ADTTE <- tmc_ex_adtte

  # responder

  ADRS <- tmc_ex_adrs %>%
    mutate(
      AVALC = d_onco_rsp_label(AVALC) %>%
        with_label("Character Result/Finding")
    ) %>%
    filter(PARAMCD != "OVRINV" | AVISIT == "FOLLOW UP")


  ADQS <- tmc_ex_adqs %>%
    filter(ABLFL != "Y" & ABLFL2 != "Y") %>%
    filter(AVISIT %in% c("WEEK 1 DAY 8", "WEEK 2 DAY 15", "WEEK 3 DAY 22")) %>%
    mutate(
      AVISIT = as.factor(AVISIT),
      AVISITN = rank(AVISITN) %>%
        as.factor() %>%
        as.numeric() %>%
        as.factor() #' making consecutive numeric factor
    )
})
join_keys(data) <- default_cdisc_join_keys[names(data)]

ADSL <- data[["ADSL"]]
ADRS <- data[["ADRS"]]

app <- init(
  data = data,
  modules = modules(
    # -------------------------------------------------------------------------
    tm_a_mmrm(
      label = "MMRM",
      dataname = "ADQS",
      aval_var = choices_selected(c("AVAL", "CHG"), "AVAL"),
      id_var = choices_selected(c("USUBJID", "SUBJID"), "USUBJID"),
      arm_var = choices_selected(c("ARM", "ARMCD"), "ARM"),
      visit_var = choices_selected(c("AVISIT", "AVISITN"), "AVISIT"),
      arm_ref_comp = arm_ref_comp,
      paramcd = choices_selected(
        choices = value_choices(data[["ADQS"]], "PARAMCD", "PARAM"),
        selected = "FKSI-FWB"
      ),
      cov_var = choices_selected(c("BASE", "AGE", "SEX", "BASE:AVISIT"), NULL)
      , decorators = list(
        lsmeans_table = insert_rrow_decorator("A", .var_to_replace = "lsmeans_table")
        , lsmeans_plot = add_title_decorator("B", .var_to_replace = "lsmeans_plot")
        , covariance_table = insert_rrow_decorator("C", .var_to_replace = "covariance_table")
        , fixed_effects_table = insert_rrow_decorator("D", .var_to_replace = "fixed_effects_table")
        , diagnostic_table = insert_rrow_decorator(.var_to_replace = "diagnostic_table")
        , diagnostic_plot = add_title_decorator(.var_to_replace = "diagnostic_plot")
      )
    ),
    # -------------------------------------------------------------------------
    tm_t_binary_outcome(
      label = "Responders",
      dataname = "ADRS",
      paramcd = choices_selected(
        choices = value_choices(ADRS, "PARAMCD", "PARAM"),
        selected = "BESRSPI"
      ),
      arm_var = choices_selected(
        choices = variable_choices(ADRS, c("ARM", "ARMCD", "ACTARMCD")),
        selected = "ARM"
      ),
      arm_ref_comp = arm_ref_comp,
      strata_var = choices_selected(
        choices = variable_choices(ADRS, c("SEX", "BMRKR2", "RACE")),
        selected = "RACE"
      ),
      default_responses = list(
        BESRSPI = list(
          rsp = c("Complete Response (CR)", "Partial Response (PR)"),
          levels = c(
            "Complete Response (CR)", "Partial Response (PR)",
            "Stable Disease (SD)", "Progressive Disease (PD)"
          )
        ),
        INVET = list(
          rsp = c("Stable Disease (SD)", "Not Evaluable (NE)"),
          levels = c(
            "Complete Response (CR)", "Not Evaluable (NE)", "Partial Response (PR)",
            "Progressive Disease (PD)", "Stable Disease (SD)"
          )
        ),
        OVRINV = list(
          rsp = c("Progressive Disease (PD)", "Stable Disease (SD)"),
          levels = c("Progressive Disease (PD)", "Stable Disease (SD)", "Not Evaluable (NE)")
        )
      ),
      decorators = list(insert_rrow_decorator("I am a new row"))
    ),
    # -------------------------------------------------------------------------
    tm_t_events_summary(
      label = "Adverse Events Summary",
      dataname = "ADAE",
      arm_var = choices_selected(
        choices = variable_choices("ADSL", c("ARM", "ARMCD")),
        selected = "ARM"
      ),
      flag_var_anl = choices_selected(
        choices = variable_choices("ADAE", data[[".ae_anl_vars"]]),
        selected = data[[".ae_anl_vars"]][1],
        keep_order = TRUE,
        fixed = FALSE
      ),
      flag_var_aesi = choices_selected(
        choices = variable_choices("ADAE", data[[".aesi_vars"]]),
        selected = data[[".aesi_vars"]][1],
        keep_order = TRUE,
        fixed = FALSE
      ),
      add_total = TRUE,
      decorators = list(insert_rrow_decorator())
    ),
    # -------------------------------------------------------------------------
    tm_t_summary(
      label = "Demographic Table",
      dataname = "ADSL",
      arm_var = choices_selected(c("ARM", "ARMCD"), "ARM"),
      add_total = TRUE,
      summarize_vars = choices_selected(
        c("SEX", "RACE", "BMRKR2", "EOSDY", "DCSREAS", "AGE"),
        c("SEX", "RACE")
      ),
      useNA = "ifany",
      decorators = list(insert_rrow_decorator())
    )
  )
) |> shiny::runApp()
```

</details>
averissimo added a commit to insightsengineering/teal.modules.clinical that referenced this issue Dec 17, 2024
# Pull Request

<!--- Replace `#nnn` with your issue link for reference. -->

Part of
insightsengineering/teal#1371 (comment)

### Changes description

- Tracks changes in the template code of the decorators feature branch
- Renames variables to be `plot`, `table` or (in case of multiple
decoratable elements) `<name>_plot` and `<name>_table`

### Workflow

Manually triggered:
https://github.com/insightsengineering/teal.modules.clinical/actions/runs/12359120026

[![Check
🛠](https://github.com/insightsengineering/teal.modules.clinical/actions/workflows/check.yaml/badge.svg?branch=snapshots%401187_decorate_output%40main)](https://github.com/insightsengineering/teal.modules.clinical/actions/workflows/check.yaml)
averissimo added a commit to insightsengineering/teal.modules.clinical that referenced this issue Dec 17, 2024
- Partner to insightsengineering/teal#1357
- Introduces decorators to modules. More about decorators in here
insightsengineering/teal#1384
- Part 1 of
insightsengineering/teal#1371 (comment)

### Changes description

- Adds internal wrapper around `srv_decorate_data` as utility to append
code after decorator _(such as `print(plot)`)_
- Implements decorators in modules

#### Checklist for final review:

Double check check for every module:

- Works with and without decorators
- Has param and section in documentation
- Code shows in "Show R code"
- Reporter shows both the outputs and code

#### Todo on feature branch

- [x] Link the `teal_transform_module` parameter to an extended
explanation as [suggested
here](https://github.com/insightsengineering/teal.modules.clinical/pull/1252/files/a78c0baa0996fb30fdff551bccb7bab0ec86caa6#r1870909229)
- [x] Meet with SME to validate some changes in template, topics:
  - modules with listing/dt
- Merge all modules
- [x] Part 1 of
insightsengineering/teal#1371 (comment)
- [x] Part 2 of
insightsengineering/teal#1371 (comment)
- [x] Accept changes to snapshots in regression testing
#1304

#### Example apps

Not all modules could be used in same App as the examples' data are not
100% compatible. Hence the 2 apps below.

<details>
<summary>Example app</summary>

```r
# Load packages
pkgload::load_all("../teal.modules.clinical", export_all = FALSE)

# Decorators ------------------------------------------------------------------
insert_rrow_decorator <- function(default_caption = "I am a good new row", .var_to_replace = "table") {
  teal_transform_module(
    label = "New rtables row",
    ui = function(id) shiny::textInput(shiny::NS(id, "new_row"), "New row", value = default_caption),
    server = make_teal_transform_server(
      substitute({
        .var_to_replace <- rtables::insert_rrow(.var_to_replace, rtables::rrow(new_row))
      }, env = list(.var_to_replace = as.name(.var_to_replace)))
    )
  )
}
add_title_decorator <- function(default_check = TRUE, .var_to_replace = "plot") {
  teal_transform_module(
    label = "Title",
    ui = function(id) shiny::checkboxInput(NS(id, "flag"), "Add title?", TRUE),
    server = make_teal_transform_server(
      substitute({
        if (flag) .var_to_replace <-
            .var_to_replace + ggplot2::ggtitle("Title added by decorator")
      },
      env = list(.var_to_replace = as.name(.var_to_replace))
      )
    )
  )
}
caption_decorator <- function(default_caption = "I am a good decorator", .var_to_replace = "plot") {
  teal_transform_module(
    label = "Caption",
    ui = function(id) shiny::textInput(shiny::NS(id, "footnote"), "Footnote", value = default_caption),
    server = make_teal_transform_server(
      substitute({
        .var_to_replace <- .var_to_replace + ggplot2::labs(caption = footnote)
      }, env = list(.var_to_replace = as.name(.var_to_replace)))
    )
  )
}
change_theme_decorator <- function(default_check = TRUE, .var_to_replace = "plot") {
  teal_transform_module(
    label = "Theme",
    ui = function(id) shiny::checkboxInput(NS(id, "flag"), "Apply dark theme?", TRUE),
    server = make_teal_transform_server(
      substitute({
        if (flag) .var_to_replace <- .var_to_replace + ggplot2::theme_dark()
      },
      env = list(.var_to_replace = as.name(.var_to_replace))
      )
    )
  )
}
add_cowplot_title_decorator <- function(default_check = TRUE, .var_to_replace = "plot") {
  teal_transform_module(
    label = "Cowplot title",
    ui = function(id) shiny::checkboxInput(NS(id, "flag"), "Add title?", TRUE),
    server = make_teal_transform_server(
      substitute({
        if (flag) .var_to_replace <-
            .var_to_replace +
            ggplot2::ggtitle("Title added by decorator") +
            cowplot::theme_cowplot()
      },
      env = list(.var_to_replace = as.name(.var_to_replace))
      )
    )
  )
}
rlisting_footer <- function(default_footer = "I am a good footer", .var_to_replace = "table_listing") {
  teal_transform_module(
    label = "New row",
    ui = function(id) shiny::textInput(shiny::NS(id, "footer"), "footer", value = default_footer),
    server = make_teal_transform_server(
      substitute({
        rlistings::main_footer(.var_to_replace) <- footer
      }, env = list(.var_to_replace = as.name(.var_to_replace)))
    )
  )
}

# End of decorators -----------------------------------------------------------

library(dplyr)

# arm_ref_comp <- list(ARMCD = list(ref = "ARM B", comp = c("ARM A", "ARM C")))

arm_ref_comp <- list(
  ACTARMCD = list(ref = "ARM B", comp = c("ARM A", "ARM C")),
  ARM = list(ref = "B: Placebo", comp = c("A: Drug X", "C: Combination"))
)

data <- within(teal_data(), {
  ADSL <- tmc_ex_adsl |>
    mutate(ITTFL = factor("Y") |> with_label("Intent-To-Treat Population Flag")) |>
    mutate(DTHFL = case_when(!is.na(DTHDT) ~ "Y", TRUE ~ "") |> with_label("Subject Death Flag"))

  ADAE <- tmc_ex_adae |>
    filter(!((AETOXGR == 1) & (AESEV == "MILD") & (ARM == "A: Drug X")))

  ADAE$ASTDY <- structure(
    as.double(ADAE$ASTDY, unit = attr(ADAE$ASTDY, "units", exact = TRUE)),
    label = attr(ADAE$ASTDY, "label", exact = TRUE)
  )

  .lbls_adae <- col_labels(tmc_ex_adae)
  ADAE <- tmc_ex_adae %>%
    mutate_if(is.character, as.factor) #' be certain of having factors
  col_labels(ADAE) <- .lbls_adae

  ADTTE <- tmc_ex_adtte

  ADLB <- tmc_ex_adlb |>
    mutate(AVISIT == forcats::fct_reorder(AVISIT, AVISITN, min)) |>
    mutate(
      ONTRTFL = case_when(
        AVISIT %in% c("SCREENING", "BASELINE") ~ "",
        TRUE ~ "Y"
      ) |> with_label("On Treatment Record Flag")
    )

  ADVS <- tmc_ex_advs

  ADRS <- tmc_ex_adrs |>
    mutate(
      AVALC = d_onco_rsp_label(AVALC) |>
        with_label("Character Result/Finding")
    ) |>
    filter(PARAMCD != "OVRINV" | AVISIT == "FOLLOW UP") |>
    filter(PARAMCD %in% c("BESRSPI", "INVET"))

  ADAETTE <- tmc_ex_adaette %>%
    filter(PARAMCD %in% c("AETTE1", "AETTE2", "AETTE3")) %>%
    mutate(is_event = CNSR == 0) %>%
    mutate(n_events = as.integer(is_event))

  .add_event_flags <- function(dat) {
    dat <- dat %>%
      mutate(
        TMPFL_SER = AESER == "Y",
        TMPFL_REL = AEREL == "Y",
        TMPFL_GR5 = AETOXGR == "5",
        TMP_SMQ01 = !is.na(SMQ01NAM),
        TMP_SMQ02 = !is.na(SMQ02NAM),
        TMP_CQ01 = !is.na(CQ01NAM)
      )
    column_labels <- list(
      TMPFL_SER = "Serious AE",
      TMPFL_REL = "Related AE",
      TMPFL_GR5 = "Grade 5 AE",
      TMP_SMQ01 = aesi_label(dat[["SMQ01NAM"]], dat[["SMQ01SC"]]),
      TMP_SMQ02 = aesi_label("Y.9.9.9.9/Z.9.9.9.9 AESI"),
      TMP_CQ01 = aesi_label(dat[["CQ01NAM"]])
    )
    col_labels(dat)[names(column_labels)] <- as.character(column_labels)
    dat
  }

  ADEX <- tmc_ex_adex

  set.seed(1, kind = "Mersenne-Twister")
  .labels <- col_labels(ADEX, fill = FALSE)
  ADEX <- ADEX %>%
    distinct(USUBJID, .keep_all = TRUE) %>%
    mutate(
      PARAMCD = "TDURD",
      PARAM = "Overall duration (days)",
      AVAL = sample(x = seq(1, 200), size = n(), replace = TRUE),
      AVALU = "Days"
    ) %>%
    bind_rows(ADEX)
  col_labels(ADEX) <- .labels

  ADCM <- tmc_ex_adcm

  ADMH <- tmc_ex_admh

  ADCM$CMASTDTM <- ADCM$ASTDTM
  ADCM$CMAENDTM <- ADCM$AENDTM

  ADEG <- tmc_ex_adeg

  # smq
  .names_baskets <- grep("^(SMQ|CQ).*NAM$", names(ADAE), value = TRUE)
  .names_scopes <- grep("^SMQ.*SC$", names(ADAE), value = TRUE)

  .cs_baskets <- choices_selected(
    choices = variable_choices(ADAE, subset = .names_baskets),
    selected = .names_baskets
  )

  .cs_scopes <- choices_selected(
    choices = variable_choices(ADAE, subset = .names_scopes),
    selected = .names_scopes,
    fixed = TRUE
  )

  # summary
  ADSL$EOSDY[1] <- NA_integer_
})
join_keys(data) <- default_cdisc_join_keys[names(data)]
adcm_keys <- c("STUDYID", "USUBJID", "ASTDTM", "CMSEQ", "ATC1", "ATC2", "ATC3", "ATC4")
join_keys(data)["ADCM", "ADCM"] <- adcm_keys

# Use in choices selected -----------------------------------------------------

ADSL <- data[["ADSL"]]
ADQS <- data[["ADQS"]]
ADAE <- data[["ADAE"]]
ADTTE <- data[["ADTTE"]]
ADLB <- data[["ADLB"]]
ADAE <- data[["ADAE"]]
ADVS <- data[["ADVS"]]
ADRS <- data[["ADRS"]]
ADAETTE <- data[["ADAETTE"]]
ADEX <- data[["ADEX"]]
ADCM <- data[["ADCM"]]
ADMH <- data[["ADMH"]]
ADEG <- data[["ADEG"]]

# Init ------------------------------------------------------------------------

init(
  data = data,
  modules = modules(
    # -------------------------------------------------------------------------
    tm_t_summary_by(
      label = "Summary by Row Groups Table",
      dataname = "ADLB",
      arm_var = choices_selected(
        choices = variable_choices(ADSL, c("ARM", "ARMCD")),
        selected = "ARM"
      ),
      add_total = TRUE,
      by_vars = choices_selected(
        choices = variable_choices(ADLB, c("PARAM", "AVISIT")),
        selected = c("AVISIT")
      ),
      summarize_vars = choices_selected(
        choices = variable_choices(ADLB, c("AVAL", "CHG")),
        selected = c("AVAL")
      ),
      useNA = "ifany",
      paramcd = choices_selected(
        choices = value_choices(ADLB, "PARAMCD", "PARAM"),
        selected = "ALT"
      ),
      decorators = list(insert_rrow_decorator())
    ),
    # -------------------------------------------------------------------------
    tm_t_smq(
      label = "Adverse Events by SMQ Table",
      dataname = "ADAE",
      arm_var = choices_selected(
        choices = variable_choices(data[["ADSL"]], subset = c("ARM", "SEX")),
        selected = "ARM"
      ),
      add_total = FALSE,
      baskets = data[[".cs_baskets"]],
      scopes = data[[".cs_scopes"]],
      llt = choices_selected(
        choices = variable_choices(data[["ADAE"]], subset = c("AEDECOD")),
        selected = "AEDECOD"
      ),
      decorators = list(insert_rrow_decorator())
    ),
    # -------------------------------------------------------------------------
    tm_t_shift_by_grade(
      label = "Grade Laboratory Abnormality Table",
      dataname = "ADLB",
      arm_var = choices_selected(
        choices = variable_choices(ADSL, subset = c("ARM", "ARMCD")),
        selected = "ARM"
      ),
      paramcd = choices_selected(
        choices = value_choices(ADLB, "PARAMCD", "PARAM"),
        selected = "ALT"
      ),
      worst_flag_var = choices_selected(
        choices = variable_choices(ADLB, subset = c("WGRLOVFL", "WGRLOFL", "WGRHIVFL", "WGRHIFL")),
        selected = c("WGRLOVFL")
      ),
      worst_flag_indicator = choices_selected(
        value_choices(ADLB, "WGRLOVFL"),
        selected = "Y", fixed = TRUE
      ),
      anl_toxgrade_var = choices_selected(
        choices = variable_choices(ADLB, subset = c("ATOXGR")),
        selected = c("ATOXGR"),
        fixed = TRUE
      ),
      base_toxgrade_var = choices_selected(
        choices = variable_choices(ADLB, subset = c("BTOXGR")),
        selected = c("BTOXGR"),
        fixed = TRUE
      ),
      add_total = FALSE,
      decorators = list(insert_rrow_decorator())
    ),
    # -------------------------------------------------------------------------
    tm_t_shift_by_arm(
      label = "Shift by Arm Table",
      dataname = "ADEG",
      arm_var = choices_selected(
        variable_choices(ADSL, subset = c("ARM", "ARMCD")),
        selected = "ARM"
      ),
      paramcd = choices_selected(
        value_choices(ADEG, "PARAMCD"),
        selected = "HR"
      ),
      visit_var = choices_selected(
        value_choices(ADEG, "AVISIT"),
        selected = "POST-BASELINE MINIMUM"
      ),
      aval_var = choices_selected(
        variable_choices(ADEG, subset = "ANRIND"),
        selected = "ANRIND",
        fixed = TRUE
      ),
      baseline_var = choices_selected(
        variable_choices(ADEG, subset = "BNRIND"),
        selected = "BNRIND",
        fixed = TRUE
      ),
      useNA = "ifany",
      decorators = list(insert_rrow_decorator())
    ),
    # -------------------------------------------------------------------------
    tm_t_shift_by_arm_by_worst(
      label = "Shift by Arm Table (by worst)",
      dataname = "ADEG",
      arm_var = choices_selected(
        variable_choices(ADSL, subset = c("ARM", "ARMCD")),
        selected = "ARM"
      ),
      paramcd = choices_selected(
        value_choices(ADEG, "PARAMCD"),
        selected = "ECGINTP"
      ),
      worst_flag_var = choices_selected(
        variable_choices(ADEG, c("WORS02FL", "WORS01FL")),
        selected = "WORS02FL"
      ),
      worst_flag = choices_selected(
        value_choices(ADEG, "WORS02FL"),
        selected = "Y",
        fixed = TRUE
      ),
      aval_var = choices_selected(
        variable_choices(ADEG, c("AVALC", "ANRIND")),
        selected = "AVALC"
      ),
      baseline_var = choices_selected(
        variable_choices(ADEG, c("BASEC", "BNRIND")),
        selected = "BASEC"
      ),
      useNA = "ifany",
      decorators = list(insert_rrow_decorator())
    ),
    # -------------------------------------------------------------------------
    tm_t_pp_prior_medication(
      label = "Prior Medication",
      dataname = "ADCM",
      parentname = "ADSL",
      patient_col = "USUBJID",
      atirel = choices_selected(
        choices = variable_choices(ADCM, "ATIREL"),
        selected = "ATIREL"
      ),
      cmdecod = choices_selected(
        choices = variable_choices(ADCM, "CMDECOD"),
        selected = "CMDECOD"
      ),
      cmindc = choices_selected(
        choices = variable_choices(ADCM, "CMINDC"),
        selected = "CMINDC"
      ),
      cmstdy = choices_selected(
        choices = variable_choices(ADCM, "ASTDY"),
        selected = "ASTDY"
      ),
      decorators = list(
        table = rlisting_footer(.var_to_replace = "table")
      )
    ),
    # -------------------------------------------------------------------------
    tm_t_pp_medical_history(
      label = "Medical History",
      dataname = "ADMH",
      parentname = "ADSL",
      patient_col = "USUBJID",
      mhterm = choices_selected(
        choices = variable_choices(ADMH, c("MHTERM")),
        selected = "MHTERM"
      ),
      mhbodsys = choices_selected(
        choices = variable_choices(ADMH, "MHBODSYS"),
        selected = "MHBODSYS"
      ),
      mhdistat = choices_selected(
        choices = variable_choices(ADMH, "MHDISTAT"),
        selected = "MHDISTAT"
      ),
      decorators = list(insert_rrow_decorator())
    ),
    # -------------------------------------------------------------------------
    tm_t_pp_laboratory(
      label = "Vitals",
      dataname = "ADLB",
      patient_col = "USUBJID",
      paramcd = choices_selected(
        choices = variable_choices(ADLB, "PARAMCD"),
        selected = "PARAMCD"
      ),
      param = choices_selected(
        choices = variable_choices(ADLB, "PARAM"),
        selected = "PARAM"
      ),
      timepoints = choices_selected(
        choices = variable_choices(ADLB, "ADY"),
        selected = "ADY"
      ),
      anrind = choices_selected(
        choices = variable_choices(ADLB, "ANRIND"),
        selected = "ANRIND"
      ),
      aval_var = choices_selected(
        choices = variable_choices(ADLB, "AVAL"),
        selected = "AVAL"
      ),
      avalu_var = choices_selected(
        choices = variable_choices(ADLB, "AVALU"),
        selected = "AVALU"
      ),
      decorators = list(table = rlisting_footer(.var_to_replace = "table"))
    ),
    # -------------------------------------------------------------------------
    tm_t_pp_basic_info(
      label = "Basic Info",
      dataname = "ADSL",
      patient_col = "USUBJID",
      vars = choices_selected(choices = variable_choices(ADSL), selected = c("ARM", "AGE", "SEX", "COUNTRY", "RACE", "EOSSTT"))
      , decorators = list(
        table = rlisting_footer(.var_to_replace = "table")
      )
    ),
    # -------------------------------------------------------------------------
    tm_t_mult_events(
      label = "Concomitant Medications by Medication Class and Preferred Name",
      dataname = "ADCM",
      arm_var = choices_selected(c("ARM", "ARMCD"), "ARM"),
      seq_var = choices_selected("CMSEQ", selected = "CMSEQ", fixed = TRUE),
      hlt = choices_selected(
        choices = variable_choices(ADCM, c("ATC1", "ATC2", "ATC3", "ATC4")),
        selected = c("ATC1", "ATC2", "ATC3", "ATC4")
      ),
      llt = choices_selected(choices = variable_choices(ADCM, c("CMDECOD")), selected = c("CMDECOD")),
      add_total = TRUE,
      event_type = "treatment",
      decorators = list(insert_rrow_decorator())
    ),
    # -------------------------------------------------------------------------
    tm_t_logistic(
      label = "Logistic Regression",
      dataname = "ADRS",
      arm_var = choices_selected(
        choices = variable_choices(ADRS, c("ARM", "ARMCD")),
        selected = "ARM"
      ),
      arm_ref_comp = arm_ref_comp,
      paramcd = choices_selected(
        choices = value_choices(ADRS, "PARAMCD", "PARAM"),
        selected = "BESRSPI"
      ),
      cov_var = choices_selected(
        choices = c("SEX", "AGE", "BMRKR1", "BMRKR2"),
        selected = "SEX"
      ),
      decorators = list(insert_rrow_decorator())
    ),
    # -------------------------------------------------------------------------
    tm_t_exposure(
      label = "Duration of Exposure Table",
      dataname = "ADEX",
      paramcd = choices_selected(
        choices = value_choices(data[["ADEX"]], "PARAMCD", "PARAM"),
        selected = "TDURD"
      ),
      col_by_var = choices_selected(
        choices = variable_choices(data[["ADEX"]], subset = c("SEX", "ARM")),
        selected = "SEX"
      ),
      row_by_var = choices_selected(
        choices = variable_choices(data[["ADEX"]], subset = c("RACE", "REGION1", "STRATA1", "SEX")),
        selected = "RACE"
      ),
      parcat = choices_selected(
        choices = value_choices(data[["ADEX"]], "PARCAT2"),
        selected = "Drug A"
      ),
      add_total = FALSE,
      decorators = list(insert_rrow_decorator())
    ),
    # -------------------------------------------------------------------------
    tm_t_events(
      label = "Adverse Event Table",
      dataname = "ADAE",
      arm_var = choices_selected(c("ARM", "ARMCD"), "ARM"),
      llt = choices_selected(
        choices = variable_choices(ADAE, c("AETERM", "AEDECOD")),
        selected = c("AEDECOD")
      ),
      hlt = choices_selected(
        choices = variable_choices(ADAE, c("AEBODSYS", "AESOC")),
        selected = "AEBODSYS"
      ),
      add_total = TRUE,
      event_type = "adverse event",
      decorators = list(insert_rrow_decorator())
    ),
    # -------------------------------------------------------------------------
    tm_t_events_patyear(
      label = "AE Rate Adjusted for Patient-Years At Risk Table",
      dataname = "ADAETTE",
      arm_var = choices_selected(
        choices = variable_choices(ADSL, c("ARM", "ARMCD")),
        selected = "ARMCD"
      ),
      add_total = TRUE,
      events_var = choices_selected(
        choices = variable_choices(ADAETTE, "n_events"),
        selected = "n_events",
        fixed = TRUE
      ),
      paramcd = choices_selected(
        choices = value_choices(ADAETTE, "PARAMCD", "PARAM"),
        selected = "AETTE1"
      ),
      decorators = list(insert_rrow_decorator())
    ),
    # -------------------------------------------------------------------------
    tm_t_events_by_grade(
      label = "Adverse Events by Grade Table",
      dataname = "ADAE",
      arm_var = choices_selected(c("ARM", "ARMCD"), "ARM"),
      llt = choices_selected(
        choices = variable_choices(ADAE, c("AETERM", "AEDECOD")),
        selected = c("AEDECOD")
      ),
      hlt = choices_selected(
        choices = variable_choices(ADAE, c("AEBODSYS", "AESOC")),
        selected = "AEBODSYS"
      ),
      grade = choices_selected(
        choices = variable_choices(ADAE, c("AETOXGR", "AESEV")),
        selected = "AETOXGR"
      ),
      decorators = list(insert_rrow_decorator())
    ),
    # -------------------------------------------------------------------------
    tm_t_coxreg(
      label = "Cox Reg.",
      dataname = "ADTTE",
      arm_var = choices_selected(c("ARM", "ARMCD", "ACTARMCD"), "ARM"),
      arm_ref_comp = arm_ref_comp,
      paramcd = choices_selected(
        value_choices(ADTTE, "PARAMCD", "PARAM"), "OS"
      ),
      strata_var = choices_selected(
        c("COUNTRY", "STRATA1", "STRATA2"), "STRATA1"
      ),
      cov_var = choices_selected(
        c("AGE", "BMRKR1", "BMRKR2", "REGION1"), "AGE"
      ),
      multivariate = TRUE,
      decorators = list(insert_rrow_decorator())
    ),
    # -------------------------------------------------------------------------
    tm_t_abnormality(
      label = "Abnormality Table",
      dataname = "ADLB",
      arm_var = choices_selected(
        choices = variable_choices(ADSL, subset = c("ARM", "ARMCD")),
        selected = "ARM"
      ),
      add_total = FALSE,
      by_vars = choices_selected(
        choices = variable_choices(ADLB, subset = c("LBCAT", "PARAM", "AVISIT")),
        selected = c("LBCAT", "PARAM"),
        keep_order = TRUE
      ),
      baseline_var = choices_selected(
        variable_choices(ADLB, subset = "BNRIND"),
        selected = "BNRIND", fixed = TRUE
      ),
      grade = choices_selected(
        choices = variable_choices(ADLB, subset = "ANRIND"),
        selected = "ANRIND",
        fixed = TRUE
      ),
      abnormal = list(low = "LOW", high = "HIGH"),
      exclude_base_abn = FALSE,
      decorators = list(insert_rrow_decorator("I am a good new row"))
    ),
    # -------------------------------------------------------------------------
    tm_g_pp_vitals(
      label = "Vitals",
      dataname = "ADVS",
      parentname = "ADSL",
      patient_col = "USUBJID",
      plot_height = c(600L, 200L, 2000L),
      paramcd = choices_selected(
        choices = variable_choices(ADVS, "PARAMCD"),
        selected = "PARAMCD"
      ),
      xaxis = choices_selected(
        choices = variable_choices(ADVS, "ADY"),
        selected = "ADY"
      ),
      aval_var = choices_selected(
        choices = variable_choices(ADVS, "AVAL"),
        selected = "AVAL"
      ),
      decorators = list(plot = add_title_decorator("plot"))
    ),
    # -------------------------------------------------------------------------
    tm_g_pp_adverse_events(
      label = "Adverse Events",
      dataname = "ADAE",
      parentname = "ADSL",
      patient_col = "USUBJID",
      plot_height = c(600L, 200L, 2000L),
      aeterm = choices_selected(
        choices = variable_choices(ADAE, "AETERM"),
        selected = "AETERM"
      ),
      tox_grade = choices_selected(
        choices = variable_choices(ADAE, "AETOXGR"),
        selected = "AETOXGR"
      ),
      causality = choices_selected(
        choices = variable_choices(ADAE, "AEREL"),
        selected = "AEREL"
      ),
      outcome = choices_selected(
        choices = variable_choices(ADAE, "AEOUT"),
        selected = "AEOUT"
      ),
      action = choices_selected(
        choices = variable_choices(ADAE, "AEACN"),
        selected = "AEACN"
      ),
      time = choices_selected(
        choices = variable_choices(ADAE, "ASTDY"),
        selected = "ASTDY"
      ),
      decod = NULL,
      decorators = list(
        plot = caption_decorator('I am a good caption', 'plot'),
        table = rlisting_footer(.var_to_replace = 'table')
      )
    ),
    # -------------------------------------------------------------------------
    tm_g_lineplot(
      label = "Line Plot",
      dataname = "ADLB",
      strata = choices_selected(
        variable_choices(ADSL, c("ARM", "ARMCD", "ACTARMCD")),
        "ARM"
      ),
      y = choices_selected(
        variable_choices(ADLB, c("AVAL", "BASE", "CHG", "PCHG")),
        "AVAL"
      ),
      param = choices_selected(
        value_choices(ADLB, "PARAMCD", "PARAM"),
        "ALT"
      ),
      decorators = list(add_cowplot_title_decorator("plot"))
    ),
    # -------------------------------------------------------------------------
    tm_g_km(
      label = "Kaplan-Meier Plot",
      dataname = "ADTTE",
      arm_var = choices_selected(
        variable_choices(ADSL, c("ARM", "ARMCD", "ACTARMCD")),
        "ARM"
      ),
      paramcd = choices_selected(
        value_choices(ADTTE, "PARAMCD", "PARAM"),
        "OS"
      ),
      arm_ref_comp = arm_ref_comp,
      strata_var = choices_selected(
        variable_choices(ADSL, c("SEX", "BMRKR2")),
        "SEX"
      ),
      facet_var = choices_selected(
        variable_choices(ADSL, c("SEX", "BMRKR2")),
        NULL
      ),
      decorators = list(plot = add_cowplot_title_decorator(TRUE, "plot"))
    ),
    # -------------------------------------------------------------------------
    tm_g_barchart_simple(
      label = "ADAE Analysis",
      x = data_extract_spec(
        dataname = "ADSL",
        select = select_spec(
          choices = variable_choices(
            ADSL,
            c(
              "ARM", "ACTARM", "SEX",
              "RACE", "ITTFL", "SAFFL", "STRATA2"
            )
          ),
          selected = "ACTARM",
          multiple = FALSE
        )
      ),
      fill = list(
        data_extract_spec(
          dataname = "ADSL",
          select = select_spec(
            choices = variable_choices(
              ADSL,
              c(
                "ARM", "ACTARM", "SEX",
                "RACE", "ITTFL", "SAFFL", "STRATA2"
              )
            ),
            selected = "SEX",
            multiple = FALSE
          )
        ),
        data_extract_spec(
          dataname = "ADAE",
          select = select_spec(
            choices = variable_choices(ADAE, c("AETOXGR", "AESEV", "AESER")),
            selected = NULL,
            multiple = FALSE
          )
        )
      ),
      x_facet = list(
        data_extract_spec(
          dataname = "ADAE",
          select = select_spec(
            choices = variable_choices(ADAE, c("AETOXGR", "AESEV", "AESER")),
            selected = "AETOXGR",
            multiple = FALSE
          )
        ),
        data_extract_spec(
          dataname = "ADSL",
          select = select_spec(
            choices = variable_choices(
              ADSL,
              c(
                "ARM", "ACTARM", "SEX",
                "RACE", "ITTFL", "SAFFL", "STRATA2"
              )
            ),
            selected = NULL,
            multiple = FALSE
          )
        )
      ),
      y_facet = list(
        data_extract_spec(
          dataname = "ADAE",
          select = select_spec(
            choices = variable_choices(ADAE, c("AETOXGR", "AESEV", "AESER")),
            selected = "AESEV",
            multiple = FALSE
          )
        ),
        data_extract_spec(
          dataname = "ADSL",
          select = select_spec(
            choices = variable_choices(
              ADSL,
              c(
                "ARM", "ACTARM", "SEX",
                "RACE", "ITTFL", "SAFFL", "STRATA2"
              )
            ),
            selected = NULL,
            multiple = FALSE
          )
        )
      ),
      decorators = list(plot = caption_decorator('The best', 'plot'))
    )
  )
) |> shiny::runApp()

```

</details>    

<details>
<summary>Second App</summary>

```r
# Load packages
pkgload::load_all("../teal.modules.clinical", export_all = FALSE)
# Example below

insert_rrow_decorator <- function(default_caption = "I am a good new row", .var_to_replace = "table") {
  teal_transform_module(
    label = "New row",
    ui = function(id) shiny::textInput(shiny::NS(id, "new_row"), "New row", value = default_caption),
    server = make_teal_transform_server(
      substitute({
        .var_to_replace <- rtables::insert_rrow(.var_to_replace, rtables::rrow(new_row))
      }, env = list(.var_to_replace = as.name(.var_to_replace)))
    )
  )
}

# Preparation of the test case - use `EOSDY` and `DCSREAS` variables to demonstrate missing data.
data <- teal_data()
data <- within(data, {
  ADSL <- tmc_ex_adsl |>
    mutate(
      DTHFL = case_when(
        !is.na(DTHDT) ~ "Y",
        TRUE ~ ""
      ) %>% with_label("Subject Death Flag")
    )
  ADSL$EOSDY[1] <- NA_integer_

  ADAE <- tmc_ex_adae

  .add_event_flags <- function(dat) {
    dat <- dat %>%
      mutate(
        TMPFL_SER = AESER == "Y",
        TMPFL_REL = AEREL == "Y",
        TMPFL_GR5 = AETOXGR == "5",
        TMP_SMQ01 = !is.na(SMQ01NAM),
        TMP_SMQ02 = !is.na(SMQ02NAM),
        TMP_CQ01 = !is.na(CQ01NAM)
      )
    column_labels <- list(
      TMPFL_SER = "Serious AE",
      TMPFL_REL = "Related AE",
      TMPFL_GR5 = "Grade 5 AE",
      TMP_SMQ01 = aesi_label(dat[["SMQ01NAM"]], dat[["SMQ01SC"]]),
      TMP_SMQ02 = aesi_label("Y.9.9.9.9/Z.9.9.9.9 AESI"),
      TMP_CQ01 = aesi_label(dat[["CQ01NAM"]])
    )
    col_labels(dat)[names(column_labels)] <- as.character(column_labels)
    dat
  }

  #' Generating user-defined event flags.
  ADAE <- ADAE %>% .add_event_flags()

  .ae_anl_vars <- names(ADAE)[startsWith(names(ADAE), "TMPFL_")]
  .aesi_vars <- names(ADAE)[startsWith(names(ADAE), "TMP_")]

  ADTTE <- tmc_ex_adtte

  # responder

  ADRS <- tmc_ex_adrs %>%
    mutate(
      AVALC = d_onco_rsp_label(AVALC) %>%
        with_label("Character Result/Finding")
    ) %>%
    filter(PARAMCD != "OVRINV" | AVISIT == "FOLLOW UP")


  ADQS <- tmc_ex_adqs %>%
    filter(ABLFL != "Y" & ABLFL2 != "Y") %>%
    filter(AVISIT %in% c("WEEK 1 DAY 8", "WEEK 2 DAY 15", "WEEK 3 DAY 22")) %>%
    mutate(
      AVISIT = as.factor(AVISIT),
      AVISITN = rank(AVISITN) %>%
        as.factor() %>%
        as.numeric() %>%
        as.factor() #' making consecutive numeric factor
    )
})
join_keys(data) <- default_cdisc_join_keys[names(data)]

ADSL <- data[["ADSL"]]
ADRS <- data[["ADRS"]]

app <- init(
  data = data,
  modules = modules(
    # -------------------------------------------------------------------------
    tm_a_mmrm(
      label = "MMRM",
      dataname = "ADQS",
      aval_var = choices_selected(c("AVAL", "CHG"), "AVAL"),
      id_var = choices_selected(c("USUBJID", "SUBJID"), "USUBJID"),
      arm_var = choices_selected(c("ARM", "ARMCD"), "ARM"),
      visit_var = choices_selected(c("AVISIT", "AVISITN"), "AVISIT"),
      arm_ref_comp = arm_ref_comp,
      paramcd = choices_selected(
        choices = value_choices(data[["ADQS"]], "PARAMCD", "PARAM"),
        selected = "FKSI-FWB"
      ),
      cov_var = choices_selected(c("BASE", "AGE", "SEX", "BASE:AVISIT"), NULL)
      , decorators = list(
        lsmeans_table = insert_rrow_decorator("A", .var_to_replace = "lsmeans_table")
        , lsmeans_plot = add_title_decorator("B", .var_to_replace = "lsmeans_plot")
        , covariance_table = insert_rrow_decorator("C", .var_to_replace = "covariance_table")
        , fixed_effects_table = insert_rrow_decorator("D", .var_to_replace = "fixed_effects_table")
        , diagnostic_table = insert_rrow_decorator(.var_to_replace = "diagnostic_table")
        , diagnostic_plot = add_title_decorator(.var_to_replace = "diagnostic_plot")
      )
    ),
    # -------------------------------------------------------------------------
    tm_t_binary_outcome(
      label = "Responders",
      dataname = "ADRS",
      paramcd = choices_selected(
        choices = value_choices(ADRS, "PARAMCD", "PARAM"),
        selected = "BESRSPI"
      ),
      arm_var = choices_selected(
        choices = variable_choices(ADRS, c("ARM", "ARMCD", "ACTARMCD")),
        selected = "ARM"
      ),
      arm_ref_comp = arm_ref_comp,
      strata_var = choices_selected(
        choices = variable_choices(ADRS, c("SEX", "BMRKR2", "RACE")),
        selected = "RACE"
      ),
      default_responses = list(
        BESRSPI = list(
          rsp = c("Complete Response (CR)", "Partial Response (PR)"),
          levels = c(
            "Complete Response (CR)", "Partial Response (PR)",
            "Stable Disease (SD)", "Progressive Disease (PD)"
          )
        ),
        INVET = list(
          rsp = c("Stable Disease (SD)", "Not Evaluable (NE)"),
          levels = c(
            "Complete Response (CR)", "Not Evaluable (NE)", "Partial Response (PR)",
            "Progressive Disease (PD)", "Stable Disease (SD)"
          )
        ),
        OVRINV = list(
          rsp = c("Progressive Disease (PD)", "Stable Disease (SD)"),
          levels = c("Progressive Disease (PD)", "Stable Disease (SD)", "Not Evaluable (NE)")
        )
      ),
      decorators = list(insert_rrow_decorator("I am a new row"))
    ),
    # -------------------------------------------------------------------------
    tm_t_events_summary(
      label = "Adverse Events Summary",
      dataname = "ADAE",
      arm_var = choices_selected(
        choices = variable_choices("ADSL", c("ARM", "ARMCD")),
        selected = "ARM"
      ),
      flag_var_anl = choices_selected(
        choices = variable_choices("ADAE", data[[".ae_anl_vars"]]),
        selected = data[[".ae_anl_vars"]][1],
        keep_order = TRUE,
        fixed = FALSE
      ),
      flag_var_aesi = choices_selected(
        choices = variable_choices("ADAE", data[[".aesi_vars"]]),
        selected = data[[".aesi_vars"]][1],
        keep_order = TRUE,
        fixed = FALSE
      ),
      add_total = TRUE,
      decorators = list(insert_rrow_decorator())
    ),
    # -------------------------------------------------------------------------
    tm_t_summary(
      label = "Demographic Table",
      dataname = "ADSL",
      arm_var = choices_selected(c("ARM", "ARMCD"), "ARM"),
      add_total = TRUE,
      summarize_vars = choices_selected(
        c("SEX", "RACE", "BMRKR2", "EOSDY", "DCSREAS", "AGE"),
        c("SEX", "RACE")
      ),
      useNA = "ifany",
      decorators = list(insert_rrow_decorator())
    )
  )
) |> shiny::runApp()
```

</details>

---------

Signed-off-by: Marcin <[email protected]>
Signed-off-by: Lluís Revilla <[email protected]>
Signed-off-by: André Veríssimo <[email protected]>
Co-authored-by: 27856297+dependabot-preview[bot]@users.noreply.github.com <27856297+dependabot-preview[bot]@users.noreply.github.com>
Co-authored-by: Marcin <[email protected]>
Co-authored-by: m7pr <[email protected]>
Co-authored-by: Lluís Revilla <[email protected]>
Co-authored-by: Lluís Revilla <[email protected]>
Co-authored-by: github-actions <41898282+github-actions[bot]@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

4 participants