'How to group_by() and summarise() data reactively with shiny?

I am constructing a shiny web app that allows users to get the best of dplyr (data wrangling & manipulation R package) without coding in R.

I would like to group_by() and summarise() using respectively a selectInput that allow choosing a variable among all those available in the "movies" file (http://s3.amazonaws.com/assets.datacamp.com/production/course_4850/datasets/movies.Rdata")

Any body knows how to fix this please?

When using the following server function, I get an empty table ...

  shinyServer(function(input, output){
    output$table <- DT::renderDataTable({
      moviesSummarise <- movies %>% 
        group_by(inputx) %>%
        summarise(Moyenne = mean(input$y)) 

      DT::datatable(data = moviesSummarise)
    })
  })

Many thanks.

 if (interactive()){

  load(url("http://s3.amazonaws.com/assets.datacamp.com/production/course_4850/datasets/movies.Rdata"))

  # Libraries 
     library(dplyr)
      library(shiny)
      library(shinydashboard)
      library(DT)

  ui1 <- shinyUI(
    dashboardPage(
      dashboardHeader(title = "Data Viewer"), 
      dashboardSidebar(
        selectInput(inputId = "x", 
                    label = "Grouper par :", 
                    choices = c("title_type", "genre", "mpaa_rating",                               
                   "studio", "thtr_rel_year"), 
                    selected = "thtr_rel_year"),
        selectInput(inputId = "y", 
                    label = "Résumé par :", 
                    choices = c("runtime","imdb_num_votes", 
                    "critics_score", "audience_score"), 
                    selected = "runtime")
      ), 
      dashboardBody(
        fluidPage(
          box(DT::dataTableOutput(outputId = "table"), title="Résumé des données :", height = 300)
        )
      )
    )
  )
server1 <- shinyServer(function(input, output){
    output$table <- DT::renderDataTable({
      moviesSummarise <- movies %>% 
        group_by(genre) %>% 
        ## It doesn't work when I tried group_by(input$x)

        summarise(Moyenne = mean(runtime)) 
        ## It doesn't work when I tried summarise(input$y)

      DT::datatable(data = moviesSummarise)
    })
  })
  shinyApp(ui = ui1, server = server1)
}

I expect that the summary table will change reactively when I group_by() / summarise() a new variable using the selectInput("x", ...) and selectInput("y", ...) With the above pasted code, it generates an empty table.



Solution 1:[1]

Two ways to do this: using scoped versions of group_by and summarise (which will pick up the strings) or rlang to unquote the inputs.

Neither group_by nor summarize like strings and rather expect bare names:

> movies %>% 
+         group_by("title_type") %>%
+         summarise(Moyenne = mean("runtime")) 
# A tibble: 1 x 2
  `"title_type"` Moyenne
  <chr>            <dbl>
1 title_type          NA

> movies %>% 
+         group_by(title_type) %>%
+         summarise(Moyenne = mean(runtime)) 
# A tibble: 3 x 2
  title_type   Moyenne
  <fct>          <dbl>
1 Documentary      NA 
2 Feature Film    107.
3 TV Movie        102.

Using the scope versions:

> movies %>% 
+         group_by_at("title_type") %>%
+         summarise_at(vars(one_of("runtime")), list(Moyenne = mean))
# A tibble: 3 x 2
  title_type   Moyenne
  <fct>          <dbl>
1 Documentary      NA 
2 Feature Film    107.
3 TV Movie        102.

Or you can use the rlang approach and unqoute the strings:

> movies %>% 
+         group_by(!! sym("title_type")) %>% 
+         summarise(Moyenne = mean(!!sym("runtime")))
# A tibble: 3 x 2
  title_type   Moyenne
  <fct>          <dbl>
1 Documentary      NA 
2 Feature Film    107.
3 TV Movie        102.

So:

if (interactive()){

    load(url("http://s3.amazonaws.com/assets.datacamp.com/production/course_4850/datasets/movies.Rdata"))

    # Libraries 
    library(dplyr)
    library(shiny)
    library(shinydashboard)
    library(DT)

    ui1 <- shinyUI(
        dashboardPage(
            dashboardHeader(title = "Data Viewer"), 
            dashboardSidebar(
                selectInput(inputId = "x", 
                            label = "Grouper par :", 
                            choices = c("title_type", "genre", "mpaa_rating",                               
                                        "studio", "thtr_rel_year"), 
                            selected = "thtr_rel_year"),
                selectInput(inputId = "y", 
                            label = "Résumé par :", 
                            choices = c("runtime","imdb_num_votes", 
                                        "critics_score", "audience_score"), 
                            selected = "runtime")
            ), 
            dashboardBody(
                fluidPage(
                    box(DT::dataTableOutput(outputId = "table"), title="Résumé des données :", height = 300)
                )
            )
        )
    )
    server1 <- shinyServer(function(input, output){
        output$table <- DT::renderDataTable({
            moviesSummarise <- movies %>% 
                group_by(!! sym(input$x)) %>% 
                summarise(Moyenne = mean(!!sym(input$y)))

            DT::datatable(data = moviesSummarise)
        })
    })
    shinyApp(ui = ui1, server = server1)

Solution 2:[2]

Another solution is to use the dplyr data-masking method, namely referring shiny reactive variables in dplyr verbs through .data[[input$id]] in reactive functions. Most dplyr verbs do not accept strings as inputs, data-masking method allows us refer data variables and environment variables (.env[[]]) through character strings. For example:

change group_by(input$x) %>% to group_by (.data[[input$x]]) %>%, and

change %>% summarise(Moyenne = mean(input$y)) to %>% summarise(Moyenne = mean(.data[[input$y]])).

I have checked and your code should all work now.

Solution 3:[3]

Correction of the first server.

  shinyServer(function(input, output){
    output$table <- DT::renderDataTable({
      moviesSummarise <- movies %>% 
        group_by(input$x) %>%
        summarise(Moyenne = mean(input$y)) 

      DT::datatable(data = moviesSummarise)
    })
  })

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 paqmo
Solution 2 Researchnology
Solution 3 Rodrigo Orellana