quarto-dev/quarto-cli

{gganimate} rendering fails with svg figure output

Closed this issue · 3 comments

Bug description

When rendering to html with fig-output: svg, plots which make use of {gganimate} won't render. Errors implicate device(), as below.

Error in `device()`:
! unused arguments (units = "in", res = 96)

A workaround is to set dev: png in the relevant chunk options. This fails, however, if a plot is saved and then rendered with animate().

Steps to reproduce

Apologies for the slightly long example. The document will render fine if fig-format: svg is removed from the yaml header.

---
title: "gganimate example"
execute: 
  fig-format: svg
  echo: false
---

```{r}
library(gganimate)
```

Should work (using `#| dev: png`): 

```{r}
#| dev: png
ggplot(mtcars, aes(factor(cyl), mpg)) + 
  geom_boxplot() + 
  transition_states(gear)
```

Will fail (no device override):

```{r}
ggplot(mtcars, aes(factor(cyl), mpg)) + 
  geom_boxplot() + 
  transition_states(gear)
```

Will fail (device override but uses `animate()`)

```{r}
#| dev: png
p <- ggplot(mtcars, aes(factor(cyl), mpg)) + 
  geom_boxplot() + 
  transition_states(gear)
animate(p)
```

Expected behavior

The animated plots should be created without needing to change device settings, or restrictions on devices should be clearly documented. It should be possible to render an animated plot using animate() in a document which has a global setting of fig-format: svg (at the moment that does not appear to be the case).

Actual behavior

An error is raised when attempting to render an animation, unless dev: png is in the chunk options.
However even when dev: png is in the chunk options, if animate() is called, an error is raised.

Your environment

  • IDE: RStudio 2023.06.2+561
  • OS: Arch Linux (kernel 6.4.12-zen1-1-zen)

Quarto check output

[✓] Checking versions of quarto binary dependencies...
      Pandoc version 3.1.1: OK
      Dart Sass version 1.55.0: OK
[✓] Checking versions of quarto dependencies......OK
[✓] Checking Quarto installation......OK
      Version: 1.3.450
      Path: /opt/quarto/bin

[✓] Checking basic markdown render....OK

[✓] Checking Python 3 installation....OK
      Version: 3.11.5
      Path: /usr/bin/python3
      Jupyter: (None)

      Jupyter is not available in this Python installation.
      Install with python3 -m pip install jupyter

[✓] Checking R installation...........OK
      Version: 4.3.1
      Path: /usr/lib64/R
      LibPaths:
        - /home/martinc/lib/R
        - /usr/lib/R/library
      knitr: 1.43
      rmarkdown: 2.24

[✓] Checking Knitr engine render......OK

cderv commented

I believe this is not specific to Quarto but is an issue with knitr maybe. Anyhow, this is also happening with rmarkdown

---
title: "Label shouldn't be named"
output: 
  html_document:
    dev: svg
---

```{r}
library(gganimate)
```

Should work (using `#| dev: png`): 

```{r}
#| dev: png
ggplot(mtcars, aes(factor(cyl), mpg)) + 
  geom_boxplot() + 
  transition_states(gear)
```

Will fail (no device override):

```{r}
ggplot(mtcars, aes(factor(cyl), mpg)) + 
  geom_boxplot() + 
  transition_states(gear)
```

Will fail (device override but uses `animate()`)

```{r}
#| dev: png
p <- ggplot(mtcars, aes(factor(cyl), mpg)) + 
  geom_boxplot() + 
  transition_states(gear)
animate(p)
```

So I'll look at it in this context.

cderv commented

Ok so this is an issue with svg device in ggganimate when use in knitr context

First, this is the traceback from the rendering.

Quitting from lines 24-27 [unnamed-chunk-3] (test.Rmd)
                                                                                                            
Error in `device()`:
! unused arguments (units = "in", res = 192)
Backtrace:
  1. rmarkdown::render(...)
  2. knitr::knit(knit_input, knit_output, envir = envir, quiet = quiet)
  3. knitr:::process_file(text, output)
  7. knitr:::process_group.block(group)
  8. knitr:::call_block(x)
     ...
 19. knitr (local) value_fun(ev$value, ev$visible)
 20. knitr (local) fun(x, options = options)
 23. gganimate::knit_print.gganim(x, ...)
 26. gganimate:::animate.gganim(...)
 28. gganimate (local) `<fn>`(...)

We see error comes from gganimate itself. Especially here:
https://github.com/thomasp85/gganimate/blob/7cd46dc2bc8cf18c1c81f6ef7fc4d00a1d57a385/R/animate.R#L305-L306

Basically some options are passed to svg() device function and they are not argument of grDevices::svg()

So when fig-format: svg is defined in Quarto, it will trigger usage of svg device in gganimate but it seems to be broken as the package itself defines some options unknown to svg() function.

Regarding the last chunk, this is also gganimate issue . Traceback is

Quitting from lines 13-18 [unnamed-chunk-2] (test.Rmd)
                                                                                                            
Error in `device()`:
! arguments inutilisés (units = "in", res = 96)
Backtrace:
 1. gganimate::animate(p)
 2. gganimate:::animate.gganim(p)
 4. gganimate (local) `<fn>`(...)
Exécution arrêtée

So we see here that no knit_print method used. The issue is there
https://github.com/thomasp85/gganimate/blob/7cd46dc2bc8cf18c1c81f6ef7fc4d00a1d57a385/R/animate.R#L213

knitr::opts_chunk$get() is used, which does not account for chunk level option. knitr::opts_currents$get() should be used.

Issue shoud be opened upstream: https://github.com/thomasp85/gganimate

I'll do it from the above.

cderv commented

issues have been opened upstream. I'll close this here. You should subscribe to those two issues in gganimate repo to know when this will be resolved.