Skip to contents

There are times when an app developer wants to showcase more than just one fixed slice of their dataset in their custom module. Relinquishing control of the application to a user demands the developer gives their users a degree of freedom. In case of analyzing data, teal allows app developers to open up their applications to users, letting them decide exactly what app data to analyze in the module.

A lot of teal modules use data_extract_spec objects and modules to tackle user input. You can find many examples in e.g. teal.modules.general and teal.modules.clinical.

data_extract_spec

data_extract_spec’s task is two-fold: create a UI component in a shiny application and pass the user input from the UI to the module itself. Having that formulated, let’s have a look at how it supports both its responsibilities.

Example module

In order to showcase different initialization options of data_extract_spec, first we define a shiny module which uses data_extract_ui and data_extract_srv designed to handle data_extract_spec objects. The module creates a UI component for a single data_extract_spec and prints a list of values returned from data_extract_srv module. Please see package documentation for more information about data_extract_ui and data_extract_srv.

library(teal.transform)
#> Loading required package: magrittr
library(shiny)

extract_ui <- function(id, data_extract) {
  ns <- NS(id)
  teal.widgets::standard_layout(
    output = teal.widgets::white_small_well(verbatimTextOutput(ns("output"))),
    encoding = data_extract_ui(ns("data_extract"), label = "variable", data_extract)
  )
}

extract_srv <- function(id, datasets, data_extract, join_keys) {
  moduleServer(id, function(input, output, session) {
    reactive_extract_input <- data_extract_srv("data_extract", datasets, data_extract, join_keys)
    s <- reactive({
      format_data_extract(reactive_extract_input())
    })
    output$output <- renderPrint({
      cat(s())
    })
  })
}

Example data

data_extract_srv module depends on either a list of reactive or non-reactive data.frame objects. Here, we show the usage of a list of data.frame objects as input to datasets where a list of necessary join keys per data.frame object is required:

# Define data.frame objects
ADSL <- teal.transform::rADSL # nolint
ADTTE <- teal.transform::rADTTE # nolint

# create a list of data.frame objects
datasets <- list(ADSL = ADSL, ADTTE = ADTTE)

# create join_keys
join_keys <- teal.data::join_keys(
  teal.data::join_key("ADSL", "ADSL", c("STUDYID", "USUBJID")),
  teal.data::join_key("ADSL", "ADTTE", c("STUDYID", "USUBJID")),
  teal.data::join_key("ADTTE", "ADTTE", c("STUDYID", "USUBJID", "PARAMCD"))
)

Consider the following example, where we create two UI elements, one to filter on a specific level from SEX variable, and a second one to select a variable from c("BMRKR1", "AGE"). data_extract_spec object is handed over to the shiny app and gives instructions to generate UI components.

simple_des <- data_extract_spec(
  dataname = "ADSL",
  filter = filter_spec(vars = "SEX", choices = c("F", "M")),
  select = select_spec(choices = c("BMRKR1", "AGE"))
)

Shiny app

Finally, we pass extract_ui to the ui of the shinyApp and we use extract_srv in the server function of the shinyApp:

shinyApp(
  ui = fluidPage(extract_ui("data_extract", simple_des)),
  server = function(input, output, session) {
    extract_srv("data_extract", datasets, simple_des, join_keys)
  }
)