rshinyrenderui

In R shiny, why am I getting an error message after making simple adaptation to renderUI?


When running the below "MWE code using renderUI", in R studio console I get the message "Error in :: argument of length 0" though the App keeps working correctly. This MWE reflects a simple adaptation from the below "MWE code this was adapted from without renderUI" where renderUI isn't used, and this MWE doesn't show any type of error.

What could be causing this error? I need renderUI.

MWE code using renderUI:

 library(shiny)
    library(tidyverse)
    library(ggplot2)
    
    ui <- fluidPage(
      sidebarLayout(sidebarPanel(uiOutput("panel")),
      mainPanel(plotOutput("plot")),
    ))
    
    server <- function(input, output, session) {
      
      output$panel <- renderUI({
        tagList(
          sliderInput('samples','Number of samples (X):',min=2,max=10,value=10),
          actionButton("add", "Add scenario")
        )
      })
      
      numScenarios <- reactiveValues(numS=1)
      
      observeEvent(input$add, {showModal(modalDialog(footer = modalButton("Close")))
        numScenarios$numS <- (numScenarios$numS+1)
      })
      
      output$plot <- renderPlot({
        v <- tibble()
        for (i in 1: numScenarios$numS){
          results=tibble(Scenario=i,X=1:input$samples,Y=runif(input$samples))
          v <- bind_rows(v, results)
        }
        v %>% ggplot() + geom_line(aes(x=X, y=Y, colour=as.factor(Scenario)))
      })
    }
    
    shinyApp(ui, server)

MWE code this was adapted from without renderUI:

ui <- fluidPage(
  sliderInput('samples','Number of samples (X):',min=2,max=10,value=10),
  actionButton("add", "Add scenario"),
  plotOutput("plot"),
)

server <- function(input, output, session) {
  
  numScenarios <- reactiveValues(numS=1)
  
  observeEvent(input$add, {showModal(modalDialog(footer = modalButton("Close")))
    numScenarios$numS <- (numScenarios$numS+1)
  })
  
  output$plot <- renderPlot({
    v <- tibble()
    for (i in 1: numScenarios$numS){
      results=tibble(Scenario=i,X=1:input$samples,Y=runif(input$samples))
      v <- bind_rows(v, results)
    }
    v %>% ggplot() + geom_line(aes(x=X, y=Y, colour=as.factor(Scenario)))
  })
}

shinyApp(ui, server)

Solution

  • It's a "scheduling issue". With renderUI(), input$samples doesn't exist when your renderPlot() is called. Exactly why is probably too complicated to work out. But we don't need to - the fix is easy: add

    req(input$samples)
    

    at the start of your renderPlot().

    By the way,

    v <- lapply(
            1:numScenarios$numS,
            function(i) tibble(Scenario=i,X=1:input$samples,Y=runif(input$samples))
         ) %>%
         bind_rows()
    

    is more efficient than your current implementation because you bind the data frames just once at the end of the loop rather than once on each iteration. That's not an issue for a toy example like this, but might be important in real world use.