Reputation: 303
So I am making a shiny app that takes multiple inputs and produces multiple plots and tables of those inputs.
Sample RenderTable code to make one table is below:
output$Table1 <-
renderTable(data.frame(Shape = c("\u25CF", "\u25B2", "\u25FC", ""),
"Genes" = c(input$custom_genes1, "Mean"),
Analysed_values = c(t(analysis1()), mean(analysis1()))),
striped = TRUE, bordered = TRUE, hover = TRUE)
Where Shape is the symbol on the plot, "Genes" are the genes selected using a selectizeInput, and analysis1() is the result of a reactive calculation defined earlier in the code.
However I have 8-9 tables that need to be displayed depending on various checkboxes etc. Rather than copy-pasting the code out and replacing all the relevant values, I wanted to make a function that I could use to quickly display all the tables, and if I needed to change the formatting or add anything later I can just edit the function rather than each table individually.
I tried making a re-usable function using the code below:
construct_table <- function(genes_select, dataset){
renderTable(data.frame(Shape = c("\u25CF", "\u25B2", "\u25FC", ""),
"Genes" = genes_select,
Analysed_values = c(t(dataset), mean(dataset))),
striped = TRUE, bordered = TRUE, hover = TRUE)
}
And then making it easier to call each table directly:
output$Table1 <- construct_table(input$custom_genes1, analysis1())
This works in that is creates the table using the initial input values, but doesn't make the table reactive.
How can I call the renderTable reactive function inside a normal function, or is there another reactive function that I have overlooked that I can nest the renderTable function inside of that works the same way as the normal function does?
Upvotes: 0
Views: 1025
Reputation: 2835
Simply adding a output$Table1 <- construct_table(input$custom_genes1, analysis1())
call anywhere will not work because analysis()
is a reactive variable depending on other inputs the user can change. Hence analysis()
can be used from a reactive context. ie. from inside observe, observeEvent, reactive, eventReactive or inside any renderXXX call ex: renderTable, renderPlot...
When we call output$Table1 <- construct_table(input$custom_genes1, analysis1())
,
we are using analysis1()
from outside a reactive context which will cause an error. The solution is Shiny Modules which is specifically designed to modularize code, which seems to be the goal here.
Here is an example,
dataset = mtcars
generatePlot = function(input,output,session,data){
output$plot = renderPlot({
plot(data()$hp,data()$mpg)
})
}
generateUI = function(id){
ns = NS(id)
plotOutput(ns("plot"))
}
shinyApp(
ui = {
fluidPage(
sliderInput("slider","MPG filter",min(dataset$mpg),max(dataset$mpg),dataset$mpg),
generateUI("mod1"),
generateUI("mod2")
)
},
server = function(input,output,session){
data = eventReactive(input$slider,{
dataset%>%
dplyr::filter(between(mpg,input$slider[[1]],input$slider[[2]]))%>%
return(.)
})
callModule(generatePlot,"mod1",data = data)
callModule(generatePlot,"mod2",data = data)
}
)
You can add many more identical plots by simply adding a new generateUI
and a new callModule
call.
Upvotes: 2