Marijn Stevering
Marijn Stevering

Reputation: 1293

suppress effect of submitButton on startup of shiny app

I have a shiny app with a reactive bit of UI which is used to filter my data. I then use the data for plotting. My reactive bit of UI checks all possible values of a variable, offers them as choices in a selectizeInput and starts with all of the choices selected. In my actual app changes in the filter can take quite a bit of time to run so I have submitButton to prevent the app from constantly updating. The only problem is on the initial startup of the app: It loads the choices in to the dynamic UI and selects them, but because further reactivity is blocked by the submitButton, this information doesn't reach the plot and so it shows an empty plot. All that's needed to get the desired result is hit the sumbitButton once. Once this is done the app works as desired.

I'm looking for a way to make the plot show initially without having to press the submitButton. In my following toy example this could probably be done quite easily by replacing the submitButton with an actionButton so that not all reactivity is frozen, which seems to be the solution in a lot of problems involving submitButtons in other question. However, in my actual app there are numerous inputs and sources of reactivity so configuring the actionButton and capturing all desired effects in observeEvents would be quite tedious when the submitButton does all of this with the only problem being the startup. Are there any other ways I can make the plot show on the first startup but follow the submitButton behavior from then on?

An example app:

library(shiny)
library(ggplot2)

ui <- fluidPage(
  sidebarLayout(
    sidebarPanel( 
      uiOutput("Cylselectui"),
      submitButton("Apply changes")
    ),
    mainPanel(
     plotOutput("Carsplot") 
    )
  )
)


server <- function(input, output) {
  output$Carsplot <- renderPlot({
    plotdata <- subset(mtcars, cyl %in% input$Cylselection) #Filter based on cyl

    ggplot(plotdata, aes(x = mpg, y = hp, colour = factor(cyl))) + #Create plot
      geom_point()
  })

  output$Cylselectui <- renderUI({ #Create the cyl selectize ui based on the values of cyl that are in the data
    selectizeInput(
      'Cylselection', 'Select by Cylinder', 
      choices = sort(unique(mtcars$cyl)),
      selected = sort(unique(mtcars$cyl)),
      multiple = TRUE
    )
  })
}

shinyApp(ui = ui, server = server)

Upvotes: 3

Views: 852

Answers (1)

HubertL
HubertL

Reputation: 19544

You can use a reactive to check whether the input is null (first time) and then provide your defaults values:

  Cylselection <- reactive({
    if(is.null(input$Cylselection)) 
       sort(unique(mtcars$cyl)) 
    else 
       input$Cylselection})

  output$Carsplot <- renderPlot({
    plotdata <- subset(mtcars, cyl %in% Cylselection()) #Filter based on cyl
    ggplot(plotdata, aes(x = mpg, y = hp, colour = factor(cyl))) + #Create plot
      geom_point()
  })

More elegant is to put your data subset in the reactive:

  plotdata <- reactive({
    if(is.null(input$Cylselection)) 
      mtcars
    else 
      subset(mtcars, cyl %in% input$Cylselection)})

  output$Carsplot <- renderPlot({
    ggplot(plotdata(), aes(x = mpg, y = hp, colour = factor(cyl))) + #Create plot
      geom_point()
  })

Upvotes: 2

Related Questions