Reputation: 1751
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
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
Reputation: 1751
Using
reactiveValues
to create a list of defaults, and observeEvent
for the input$bins
, updating the defaultsseems 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