knitr/rmarkdown/Latex: How to cross-reference figures and tables?
Asked Answered
E

4

71

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

enter image description here

Embed answered 9/8, 2016 at 21:54 Comment(1)
This issue appears to have been discussed here: I can't generate \label{fig:mwe-plot} with knitr. Hard-coding {r fig1, echo=FALSE, fig.cap="\\label{fig:fig1}This is a caption"} appears to work.Runagate
S
53

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

Southernmost answered 10/8, 2016 at 22:9 Comment(7)
is there a way to do this that is compatible with custom rmarkdown formats, e.g. from rticles templates?Thus
@Thus Yes. Maybe I didn't make it clear enough: bookdown.org/yihui/bookdown/latexpdf.html You can change base_format to whatever output format function in any packages.Southernmost
Yihui's answer above doesn't seem to work for bookdown::tufte_book2. For a figure cross-reference that shows up correctly with pdf_document2 shows up as "??" when the output format is changed to tufte_book2.Icsh
FYI it seems that one cannot change the base_format for bookdown::pdf_document2 but should use bookdown::pdf_book instead… https://mcmap.net/q/276577/-can-39-t-use-plos-rticles-template-with-bookdownFitch
I'm not sure how to use pdf_document2 format on an rmarkdown file? I only know how to use it with render_book. After adding bookdown::pdf_document2 to the YAML front matter, the option "knit to pdf_document2" appears in RStudio, but otherwise I don't know how from the command line.Neolith
@JamesHirschorn render_book is a bookdown function, with rmarkdown you can use render and pass bookdown::pdf_document2 as output_format, e.g. : rmarkdown::render("Index.Rmd", output_format = bookdown::pdf_document2").Palmette
This solves the figure reference isssue, but replaces section numbering by chapter numberingSpade
R
44

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")
```
Runagate answered 9/8, 2016 at 23:5 Comment(3)
@Yihui, since this is based on a 2-year-old answer, is this still the state of the art, or are there better ways to do this now?Embed
There are better ways now. In short, use bookdown::pdf_document2 instead of pdf_document; see bookdown.org/yihui/bookdown/figures.htmlSouthernmost
This solution has this advantage that it doesn't depend on bookdown.Torrance
T
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")`
Teens answered 24/10, 2018 at 10:7 Comment(1)
Here we are in April 2022 and I still can't find an answer to the question of how to reference a figure in the caption of another figure using bookdown::tufte_book2. I've tried every suggestion I can find for the past 6 years and nothing seems to work. Does anyone know of a definitive guide to doing this? Here's what I'm trying to do ```{r Fig608,echo=F,fig.fullwidth=T,fig.show='hold',fig.width=5.5,warning=F, message=F,fig.asp=0.35,fig.cap='New plot title from \\label{fig:Fig607}'} in which Fig607 is previously defined in a chunk. The result is the caption ends with 'from '.Marginalia
M
1

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.

Marginalia answered 29/4, 2022 at 17:39 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.