knitr plots, labels, and captions within one chunk - r

I am producing a latex report which produces multiple plots in a dlply call. The dlply call is of course in a single chunk and in order to get labels and captions to change I am using a snippet from Steve Powell below. The approach works but it seems knitr doesnt quite format the output correctly. A simple example that demonstrates:
\documentclass{article}
\begin{document}
<startup,echo=FALSE,results='hide',message=FALSE,tidy=FALSE,warning=FALSE,fig.keep='all',comment=NA>>=
require(knitr)
require(ggplot2)
opts_knit$set(progress = F, verbose = F)
opts_chunk$set(comment=NA,
tidy=FALSE,
warning=FALSE,
message=FALSE,
echo=FALSE,
dpi=600,
fig.width=6.75, fig.height=4, # Default figure widths
dev=c("pdf",'tiff'),
dev.args=list(pdf=list(NULL),tiff=list(compression='lzw')),
error=FALSE)
#
<<plotloop,results='asis'>>=
for(x in seq(1,20)){
x1<-data.frame(x=seq(1,10),y=seq(1,10))
plt<-ggplot(data=x1,aes(x,y))+geom_point()
figLabel=paste('Figure',x,sep='')
capt<-paste('Caption for fig.',x)
cat(knit(text=(paste("<<",figLabel,",fig.pos='ht',fig.cap='",capt,"'>>=\nplt\n#",sep=''))))
}
#
\end{document}
This almost works. The trouble is that knitr places the closing \caption brace outside the \label brace which can be seen in the snippet from the .tex file below:
\begin{knitrout}
\definecolor{shadecolor}{rgb}{0.969, 0.969, 0.969}
\color{fgcolor}
\begin{figure}[ht]
\includegraphics[width=\maxwidth]{figure/Figure1} \caption[Caption for fig]{Caption for fig. 1\label{fig:Figure1}}
\end{figure}
\end{knitrout}
latex can handle this if there are only a few figures like this but with larger numbers of plots, it starts to place them incorrectly.
I have also tried this with a
fig.cap=paste('testLoop',seq(1,20))
approach and get the same result.
Further clarification: I found this on wikipedia's Latex/Floats... page:
If you want to label a figure so that you can reference it later, you have to add the label after the caption (inside seems to work in LaTeX 2e) but inside the floating environment. If it is declared outside, it will give the section number.
The 'inside seems to work in LaTeX 2e' part caught my attention. It seems it works only because the error is ignored a number of times? I am using
LaTeX2e <2005/12/01>.
I think the bit of code is in hook_plot_tex function line 120 of hooks-latex.R:
fig2 = sprintf('\\caption%s{%s\\label{%s}}\n\\end{%s}\n', scap, cap,
paste(lab, if (mcap) fig.cur, sep = ''), options$fig.env)
This would fix it?
fig2 = sprintf('\\caption%s{%s}\\label{%s}\n\\end{%s}\n', scap, cap,
paste(lab, if (mcap) fig.cur, sep = ''), options$fig.env)
Suggestions? I am not familiar with the github process...
Thanks!

