thomasp85/gganimate

Error in 'vec_rbind()': can't combine <double> and <character>

trevorld opened this issue · 4 comments

  • The {ggpattern} {gganimate} vignette example no longer works

  • I suspect perhaps some subtle side effect from {ggplot2} v3.4.0 switching to {vctrs}?

    • All the {ggpattern} visual tests pass after updating {ggplot2}, the only time we see an error is when trying to use {gganimate}...
library("ggplot2")
library(ggpattern)
library(gganimate)

df1 <- data.frame(time = 1, offset = 0    , trt = c("a", "b", "c"), outcome = c(2.3, 1.9, 3.2), stringsAsFactors = FALSE)
df2 <- data.frame(time = 2, offset = 0.045, trt = c("a", "b", "c"), outcome = c(2.3, 1.9, 3.2), stringsAsFactors = FALSE)
df  <- rbind(df1, df2)

# Plot the two different states and transition between them.
p <- ggplot(df, aes(trt, outcome)) +
  geom_col_pattern(
    aes(
      pattern_fill    = trt, 
      pattern_xoffset = I(offset), 
      pattern_yoffset = I(-offset)
    ), 
    colour          = 'black', 
    fill            = 'white',
    pattern_density = 0.5,
    pattern_angle   = 45
  ) +
  theme_bw() +
  labs(title = "ggpattern + gganimate") + 
  theme(legend.position = 'none') + 
  coord_fixed(ratio = 1/2) 

plot(p)

gganimate_pic

p <- p + transition_states(time, transition_length = 2,
                    state_length = 0, wrap = FALSE)

animate(p, nframes = 60, fps = 20)
Error in `vec_rbind()`:
! Can't combine `..1$pattern_xoffset` <double> and `..2$pattern_xoffset` <character>.
Run `rlang::last_error()` to see where the error occurred.

