rstudio / shiny

Easy interactive web applications with R
https://shiny.posit.co/
Other
5.37k stars 1.87k forks source link

Recent update causes error in data.table dcast() in Shiny #3303

Open l-jaye opened 3 years ago

l-jaye commented 3 years ago

Describe the problem in detail

Hello! I am having an issue with recent update to either Shiny or data.table, in the data.table dcast() function. I have filed the issue in Rdatatable/data.table#4913, but just to cross-reference. data.table.dcast works fine outside of Shiny.

Example application or steps to reproduce the problem

library(data.table)
library(shiny)

shinyApp(

  ui = fluidPage(
    actionButton("do.btn","Go!")
  ),

  server = function(input, output){

    observeEvent(input$do.btn, {

      metrics = c("col.x","col.y")
      dt = data.table(x = 1:10, y = "test", col.x = 3, col.y = 4)
      melt.dt = melt(dt, measure.vars = metrics, variable.name = "metric")

      dt = dcast(melt.dt, ... ~ metric, value.var = "value", fill = NA) # this throws the error

    })

  }
)

System details

Browser Version:

Output of sessionInfo():

R version 3.6.2 (2019-12-12)
Platform: x86_64-w64-mingw32/x64 (64-bit)
Running under: Windows 10 x64 (build 19041)

Matrix products: default

attached base packages:
[1] stats     graphics  grDevices utils     datasets  methods   base     

other attached packages:
[1] cardiopyrate_0.7.12 shiny_1.6.0         data.table_1.13.6  

loaded via a namespace (and not attached):
  [1] backports_1.2.1         Hmisc_4.4-2             lazyeval_0.2.2         
  [4] splines_3.6.2           crosstalk_1.1.1         usethis_2.0.1          
  [7] ggplot2_3.3.3           TH.data_1.0-10          pryr_0.1.4             
 [10] digest_0.6.27           foreach_1.5.1           htmltools_0.5.1.1      
 [13] checkmate_2.0.0         magrittr_2.0.1          memoise_2.0.0          
 [16] colourvalues_0.3.7      cluster_2.1.0           doParallel_1.0.16      
 [19] bigassertr_0.1.3        bigstatsr_1.3.1         remotes_2.2.0          
 [22] sandwich_3.0-0          prettyunits_1.1.1       jpeg_0.1-8.1           
 [25] colorspace_2.0-0        xfun_0.21               dplyr_1.0.4            
 [28] callr_3.5.1             crayon_1.4.1            jsonlite_1.7.2         
 [31] lme4_1.1-26             survival_3.1-8          flock_0.7              
 [34] zoo_1.8-8               iterators_1.0.13        glue_1.4.2             
 [37] polyclip_1.10-0         gtable_0.3.0            emmeans_1.5.4          
 [40] webshot_0.5.2           pkgbuild_1.2.0          RcppZiggurat_0.1.6     
 [43] scales_1.1.1            mvtnorm_1.1-1           bigparallelr_0.3.1     
 [46] miniUI_0.1.1.1          Rcpp_1.0.6              htmlTable_2.1.0        
 [49] viridisLite_0.3.0       xtable_1.8-4            reticulate_1.18        
 [52] foreign_0.8-72          Formula_1.2-4           DT_0.17                
 [55] Rfast2_0.0.8            htmlwidgets_1.5.3       httr_1.4.2             
 [58] RColorBrewer_1.1-2      ellipsis_0.3.1          pkgconfig_2.0.3        
 [61] farver_2.0.3            nnet_7.3-12             sass_0.3.1             
 [64] tidyselect_1.1.0        rlang_0.4.10            manipulateWidget_0.10.1
 [67] later_1.1.0.1           munsell_0.5.0           tools_3.6.2            
 [70] cachem_1.0.4            cli_2.3.0               generics_0.1.0         
 [73] devtools_2.3.2          evaluate_0.14           stringr_1.4.0          
 [76] fastmap_1.1.0           yaml_2.2.1              processx_3.4.5         
 [79] knitr_1.31              fs_1.5.0                rgl_0.105.13           
 [82] purrr_0.3.4             RANN_2.6.1              rootSolve_1.8.2.1      
 [85] nlme_3.1-142            mime_0.10               compiler_3.6.2         
 [88] rstudioapi_0.13         plotly_4.9.3            png_0.1-7              
 [91] testthat_3.0.2          bcp_4.0.3               tibble_3.0.6           
 [94] statmod_1.4.35          tweenr_1.0.1            bslib_0.2.4            
 [97] Directional_4.8         stringi_1.5.3           ps_1.5.0               
[100] desc_1.2.0              lattice_0.20-38         Matrix_1.2-18          
[103] nloptr_1.2.2.2          vctrs_0.3.6             pillar_1.4.7           
[106] lifecycle_1.0.0         jquerylib_0.1.3         estimability_1.3       
[109] cowplot_1.1.1           httpuv_1.5.5            R6_2.5.0               
[112] latticeExtra_0.6-29     promises_1.2.0.1        gridExtra_2.3          
[115] sessioninfo_1.1.1       codetools_0.2-16        boot_1.3-23            
[118] MASS_7.3-51.4           assertthat_0.2.1        pkgload_1.1.0          
[121] rprojroot_2.0.2         withr_2.4.1             multcomp_1.4-16        
[124] mgcv_1.8-34             parallel_3.6.2          grid_3.6.2             
[127] rpart_4.1-15            tidyr_1.1.2             coda_0.19-4            
[130] minqa_1.2.4             rmarkdown_2.7           Rfast_2.0.1            
[133] ggforce_0.3.2           base64enc_0.1-3         tinytex_0.29   
wch commented 3 years ago

This is an interaction between rlang and data.table. It can be reproduced with the following:

library(rlang)
library(data.table)

x <- quo({
  metrics = c("col.x","col.y")
  dt = data.table(x = 1:10, y = "test", col.x = 3, col.y = 4)
  melt.dt = melt(dt, measure.vars = metrics, variable.name = "metric")
  dt = dcast(melt.dt, ... ~ metric, value.var = "value", fill = NA)
})  

eval_tidy(x)
#> Error in check_formula(formula, names(data), valnames) : 
#>   '...' used in an incorrect context

cc: @lionel-

ColeMiller1 commented 3 years ago

Hi @wch - what is rlang doing with ...? While data.table does NSE to substitute names into the ..., R still parses the formula without error. Mainly just curious.

... ~ x
#> ... ~ x
rlang::eval_tidy(rlang::quo(...~x))
#> Error in rlang::eval_tidy(rlang::quo(... ~ x)): '...' used in an incorrect context
lionel- commented 3 years ago

Now tracked in r-lib/rlang#1124. Thanks for the reprex @ColeMiller1.

lionel- commented 3 years ago

Quosures are implemented as formulas for practical/historical reasons. For this reason tidy eval masks contain a special function bound to ~. The problem is that you can't pass a ... argument to a closure in a context where none is bound, even if that ... argument is never evaluated.

tilde <- function(x, y) list(substitute(x), substitute(y))
tilde(1, ...)
#> Error: '...' used in an incorrect context

ignore <- function(x, y) NULL
ignore(1, ...)
#> Error: '...' used in an incorrect context

This is a limitation of R. The argument application routine of the interpreter checks that the calling environment has dots: https://github.com/wch/r-source/blob/2ab3b85b/src/main/eval.c#L3203-L3204 Only SPECIALSXP primitive functions like ~ can be supplied ... without this check.

So I don't see a simple way forward here.