'knitr/rmarkdown/Latex: How to cross-reference figures and tables?
I'm trying to cross-reference figures and tables in a PDF produced with knitr/rmarkdown. There are some questions on SO and tex.stackexchange (here and here, for example), that suggest the way to do this inline is to add \ref{fig:my_fig}
, where my_fig
is the chunk label. However, when I try that in my rmarkdown
document, I get ??
where the figure number should be. I'd like to find out how to get cross-referencing to work properly.
A reproducible example is below. There are two files: the rmarkdown
file plus a header.tex
file that I've included just in case it affects the answer (though I have the same problem whether I include the header.tex
file or not).
In the rmarkdown
file there are three cross-reference examples. Example 1 is a figure for which cross-referencing fails (??
is displayed instead of the figure number). There's also a second, commented-out attempt (based on this SO answer), where I try setting the figure environment, label, and caption with latex
markup before and after the chunk, but this results in a pandoc
error when I try to knit the document. The error is:
! Missing $ inserted. <inserted text> $ l.108 ![](testCrossRef_
Example 2 uses xtable
and cross-referencing works. Example 3 uses kable
and cross-referencing fails.
A screenshot of the PDF output is included at the bottom of this post.
rmarkdown
file
---
title: |
| My Title
author: |
| eipi10
| Department of Redundancy Department
date: "`r format(Sys.time(), '%B %e, %Y')`"
output:
pdf_document:
fig_caption: yes
includes:
in_header: header.tex
keep_tex: yes
fontsize: 11pt
geometry: margin=1in
graphics: yes
---
```{r setup, include=FALSE}
knitr::opts_chunk$set(echo = FALSE, message=FALSE, warning=FALSE, fig.height=2, fig.width=4)
```
# Example 1. Figure
This is a report. Take a look at Figure \ref{fig:fig1}.
```{r fig1, echo=FALSE, fig.cap="This is a caption"}
plot(mtcars$wt, mtcars$mpg)
```
<!-- Now, let's take a look at this other plot in Figure \ref{fig:fig2}. -->
<!-- \begin{figure} -->
<!-- ```{r fig2, echo=FALSE} -->
<!-- plot(mtcars$cyl, mtcars$mpg) -->
<!-- ``` -->
<!-- \caption{This is another caption} -->
<!-- \label{fig:fig2} -->
<!-- \end{figure} -->
# Example 2: `xtable`
Some more text. See Table \ref{tab:tab1} below.
```{r echo=FALSE, results="asis"}
library(xtable)
print.xtable(
xtable(mtcars[1:3,1:4], label="tab:tab1", caption="An xtable table"),
comment=FALSE)
```
# Example 3: `kable`
Some more text. See Table \ref{tab:tab2} below.
```{r tab2, echo=FALSE}
library(knitr)
kable(mtcars[1:3,1:4], caption="A `kable` table")
```
header.tex
file
% Caption on top
% https://tex.stackexchange.com/a/14862/4762
\usepackage{floatrow}
\floatsetup[figure]{capposition=top}
\floatsetup[table]{capposition=top}
PDF output
Solution 1:[1]
You can use the output format bookdown::pdf_document2
instead of pdf_document
, and the syntax for referencing a figure is \@ref(fig:chunk-label)
; see the documentation for details: https://bookdown.org/yihui/bookdown/figures.html
Solution 2:[2]
Following I can't generate \label{fig:mwe-plot} with knitr, adding \label{...}
to the caption arguments will produce labels in the underlying tex
file, i.e.
```{r fig1, echo=FALSE, fig.cap="\\label{fig:fig1}This is a caption"}
plot(mtcars$wt, mtcars$mpg)
```
and
```{r tab2, echo=FALSE}
library(knitr)
kable(mtcars[1:3,1:4], caption="\\label{tab:tab2}A `kable` table")
```
Solution 3:[3]
You can try the captioner package. You can find examples in this link.
In my case, I include a code chunk with:
table_captions <- captioner::captioner(prefix="Tab.")
figure_captions <- captioner::captioner(prefix="Fig.")
t.ref <- function(label){
stringr::str_extract(table_captions(label), "[^:]*")
}
f.ref <- function(label){
stringr::str_extract(figure_captions(label), "[^:]*")
}
I include captions in tables and figures when defining code chunks, like this:
```{r chunk_creating_one_figure, echo=FALSE, fig.cap=figure_captions("one_figure", "figure label")}
plot(1)
```
or
```{r chunk_creating_one_table, echo=FALSE, fig.cap=table_captions("one_table", "table label")}
knitr::kable(data.frame(col="something"), format="markdown")
```
References are included as inline_text all across my Rmarkdown with:
As shown in figure `r f.ref("one_figure")`
Data is shown on table `r t.ref("one_table")`
Solution 4:[4]
After much searching I stumbled on a solution that seems to work (link for this approach), even though I never found it in any of the bookdown standard references (I'll keep looking). Just above the chunk that creates the plot in the .rmd file, define the caption as a string, here called "crossref2" and put the Figure reference in the string in the normal way, \@ref(fig:myChunkLabel)
. No quotes are needed. Here's an example where Fig207 is the chunk label for the figure being referenced:
(ref:crossref2) Variations on boxplot using data from Figure \@ref(fig:Fig207) a) plain violin plot, b) enchanced violin plot, c) add outliers, d) Beeswarm plot
Then in the chunk header for the figure where you want Fig207 to be included in the caption, the figure caption is written as
fig.cap='(ref:crossref2)'
After doing this, the Figure number connected to ref(fig:Fig207) is displayed nicely in the caption.
Note that the same procedure allows you to put a bibliography reference in a figure caption by replacing \@ref(fig:Fig207)
with [@bibref]
where bibref is the keyword for the reference as defined in your .bib file of literature citations.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | Yihui Xie |
Solution 2 | Community |
Solution 3 | Gitanoqevaporelmundoentero |
Solution 4 | Dr Dave |