library(teal)
library(dplyr)
library(ggplot2)
my_custom_module_ui <- function(id) {
ns <- NS(id)
tags$div(
# variable selector
selectInput(
inputId = ns("variable"),
label = "Select variable",
# initialize empty - to be updated from within server
choices = NULL
),
plotOutput(ns("plot"))
)
}
my_custom_module_srv <- function(id, data) {
moduleServer(id, function(input, output, session) {
# update variable selector by names of data
updateSelectInput(
inputId = "variable",
choices = data()[["ADSL"]] |> select(where(is.numeric)) |> names()
)
# add plot call to qenv
result <- reactive({
req(input$variable)
within(
data(),
{
my_plot <- ggplot(ADSL, aes(x = input_var)) +
geom_histogram()
my_plot
},
input_var = as.name(input$variable)
)
})
# render to output the object from qenv
output$plot <- renderPlot({
result()[["my_plot"]]
})
})
}
my_custom_module <- module(
label = "My Custom Module",
ui = my_custom_module_ui,
server = my_custom_module_srv
)
data <- teal_data()
data <- within(data, {
ADSL <- rADSL
})
app <- init(
data = data,
modules = list(
my_custom_module
)
)
if (Sys.getenv("QUARTO_ROOT") == "") {
shinyApp(app$ui, app$server)
}
Exercise 3
Create your custom module!
Create a custom module that does a simple histogram plot based on user selected columns.
Reference:
teal::module()
- “Creating Custom Modules” vignette
"qenv"
article on how to interact with internalqenv
object - in particular:teal.code::within()
function
Code
App
Exercise
Let’s enhance the module:
- Let’s create a new parameter
binwidth
:- add a new widget to the UI
- that widget should be created with
shiny::sliderInput()
- make reasonable values of
min
,max
,step
and initialvalue
- that widget should be created with
- read and use that widget in server
- pass this parameter value as
binwidth
argument to thegeom_histogram()
function
- pass this parameter value as
Answermy_custom_module_srv <- function(id, data) { moduleServer(id, function(input, output, session) { ... # add plot call to qenv result <- reactive({ req(input$variable) within( data(), { my_plot <- ggplot(ADSL, aes(x = input_var)) + geom_histogram(binwidth = input_binwidth) my_plot }, input_var = as.name(input$variable), input_binwidth = input$binwidth ) }) ... }) }
- add a new widget to the UI
- Let’s add more datasets
- extend
data
withADAE = teal.data::rADAE
- add a new widget in the UI
- that widget should be created with
shiny::selectInput()
- initialize empty and update values in the same way as for
input$variable
- that widget should be created with
- read and use in the server
- modify the variable selection - it has to be chosen from the currently selected dataset
- convert to
observeEvent()
oninput$dataset
- add at the beggining:
req(input$dataset)
to assure non empty selection - modify to
choices = names(data()[[input$dataset]])
- convert to
- modify the observer call
- add
req(input$dataset)
- add
req(input$variables %in% names(data()[[input$dataset]]))
- add
- modify ggplot call
- convert the value to a symbol and use as a first argument of
ggplot()
- convert the value to a symbol and use as a first argument of
- modify the variable selection - it has to be chosen from the currently selected dataset
Answermy_custom_module_srv <- function(id, data) { moduleServer(id, function(input, output, session) { updateSelectInput( inputId = "dataset", choices = names(data()) ) observeEvent( input$dataset, { req(input$dataset) updateSelectInput( inputId = "variable", choices = data()[[input$dataset]] |> select(where(is.numeric)) |> names() ) } ) result <- reactive({ req(input$dataset) req(input$variable) within( data(), { my_plot <- ggplot(input_dataset, aes(x = input_var)) + geom_histogram() my_plot }, input_dataset = as.name(input$dataset), input_var = as.name(input$variable) ) }) output$plot <- renderPlot({ result()[["my_plot"]] }) }) }
- extend
Exercise (bonus)
- Convert module to a function and let
label
be a function parameter.