Display blank plot in shiny instead of error

8k views Asked by At

When I have reactive data that gets passed to renderPlot (or other rendering functions), the data is often initially empty until some action happens. The default rendering typically displays an error in the app before the action happens because the data is empty, ie

Error 'x' must be numeric

in this example. Is there some standard way to have the rendering functions act when they don't have data (maybe not rendering if there is an error or just being blank)? I know I could go to the trouble of structuring all the reactive values so the output would be blank, but it seems like unnecessary work.

Example in rMarkdown shiny

---
title: "Example"
runtime: shiny
output: html_document
---

```{r}
shinyApp(
    shinyUI(fluidPage(
        inputPanel( 
            numericInput("n", "n", 10),
            actionButton("update", "Update")
        ),
        plotOutput("plot")
    )),

    shinyServer(function(input, output) {
        values <- reactiveValues()
        values$data <- c()

        obs <- observe({
            input$update
            isolate({ values$data <- c(values$data, runif(as.numeric(input$n), -10, 10)) })
        }, suspended=TRUE)

        obs2 <- observe({
            if (input$update > 0) obs$resume()
        })

        output$plot <- renderPlot({
            dat <- values$data
            hist(dat)
        })
    }) 
)
```
2

There are 2 answers

2
jeremycg On

You can use the exists function to see if a variable exists before trying to plot it, and change it as desired otherwise:

renderPlot({
    if(exists("values$data")) {
      dat <- values$data 
    } else {
      dat <- 0
    }
    hist(dat)
})
0
stevec On

Try surrounding the line that might error in a tryCatch. In your example, hist(dat) is what errors, so surround it like so:

tryCatch(
  { hist(dat) }, # Code that might error goes here, between the { }
  error = function(e) {""} # Leave this line as-is.
)

That's telling shiny:

  • try to run hist(dat), and
  • if you can't run it without an error, simply display an empty string instead.

Now there's no more error message and your histogram still works as expected.

Working example

Here's your MRE with the tryCatch solution implemented - scroll down to where the comment says # CHANGES HERE; it simply replaces hist(dat) with the 4 tryCatch() lines - that's the only change.

---
title: "Example"
runtime: shiny
output: html_document
---

```{r}
shinyApp(
    shinyUI(fluidPage(
        inputPanel( 
            numericInput("n", "n", 10),
            actionButton("update", "Update")
        ),
        plotOutput("plot")
    )),

    shinyServer(function(input, output) {
      

        values <- reactiveValues()
        values$data <- c()

        obs <- observe({
            input$update
            isolate({ values$data <- c(values$data, runif(as.numeric(input$n), -10, 10)) })
        }, suspended=TRUE)

        obs2 <- observe({
            if (input$update > 0) obs$resume()
        })

        output$plot <- renderPlot({
            dat <- values$data
            # CHANGES HERE (NEXT 4 LINES)
            tryCatch(
              { hist(dat) }, 
              error = function(e) {""} 
              )
        })
    }) 
)
```