setempler
setempler

Reputation: 1751

How to initialise default values for rendered items in a shiny app

Introduction

In a shinyApp, I would like to render output with dynamic input.

My problem is, using shinydashboard with different tabs, that default values from *Input()s only get rendered when the respective tab is activated (think of an input and an output tab).

I get the same behaviour, when using a switch statement on input$* values in a simple example (unless after rendering the input, the switch does work and output appears). See the following:

Code

library(shiny)
shinyApp(
  ui = shinyUI(fluidPage(sidebarLayout(sidebarPanel(uiOutput("select_bin")),
                                       mainPanel( plotOutput("distPlot"))))),
  server = function(input, output) {
    output$select_bin <- renderUI({
      selectInput("bins", "Number of bins:", c("few", "many"))
    })
    output$distPlot <- renderPlot({
      x    <- faithful[, 2]
      bins <- switch(input$bins, few = 10L, many = 100L)
      bins <- seq(min(x), max(x), length.out = bins)
      hist(x, breaks = bins, col = 'darkgray', border = 'white')
    })
  })

The code above works, but throws a

Warning: Error in switch: EXPR must be a length 1 vector.

I suppose that input$bins is not available until the selectInput is rendered.

Question

How can I define a default value for input$bins, so before the selectInput is rendered, the expression in renderPlot does not throw the warning?

First approach

I tried to use observe as in this post, but I am not sure of it's exact meaning, and thus struggle to solve the problem.

library(shiny)
shinyApp(
  ui = shinyUI(fluidPage(sidebarLayout(sidebarPanel(uiOutput("select_bin")),
                                       mainPanel( plotOutput("distPlot"))))),
  server = function(input, output) {
    output$select_bin <- renderUI({
      selectInput("bins", "Number of bins:", c("few", "many"))
    })
    observe({
      bins <- switch(input$bins, few = 10L, many = 100L)
      bins
    })
    output$distPlot <- renderPlot({
      x    <- faithful[, 2]
      bins <- seq(min(x), max(x), length.out = bins)
      hist(x, breaks = bins, col = 'darkgray', border = 'white')
    })
  })

Which does not work at all and throws the additional Warning: Error in seq.default: object 'bins' not found.

Upvotes: 2

Views: 2948

Answers (2)

Hao
Hao

Reputation: 7836

You need req() in renderPlot(). req() will tell shiny to render that plot only when input$bins is not empty.

library(shiny)
shinyApp(
  ui = 
shinyUI(fluidPage(sidebarLayout(sidebarPanel(uiOutput("select_bin")),
                                   mainPanel( 
plotOutput("distPlot"))))),
  server = function(input, output) {
    output$select_bin <- renderUI({
       selectInput("bins", "Number of bins:", c("few", "many"))
    })
    output$distPlot <- renderPlot({
      req(input$bins)
      x    <- faithful[, 2]
      bins <- switch(input$bins, few = 10L, many = 100L)
      bins <- seq(min(x), max(x), length.out = bins)
      hist(x, breaks = bins, col = 'darkgray', border = 'white')
    })
  })

Upvotes: 2

setempler
setempler

Reputation: 1751

Using

  • reactiveValues to create a list of defaults, and
  • observeEvent for the input$bins, updating the defaults

seems to solve the problem:

library(shiny)
shinyApp(
  ui = shinyUI(fluidPage(sidebarLayout(sidebarPanel(uiOutput("select_bin")),
                                       mainPanel( plotOutput("distPlot"))))),
  server = function(input, output) {
    values <- reactiveValues(bins = 10L)
    output$select_bin <- renderUI({
      selectInput("bins", "Number of bins:", c("few", "many"))
    })
    observeEvent(input$bins, {
      values$bins <- switch(input$bins, few = 10L, many = 100L)
    })
    output$distPlot <- renderPlot({
      x    <- faithful[, 2]
      bins <- seq(min(x), max(x), length.out = values$bins)
      hist(x, breaks = bins, col = 'darkgray', border = 'white')
    })
  })

Upvotes: 2

Related Questions