Home > Software engineering >  in shiny app, reactive output gives error when used to subset
in shiny app, reactive output gives error when used to subset

Time:10-06

Here's a simple reproducible example of my problem.

setup

library(shiny)
library(dplyr)

original.data <- tibble(
  year = seq(2000, 2020, 2),
  count = rnorm(11)
)

This app works, but it gives an error.

ui <- fluidPage(
  # Sidebar
  sidebarLayout(
    sidebarPanel(
      uiOutput("year"),
    ),
    # Show the table
    mainPanel(
    tableOutput("subset")  
    )
  )
)

server <- function(input, output) {
  output$year <- renderUI({
    shinyWidgets::sliderTextInput(inputId = "year",
                                  label = "Year to map",
                                  choices = seq(2000, 2020, 2),
                                  selected = 2020)
  })
  
  output$subset <- renderTable({
    original.data[original.data$year == input$year,]
  })

}

# Run the application 
shinyApp(ui = ui, server = server)

It looks like this: enter image description here

But it gives this error:

Warning: Error in : Must subset rows with a valid subscript vector. ℹ Logical subscripts must match the size of the indexed input. x Input has size 11 but subscript original.data$year == input$year has size 0.

The error only occurs with the reactive input. If I move sliderTextInput into the ui, the app runs without an error.

ui <- fluidPage(
  # Sidebar
  sidebarLayout(
    sidebarPanel(
      shinyWidgets::sliderTextInput(inputId = "year",
                                    label = "Year to map",
                                    choices = seq(2000, 2020, 2),
                                    selected = 2020),
    ),
    # Show the table
    mainPanel(
      tableOutput("subset")  
    )
  )
)

server <- function(input, output) {
  
  output$subset <- renderTable({
    original.data[original.data$year == input$year,]
  })
  
}

# Run the application 
shinyApp(ui = ui, server = server)

My actual use-case is a much more complicated application, where I need error-free reactive generated inputs. Does anyone see the error in my code?

CodePudding user response:

Up front, add req(input$year) to your reactive block.

The size 0 error can occur when the app is starting up: often with larger shiny apps (lots of components/widgets and reactive blocks) and with dynamic inputs, the input widget may not be completely defined when a reactive block fires. When that happens, input$year is not yet available, so it returns NULL. We can reproduce it with:

tibble(mtcars)[mtcars$cyl == NULL,]
# Error: Must subset rows with a valid subscript vector.
# i Logical subscripts must match the size of the indexed input.
# x Input has size 32 but subscript `mtcars$cyl == NULL` has size 0.

Two ways to deal with this:

  1. If you intend that the lack of year defined yet should mean the table is not rendered, then add req(.), as in

      output$subset <- renderTable({
        req(input$year)
        original.data[original.data$year == input$year,]
      })
    
  2. If you think the table should be rendered but with 0 rows (similar but a little different), then you can use %in% instead of ==:

      output$subset <- renderTable({
        original.data[original.data$year %in% input$year,]
      })
    
  • Related