rshinyrenderui

Display dynamic UI elements in Shiny


I'm trying to generate dynamic plots in Shiny. The number of plots is not known in advance so I use renderUI. The problem is that the elements are displayed one above the other. Is there a way to specify the number of elements to be displayed by row and then once the row is filled the code pass to the next row? Here is my simple reproducible example:

library(shiny)

max_plots <- 50

server <- function(input, output) {
  
  output$plots <- renderUI({
    plot_and_radio_output_list <- lapply(1:input$n, function(i) {
      plotname <- paste("plot", i, sep="")
      list(
        plotOutput(plotname, height = 280, width = 250)
      )
    })
    do.call(tagList, unlist(plot_and_radio_output_list, recursive = FALSE))
  })
  
  for (i in 1:max_plots) {
    local({
      my_i <- i
      plotname <- paste("plot", my_i, sep="")
      output[[plotname]] <- renderPlot({
        plot(1:my_i, 1:my_i,
             xlim = c(1, max_plots),
             ylim = c(1, max_plots),
             main = paste("1:", my_i, ".  n is ", input$n, sep = "")
        )
      })
    })
  }
  
}

ui <- pageWithSidebar(
  
  headerPanel("Dynamic number of plots"),
  
  sidebarPanel(
    sliderInput("n", "Number of plots", value=1, min=1, max=5)
  ),
  
  mainPanel(
    uiOutput("plots")
  )
)

shinyApp(ui, server)

Solution

  • You can put your plots in a div and give them the CSS property "inline-block"

      output$plots <- renderUI({
        plot_and_radio_output_list <- lapply(1:input$n, function(i) {
          plotname <- paste("plot", i, sep="")
          list(
            div(
              plotOutput(plotname, height = 280, width = 250),
              style = "display:inline-block;"
            )
            
          )
        })
        do.call(tagList, unlist(plot_and_radio_output_list, recursive = FALSE))
      })