1

I'm creating Shiny app and I want to use checkboxGroupInput in order to print out multiple plots. However, I want to print out plots only for the elements of checkboxGroupInput that were checked. There is a similar example in Shiny gallery to create UI elements in a loop that uses lapply. Here is a simplified version of that example to show what I want to do:

#server.R
library(shiny)
library(ggplot2)

shinyServer(function(input, output, session) {
  numberInput <- reactive({
    input$checkbox
  })

  lapply(1:10, function(i) {
    output[[paste0('b', i)]] <- renderPlot({
      qplot(x = rnorm(100, mean = as.numeric(numberInput()[i]))) +
        ggtitle(paste("This plot was plotted with", numberInput()[i], "option"))
    })
  })
})

#ui.R
library(shiny)    
shinyUI(fluidPage(
  title = 'lapply example',

  sidebarLayout(
    sidebarPanel(
      checkboxGroupInput("checkbox", "Checkbox",
                         choices = sample(1:10, 5))
    ),

    mainPanel(
      lapply(1:10, function(i) {
        plotOutput(paste0('b', i))
      })
    )
  )
))

This works, but obviously when Shiny tries to extract numberInput()[i] where i is bigger than number of currently checked elements, there is nothing to extract and instead of a plot there is an error. Therefore I need to somehow tell lapply to iterate only n number of times where n is length(input$checkbox).

I tried to use length(input$checkbox) directly, tried putting that element in the numberInput() reactive statement and returning it as the list, I tried to use reactiveValues() in a following way:

  v <- reactiveValues(n = length(input$checkbox))

  lapply(1:isolate(v$n), function(i) {

However, in all of those instances Shiny complains about lack of active reactive context.

So, what am I missing? How can I use length of input in lapply outside of reactive context?

1 Answers1

1

I've generally had more luck using this approach (only because it's easier for me to wrap my head around it), but the idea is to render your plots into a UI on the server and then render the UI in ui.R

#server.R
library(shiny)
library(ggplot2)

server <- shinyServer(function(input, output, session) {
  output$checks <- renderText(input$checkbox)

  output$plots <- renderUI({
    plot_output_list <- 
      lapply(input$checkbox,
             function(i){ 
               plotOutput(paste0("plot", i))
             })
    do.call(tagList, plot_output_list)
  })

  observe({
    for (i in input$checkbox) {
      local({
        local_i <- i
        output[[paste0("plot", local_i)]] <- 
          renderPlot({
            qplot(x = rnorm(100, mean = as.numeric(local_i))) +
        ggtitle(paste("This plot was plotted with", local_i, "option"))
          })
      })
    }
  })



})

#ui.R
library(shiny)    
ui <- shinyUI(fluidPage(
  title = 'lapply example',

  sidebarLayout(
    sidebarPanel(
      checkboxGroupInput("checkbox", "Checkbox",
                         choices = sample(1:10, 5))
    ),

    mainPanel(
        verbatimTextOutput("checks"),
        uiOutput('plots')
    )
  )
))

shinyApp(ui = ui, server = server)
Community
  • 1
  • 1
Benjamin
  • 16,897
  • 6
  • 45
  • 65