Search code examples
rggplot2parallel-processingtidyversegganimate

gganimate parallel - Provided file does not exist error


I am attempting to use gganimate with parallel processing, but when using anim_save, I get a "Provided file does not exist" error." It also says "Called from: png_dim(frames1)". The error seems to be coming from the aaa.R file from the package, and only happens in some cases. I don't know if it is relevant, but I am using RStudio and a Mac.

I am using a modified version of gganimate from a Github pull request as described in the answer to this question: How to use multiple cores to make gganimate faster. I call this new package gganimatep. The way I did this, based on the answer, was to download the zipped file from the link in the answer, change the file name in DESCRIPTION (to gganimatep), delete the vignettes folder, and then do RStudio / Build / Install and restart. (I am not very familiar with Github, but I noticed that the gganimate parallel page (https://github.com/HenrikBengtsson/gganimate/tree/feature/parallel-animate) says This branch is 2 commits ahead, 42 commits behind thomasp85:master. I don't know if this means that when I install it, I am basically installing an old version of gganimate.)

First example (with base code taken from https://ggplot2.tidyverse.org/reference/ggsf.html):

library(tidyverse)
library(sf)
library(gganimate)
library(future)

nc <- sf::st_read(system.file("shape/nc.shp", package = "sf"), quiet = TRUE)

set.seed(1)
nc1 <- nc %>% mutate(value = AREA, year = 1)
nc2 <- nc %>% mutate(value = AREA + runif(1, -.2, .2), year = 2)
nc3 <- nc2 %>% mutate(value = value + runif(1, -.2, .2), year = 3)

nc_new <- bind_rows(nc1, nc2, nc3)

b <- ggplot(nc_new) +
    geom_sf(aes(fill = value)) +
    labs(title = 'Year: {frame_time}') +
    transition_time(year) 

If we use the base gganimate (without parallel processing), it works:

b

or

gganimate::anim_save("test.gif", b, end_pause=8, width = 600, height = 400, duration=5, nframes=50)

But if we use gganimatep with parallel processing, it doesn't work:

library(gganimatep)
plan(multisession, workers = 7)
b

or

plan(multisession, workers = 7)
gganimatep::anim_save("test.gif", b, end_pause=8, width = 600, height = 400, duration=5, nframes=50)

Screenshot:

enter image description here

Because both b and anim_save give the same or very similar errors, I conclude that it is not a problem with anim_save, but more likely something having to do with gganimatep.

Another example. Using example code from the gganimate website (https://gganimate.com/), this does work:

library(gganimatep)
library(gganimate)
library(ggplot2)
library(gapminder)
library(future)
library(countrycode)
#devtools::install_github("rensa/ggflags")
library(ggflags)

g <- ggplot(gapminder, aes(gdpPercap, lifeExp, size = pop, colour = country)) +
    geom_point(alpha = 0.7, show.legend = FALSE) +
    scale_colour_manual(values = country_colors) +
    scale_size(range = c(2, 12)) +
    scale_x_log10() +
    facet_wrap(~continent) +
    labs(title = 'Year: {frame_time}', x = 'GDP per capita', y = 'life expectancy') +
    transition_time(year) +
    ease_aes('linear')

plan(multisession, workers = 7)
gganimatep::anim_save("test.gif", g, end_pause=8, width = 600, height = 400, duration=5, nframes=50)

When I do a slightly different thing (changing dots to flags), the base gganimate (not parallel processing) works:

gapminder2 <- gapminder
gapminder2$country2 <- countrycode(as.character(gapminder2$country),"country.name","iso2c")
gapminder2$country2 <- tolower(gapminder2$country2)
gapminder2$country2 <- as.character(gapminder2$country2)

g2 <- ggplot(gapminder2, aes(gdpPercap, lifeExp, size = pop, country=country2)) +
    geom_flag(show.legend=FALSE) +
    scale_colour_manual(values = country_colors) +
    scale_size(range = c(2, 12)) +
    scale_x_log10() +
    facet_wrap(~continent) +
    labs(title = 'Year: {frame_time}', x = 'GDP per capita', y = 'life expectancy') +
    transition_time(year) +
    ease_aes('linear')

gganimate::anim_save("test.gif", g2, end_pause=8, width = 600, height = 400, duration=5, nframes=50)

BUT, when I switch to gganimatep, it does not work:

plan(multisession, workers = 7)
gganimatep::anim_save("test.gif", g2, end_pause=8, width = 600, height = 400, duration=5, nframes=50)

I get the following error:

enter image description here

As mentioned above, it is the "Provided file does not exist" error." And "Called from: png_dim(frames1)". It appears to be from the aaa.R file.

In another instance, it said:

Inserting image 300 at 29.90s (100%)...
Encoding to gif... done!
Warning message:
In file.create(to[okay]) :
  cannot create file 'tmean_2020.gif', reason 'Read-only file system'

In another instance, it said:

enter image description here

Note that another thing (not a MWE) that also doesn't work with gganimatep is:

a <- ggplot(weather2) + 
    geom_sf(aes(fill = temp, geometry=geometry, group=NAME)) + 
    scale_fill_viridis_c(name = NULL) + 
    theme_map() +
    transition_time(as.integer(date)) +
    labs(subtitle = paste('Date: {frame_time}')) 

setwd("/")
plan(multisession, workers = 7)
gganimatep::anim_save("tmean_2020.gif", a, end_pause=8, width = 600, height = 400, duration=30, nframes=300)

What can I do to fix this? Thanks!


Solution

  • From trial and error, the following seems to be the problem: the package needs to be build from the GitHub pull request (a) (as described here) and needs to be named gganimate to satisfy internal dependencies.

    After setting up the environment correctly, parallel processing seems to work without using the plan(multisession, workers=7) command, but using it appears to throw an error.

    (see the discussion under the question for more details)