help with magick package

Tags: #<Tag:0x00007f16f996da18> #<Tag:0x00007f16f996d950>

Hi All,

I am struggling to understand a couple of things about what the magick package is doing, and whether there are better ways to use it. If more appropriate, I’m happy to repost this on SO, please just let me know.

I’m having trouble using magick to stitch together two gifs from gganimate, as described here: https://github.com/thomasp85/gganimate/issues/140.

My two specific questions (a lot more detail below):

  1. Why does image_animate() seem to scale badly with the number of frames (i.e. execution time seems to increase much more than linearly with number of frames)?

  2. What is the difference between calling a magick object directly to get the animation, and calling image_animate() (in my hands, the

It works OK. It’s just that building the final animation with magick is reaaally slow, and I’m trying to understand why, to see if there’s anything I can do about it. (Note: this is for a package we’re developing, so I’m seeking to understand whether this can be sped up to the point that it will be useable for others).

Here’s what I’m doing:

  1. Creating two gifs with the same number of frames using gganimate()
  2. Decomposing both gifs into individual images using image_read() (this is very fast)
  3. Combining the frames one-by-one using newframe <- image_append(c(frame_a, frame_b)) then final_gif <- c(final_gif, new_frame) (this is also fast)
  4. Animating final_gif using image_animate(final_gif).

Here’s what the final_gif looks like, for information:

# A tibble: 150 x 7
   format width height colorspace matte filesize density
   <chr>  <int>  <int> <chr>      <lgl>    <int> <chr>  
 1 GIF      600    550 sRGB       TRUE         0 72x72  
 2 GIF      600    550 sRGB       TRUE         0 72x72  
 3 GIF      600    550 sRGB       TRUE         0 72x72  
 4 GIF      600    550 sRGB       TRUE         0 72x72  
 5 GIF      600    550 sRGB       TRUE         0 72x72  
 6 GIF      600    550 sRGB       TRUE         0 72x72  
 7 GIF      600    550 sRGB       TRUE         0 72x72  
 8 GIF      600    550 sRGB       TRUE         0 72x72  
 9 GIF      600    550 sRGB       TRUE         0 72x72  
10 GIF      600    550 sRGB       TRUE         0 72x72  
# … with 140 more rows

Now the questions.

Question 1: Why does image_animate() step scale badly with the number of frames? And is there any way to get around this?

(Note: I don’t see the same issues in gganimate, where the animation steps scale roughly linearly with the number of frames, as I’d naively expect).

Here are some timings from system.time() with different numbers of frames to illustrate:

30 frames: 2.1s
60 frames: 4.2s
120 frames: 11.2s (so far so linear)
240 frames: 251s (not so linear anymore)

FWIW, it doesn’t seem to be a memory issue, because I tracked memory usage and saw no issues.

Question 2: What is the difference between calling the magick object directly (i.e. final_gif), and calling image_animate(final_gif)?

I note two big differences (which I assume are related). The above scaling issue seems a lot worse when calling the object directly; and calling image_animate() gives really horrible grainy gifs (in RStudio at least), while calling the object directly gives beautifully rendered gifs with all of their pixels.

If anyone can shed any light on either of these issues, I’d be very interested. Happy to build replicable examples if it helps.

Rob

Indeed, you may not need image_animate() atl all. This calls out to imagemagick’s coalesceImages but this is mostly useful for transitioning if frames have transparency.

You can write the object directly to gif using image_write() or image_write_gif(). The former uses imagemagick’s internal gif encoder, whereas the latter uses the gifski package (which may be a bit faster in some cases).

Thanks for the tips!

Writing them out might be useful, but what I’m really looking for (sorry - didn’t explain in the original post) is a way to display them in R studio. Just calling the final_gif object itself does this very nicely, but is extremely slow.

When you print the image object in rstudio, what happens is that it calls write_image() to save it as a temporary image and opens that in the rstudio viewer: https://github.com/ropensci/magick/blob/f611bbbe85c5fd280b1076a5b48c7a11b0218615/R/base.R#L147-L175

OK, after digging around some more it’s clear that the answer to both my questions is due to differences between image_write() and image_write_gif()

As you suggested, the former is much slower than the latter (~20s vs. ~480s on my 240 frame gif).

The remaining issue is that when I call image_write_gif() the gifs I get are super grainy after the first frame. I’ve checked in the tmp directory and the issue is with the pngs that it is outputting. It looks to me like I might be able to address this with some of the settings in image_convert() , which is called by write_png_files() .

Here’s an example in case it helps. It looks like a transparency issue or something related.

If you have any pointers for ways to address that, I’d be very grateful. And thanks either way for your help and time.

compare to the first frame, which is spot on:

update - I’ve played around with all the settings in image_convert() (including toggling matte) but couldn’t find a way to fix the issue.

If there’s some way to get image_convert() to write png files that match those written out by image_write(), I think that would fix it. I just haven’t been able to figure it out.