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)
})
})
)
```
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:
hist(dat)
, andNow there's no more error message and your histogram still works as expected.
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) {""}
)
})
})
)
```
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)
})
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With