Prevent Shiny rendering until input variables are selected

ggplot2
shiny

#1

Hi everyone,

I'd like to prevent a shiny figure from rendering until two required input variables are entered by the user. The two selections are used to filter a data set, and then that filtered output is placed into a ggplotly figure as one of two geom_lines. Here's my minimal working example:

library(plotly)
library(dplyr)
library(ggplot2)
library(shiny)

d <- data.frame(Group = rep(c("a","b"),each = 20),
                Value = rnorm(40),
                Location = rep(c("USA","EU"),each = 10),
                Time = rep(1:10, 4))


ui <- fluidPage(
  
  
  sidebarLayout(
    
    sidebarPanel(
    #--------------------------------------------------------
    
    selectInput("Var1",
                label = "Variable", #DATA CHOICE 1
                selected = "a",
                choices = c(as.character(unique(d$Group)))),
    
    selectInput("Loc1",
                label = "Select location", #Location filter 1
                selected = "USA",
                choices = c(as.character(unique(d$Location)))),
    
    #--------------------------------------------------------
    
    selectInput("Var2",
                label = "Variable2", #DATA CHOICE 2
                selected = "",
                choices = c("",as.character(unique(d$Group)))),
    
    selectInput("Loc2",
                label = "Select location", #Location filter 2
                selected = "",
                choices = c("",as.character(unique(d$Location))))
    ),
    
    #--------------------------------------------------------
    # Show a plot of the generated distribution
    

    mainPanel(
      plotlyOutput('plot') #Draw figure
      ),
    position = "left")
    
  )



server <- function(input, output) {
  
  out <- reactive({
    
      d %>% filter(Group == input$Var1, Location == input$Loc1)
    
  })
  
  out2 <- reactive({
    
    if (input$Var2 =="")
      return(NULL)
    
    d %>% filter(Group == input$Var2, Location == input$Loc2)
    
  })
  
  output$plot <- renderPlotly({
    p <- ggplot() +
      geom_line(data = out(), aes(x = Time, y = Value))+ #Add both data sets in one ggplot
      {if (!is.null(out2())) geom_line(data = out2(), aes(x = Time, y = Value), color = "red")}
      theme_bw()
    ggplotly(p)
  })
  
}

# Run the application 
shinyApp(ui = ui, server = server)

The code works as expected except that I only want to re-render the ggplotly object to include the second geom_line once both filtering variables are selected for that reactive object (i.e. out2()). Using the req function seems like a good start, except that I don't know how to nest the affected reactive statement as a conditional geom_line.

Thanks!!!


#2

If I understand correctly, you can modify the if case of the out2 reactive to prevent adding the red line until both input$Var2 and input$Loc2 are specified.

out2 <- reactive({
    
  if (input$Var2 == "" || input$Loc2 == "") {
    return(NULL)
  }
    
  d %>% filter(Group == input$Var2, Location == input$Loc2)
})

You could take this a step further and have your reactive return the geom_line.

highlightLine <- reactive({ 
  
  if (input$Var2 == "" || input$Loc2 == "") {
    return(NULL)
  }
    
  d %>% 
    filter(Group == input$Var2, Location == input$Loc2) %>% 
    geom_line(mapping = aes(x = Time, y = Value), color = "red")  # <-
})
  
output$plot <- renderPlotly({
  p <- ggplot() +
    geom_line(data = out(), aes(x = Time, y = Value)) +
    highlightLine() +  # <-
    theme_bw()
    
  ggplotly(p)
})

#3

Thank you! Your first solution was exactly what I was looking for. Trying to implement your second answer I get "Error: mapping must be created by aes().


#4

My mistake, I forget that the mapping comes before data in geoms. This ought to do the trick.

geom_line(mapping = aes(x = Time, y = Value), color = "red") 

(I have also updated the original example)


#5

This topic was automatically closed 7 days after the last reply. New replies are no longer allowed.