Skip to content

animation.hook is ignored for LaTeX output in the knitr engine #14814

Description

@cderv

The animation.hook chunk option works for HTML output but has no effect for LaTeX/PDF output.

For a chunk with fig.show: animate, we only inject a default hook when the format is not LaTeX

# automatically set gifski hook for fig.animate
opts_hooks[["fig.show"]] <- function(options) {
# get current value of fig.show
fig.show <- options[["fig.show"]]
# use gifski as default animation hook for non-latex output
if (identical(fig.show, "animate")) {
if (
!is_pandoc_latex_output(format) && is.null(options[["animation.hook"]])
) {
options[["animation.hook"]] <- "gifski"
}

The HTML branch then delegates to knitr's hook_animation(), so a user-supplied hook is honored there. The LaTeX branch instead calls our own latex_animation(), which always emits \animategraphics{} and never looks at animation.hook

# ported from:
# https://github.com/yihui/knitr/blob/f8f90baad99d873202b8dc8042eab7a88fac232f/R/hooks-latex.R#L151-L171
latex_animation <- function(x, options) {
fig.num = options$fig.num %||% 1L
ow = options$out.width
# maxwidth does not work with animations
if (identical(ow, '\\maxwidth')) {
ow = NULL
}
if (is.numeric(ow)) {
ow = paste0(ow, 'px')
}
size = paste(
c(
sprintf('width=%s', ow),
sprintf('height=%s', options$out.height),
options$out.extra
),
collapse = ','
)
aniopts = options$aniopts
aniopts = if (is.na(aniopts)) NULL else gsub(';', ',', aniopts)
size = paste(c(size, sprintf('%s', aniopts)), collapse = ',')
if (nzchar(size)) {
size = sprintf('[%s]', size)
}
sprintf(
'\\animategraphics%s{%s}{%s}{%s}{%s}',
size,
1 / options$interval,
sub(sprintf('%d$', fig.num), '', xfun::sans_ext(x)),
1L,
fig.num
)
}

It also adds a dependency on the LaTeX animate package unconditionally

# check for latex
if (is_pandoc_latex_output(format)) {
# include dependency on animate package
knitr::knit_meta_add(list(
rmarkdown::latex_dependency("animate")
))

Upstream knitr changed this in yihui/knitr#2452: hook_plot_tex() now calls a user-supplied animation.hook (or the package option animation.fun) to generate the LaTeX code, so LaTeX packages other than animate can be used, xmpmulti for beamer overlays being the motivating example. The built-in hooks (ffmpeg, gifski, scianimator, r2swf) generate HTML and keep being ignored for LaTeX. Our latex_animation() is a port of knitr's code from before that change.

So with the next knitr release this will work in .Rmd but not in .qmd.

We could port the same logic into latex_animation(): when animation.hook is a function and is not one of knitr's built-in HTML hooks, call it instead of emitting \animategraphics{}, and skip the animate dependency in that case.

Two things to sort out if we do this. Our schema documents animation-hook with default: ffmpeg while we actually inject gifski for non-LaTeX output, and it is typed as a string with completions, so a function can only be passed with the classic R chunk syntax ({r, animation.hook=my_hook}) and not with #| YAML.

- name: animation-hook
tags:
engine: knitr
schema:
string:
completions: [ffmpeg, gifski]
default: ffmpeg
description:
short: "Hook function to create animations in HTML output"
long: |
Hook function to create animations in HTML output.
The default hook (`ffmpeg`) uses FFmpeg to convert images to a WebM video.
Another hook function is `gifski` based on the
[**gifski**](https://cran.r-project.org/package=gifski) package to
create GIF animations.

Metadata

Metadata

Assignees

No one assigned

    Labels

    engines-knitrAnything regarding knitr enginesenhancementNew feature or requestfigureslatexLaTeX engines related libraries and technologies

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions