Attempting reactive filtering and plotting in Shiny

Before we jump in, I put this reprex together with mpg which might have not been the best choice of data for this exercise, but bear with me.

I'm trying to create a Shiny app that adapts to whether or not something is checked out of each of the checkboxGroupInput groups. However, when I run the app I get no errors and no plot either.

The goal is for the app to look at the checkbox selections, run a dplyr filter and tally, and then plot that new dataframe in a bar chart. If nothing is selected in one of the checkbox groups, offer up a bar chart of the other. If something is checked from both groups, one becomes the X, the other becomes the fill.

Can anybody pinpoint where I'm going wrong in this reprex?

library(shiny)
library(tidyverse)

ui <- fluidPage("Car breakdown",
                sidebarLayout(
                  sidebarPanel(
                    checkboxGroupInput("manuSelector", "Manufacturers to show:",
                                       choices = c("Audi" = "audi",
                                                   "Chevrolet" = "chevrolet",
                                                   "Dodge" = "dodge",
                                                   "Ford" = "ford",
                                                   "Honda" = "honda",
                                                   "Hyundai" = "hyundai",
                                                   "Jeep" = "jeep",
                                                   "Land Rover" = "land rover",
                                                   "Lincoln" = "lincoln", 
                                                   "Mercury" = "mercury",
                                                   "Nissan" = "nissan",
                                                   "Pontiac" = "pontiac",
                                                   "Subaru" = "subaru",
                                                   "Toyota" = "toyota",
                                                   "Volkswagen" = "volkswagen"),
                                       selected = c("ford", "chevrolet")
                    ),
                    checkboxGroupInput("classSelector", "Classes to show:",
                                       choices = c("Two-seater" = "2seater",
                                                   "Compact" = "compact",
                                                   "Mid-size" = "midsize",
                                                   "Minivan" = "minivan",
                                                   "Pickup" = "pickup",
                                                   "Sub-compact" = "subcompact",
                                                   "SUV" = "suv"),
                                       selected = c("2seater", "midsize", "pickup")
                    )
                  ),
                  
                  mainPanel(
                    plotOutput("distPlot")
                  )
                )
)

server <- function(input, output) {
  
  filteredData <- reactive({
    if (length(input$manuSelector) == 0){
      mpg %>%
        filter(class %in% input$classSelector) %>%
        tally()
    }
    else if (length(input$classSelector) == 0){
      mpg %>%
        filter(manufacturer %in% input$manuSelector) %>%
        tally()
    }
    else {
      mpg %>%
        filter(class %in% input$classSelector, manufacturer %in% input$manuSelector) %>%
        tally()
    }
  })
  
  output$distPlot <- renderPlot({
    ifelse(length(input$manuSelector == 0),
           ggplot(data = filteredData(), aes(x = class, y = n)) +
             geom_bar(stat = "identity"),
           ifelse(length(input$classSelector == 0),
                  ggplot(data = filteredData(), aes(x = manufacturer, y = n)) +
                    geom_bar(stat = "identity"),
                  ggplot(data = filteredData(), aes(x = manufacturer, y = n, fill = class)) +
                    geom_bar(stat = "identity")
           )
    )
  })
}

shinyApp(ui = ui, server = server)

Thank you in advance!

I do not think you should use ifelse() in the renderPlot(). Use a plain if() {} else {} as you did in fiteredData().

Just made the switch and it uncovered a problem with recognizing my X in some of the plots

Warning: Error in FUN: object 'manufacturer' not found

Attempted to debug with a print of filteredData but all it returned was the formula I'd typed in, starting with reactive({

I would try debugging outside of shiny. I tried to adapt your code as shown below. filteredData is now just a data frame, not a function. I got the error about 'manufacturer' not found because I had not loaded the dplyr library and so the code was calling the filter() function from base R. You should not have that problem since you load tidyverse, but I thought I would mention it.

In this code, tally() returns a single row of one variable, which is not something you want to feed to ggplot().

library(ggplot2)
library(dplyr)