Short answer is it seems to be a LaTeX issue caused by too many \includegraphics commands and no pagebreaks. Function to accomplish multiple figures with captions and labels from within loop (with credit to Steve Powell and Yihui):
plot.knit<-function(chunkLabel,#text for chunk label which is also used for figure file name
capt,#text for caption
plt)#plot object to be placed
{
cat(knit(text=(paste("<<",chunkLabel,",fig.pos='h',fig.cap='",capt,"'>>=\nplt\n#",sep=''))))
}
cat('\\newpage')#some sort of page break must be inserted along the way to keep latex from breaking.
This can be modified to add any of chunk options you would like.
Long Answer:
Here is what I did to get it to work. I downloaded knitr from github, made the suggested alteration above, compiled, and ran example. The altered code did not change the outcome. Further investigation of latex error took me to the LaTeX FAQ where it states:
The error also occurs in a long sequence of float environments, with no intervening text. Unless the environments will fit “here” (and you’ve allowed them to go “here”), there will never be a page break, and so there will never be an opportunity for LaTeX to reconsider placement. (Of course, the floats can’t all fit “here” if the sequence is sufficiently prolonged: once the page fills, LaTeX won’t place any more floats, leading to the error.
Techniques for resolution may involve redefining the floats using the float package’s [H] float qualifier, but you are unlikely to get away without using \clearpage from time to time.
So, I added
cat('\\clearpage')
after the plots are generated in each step of the loop. This resulted in no errors being thrown and the figures in correct locations. Also,
cat('\\newpage')
works and seems to do a better job at placing the figures 2 on a page in my actual document.
The working code:
\documentclass{article}
\begin{document}
<<startup,echo=FALSE,results='hide',message=FALSE,tidy=FALSE,warning=FALSE,fig.keep='all',comment=NA>>=
require(knitr)
require(ggplot2)
opts_knit$set(progress = F, verbose = F)
opts_chunk$set(comment=NA,
tidy=FALSE,
warning=FALSE,
message=FALSE,
echo=FALSE,
dpi=600,
fig.width=6.75, fig.height=4, # Default figure widths
dev=c("pdf",'tiff'),
dev.args=list(pdf=list(NULL),tiff=list(compression='lzw')),
error=FALSE)
#
<<plotloop,results='asis'>>=
for(x in seq(1,20)){
x1<-data.frame(x=seq(1,10),y=seq(1,10))
plt<-ggplot(data=x1,aes(x,y))+geom_point()
figLabel=paste('Figure',x,sep='')
capt<-paste('Caption for fig.',x)
cat(knit(text=(paste("<<",figLabel,",fig.pos='h',fig.cap='",capt,"'>>=\nplt\n#",sep=''))))
cat('\\newpage')
}
#
\end{document}

Related

Interaction between \parskip and tikzDevice affecting plot margins in .Rnw

I am knitting an .Rnw file and, unexpectedly, vertical space is lost from the bottom inner margin of my plots and added to the top outer margin.
Here is a minimal working example:
\documentclass{article}
\setlength{\parskip}{1em}
\begin{document}
<<mwe-plot, dev="tikz", dev.args=list(bg="grey95")>>=
par(mar=rep(2,4), oma=rep(0,4))
x <- seq(0, 2*pi, length.out=21)
plot(x, sin(x), type="l")
box("inner")
#
\end{document}
knit() generates mwe-plot-1.pdf, which looks like this:
, but what I expect is this:
.
The issue is apparently due to an interaction between \parskip and tikzDevice, since it is corrected by setting \parskip to zero in the preamble or switching from dev="tikz" to the default dev="pdf". While these are possible solutions, I am looking for a fix that doesn't require doing either.
Note that I tried adding \setlength{\parskip}{0em} immediately before the chunk (after \begin{document}) but this didn't affect the output.
Any hints are appreciated...
Your proximal problem is that the \setlength{\parskip}{1em} statement is being included in the tikz .tex file, which is throwing off the spacing. The solution is to move it from your preamble into the body of your document, i.e.
\documentclass{article}
\begin{document}
\setlength{\parskip}{1em}
...
I figured this out by descending through the layers - first looking at the .tex output created by knit (before the LaTeX -> PDF conversion), then looking at figure/mwe-plot-1.pdf (and realizing, as you suggested, that the problem isn't with stuff that knitr puts in the LaTeX file, but with stuff that tikzDevice puts in the tikz-.tex file), then looking at figure/mwe-plot-1.tex and realizing that it had the \parskip statement embedded. I looked around for a tikzDevice option that would override it, but then realized that it was probably only including stuff from the preamble ...

Is it possible to give a figure/plot a label in Sweave? [duplicate]

I can't get R/KnitR to create the LaTeX \label{} statement for a figure. The manual seems to indicate that a \label{} statement will be created by concatenating the string in fig.lp ("fig:" by default) with the label for the R-code chunk. I haven't been able to get this to work, however. No \label{} statement is created for the first figure created by knitting the MWE below. The second figure has it's label added with a workaround that I just discovered, putting the R chunk in a figure environment, and putting the \label tag after or inside the \caption tag.
\documentclass[12pt, english, oneside]{amsart}
\begin{document}
Figure \ref{fig:plot} doesn't have it's label.
<<plot>>=
plot(x=0, y=0)
#
Figure \ref{fig:plot2} has its label.
\begin{figure}
\caption{\label{fig:plot2}}
<<>>=
plot(x=1,y=1)
#
\end{figure}
\end{document}
Okay, I've found a workaround by putting the R chunk in a \begin{figure} . . .\end{figure} environment in LaTeX. I can create the label in that same environment. Still, I'd like to understand how Yihui intends for this to be handled with KnitR.
You need to set fig.cap = '' (or whatever you wish) to ensure that a figure environment is used in the latex document. (you may have noticed that the \begin{figure} ... \end{figure} is missing along with the \label{} component
eg
\documentclass[12pt, english, oneside]{amsart}
\begin{document}
See Figure \ref{fig:plot}.
<<plot, fig.lp="fig:", fig.cap = ''>>=
plot(x=0, y=0)
#
\end{document}
I would agree that the description from the website is less than clear as to this being necessary.
fig.env: ('figure') the LaTeX environment for figures, e.g. set fig.env='marginfigure' to get \begin{marginfigure}
fig.cap: (NULL; character) figure caption to be used in a figure environment in LaTeX (in \caption{}); if NULL or NA, it will be
ignored, otherwise a figure environment will be used for the plots in
the chunk (output in \begin{figure} and \end{figure})
Although the graphics manual is clear, and the reasoning makes sense
Figure Caption
If the chunk option fig.cap is not NULL or NA, the
plots will be put in a figure environment when the output format is
LATEX, and this option is used to write a caption in this environment
using \caption{}. The other two related options are fig.scap and
fig.lp which set the short caption and a prefix string for the figure
label. The default short caption is extracted from the caption by
truncating it at the first period or colon or semi-colon. The label is
a combination of fig.lp and the chunk label. Because figure is a float
environment, it can float away from the chunk output to other places
such as the top or bottom of a page when the TEX document is compiled.
If you were wishing to replicate a R session output, you wouldn't want the figures to float away from the line of code which defines how they were created.

Manually use R Knit/Markdown to produce plots for HTML

I am using knit()and markdownToHTML() to automatically generate reports.
The issue is that I am not outputting plots when using these commands. However, when I use RStudio's Knit HTML button, the plots get generated. When I then use my own knit/markdown function, it suddenly outputs the plot. When I switch to another document and knit that one, the old plot appears.
Example:
```{r figA, result='asis', echo=TRUE, dpi=300, out.width="600px",
fig=TRUE, fig.align='center', fig.path="figure/"}
plot(1:10)
```
Using commands:
knit(rmd, md, quiet=TRUE)
markdownToHTML(md, html, stylesheet=style)
So I guess there are 2 questions, depending on how you want to approach it:
What magic is going on in Rstudio's Knit HTML?
How can I produce/include without depending on RStudio's Knit HTML button?
The only issue I see here is that this doesn't work when you have the chunk options {...} spanning two lines. If it's all on one line, it works fine. Am I missing something?
See how this is not allowed under knitr in the documentation:
Chunk options must be written in one line; no line breaks are allowed inside chunk options;
RStudio must handle linebreaks in a non-standard way.
This is really embarrassing, I really thought I read the documentation carefully:
include: (TRUE; logical) whether to include the chunk output in the
final output document; if include=FALSE, nothing will be written into
the output document, but the code is still evaluated and plot files
are generated if there are any plots in the chunk, so you can manually
insert figures; note this is the only chunk option that is not cached,
i.e., changing it will not invalidate the cache
Simply adding {..., include=TRUE} did the trick. I would say it would be a pretty sensible default though.

How to control wrong pagebreaks of longtable in latex() from Hmisc package?

I'm using Sweave and latex() from the Hmisc package to insert a longtable in my PDF.
When I do it the first time, the table is spread nicely, filling up the pages with the table.
If I do it again, some pages are only half full (like page 4 of PDF), which looks weird and somehow wrong because it seems to be unnecessary space.
Is there a way to control this? Or what could I do to improve the look?
Especially, if I'm adding some text and graphs, it won't look good with the empty space on page 4.
\documentclass{article}
\usepackage{Sweave}
\usepackage{longtable}
\usepackage{booktabs}
\begin{document}
\SweaveOpts{concordance=TRUE}
I want to insert this longtable
<<tab.R,echo=FALSE,results=tex>>=
library(Hmisc)
#library(xtable)
x <- matrix(rnorm(1000), ncol = 10)
x.big <- data.frame(x)
latex(x.big,"",file="",longtable=TRUE, dec=2,caption='First longtable spanning several pages')
#
then write some text. Maybe add a graph...
And then another table
<<tab.R,echo=FALSE,results=tex>>=
latex(x.big,"",file="",longtable=TRUE, dec=2,caption='Second longtable spanning wrongly')
#
\end{document}
Don't pass this question over to the latex group, this is a problem of Hmisc/latex that adds a \clearpage into tex every 40 lines by default. Check parameter lines.page=40 of latex. I do not understand why this default has been set, but something like
latex(x.big,"",file="",longtable=TRUE, dec=2,
caption='Second longtable spanning wrongly', lines.page=4000)
gets you around the problem.

figure* environment in twocolumn knitr/Sweave document

Sounds like it should be a common problem, but I didn't find an obvious trick.
Consider the knitr Rnw file below,
\documentclass[twocolumn, 12pt]{article}
\usepackage{graphicx}
\begin{document}
%\SweaveOpts{dev=pdf, fig.align=center}
\begin{figure*}
<<aaa, fig.width=8, fig.height=5, fig.show=hold>>=
plot(1,1)
#
\end{figure*}
\end{document}
I would like this wide figure to span two columns, using a {figure*} LaTeX environment. Is there a hook for that?
EDIT: wrapping the chunk in figure* gives the following output.
Two facts:
knitr makes everything accessible for you, so LaTeX tricks are often unnecessary;
there is a chunk hook with which you can wrap your chunk results;
A simple-minded solutions is:
knit_hooks$set(chunk = function(x, options) {
sprintf('\\begin{figure*}\n%s\n\\end{figure*}', x)
})
I leave the rest of work to you to take care of more details in options (e.g. when options$fig.keep == 'none', you should not wrap the output in figure*). You may want to see how the default chunk hook for LaTeX is defined in knitr to know better how the chunk hook works.
However, in this case, I tend to write the LaTeX code by myself in the document instead of automatically creating it. After you have got figure*, you may start to think about \caption{} and \label{} (not hard, but I still want to see them in LaTeX).
Not sure about how knitr but for Sweave (and basic latex) there is in fact a trick: have the R code produce a pdf file, and then use standard \includegraphics to pull it in.
So with this:
\documentclass[twocolumn, 12pt]{article}
\usepackage{graphicx}
\begin{document}
%\SweaveOpts{dev=pdf}
<<aaa,fig=FALSE,print=FALSE,echo=FALSE>>=
pdf("mychart.pdf", width=6, height=3)
set.seed(42)
plot(cumsum(rnorm(100)), type='l', main="yet another random walk")
invisible(dev.off())
#
\begin{figure*}
\includegraphics{mychart.pdf}
\end{figure*}
\end{document}
I got the document below (which I then converted from pdf to png):
I also had a similar problem while preparing a figure that should span two columns in a IEEE two-column conference paper.
Setting the chunk hook caused some strange error in my setup.
Even this simple hook: knit_hooks$set(chunk = function(x, options) x)
But after looking into knitr::opts_chunk$get(), I realized that simply setting fig.env="figure*" solves the problem in an elegant way.
Here is how my chunk looks like in an Rnw file:
<<fig1, fig.width=18, fig.height=6, fig.env="figure*">>=
#

Resources