I want to be able to print out non-predetermined list of plots in knitr. I am able to do that, but there are a few wrinkles left to iron out. Namely:
1) How do you suppress the list indices (like [[2]]) on each page that precede each plot? Using echo=FALSE doesn't do anything.
2) Is it possible to set the size for each plot as they are rendered? I've tried setting a size variable outside of the chunk, but that only lets me use one value and not a different value per plot.
I'm asking this as one question because they seem to speak to the same lesson, i.e., producing a list of plots.
Some sample code:
\documentclass{article}
\usepackage[margin=.5in, landscape]{geometry}
\begin{document}
<<diamond_plots, echo = FALSE, results = 'hide'>>==
library(ggplot2)
diamond_plot = function(data, cut_type){
ggplot(data, aes(color, fill=cut)) +
geom_bar() +
ggtitle(paste("Cut:", cut_type, sep = ""))
}
cuts = unique(diamonds$cut)
plots = list()
for(i in 1:length(cuts)){
data = subset(diamonds, cut == cuts[i])
plots[[i]] = diamond_plot(data, cuts[i])
}
height = 3
@
<<print_plots, results='asis', echo=FALSE, fig.width=10, fig.height=height>>=
plots
@
\end{document}
The PDF of the plots looks like this:
1) How do you suppress the list indices (like [[2]]) on each page that precede each plot? Using echo=FALSE doesn't do anything.
Plot each element in the list separately (lapply
) and hide the output from lapply
(invisible
):
invisible(lapply(plots, print))
2) Is it possible to set the size for each plot as they are rendered? I've tried setting a size variable outside of the chunk, but that only let's me use one value and not a different value per plot.
Yes. In general, when you pass vectors to figure-related chunk options, the i
th element is used for the i
th plot. This applies to options that are "figure specific" like e.g. fig.cap
, fig.scap
, out.width
and out.height
.
However, other figure options are "device specific". To understand this, it is important to take a look at the option dev
:
dev
: the function name which will be used as a graphical device to record plots […] the optionsdev
,fig.ext
,fig.width
,fig.height
anddpi
can be vectors (shorter ones will be recycled), e.g.<<foo, dev=c('pdf', 'png')>>=
creates two files for the same plot:foo.pdf
andfoo.png
While passing a vector to the "figure specific" option out.height
has the consequence of the i
th element being used for the i
thplot, passing a vector to the "device specific" option has the consequence of the i
th element being used for the i
thdevice.
Therefore, generating dynamically-sized plots needs some hacking on chunks because one chunk cannot generate plots with different fig.height
settings. The following solution is based on the knitr
example `075-knit-expand.Rnw and this post on r-bloggers.com (which explains this answer on SO).
The idea of the solution is to use a chunk template and expand the template values with the appropriate expressions to generate chunks that, in turn, generate the plots with the right fig.height
setting. The expanded template is passed to knit
in order to evaluate the chunk:
\documentclass{article}
\begin{document}
<<diamond_plots, echo = FALSE, results = "asis">>==
library(ggplot2)
library(knitr)
diamond_plot = function(data, cut_type){
ggplot(data, aes(color, fill=cut)) +
geom_bar() +
ggtitle(paste("Cut:", cut_type, sep = ""))
}
cuts = unique(diamonds$cut)
template <- "<<plot-cut-{{i}}, fig.height = {{height}}, echo = FALSE>>=
data = subset(diamonds, cut == cuts[i])
plot(diamond_plot(data, cuts[i]))
@"
for (i in seq_along(cuts)) {
cat(knit(text = knit_expand(text = template, i = i, height = 2 * i), quiet = TRUE))
}
@
\end{document}
The template is expanded using knit_expand
which replaces the expressions in {{}}
by the respective values.
For the knit
call, it is important to use quite = TRUE
. Otherwise, knit
would pollute the main document with log information.
Using cat
is important to avoid the implicit print
that would deface the output otherwise. For the same reason, the "outer" chunk (diamond_plots
) uses results = "asis"
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With