Search code examples
rshinyshiny-servershinyappsshiny-reactivity

How to group data dynamically in r shiny app


I am creating a shiny App where it will do two things on mtcars dataset

  1. group data based on user selected values and calculate the mean mpg

  2. and then filter based on selected values to display the output

    library(shiny)
    library(dplyr)
    
    ui <- fluidPage(
    titlePanel(" APP"),
    sidebarLayout(
    sidebarPanel(selectInput("x","Select cylinder",choices = c(mtcars$cyl),multiple = TRUE),
              selectInput("y","Select gear",choices = c(mtcars$gear),multiple = TRUE),
              submitButton("Submit")),
    
    mainPanel(
    
    tableOutput("m")
    
    )))
    
    
    server <- function(input,output){
    
    
    check <- reactive({
    if(is.null(input$x) & is.null(input$y)){
    mtcars %>% summarise(Average_mpg = mean(mpg))
    }else if(!is.null(input$x) & is.null(input$y)){
    a <- mtcars %>% group_by(cyl) %>% summarise(Average_mpg = mean(mpg))
    a %>% filter(cyl==input$x)
    }else if(is.null(input$x) & !is.null(input$y)){
    a <- mtcars %>% group_by(gear) %>% summarise(Average_mpg = mean(mpg))
    a %>% filter(gear==input$y)
    }else{
    a <-  mtcars %>% group_by(gear,cyl) %>% summarise(Average_mpg = mean(mpg))
    a %>% filter(cyl==input$x & gear==input$y)
    }
    })
    
    output$m <- renderTable(
    check()
    )  
    }
    shinyApp(ui = ui, server = server)
    

Currently I have hard coded all possible combination using if else statement and then realized its not efficient way. If the filters/widgets increase then its difficult to manage

for e.g. If I add one more filter here for variable "carb" in mtcars dataset I have to include all possible scenarios what the user will select and hard code it.

My actual app is having 5 -6 more filters.

Is there any way where whatever the user selects the app will group by on the fly and then filter and show results.


Solution

  • This is not a perfect approach as it still involves some copy & paste and duplicated code. But as a first step it gets rid of the if-else to filter your data:

    library(shiny)
    library(dplyr)
    
    choices_cyl <- unique(mtcars$cyl)
    choices_gear <- unique(mtcars$gear)
    
    ui <- fluidPage(
      titlePanel(" APP"),
      sidebarLayout(
        sidebarPanel(
          selectInput("x", "Select cylinder", choices = choices_cyl, multiple = TRUE),
          selectInput("y", "Select gear", choices = choices_gear, multiple = TRUE),
          submitButton("Submit")
        ),
        mainPanel(
          tableOutput("m")
        )
      )
    )
    
    server <- function(input, output) {
      check <- reactive({
        cyls <- input$x
        gears <- input$y
        grps <- c("cyl", "gear")[c(!is.null(cyls), !is.null(gears))]
        if (is.null(cyls)) cyls <- choices_cyl
        if (is.null(gears)) gears <- choices_gear
        mtcars %>%
          filter(cyl %in% cyls, gear %in% gears) %>%
          group_by(across(all_of(grps))) %>%
          summarise(Average_mpg = mean(mpg))
      })
    
      output$m <- renderTable(
        check()
      )
    }
    shinyApp(ui = ui, server = server)
    

    enter image description here