Enter a frame number, or 0 to exit   

 1: animate(p, nframes = 60, fps = 20)
 2: animate.gganim(p, nframes = 60, fps = 20)
 3: prerender(plot, nframes_total)
 4: ggplot_build(plot)
 5: ggplot_build.gganim(plot)
 6: scene$after_defaults(data)
 7: after_defaults(..., self = self)
 8: self$transition$expand_data(layer_data[tween_last], self$layer_type[tween_l
 9: expand_data(..., self = self)
10: Map(function(data, type, id, match, ease, enter, exit, layer_index) {
    se
11: mapply(FUN = f, ..., SIMPLIFY = FALSE)
12: (function (data, type, id, match, ease, enter, exit, layer_index) 
{
    self
13: self$expand_layer(data, type, id, match, ease, enter, exit, params, layer_i
14: expand_layer(..., self = self)
15: lapply(split(data, data$PANEL), function(data) {
    self$expand_panel(data,
16: FUN(X[[i]], ...)
17: self$expand_panel(data, type, id, match, ease, enter, exit, params, layer_i
18: expand_panel(..., self = self)
19: tween_state(all_frames, next_state, ease, params$transition_length[i], !!id
20: vec_rbind(if (nframes > 1) vec_cbind(from, .frame = rep(1, nrow(from))) els
21: (function () 
vec_default_ptype2(x = x, y = y, x_arg = x_arg, y_arg = y_arg,
22: vec_default_ptype2(x = x, y = y, x_arg = x_arg, y_arg = y_arg, call = call,
23: vec_ptype2_asis_left(x, y, x_arg = x_arg, y_arg = y_arg, call = call)
24: vec_ptype2_asis(x, y, ...)
25: vec_ptype2(x, y, ...)
26: (function () 
vec_default_ptype2(x = x, y = y, x_arg = x_arg, y_arg = y_arg,
27: vec_default_ptype2(x = x, y = y, x_arg = x_arg, y_arg = y_arg, call = call,
28: withRestarts(stop_incompatible_type(x, y, x_arg = x_arg, y_arg = y_arg, `vc
29: withOneRestart(expr, restarts[[1]])
30: doWithOneRestart(return(expr), restart)
31: stop_incompatible_type(x, y, x_arg = x_arg, y_arg = y_arg, `vctrs:::from_di
32: stop_incompatible(x, y, x_arg = x_arg, y_arg = y_arg, details = details, ..
33: stop_vctrs(message, class = c(class, "vctrs_error_incompatible"), x = x, y 
34: abort(message, class = c(class, "vctrs_error"), ..., call = vctrs_error_cal
35: signal_abort(cnd, .file)

Enter an item from the menu, or 0 to exit
xfun::session_info()
> xfun::session_info()
R version 4.2.1 (2022-06-23)
Platform: x86_64-pc-linux-gnu (64-bit)
Running under: Ubuntu 22.04.1 LTS

Locale:
  LC_CTYPE=C.UTF-8       LC_NUMERIC=C           LC_TIME=C.UTF-8       
  LC_COLLATE=C.UTF-8     LC_MONETARY=C.UTF-8    LC_MESSAGES=C.UTF-8   
  LC_PAPER=C.UTF-8       LC_NAME=C              LC_ADDRESS=C          
  LC_TELEPHONE=C         LC_MEASUREMENT=C.UTF-8 LC_IDENTIFICATION=C   

Package version:
  askpass_1.1         assertthat_0.2.1    brew_1.0.7         
  brio_1.1.3          cachem_1.0.6        callr_3.7.3        
  class_7.3-20        classInt_0.4-8      cli_3.4.1          
  clipr_0.8.0         colorspace_2.0-3    commonmark_1.8.0   
  compiler_4.2.1      cpp11_0.4.3         crayon_1.5.2       
  credentials_1.3.2   curl_4.3.3          DBI_1.1.3          
  desc_1.4.2          devtools_2.4.3      diffobj_0.3.5      
  digest_0.6.30       dplyr_1.0.10        e1071_1.7-12       
  ellipsis_0.3.2      evaluate_0.18       fansi_1.0.3        
  farver_2.1.1        fastmap_1.1.0       fs_1.5.2           
  generics_0.1.3      gert_1.6.0          gganimate_1.0.8    
  ggpattern_1.0.1     ggplot2_3.4.0       gh_1.3.0           
  gifski_1.6.6-1      gitcreds_0.1.1      glue_1.6.2         
  graphics_4.2.1      grDevices_4.2.1     grid_4.2.1         
  gridpattern_1.0.2   gtable_0.3.1        highr_0.9          
  hms_1.1.2           httr_1.4.2          ini_0.3.1          
  isoband_0.2.6       jsonlite_1.8.3      KernSmooth_2.23-20 
  knitr_1.40          labeling_0.4.2      lattice_0.20.45    
  lifecycle_1.0.3     magrittr_2.0.3      MASS_7.3.58        
  Matrix_1.5.1        memoise_2.0.1       methods_4.2.1      
  mgcv_1.8.40         mime_0.12           munsell_0.5.0      
  nlme_3.1.160        openssl_2.0.0       parallel_4.2.1     
  pillar_1.8.1        pkgbuild_1.3.1      pkgconfig_2.0.3    
  pkgload_1.3.1       png_0.1.7           praise_1.0.0       
  prettyunits_1.1.1   processx_3.8.0      progress_1.2.2     
  proxy_0.4-27        ps_1.7.2            purrr_0.9000.0.9000
  R6_2.5.1            rappdirs_0.3.3      rcmdcheck_1.4.0    
  RColorBrewer_1.1.3  Rcpp_1.0.9          rematch2_2.1.2     
  remotes_2.4.2       rlang_1.0.6         roxygen2_7.2.1     
  rprojroot_2.0.3     rstudioapi_0.13     rversions_2.1.1    
  s2_1.1.0.9000       scales_1.2.1        sessioninfo_1.2.2  
  sf_1.0-8            splines_4.2.1       stats_4.2.1        
  stringi_1.7.8       stringr_1.4.1       sys_3.4.1          
  testthat_3.1.5      tibble_3.1.8        tidyselect_1.1.2   
  tools_4.2.1         tweenr_2.0.2        units_0.8-0        
  usethis_2.1.5       utf8_1.2.2          utils_4.2.1        
  vctrs_0.5.0.9000    viridisLite_0.4.1   waldo_0.4.0        
  whisker_0.4         withr_2.5.0         wk_0.7.0           
  xfun_0.34           xml2_1.3.3          xopen_1.0.0        
  yaml_2.3.6          zip_2.2.1          

ditto for transition_layers(). running the examples from the help file gives the error message:

 Error in `vec_rbind()`:                                                        
 ! Can't combine `..1$fill` <logical> and `..2$fill` <character>. 

Running 1.0.8 in R 4.2.1 on MacOS 12.6.1. I'm still on ggplot2 3.3.6 though.

The vignette example works without the use of I() in aesthetic mappings. I.e.:

    aes(
      pattern_fill    = trt, 
      pattern_xoffset = offset, 
      pattern_yoffset = -offset
    )

instead of

    aes(
      pattern_fill    = trt, 
      pattern_xoffset = I(offset), 
      pattern_yoffset = I(-offset)
    )

I'm not sufficiently familiar with ggpattern to understand why it was used in the first place, but its usage led to the columns' classes being AsIs instead of numeric, and consequently interpolated as constants within tweenr::tween_state during the animation process. The interpolation for constants is

> tweenr:::interpolate_constant_state
function (data, states) 
{
    constant_state_interpolator(lapply(data, as.character), states)
}

In other words, a conversation of the columns to character class.

Trying to combine the results with the original, un-interpolated dataframe (where pattern_xoffset / pattern_yoffset were still numeric in nature) then led to the above error.

@linzi-sg Thanks for the code tweak! I've updated the {ggpattern} vignette with your suggestion and it seems to work again. I also don't know why the original {ggpattern} author used the I() in the first place...

I'm keeping the issue open for now since I'm not sure if this is still considered a bug in {gganimate} since the original version of the code still works in {ggplot2} and this code used to work in {gganimate}.

Fixed now with the latest tweenr dev version. However, I would argue that removing the I() is the right course of action for the example as this allows the pattern offset to be smoothly tweeted rather than jump from state to state.

In any case, both works again now