Johann Baptista Johann Baptista - 3 months ago 112
R Question

Cannot render plot inside dynamic UI, when using a shiny module

Normally, Shiny has no problem generating plots from within UIs that the user calls reactively, but I've noticed that when using a shiny module to dynamically generate the UI, the plot does not appear.

Below is a minimal example of a modularized shiny app that reproduces the problem; it is supposed to generate a ui with a plot in it when the user presses the "go" button:

library("shiny")

exampleUI <- function(id, label = "example") {
ns <- NS(id)
tagList( actionButton(ns("go"), "Go"), uiOutput(ns("ui")) )
}


ui <- fluidPage( exampleUI("example") )

example <- function(input, output, session) {
observeEvent(input$go, {
output$plot <- renderPlot( plot(1:5, 1:5) )
output$ui <- renderUI( plotOutput("plot") )
})
}

server <- function(input, output) { callModule(example, "example") }

shinyApp(ui, server)


By contrast, the non-modularized version works as expected:

ui <- fluidPage(
tagList( actionButton("go", "Go"), uiOutput("ui") )
)

server <- function(input, output) {

observeEvent(input$go, {
output$plot <- renderPlot( plot(1:5, 1:5) )
output$ui <- renderUI( plotOutput("plot") )
})
}

shinyApp(ui, server)


I would appreciate any pointers on how to make the first code block behave like the second.

Answer
library(shiny)

exampleUI <- function(id, label = "example") {
    ns <- NS(id)
    tagList(   actionButton(ns("go"), "Go"),   uiOutput(ns("ui"))   )
}


example <- function(input, output, session) {
    observeEvent(input$go, {
        output$plot <- renderPlot(   plot(1:5, 1:5)   )
        ns <- session$ns
        output$ui <- renderUI(   plotOutput(ns("plot"))   )
    })
}


ui <- fluidPage(   exampleUI("example")   )

server <- function(input, output, session) {
    callModule(example, "example") 
}
shinyApp(ui, server)

Two things:

  1. You referred to exampleUI before defining it (In your actual example, you will probably source the module, so this shouldn't be a problem)

  2. When using renderUI in modules which contain input/output you need to wrap it within ns. Read the section on Using renderUI within modules for more

Comments