I'm writing an R shiny app which should allow the user to create customisable plots of some data. The idea is that my app offers a "create new plot" button, which renders the plot and stores it in a reactive. A renderUI function "watches" this list and renders all plots in that reactive.
I found a couple of related questions r-markdown-shiny-renderplot-list-of-plots-from-lapply or shiny-r-renderplots-on-the-fly which however did not really help in my case. I hope I didn't miss a good answer somewhere (which I would assume there is because I think this is not a rare use case).
When implementing, I noticed a strange behaviour: When there is only one plot to be shown, everything works well. However, when I have n (n>1) plots, instead of rendering plot 1, plot 2, ..., plot n, the app only showed n times the plot n.
See my example app below. I simplified the problem by just letting the user choose the number of plots to be displayed. The renderUI function then has a loop creating thees plots in a variable p and then calls renderPlot(p). I assume shiny does some caching and for some reason fails to recognise that p changes in the loop?!
I found a workaround by replacing the renderPlot(p) by do.call("renderPlot", list(expr = p). This does the job but I'm still curious to learn why the direct renderPlot does not work.
Here is my example app:
library(shiny)
library(ggplot2)
# Define UI
ui <- shinyUI(fluidPage(
titlePanel("renderPlot Test"),
sidebarLayout(
sidebarPanel(
numericInput(inputId = "n", label = "Number of Plots", value = 1L, min = 1L, max = 5L, step = 1L),
checkboxInput(inputId = "use_do.call", label = "use 'do.call'", value = FALSE)
),
mainPanel(
uiOutput("show_plots")
)
)
))
# Define server logic
server <- shinyServer(function(input, output) {
output$show_plots <- renderUI({
ui <- tags$div(tags$h4("Plots"))
for( i in 1:input$n ) {
p <- ggplot() + ggtitle(paste("plot", i))
if( input$use_do.call ) { # this works
ui <- tagAppendChild(ui, do.call("renderPlot", args=list(expr=p, width = 200, height = 200)))
} else { # this doesn't ...
ui <- tagAppendChild(ui, renderPlot(p, width = 200, height = 200))
}
}
return(ui)
})
})
# Run the application
shinyApp(ui = ui, server = server)