jsvejk
jsvejk

Reputation: 23

Cross-referencing a table or figure in rmarkdown in the caption of another figure or table

I am producing a rmarkdown document, knitting to PDF and have a figure (figure 1) and a table (table 1) where the table explains the figure in more detail. I have no issue giving either of them a standard caption but I would like to change the table caption to be "Explanation of Figure 1". Is there any way of doing this?

The code chunks are listed below, please let me know if I need to provide more information:

YAML:

- \usepackage{caption} #and several others

output:
  bookdown::pdf_document2:
    keep_tex: no
    latex_engine: xelatex

Code Chunks: Figure 1:

```{r figure-1, fig.cap="Figure"}
ggplot()
```

Table 1:

```{r table, fig.cap="Explanation of Figure \@ref(fig:figure-1)"}
knitr
kableExtra::kable(caption = "Explanation of Figure \@ref(fig:figure-1)")
```

The main error message with one backslash is "Error: '@' is an unrecognized escape in character string" and suggests I forgot to quote character options, which is not true.

With two backslashes the document knits but produces the caption "Explanation of Figure reffig:table"

3 backslashes: the same error as with 1.

4 backslashes: the error is "pandoc-citeproc: reference ref not found. ! Package caption Error: \caption outside float."

Appreciate any suggestions!

Upvotes: 2

Views: 3051

Answers (4)

AlexaQuinoa
AlexaQuinoa

Reputation: 92

Another work around.

Add the following above your chunk:

######  {#your-chunk .unnumbered}

Link header, either using

[text](#your-chunk) 

or using the link button in the visual setting of R Studio IDE.

Upvotes: 0

J_F referenced Yihui Xie's excellent explanation of using text references in RMarkdown (https://bookdown.org/yihui/bookdown/markdown-extensions-by-bookdown.html#text-references), which you can use for figure and table captions that require more complicated things than plain text (e.g., formatting, cross-references, etc.). This may be a more flexible solution overall than remembering to escape the backslash in Robert's answer, and does not require a workaround with LaTeX.

As Yihui explains, all you need to do is define a text reference on a single line in markdown and reference that in the chunk option "fig.cap" or the "caption" parameter in knitr::kable(). Just be careful to make sure that each text reference is one paragraph that does not end in a white space.

Here's a basic example.

---
title: "Cross-referencing figures and tables within captions."
output: bookdown::pdf_document2
editor_options: 
  chunk_output_type: console
---

```{r load-packages}
library(knitr)
library(flextable)
```

(ref:first-fig-caption) Here's a complicated figure caption for the first figure, which can include complicated text styling like $m^2$ and references to other elements in the document, like Table \@ref(tab:mtcars) or Fig. \@ref(fig:cars).

```{r pressure, fig.cap = '(ref:first-fig-caption)'}
plot(pressure)
```

(ref:second-fig-caption) Here's a second complicated figure caption, also referencing Table \@ref(tab:mtcars).

```{r cars, fig.cap = '(ref:second-fig-caption)'}
plot(cars)
```

(ref:caption-table1) A caption for the first table. Check out this cross reference to Fig. \@ref(fig:pressure).

```{r mtcars}
mtcars |>
  head() |>
  kable(caption = '(ref:caption-table1)')
```

Upvotes: 0

Robatt
Robatt

Reputation: 207

Just a workaround, but may helps. The \\@ref(fig:xxx) option works well when knitting to a html_document2. To me pdf - creation worked fine when using pandoc in the terminal. E.g.:

---
title: "Cross ref"
output:
  bookdown::html_document2:
    collapsed: no
    theme: readable
    toc: yes
link-citations: yes
---

```{r firstplot, fig.cap = "A plot with points." }
library(ggplot2)

plot_A = ggplot(data = data.frame(x = c(1:10),
                         y = seq(3, 8, length.out = 10)),
       aes(x = x, y =y))+
  geom_point()

plot_A

```

Now a second plot with a reference to Fig.: \@ref(fig:firstplot).


```{r secondplot, fig.cap = "This is the same as Fig.: \\@ref(fig:firstplot) 
but now with a red line." }
library(ggplot2)

plot_A + geom_line(alpha = .75,col = "red")

```

after knitting just move to the folder containing the html and using pandoc

pandoc mini_ex-crossref.html -o mini_ex.pdf

Upvotes: 1

J_F
J_F

Reputation: 10352

I tried many different approaches text references, chunk captions, caption argument in the kable function and I´m sure there is a clever solution somewhere, so here is just a workaround with pure Latex.

Add a latex chunk with a label before the chunk with the figure:

```{=latex}
\begin{figure}
\caption{Figure 1}
\label{Fig-1}
``` 
```{r figure-1, echo = FALSE}
ggplot(mtcars) +
  geom_point(aes(cyl, gear))
```
```{=latex}
\end{figure}
``` 

Now you can refer to Fig-1 in your latex-caption for the table with normal latex code \ref{Fig-1}:

```{=latex}
\begin{table}
\caption{Explanation of Figure \ref{Fig-1}}
``` 
```{r table}
kableExtra::kable(x = mtcars)
```

```{=latex}
\end{table}
``` 

Notes: * In my opinion this is just a workaround. * It´s not possible to use the chunk option fig.cap = "" and the latex code in parallel

Upvotes: 0

Related Questions