Creating a parameterized report with an rnw file. I am trying to reference specific figures from a code chunk that has multiple figures in it (generated by a loop through a list of figures). I know if there's a single figure I can reference it from the chunk label with \ref{fig:foo} as Yihui mentions in https://bookdown.org/yihui/bookdown/figures.html . But I cannot seem to reference specific figures in the chunk. I tried referencing the unique figure caption or the chunk as a whole but both give me ??. Is there a way to do this?
I searched this Dynamic LaTeX references in R comment with knitr and its linked questions but wasn't able to make it work.
Also in Figures captions and labels in knitr , the plots are combined into one big plot which bypasses the problem.
MVWE:
\documentclass{article}
\usepackage{float}
\usepackage{hyperref}
\usepackage{caption} % Needs to be after hyperref. jumps you to top of figure not to label.
\begin{document}
<<figures, fig.cap=c('fig1','fig2')>>=
library(knitr)
library(markdown)
library(rmarkdown)
library(ggplot2)
figure1 <- ggplot(mtcars) + geom_point(aes(x=mpg,y=cyl))
figure2 <- ggplot(mtcars) + geom_point(aes(x=drat,y=wt))
plots <- list(figure1,figure2)
plots
#
as we can see in \ref{fig:figures}
\end{document}
Just append a number to it:
as we can see in \ref{fig:figures1} and \ref{fig:figures2}
To figure this out, you should look at the .tex file, which contains
\begin{figure}
\includegraphics[width=\maxwidth]{figure/figures-1} \caption[fig1]{fig1}\label{fig:figures1}
\end{figure}
for the first one, and similar stuff for the other. The \label{fig:figures1} part is what your \ref needs to refer to.
Imagine I knit this Rnw file:
\documentclass{article}
\begin{document}
Table1
<<example,results='asis', echo=FALSE>>=
require(xtable)
nn <- 15
mydata <- data.frame(A=1:nn,C=nn:1, C=runif(nn), D=rnorm(nn))
xtable(mydata, caption="Table1")
#
Table2
<<example2,results='asis', echo=FALSE>>=
xtable(mydata, caption="Table2")
#
Table3
<<example3,results='asis', echo=FALSE>>=
xtable(mydata, caption="Table3")
#
\begin{obeylines}
Just some text
\end{obeylines}
\end{document}
It's a simple example that just prints some text and three tables.
Strangely it doesn't respect the order of what I've written on my code.
I get this (sideview of the two pdf pages)
But "Table3" text should appear before the table3 itself and after table2, and the text "just some text" should appear at the very end of the document.
If I write several lines there it breaks the lines.
I understand that if a table doesn't fit on a place it must be moved to the next page but so should be done with the following text and tables.
I've also observed that in other examples some tables are reallocated randomly when they don't fit well.
How can I prevent knitr from doing this?
I don't know whether is a knitr problem or latex.
I'm using Texlive 2015, Rstudio, R 3.2.3 and Windows 10 and the latest version of all packages involved.
By default print.xtable() produces a LaTeX \table{...} environment, which is defined as a floating object. See `?print.xtable and try e.g.
<<example2,results='asis', echo=FALSE>>=
print(xtable(mydata, caption="Table2"),floating=FALSE)
#
(untested ...)
alternatively you could try table.placement="H"; you may need \usepackage{float} (see this question from tex.stackexchange.com).
(also untested ...)
I was looking for a way to change the setting in my Rmd file so that the html output contains all the columns and the table does not break. I tried to change the css properties as in this solution (Output table width in Rmarkdown) but this does not affect my output.
I have currently 17 columns and using a pandoc.table, but only 5 coloumns are shown before the table is broken and the next 5 columns are displayed below.
What changes do I need to make so that the entire table can be shown in my html output?
Thanks for your help.
I can't use the pandoc package because is not currently available for R version 3.2.0. Instead, I used knitr with the kable() function. This code works fine:
{r, echo=FALSE, results='asis'}
library(knitr)
examp <- data.frame(matrix(rep("Unicorn"), nrow=5, ncol=100))
kable(examp)
I think, because you don't provide an example, that you need to specify the results='asis' chunk option.
Try ?kable for further information.
Anyway ?pandoc.table shows that there is an option split.table that may help.
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}
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*">>=
#