20

I am having trouble trying to reference chunks within a r markdown document which I am trying to convert to .pdf using pandoc.convert.

If I include \label{mylabel} within the text - I can reference this by \ref{mylabel}. However, I thought I might be able to refer to a chunk (or table / figure within a chunk) similarly - but am having no luck.

For instance, for the chunk:

```{r myplot, echo=FALSE, warning=FALSE}
plot(cars)
```

I though I might be able to put \ref{myplot} or \ref{fig:myplot} or even an internal markdown reference [car plot](myplot). The documentation seems to mention that labels are created based on the name of the chunk and these are the formats suggested in relation to similar questions. But none seem to work.

Similarly for tables (which I create using pander) - I have chunks like:

```{r car_sum}
library(pander)
car_summary<-summary(cars)
pander(car_summary, caption = "This is a summary of cars")
```

When converting to .pdf from the .md file using 'pandoc.convert' the tables are given a nice title 'Table 3 This is a summary of cars' and are numbered but I cannot seem to use the label as a reference \ref{car_sum} and it always shows as '??'. Some forums seem to mention that you have to include 'tab:' or 'fig:' before the label name but this still does not work for me.

Can chunk referencing within text be done? If so, what needs to be typed to do this correctly so it works in the final document showing something like 'see Table 2'.

Jimichanga1
  • 333
  • 2
  • 5
  • 2
    AFAIK in pandoc you have to explicitly write a latex `\label{}` inside the plot caption, and refer to that in the text. And it only works for LaTeX. I hope I'm wrong. – baptiste Jun 18 '13 at 11:02
  • 1
    I'm not sure if that is possible with Markdown. I guess the most common problem with Markdown is people are asking too much from it... LaTeX users often think of 'see Table 2', and Markdown users should only think of 'see Table below/above'. LaTeX can be nonlinear and Markdown is best to be very linear. I wish I'm wrong as well. – Yihui Xie Jun 18 '13 at 21:08
  • @Yihui, I was taking a look at LazyWeave and thinking of your engine/hook setup... My concept in the answer below could surely be made to integrate to a form such as Latex packages. There was another question along these lines where I believe you had mentioned something about a merge of html and Latex... Ah yes, http://stackoverflow.com/questions/16173995/knitr-rmd-page-break-after-n-lines-n-distance – Thell Jun 21 '13 at 00:20
  • There is an initiative to produce a flavour of markdown adding a few features required for scholarly writing (science papers, blogs etc) and one of those missing features is in-line links/references to figures and tables, without extending the markup much. See the github [repo wiki](https://github.com/scholmd/scholmd/wiki) for some more detail. – Gavin Simpson Jun 21 '13 at 01:33
  • It could be because you use an underscore in the Chunk label. See [bookdown issue](https://github.com/rstudio/bookdown/issues/941) where yihui commented on 1 Sep 2020 "It's fine to use underscores in chunk labels when you don't cross-reference the figures.". – Paul Rougieux Oct 07 '22 at 12:43

2 Answers2

19

Anything is possible!!

Please see this gist which does what you describe. Just save and knit it to see it in action... For some reason Rpub didn't want to publish it (unknown error).

Testing with converting the knitr generated .html to .pdf via pandoc resulted in working links as well, which is a nice bonus!

The workhorse is::

```{r setup, echo=FALSE, results='hide'}
chunkref <- local({
  function(chunklabel) {
    sprintf('[%s](#%s)', chunklabel, chunklabel )
  }  
})

secref <- local({
  function(seclabel) {
    sprintf('[%s](#%s)', seclabel, seclabel )
  }  
})

pgref <- local({
  function(n)
  sprintf('[Page-%i](#Page-%i)', n, n)
})

sec <- local({
  function(seclabel) {
    sprintf('# <a name="%s"/> %s', seclabel, seclabel )
  }  
})

pgcount <- local({
  pg <- 0
  function(inc=T) {
    if( inc ) { pg <<- pg + 1 }
    return( pg )
  }
})

pganchor <- local({
  function(doLabel=T) {
    if( doLabel) {
      sprintf('\n-----\nPage-%i\n<a name="Page-%i"/>\n', pgcount(inc=F), pgcount() )
    } else {
      sprintf('\n<a name="Page-%i"/>\n', pgcount() )
    }
  }
})

knit_hooks$set( anchor = function(before, options, envir) {
  if ( before ) {
    sprintf('<a name="%s"/>\n', options$label )
  }
})

knit_hooks$set( echo.label = function(before, options, envir) {
  if ( before ) {
    sprintf('> %s', options$label )
  }
})

knit_hooks$set( pgbreak = function(before, options, envir) {
  if ( !before ) {
    pganchor();
  }
})
````

Which allows for multiple types of references to be created...

Inline: `r sec("Introduction")` then `r secref("Introduction")`

Or

As chunk options:

```{r car-summary, echo=T, warning=FALSE, anchor=T, pgbreak=T, echo.label=F}`

then

`r chunkref("car-summary")`

Even 'top of page' links and 'bottom of page' markers and labels...

Thell
  • 5,883
  • 31
  • 55
6

Easier solution to referring to figures: put this in the fig.cap field (double \\ to escape the first \):

fig.cap="\\label{mylabel}Caption of my figure."

Then, use \autoref{mylabel} to refer to the figure in the main text.

I am using RStudio with Rmarkdown. Full RMD document:

---
output: pdf_document
---

```{r fig.cap="\\label{mylabel}Caption of my figure."}
plot(1)
```

The generated figure is \autoref{mylabel}.
CL.
  • 14,577
  • 5
  • 46
  • 73
nickmatzke
  • 61
  • 1
  • 1
  • Welcome to SO and thank you for sharing your solution. It's quite clever, I think. I edited your post "a little bit" to make it clearer and better readable. Feel free to rollback the edit if you don't agree with it. – CL. May 10 '16 at 07:53
  • This worked well for me, and is much simpler than the currently "winning" answer. Thanks! – Paul 'Joey' McMurdie Aug 13 '16 at 21:15
  • Does this work without adding the hyperref package in the preamble? – Koray Jan 19 '21 at 11:31