The teal
framework provides a large catalog of
plug-in-ready analysis modules to be incorporated into teal
applications. However, it is also possible to create your own modules
using the module
function.
This function contains the UI required for the module. It should be a
function with at least the argument id
. See the server
section below for more details.
This function contains the shiny
server logic for the
module and should be of the form:
function(
id,# optional; use if module needs access to application data
data, # optional; use if module needs access to filter panel; see teal.slice
filter_panel_api, # optional; use if module supports reporting; see reporting vignette
reporter,
...) {moduleServer(id, function(input, output, session) {
# module code here
}) }
The data that arrives in the module is a teal_data
object, the data container used throughout the teal
application. teal_data
is passed to the init
function when building the application and, after filtering by the
filter panel, it is passed to modules, wrapped in a reactive expression.
The teal_data
class allows modules to track the
R
code that they execute so that module outputs can be
reproduced. See the teal.data
package for a detailed
explanation.
Here is a minimal module that allows the user to select and view one
dataset at a time. By default, filtering is enabled for all datasets.
Note that dataset choices are specified by the datanames
property of the teal_data
container.
library(teal)
<- function(label = "example teal module") {
example_module ::assert_string(label)
checkmate
module(
label = label,
server = function(id, data) {
::assert_class(data, "reactive")
checkmate::assert_class(isolate(data()), "teal_data")
checkmate
moduleServer(id, function(input, output, session) {
updateSelectInput(session, "dataname", choices = isolate(datanames(data())))
$dataset <- renderPrint({
outputreq(input$dataname)
data()[[input$dataname]]
})
})
},ui = function(id) {
<- NS(id)
ns sidebarLayout(
sidebarPanel(selectInput(ns("dataname"), "Choose a dataset", choices = NULL)),
mainPanel(verbatimTextOutput(ns("dataset")))
)
}
) }
The example below allows the user to interact with the data to create a simple visualization. In addition, it prints the code that can be used to reproduce that visualization.
library(teal)
# ui function for the module
# allows for selecting dataset and one of its numeric variables
<- function(id) {
ui_histogram_example <- NS(id)
ns sidebarLayout(
sidebarPanel(
selectInput(ns("datasets"), "select dataset", choices = NULL),
selectInput(ns("numerics"), "select numeric variable", choices = NULL)
),mainPanel(
plotOutput(ns("plot")),
verbatimTextOutput(ns("code"))
),
)
}
# server function for the module
# presents datasets and numeric variables for selection
# displays a histogram of the selected variable
# displays code to reproduce the histogram
<- function(id, data) {
srv_histogram_example ::assert_class(data, "reactive")
checkmate::assert_class(isolate(data()), "teal_data")
checkmate
moduleServer(id, function(input, output, session) {
# update dataset and variable choices
# each selection stored in separate reactive expression
updateSelectInput(inputId = "datasets", choices = isolate(datanames(data())))
observe({
req(dataset())
<- vapply(data()[[dataset()]], is.numeric, logical(1L))
nums updateSelectInput(inputId = "numerics", choices = names(nums[nums]))
})<- reactive(input$datasets)
dataset <- reactive(input$numerics)
selected
# add plot code
<- reactive({
plot_code_q validate(need(length(dataset()) == 1L, "Please select a dataset"))
validate(need(length(selected()) == 1L, "Please select a variable"))
req(selected() %in% names(data()[[dataset()]]))
# evaluate plotting expression within data
# inject input values into plotting expression
within(
data(),
<- hist(dataset[, selected], las = 1),
p dataset = as.name(dataset()), selected = selected()
)
})
# view plot
$plot <- renderPlot({
outputplot_code_q()[["p"]]
})
# view code
$code <- renderPrint({
outputplot_code_q() %>%
get_code() %>%
cat()
})
})
}
# function that creates module instance to use in `teal` app
<- function(label) {
tm_histogram_example module(
label = label,
server = srv_histogram_example,
ui = ui_histogram_example,
datanames = "all"
) }
This module is ready to be used in a teal
app.
<- init(
app data = teal_data(IRIS = iris, NPK = npk),
modules = tm_histogram_example(label = "Histogram Module"),
header = "Simple app with custom histogram module"
)
if (interactive()) {
shinyApp(app$ui, app$server)
}
Refer to this
vignette to read about adding support for reporting in your
teal
module.
The teal.widgets
package provides various widgets which can be leveraged to quickly
create standard elements in your custom module.