Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

overlayed animations in beamer using knitr

I'd like to create an animation in beamer using the knitr package and the chunk option fig.show='animate' with the figures being overlayed rather than replaced similar to how \multiinclude works by default.

A minimal non-working example would be the following (Rnw file) where I'd like each point to be added one-by-one to the existing plot in the animation.

\documentclass{beamer}
\usepackage{animate}
\begin{document}
\begin{frame}[fragile]
<<fig.show='animate', fig.width=5, fig.height=5, size='tiny', out.width='.8\\linewidth', fig.align='center', echo=FALSE>>=
x = 1:2
plot(x,x,type="n")
for (i in 1:length(x)) {
  points(x[i],x[i])
}
@
\end{frame}
\end{document} 

From looking at the knitr graphics manual, it states the two sources of plots are plot.new() and grid.newpage(), but has a footnote to see ?recordPlot. So I tried putting recordPlot() after the points command (and also adding a transparent background via par(bg=NA), but this did not work as only a single plot is created.

A minimal working example is the following

\documentclass{beamer}
\usepackage{animate}
\begin{document}
\begin{frame}[fragile]
<<fig.show='animate', fig.width=5, fig.height=5, size='tiny', out.width='.8\\linewidth', fig.align='center', echo=FALSE, fig.keep='all'>>=
x = 1:2
plot(x,x,type="n")
for (i in 1:length(x)) {
  for (j in 1:i) points(x[j],x[j])
}
@
\end{frame}
\end{document}

but this seems like overkill since each figure redraws the plot and all the preceding points.

Is there some way to get rid of the loop over j? or some other way to overlay plots in beamer/knitr? If yes, how can my code above be modified to make that happen?

like image 291
jaradniemi Avatar asked Oct 02 '22 04:10

jaradniemi


1 Answers

As explained the graphics manual, only plots from high-level plotting commands (e.g. plot.new()) and complete expressions are recorded. That means if you have multiple low-level plot changes in a for-loop, these changes will not be recorded one by one, because the for-loop in only one R expression. That is what Figure 4 in the manual illustrates.

If you want to create an animation from a for-loop, there must be high-level plotting commands in the loop. Figure 7 in the manual is such an example.

In your case, you have to move the plot() call into the loop:

x = 1:2
for (i in 1:length(x)) {
  plot(x, x, type = "n")
  points(x[1:i], x[1:i])
}

Yes, this looks like a serious waste of resource, and the "natural" way should be adding points one by one as you did, instead of opening a new plot and drawing points from 1 to i, but there is no way to detect low-level graphical changes inside a single R expression.

like image 146
Yihui Xie Avatar answered Oct 13 '22 09:10

Yihui Xie