data(mpg)
input <- list(classSelector = c("2seater", "midsize", "pickup"),
              manuSelector = c("ford", "chevrolet"))
if (length(input$manuSelector) == 0){
  filteredData <- mpg %>%
    filter(class %in% input$classSelector) %>%
    tally()
} else if (length(input$classSelector) == 0){
  filteredData <- mpg %>%
    filter(manufacturer %in% input$manuSelector) %>%
    tally()
} else {
  filteredData <- mpg %>%
    filter(class %in% input$classSelector, manufacturer %in% input$manuSelector) %>%
    tally()
}

if (length(input$manuSelector == 0)) {
       ggplot(data = filteredData, aes(x = class, y = n)) +
         geom_bar(stat = "identity")
} else if(length(input$classSelector == 0)) {
              ggplot(data = filteredData, aes(x = manufacturer, y = n)) +
                geom_bar(stat = "identity")
} else {
        ggplot(data = filteredData, aes(x = manufacturer, y = n, fill = class)) +
                geom_bar(stat = "identity")
  }
1 Like

tally returns a tibble with only one column called n so there is no class, manufacturer to pass into the aes function. This app works for me.

library(shiny)
library(tidyverse)

ui <- fluidPage("Car breakdown",
								sidebarLayout(
									sidebarPanel(
										checkboxGroupInput("manuSelector", "Manufacturers to show:",
																			 choices = c("Audi" = "audi",
																			 						"Chevrolet" = "chevrolet",
																			 						"Dodge" = "dodge",
																			 						"Ford" = "ford",
																			 						"Honda" = "honda",
																			 						"Hyundai" = "hyundai",
																			 						"Jeep" = "jeep",
																			 						"Land Rover" = "land rover",
																			 						"Lincoln" = "lincoln", 
																			 						"Mercury" = "mercury",
																			 						"Nissan" = "nissan",
																			 						"Pontiac" = "pontiac",
																			 						"Subaru" = "subaru",
																			 						"Toyota" = "toyota",
																			 						"Volkswagen" = "volkswagen"),
																			 selected = c("ford", "chevrolet")
										),checkboxGroupInput("classSelector", "Classes to show:",
									 choices = c("Two-seater" = "2seater",
									 						"Compact" = "compact",
									 						"Mid-size" = "midsize",
									 						"Minivan" = "minivan",
									 						"Pickup" = "pickup",
									 						"Sub-compact" = "subcompact",
									 						"SUV" = "suv"),
									 selected = c("2seater", "midsize", "pickup")
)
),

mainPanel(
	plotOutput("distPlot")
	#dataTableOutput('data')
)
)
)

server <- function(input, output) {
	
	filteredData <- reactive({
		if (length(input$manuSelector) == 0){
			mpg %>%
				filter(class %in% input$classSelector) %>%
				group_by(class) %>% 
				summarise(n = n())
		}
		else if (length(input$classSelector) == 0){
			mpg %>%
				filter(manufacturer %in% input$manuSelector) %>%
				group_by(manufacturer) %>% 
				summarise(n = n())
		}
		else {
			mpg %>%
				filter(class %in% input$classSelector, manufacturer %in% input$manuSelector) %>%
				group_by(class, manufacturer) %>% 
				summarise(n = n())
		}
	})
	
	#output$data <- renderDataTable(filteredData())
	
	output$distPlot <- renderPlot({
		
		
		if (length(input$manuSelector) == 0) {
			ggplot(data = filteredData(), aes(x = class, y = n)) +
				geom_bar(stat = "identity")
		} else if(length(input$classSelector) == 0) {
			ggplot(data = filteredData(), aes(x = manufacturer, y = n)) +
				geom_bar(stat = "identity")
		} else {
			ggplot(data = filteredData(), aes(x = manufacturer, y = n, fill = class)) +
				geom_bar(stat = "identity")
		}
		
	})
}

shinyApp(ui = ui, server = server)
1 Like

Yep. Thought I was taking a shortcut for group_by() and summarize() by killing two birds with one stone in tally() and instead it ended up burning me.

I've got things working now. Thank you again.

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