insightsengineering / teal

Exploratory Web Apps for Analyzing Clinical Trial Data
https://insightsengineering.github.io/teal/
Other
176 stars 35 forks source link

round 2 - transform in a teal_module's ui/srv #1212

Closed gogonzo closed 3 months ago

gogonzo commented 5 months ago

Simplest solution

See the code below and transformers argument, then see example_module to see how the settings are utilized.

options(teal.log_level = "TRACE", teal.show_js_log = TRUE)
pkgload::load_all("teal")
library(teal.modules.general)
library(dplyr)
options(shiny.bookmarkStore = "server")
nest_logo <- "https://raw.githubusercontent.com/insightsengineering/hex-stickers/main/PNG/nest.png"

datasets <- c("IRIS", "MTCARS", "CO2", "AIRMILES", "TITANIC", "ADSL", "ADRS", "ADTTE", "ADLB", "ADQS")
data <- teal.data::teal_data() |> within({
  IRIS <- iris
  MTCARS <- mtcars
  CO2 <- CO2
  AIRMILES <- airmiles
  TITANIC <- Titanic
  ADSL <- teal.modules.general::rADSL %>%
    mutate(TRTDUR = round(as.numeric(TRTEDTM - TRTSDTM), 1))
  ADRS <- teal.modules.general::rADRS
  ADTTE <- teal.modules.general::rADTTE
  ADLB <- teal.modules.general::rADLB %>%
    mutate(CHGC = as.factor(case_when(
      CHG < 1 ~ "N",
      CHG > 1 ~ "P",
      TRUE ~ "-"
    )))
  ADQS <- teal.modules.clinical::tmc_ex_adqs %>%
    dplyr::filter(ABLFL != "Y" & ABLFL2 != "Y") %>%
    dplyr::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()
})
teal.data::datanames(data) <- datasets
teal.data::join_keys(data) <- teal.data::default_cdisc_join_keys[datanames(data)]
data

transform_iris_ui <- function(id) {
  ns <- NS(id)
  bslib::card(
    bslib::card_body(
      selectInput(
        ns("species"),
        "Select iris species",
        choices = c("setosa", "versicolor", "virginica"),
        selected = c("setosa", "versicolor", "virginica"),
        multiple = TRUE
      )
    )
  )
}

transform_iris_srv <- function(id, data) {
  moduleServer(id, function(input, output, session) {
    reactive({
      message("Filtering iris data")
      data() |> within(
        IRIS <- dplyr::filter(IRIS, Species %in% species),
        species = input$species
      )
    })
  })
}

transform_adrs_ui <- function(id) {
  ns <- NS(id)
  bslib::card(
    bslib::card_body(
      selectInput(
        ns("paramcd"),
        "Select Parameter",
        choices = c("BESRPSI", "INVET", "OVRINV"),
        selected = "OVRINV",
        multiple = TRUE
      ),
      selectInput(
        ns("avisit"),
        "Select a visit",
        choices = c(
          "SCREENING", "BASELINE", "CYCLE 2 DAY 1", "CYCLE 4 DAY 1",
          "END OF INDUCTION", "FOLLOW UP"
        ),
        selected = "SCREENING",
        multiple = TRUE
      )
    )
  )
}

transform_adrs_srv <- function(id, data) {
  moduleServer(id, function(input, output, session) {
    reactive({
      message("Filtering adrs data")
      data() |> within(
        ADRS <- dplyr::filter(ADRS, PARAMCD %in% paramcd, AVISIT %in% avisit),
        paramcd = input$paramcd,
        avisit = input$avisit
      )
    })
  })
}

transform_adtte_ui <- function(id) {
  ns <- NS(id)
  bslib::card(
    bslib::card_body(
      selectInput(
        ns("paramcd"),
        "Select Parameter",
        choices = c("CRSD", "EFS", "OS", "PFS", "TNE"),
        selected = "OS",
        multiple = TRUE
      )
    )
  )
}

transform_adtte_srv <- function(id, data) {
  moduleServer(id, function(input, output, session) {
    reactive({
      message("Filtering adtte data")
      data() |> within(
        ADTTE <- dplyr::filter(ADTTE, PARAMCD %in% paramcd),
        paramcd = input$paramcd
      )
    })
  })
}

app <- init(
  data = data,
  filter = teal_slices(
    teal_slice(dataname = "IRIS", varname = "Species", multiple = FALSE)
  ),
  modules = modules(
    example_module(
      label = "transform by arg",
      datanames = "all",
      transformers = list(
        teal_transform_module(
          ui = transform_iris_ui,
          server = transform_iris_srv,
          label = "transform iris"
        ),
        teal_transform_module(
          ui = transform_adrs_ui,
          server = transform_adrs_srv,
          label = "transform adrs"
        ),
        teal_transform_module(
          ui = transform_adtte_ui,
          server = transform_adtte_srv,
          label = "transform adtte"
        )
      )
    )
  )
)

shinyApp(app$ui, app$server)
m7pr commented 5 months ago

Spent some time today reviewing https://github.com/insightsengineering/teal/pull/1209 and I found this approach a lot easier and handier than what we've seen so far. Just a quick reply. Will come up with something bigger

m7pr commented 4 months ago

As I wrote in here https://github.com/insightsengineering/teal/pull/1209#issuecomment-2100147645, with this PR we are very flexible and can allow the whole module to be changed/transformed - not only the data