Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Display blank plot in shiny instead of error

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)
        })
    }) 
)
```
like image 939
Rorschach Avatar asked Jun 15 '15 15:06

Rorschach


2 Answers

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) {""} 
              )
        })
    }) 
)
```
like image 163
stevec Avatar answered Nov 12 '22 22:11

stevec


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)
})
like image 1
jeremycg Avatar answered Nov 12 '22 22:11

jeremycg