Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Using lazy_dt() Inside of a Shiny App Throws Errors in Reactive Contexts #260

Open
nigeljmckernan opened this issue Jun 16, 2021 · 2 comments
Labels
bug an unexpected problem or unintended behavior

Comments

@nigeljmckernan
Copy link

I wasn't sure whether to report this to rstudio/shiny or here, but since regular dplyr code is fine in my reactive sections, I'm pretty sure that it's dtplyr that's causing this issue, and not Shiny.

I've tried to make as minimal of a Shiny app to reproduce this, while incorporating some reactivity, as the reactivity is where I'm encountering these errors.

Both of the following code blocks run completely fine when regular dplyr code is used without lazy_dt().

The error thrown depends on if group_by() is used or not. I'll demonstrate both errors.

Here's without group_by():

library(shiny)
library(data.table)
library(dtplyr)
library(dplyr, warn.conflicts = FALSE)
library(lubridate, warn.conflicts = FALSE)
library(nycflights13)

flights <-  flights %>% mutate(Dep_Date = time_hour %>% as_date())

ui <- fluidPage(
            selectInput(
                "tail",
                "Select a Tail #",
                choices = unique(flights$tailnum), # I'm aware this isn't the best way to do this.
                multiple = TRUE
                ),
            dateRangeInput(
                "depDates",
                "Choose a Departure Date Range",
                min = min(flights$Dep_Date),
                max = max(flights$Dep_Date),
                start = min(flights$Dep_Date),
                end = max(flights$Dep_Date)
                ),
            dataTableOutput("depTable")
)

server <- function(input, output, session) {
    
    output$depTable <- renderDataTable(
        flights %>%
            lazy_dt() %>%
            filter(
                Dep_Date %>% between(input$depDates[1], input$depDates[2]),
                tailnum %in% input$tail
            ) %>%
            summarise(
                Avg_Dep_Delay = mean(dep_delay, na.rm = TRUE),
                Max_Dep_Delay = max(dep_delay, na.rm = TRUE)
            ) %>%
            collect()
    )
}

shinyApp(ui = ui, server = server)

This throw an error of Error: invalid subscript type 'closure'.

And if I basically do the same thing with group_by():

ui <- fluidPage(
            selectInput(
                "tail",
                "Select a Tail #",
                choices = unique(flights$tailnum),
                multiple = TRUE
                ),
            selectInput(
                 "groupby",
                 "Select which variables to group by",
                 choices = colnames(flights),
                 multiple = TRUE
             ),
            dateRangeInput(
                "depDates",
                "Choose a Departure Date Range",
                min = min(flights$Dep_Date),
                max = max(flights$Dep_Date),
                start = min(flights$Dep_Date),
                end = max(flights$Dep_Date)
                ),
            dataTableOutput("depTable")
)

server <- function(input, output, session) {
    
    output$depTable <- renderDataTable(
        flights %>%
            lazy_dt() %>%
            filter(
                Dep_Date %>% between(input$depDates[1], input$depDates[2]),
                tailnum %in% input$tail
            ) %>%
            group_by(across(any_of(input$groupby))) %>%
            summarise(
                Avg_Dep_Delay = mean(dep_delay, na.rm = TRUE),
                Max_Dep_Delay = max(dep_delay, na.rm = TRUE)
            ) %>%
            ungroup() %>%
            collect()
    )
}

shinyApp(ui = ui, server = server)

This throws an error of Error: object 'input' not found.

Lastly, no errors are thrown if no dplyr verbs are used except for something like collect() after lazy_dt().

ui <- fluidPage(
            dataTableOutput("depTable"),
)

server <- function(input, output, session) {
    
    output$depTable <- renderDataTable(
        flights %>%
            lazy_dt() %>%
            collect()
    )
}

shinyApp(ui = ui, server = server)

I would like to not have to use data.table explicitly, as various tidyselect verbs and across() are too useful to give up in certain circumstances.

For now I'm leveraging dtplyr for most of my pre-processing needs, and just leaving it to regular dplyr code in any reactive elements.

Thanks for any help!

@hadley
Copy link
Member

hadley commented Jun 17, 2021

This is almost certainly a bug; until it's fixed you might be able to work around it by changing group_by(across(any_of(input$groupby))) to group_by(across(any_of(!!input$groupby))) (this shouldn't be necessary in general, but if I'm guessing correctly it'll fix this problem)

@nigeljmckernan
Copy link
Author

nigeljmckernan commented Jun 17, 2021

That worked! Thank you, Hadley!

(Sort of) Minimal working reprex:

library(shiny)
library(data.table)
library(dtplyr)
library(dplyr, warn.conflicts = FALSE)
library(lubridate, warn.conflicts = FALSE)
library(nycflights13)

flights <-  flights %>% lazy_dt() %>% mutate(Dep_Date = time_hour %>% as_date()) %>% collect()

ui <- fluidPage(

            # Selecting A Tail # To Filter By
            selectInput(
                "tail",
                "Select a Tail #",
                choices = unique(flights$tailnum),
                multiple = TRUE,
                selected = "N804JB"
                ),
            
            # Selecting Grouping Variables
            selectInput(
                "groupby",
                "Select which variables to group by",
                choices = colnames(flights),
                multiple = TRUE,
                selected = c("year", "month")
            ),

            # Selecting Summarising Variables
            selectInput(
              "summarisers",
              "Select Variables to Summarise",
              choices = c("dep_delay", "arr_delay"),
              multiple = TRUE,
              selected = "arr_delay"
            ),
            
            # Date Range Selection
            dateRangeInput(
                "depDates",
                "Choose a Departure Date Range",
                min = min(flights$Dep_Date),
                max = max(flights$Dep_Date),
                start = min(flights$Dep_Date),
                end = max(flights$Dep_Date)
                ),
            
            # Outputs
            dataTableOutput("outputTable")
)

server <- function(input, output, session) {
    
    output$outputTable <- renderDataTable(
        flights %>%
          
          lazy_dt() %>%
          
          filter(
            tailnum %in% !!input$tail,
            Dep_Date %>% between(input$depDates[1], input$depDates[2])
            ) %>%

          group_by(across(any_of(!!input$groupby))) %>%

          summarise(across(any_of(!!input$summarisers), mean, na.rm = TRUE)) %>%

          ungroup() %>%
          
          collect()
    )
}

shinyApp(ui, server)

Curiously, between()'s left and right values don't need !! when using inputs. Not sure why that is.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug an unexpected problem or unintended behavior
Projects
None yet
Development

No branches or pull requests

3 participants