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

broken line at end of animation #502

Open
richarddmorey opened this issue Oct 3, 2024 · 2 comments
Open

broken line at end of animation #502

richarddmorey opened this issue Oct 3, 2024 · 2 comments

Comments

@richarddmorey
Copy link

richarddmorey commented Oct 3, 2024

When running the following code, I should get a smooth line starting from x=.5 tracing to x=0, monotonically increasing.

library(ggplot2)
library(gganimate)
library(ragg)
library(gifski)

dplyr::tibble(
  x = seq(0,.5,length.out=256),
  y = 1-pnorm(qnorm(x)/5)
  ) -> df

res = 300
w = 7
h = 4
# If this is run in knitr, w and h are in inches, otherwise
# they are in pixels
anim_w = ifelse(interactive(),w*res,w)
anim_h = ifelse(interactive(),h*res,h)


ggplot(df,aes(x=x,y=y)) +
  geom_line() +
  geom_point() +
  coord_cartesian(
    xlim=c(0,.5),ylim=c(.5,1),expand = FALSE
  ) -> gg

  ggsave(plot = gg, filename = 'test.png', 
         device = ragg::agg_png, dpi = res, width = w, height=h,
         units = 'in')
  
anim = gg + transition_reveal(x, range = c(.5,0)) 


animate(anim, device='ragg_png', res=res, width=anim_w, height=anim_h,
        renderer = gifski_renderer(file='test.gif',
                                   loop=FALSE))

The plain ggplot shows this clearly:

test

However, the end of the resulting animation appears to be broken:

test

This may be related to #486. However, I did try version 1.0.7 and the dev version (1.0.9.9) and they all seemed to show the issue, so I'm not sure.

Edited to remove second apparently unrelated issue


> xfun::session_info()
R version 4.3.2 (2023-10-31)
Platform: aarch64-apple-darwin20 (64-bit)
Running under: macOS Sonoma 14.7, RStudio 2023.6.1.524

Locale: en_US.UTF-8 / en_US.UTF-8 / en_US.UTF-8 / C / en_US.UTF-8 / en_US.UTF-8

Package version:
  class_7.3.22         classInt_0.4.10      cli_3.6.3            colorspace_2.1-1    
  compiler_4.3.2       cpp11_0.5.0          crayon_1.5.3         DBI_1.2.3           
  dplyr_1.1.4          e1071_1.7.16         fansi_1.0.6          farver_2.1.2        
  generics_0.1.3       gganimate_1.0.9.9000 ggplot2_3.5.1        gifski_1.12.0-2     
  glue_1.8.0           graphics_4.3.2       grDevices_4.3.2      grid_4.3.2          
  gtable_0.3.5         hms_1.1.3            isoband_0.2.7        KernSmooth_2.23.22  
  labeling_0.4.3       lattice_0.22.5       lifecycle_1.0.4      lpSolve_5.6.21      
  magrittr_2.0.3       MASS_7.3.60          Matrix_1.6.3         methods_4.3.2       
  mgcv_1.9.0           munsell_0.5.1        nlme_3.1.163         pillar_1.9.0        
  pkgconfig_2.0.3      prettyunits_1.2.0    progress_1.2.3       proxy_0.4.27        
  R6_2.5.1             ragg_1.3.3           RColorBrewer_1.1.3   Rcpp_1.0.13         
  renv_1.0.9           rlang_1.1.4          rstudioapi_0.15.0    s2_1.1.7            
  scales_1.3.0         sf_1.0.17            splines_4.3.2        stats_4.3.2         
  stringi_1.8.4        systemfonts_1.1.0    textshaping_0.3.7    tibble_3.2.1        
  tidyselect_1.2.1     tools_4.3.2          transformr_0.1.5     tweenr_2.0.3        
  units_0.8.5          utf8_1.2.4           utils_4.3.2          vctrs_0.6.5         
  viridisLite_0.4.2    withr_3.0.1          wk_0.9.3             xfun_0.47  
@richarddmorey
Copy link
Author

richarddmorey commented Oct 5, 2024

The first issue appears to be caused by the call to ggplot's compute_geom_1 function at

data <- by_layer(function(l, d) l$compute_geom_1(d), layers, data, "setting up geom")

The data is in the correct order prior to this, but after this call, the rows in each frame are sorted in the opposite order to what the should be. In this case, since the movement in the x direction is negative, the rows should be sorted in descending order. However, this function sorts them in ascending order so the order of the points is wrong in each frame.

The only workarounds that I see is to make as many frames as there are rows in the data (obviously with thousands of rows this would be prohibitive) or to detect the order before calling the function, then fix it after calling. However, I don't know enough about the internal workings of gganimate or ggplot2 to do this without possibly breaking something else!

Edited to add:

To confirm this is the case, I did the following:

  1. debug(gganimate:::ggplot_build.gganim)
  2. Step to after the problematic line 76 above
  3. Run this to sort the rows properly:
data <- lapply(data, 
    function(el){
        el[order(el$x, decreasing = TRUE),]
    })
  1. Continue

This results in the following correct plot:
test

@richarddmorey
Copy link
Author

If you're reading this and facing a similar issue to mine, the code below (or something like it) demonstrates a temporary work-around with version 1.0.9 and 1.0.9.9000 (line numbers in the trace call might have to be changed if that function changes in a subsequent version):

Basically, it inserts code into the gganimate method that builds the animation that sorts the x aesthetic in descending order, so that the plot renders correctly. This is super hacky and I would not expect it to work generally (so YMMV).

# Define code to be inserted
e <- quote(data <- lapply(data, function(el){
  if(is.null(el$x)) # Assuming x is the aesthetic that needs sorted
    return(el)
  el[order(el$x, decreasing = TRUE),] # Sort the aesthetic correctly
})
)

# Insert the code
trace(gganimate:::ggplot_build.gganim, e, at = 31, print = FALSE)

## RENDER THE ANIMATION HERE
# ...
##

# Revert to the gganimate's version of the function 
untrace(gganimate:::ggplot_build.gganim)

Thanks to G. Grothendieck on Stack Overflow for suggesting trace: https://stackoverflow.com/a/79057552/1129889

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant