teal_transform_module()
is a Shiny module that takes ui
and server
arguments. When provided, teal
will execute data
transformations for the specified module when it is loaded and whenever
the data changes. server
extend the logic behind data
manipulations, where ui
extends filter panel with new UI
elements that orchestrate the transformator inputs.
teal
version 0.16
introduced a new,
optional argument in teal::module
named
transformators
. This argument allows to pass a
list
of "teal_data_module"
class of objects
created using teal_transform_module()
function.
The main benefit of teal_transform_module()
is the
ability to transform data before passing it to the module. This feature
allows to extend the regular behavior of existing modules by specifying
custom data operations on data inside this module.
This vignette presents the way on how to manage custom data
transformations in teal
apps.
We initialize a simple teal
app where we pass
iris
and mtcars
as the input datasets.
data <- within(teal_data(), {
iris <- iris
mtcars <- mtcars
})
app <- init(
data = data,
modules = teal::example_module()
)
if (interactive()) {
shinyApp(app$ui, app$server)
}
Let’s create a simple teal_transform_module
that returns
the first n
number of rows of iris
based on
the user input.
We do this by creating the ui
with the
numericInput
for the user to input the number of rows to be
displayed. In the server
function we take in the reactive
data
and perform this transformation and return the new
reactive data
.
data <- within(teal_data(), {
iris <- iris
mtcars <- mtcars
})
my_transformators <- list(
teal_transform_module(
label = "Custom transformator for iris",
ui = function(id) {
ns <- NS(id)
tags$div(
numericInput(ns("n_rows"), "Number of rows to subset", value = 6, min = 1, max = 150, step = 1)
)
},
server = function(id, data) {
moduleServer(id, function(input, output, session) {
reactive({
within(data(),
{
iris <- head(iris, num_rows)
},
num_rows = input$n_rows
)
})
})
}
)
)
app <- init(
data = data,
modules = teal::example_module(transformators = my_transformators)
)
if (interactive()) {
shinyApp(app$ui, app$server)
}
Note: It is recommended to return reactive()
with teal_data()
in server
code of a
teal_transform_module
as this is more robust for
maintaining the reactivity of Shiny. If you are planning on using
eventReactive()
in the server, the event should include
data()
(example
eventReactive(list(input$a, data()), {...})
). More in
this
discussion.
Note that we can add multiple teal
transformators by
including teal_transform_module
in a list.
Let’s add another transformation to the mtcars
dataset
that creates a column with rownames
of mtcars
.
Note that this module does not have interactive UI elements.
data <- within(teal_data(), {
iris <- iris
mtcars <- mtcars
})
my_transformators <- list(
teal_transform_module(
label = "Custom transformator for iris",
ui = function(id) {
ns <- NS(id)
tags$div(
numericInput(ns("n_rows"), "Number of rows to subset", value = 6, min = 1, max = 150, step = 1)
)
},
server = function(id, data) {
moduleServer(id, function(input, output, session) {
reactive({
within(data(),
{
iris <- head(iris, num_rows)
},
num_rows = input$n_rows
)
})
})
}
),
teal_transform_module(
label = "Custom transformator for mtcars",
ui = function(id) {
ns <- NS(id)
tags$div(
"Adding rownames column to mtcars"
)
},
server = function(id, data) {
moduleServer(id, function(input, output, session) {
reactive({
within(data(), {
mtcars$rownames <- rownames(mtcars)
rownames(mtcars) <- NULL
})
})
})
}
)
)
app <- init(
data = data,
modules = teal::example_module(transformators = my_transformators)
)
if (interactive()) {
shinyApp(app$ui, app$server)
}