I want to include animated rgl
graphs in my .Rnw
document through knitr
. Here is my MWE:
\documentclass{article}
<< label = setup, include = FALSE>>=
opts_chunk$set(fig.path = 'figure/', cache = FALSE, dev = "pdf", fig.align = 'center', fig.show = 'hold', fig.width = 3, fig.height = 3, echo = TRUE, warning = FALSE, message = FALSE, size = 'footnotesize', comment=NA, results='hold')
knit_hooks$set(par = function(before, options, envir){
if (before && options$fig.show!='none')
par(mar = c(4, 4, 0.1, 0.1), cex.lab = 0.95, cex.axis = 0.9, mgp = c(2, 0.7, 0), tcl = -0.3)
}
)
knit_hooks$set(rgl = function(before, options, envir) {
if (!before) {
## after a chunk has been evaluated
if (rgl.cur() == 0) return() # no active device
name = paste(options$fig.path, options$label, sep = '')
rgl.snapshot(paste(name, '.png', sep = ''), fmt = 'png')
return(paste('\\includegraphics{', name, '}\n', sep = ''))
}
}
)
options(replace.assign = TRUE, width = 60)
@
\begin{document}
<< label=packages >>=
library(car)
@
<< label=rgl1, rgl=TRUE, fig.show='animate' >>=
scatter3d(prestige ~ income + education, data=Duncan)
@
\end{document}
I'm not getting graph in my knitted documents.
I'm still unable to get it work and getting the following warning:
Warning messages:
1: In rgl.snapshot(paste(name, ".png", sep = ""), fmt = "png") :
RGL: Pixmap save: unable to open file 'D:\A B\C D UAF\Test\knitr\rglAnimation\figure\rgl1.png' for writing
2: In rgl.snapshot(paste(name, ".png", sep = ""), fmt = "png") :
snapshot failed
3: running command '"C:\PROGRA~2\MIKTEX~1.9\miktex\bin\x64\texi2dvi.exe" --quiet --pdf "rglAnimation.tex" --max-iterations=20 -I "C:/PROGRA~1/R/R-31~1.1/share/texmf/tex/latex" -I "C:/PROGRA~1/R/R-31~1.1/share/texmf/bibtex/bst"' had status 1
My sessionInfo()
is
R version 3.1.1 (2014-07-10)
Platform: x86_64-w64-mingw32/x64 (64-bit)
locale:
[1] LC_COLLATE=English_United States.1252
[2] LC_CTYPE=English_United States.1252
[3] LC_MONETARY=English_United States.1252
[4] LC_NUMERIC=C
[5] LC_TIME=English_United States.1252
attached base packages:
[1] tools stats graphics grDevices utils datasets methods
[8] base
other attached packages:
[1] mgcv_1.8-2 nlme_3.1-117 rgl_0.93.1098 car_2.0-21 knitr_1.6.15
loaded via a namespace (and not attached):
[1] evaluate_0.5.5 formatR_1.0 grid_3.1.1 highr_0.3
[5] lattice_0.20-29 MASS_7.3-34 Matrix_1.1-4 nnet_7.3-8
[9] stringr_0.6.2
Edited
Changing fig.path = 'figure/'
to fig.path = ''
in opts_chunk$set
compiles the document with png
graphs but without any animation. How can I get animated rgl
graphs with fig.path = 'figure/'
.
I've got an example based on yours that works using knitr on Windows 8.1 within RStudio 0.99.441.
This produces a 40-frame animation of the plot. It uses the built-in hook_plot_custom
to include the plots which are generated manually by animating the 3d plot. The code for the animation was based on those in the help and source of play3d
and movie3d
. movied3d
itself cannot be used because it is too inflexible in its file naming.
I've put this up on github at https://github.com/NikNakk/testAnimateRgl/ . The pdf is at https://github.com/NikNakk/testAnimateRgl/raw/master/rglKnitr.pdf
\documentclass{article}
\usepackage{animate}
<< label = setup, include = FALSE>>=
library("rgl")
library("car")
library("knitr")
knit_hooks$set(rgl = hook_plot_custom)
@
\begin{document}
<< label=rgl1, rgl=TRUE, fig.show='animate', fig.width=5, fig.height=5, out.width='.6\\linewidth', dev='png', fig.num = 40, interval=0.1>>=
scatter3d(prestige ~ income + education, data=Duncan)
M <- par3d("userMatrix")
par3d(windowRect = 100 + opts_current$get("dpi") *
c(0, 0, opts_current$get("fig.width"),
opts_current$get("fig.height")))
spinFunc <- par3dinterp(userMatrix=list(M,
rotate3d(M, pi/2, 1, 0, 0),
rotate3d(M, pi/2, 0, 1, 0)))
for(i in 1:40) {
par3d(spinFunc(i / 10))
Sys.sleep(0.05)
rgl.snapshot(fig_path(".png", number = i), fmt = "png")
}
@
\end{document}
Edit: New version
Here's another version which demonstrates the use of custom chunk options to set the parameters for the rather simpler spin3d
. Note that with this version, the chunk is just a single line (the scatter3d
plot). spin3d.axis
is used to set the axis parameter to spin3d
; spin3d.rpm
is used to set the rpm
parameter. The number of images and the interval between images is set using the standard fig.num
and interval
parameters.
\documentclass{article}
\usepackage{animate}
<< label = setup, include = FALSE>>=
library("rgl")
library("car")
library("knitr")
hook_rgl_spin <- function(before, options, envir) {
if (!before) {
par3d(windowRect = 100 + options$dpi *
c(0, 0, options$fig.width,
options$fig.height))
if (!is.null(options$spin3d.axis)) {
spin3d.axis <- options$spin3d.axis
} else {
spin3d.axis <- c(0, 0, 1)
}
if (!is.null(options$spin3d.rpm)) {
spin3d.rpm <- options$spin3d.rpm
} else {
spin3d.rpm <- c(0, 0, 1)
}
spinFunc <- spin3d(axis = spin3d.axis, rpm = spin3d.rpm)
for(i in 1:options$fig.num) {
par3d(spinFunc(i * options$interval))
Sys.sleep(0.05)
rgl.snapshot(fig_path(".png", number = i), fmt = "png")
}
hook_plot_custom(before, options, envir)
}
}
knit_hooks$set(rgl = hook_rgl_spin)
@
\begin{document}
<< label=rgl1, rgl=TRUE, fig.show='animate', fig.width=5, fig.height=5, out.width='.6\\linewidth', dev='png', fig.num = 40, interval=0.1, spin3d.axis=c(0, 0, 1), spin3d.rpm = 20>>=
scatter3d(prestige ~ income + education, data=Duncan)
@
\end{document}