teal.picks without teal (standalone Shiny)
NEST CoreDev Team
2026-05-19
Source:vignettes/teal-picks-standalone-shiny.Rmd
teal-picks-standalone-shiny.RmdIntroduction
You can use picks_ui() and picks_srv() in a
plain Shiny app: pass a reactive teal.data::teal_data()
object to picks_srv() and combine results with
merge_srv() when you need merged analysis data. This
mirrors what tm_merge() does inside teal,
without teal::init().
Run the shinyApp chunk interactively.
library(shiny)
library(teal.data)
library(teal.picks)
data <- teal_data()
data <- within(data, {
ADSL <- data.frame(
USUBJID = sprintf("S%03d", 1:8),
AGE = sample(35:70, 8, replace = TRUE),
stringsAsFactors = FALSE
)
ADLB <- data.frame(
USUBJID = rep(sprintf("S%03d", 1:8), each = 3),
PARAM = rep(c("ALT", "AST", "BILI"), 8),
AVAL = round(rnorm(24, 42, 6), 1),
stringsAsFactors = FALSE
)
})
join_keys(data) <- join_keys(teal.data::join_key("ADSL", "ADLB", keys = "USUBJID"))
selector_default <- picks(
datasets(choices = c("ADSL", "ADLB"), selected = "ADLB"),
variables(
choices = tidyselect::everything(),
selected = c(1L, 2L),
multiple = TRUE
)
)Minimal Shiny app
ui <- fluidPage(
titlePanel("Standalone picks + merge"),
fluidRow(
column(
width = 4,
picks_ui("sel", picks = selector_default)
),
column(
width = 8,
tags$h4("Mapped variables"),
verbatimTextOutput("mapped"),
tags$h4("Merge preview"),
tableOutput("merged")
)
)
)
server <- function(input, output, session) {
data_r <- reactive(data)
selectors <- list(sel = picks_srv("sel", picks = selector_default, data = data_r))
merged <- merge_srv(
id = "merge",
data = data_r,
selectors = selectors,
output_name = "anl",
join_fun = "dplyr::left_join"
)
output$mapped <- renderPrint({
yaml::as.yaml(merged$variables())
})
output$merged <- renderTable({
merged$data()[["anl"]]
})
}
if (interactive()) {
shinyApp(ui, server)
}Notes
-
merge_srv()expectsselectorsto be a named list of reactives (as returned bypicks_srv()for each selector). - Define
join_keys()on yourteal_databefore merging across datasets. One relationship between two datasets is enough:join_keys(join_key("ADSL", "ADLB", keys = "USUBJID"))is expanded byteal.datainto a symmetric map so both names exist. Extrajoin_key("DS", "DS", …)self-keys are optional; they record primary-key / row grain (for exampleUSUBJID+PARAMon long lab rows), which matters in full CDISC-style setups more than in this minimal example. - For bookmarking,
picks_srv()stores resolved picks whenenableBookmarking = "server"is used onshinyApp(). -
values()filters the column(s) content chosen invariables(). Ifmultiple = TRUEvariables are selected, values are derived from a combined representation of those columns—so do not pairPARAM-only level choices with a selection that also includesAVAL. Usevalues()with a single categorical column, or omitvalues()when taking several columns (as in this example).