Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Does rmarkdown allow captions and references for code chunks?

Is there a trick for captioning and referencing a chuck of code in rmarkdown (not the result of running the code)? For example, how do I reference this block of code:

```{r blah}
blah <- "blah"
```

I know that I can use \@ref(fig:theFig) or \@ref(tab:theTable) to get at fig.cap or caption (with kable) but I don't see a way to caption and reference the code itself.

like image 720
itsMeInMiami Avatar asked Jun 05 '18 14:06

itsMeInMiami


Video Answer


1 Answers

This would be a great feature. And I think it is not integrated yet. Here is an approach that works for PDF documents and allows you to generate captions as well as labels for cross-referencing:

  1. Include a header.tex with the following content

\usepackage{caption}
\usepackage{floatrow}

\DeclareNewFloatType{chunk}{placement=H, fileext=chk, name=}
\captionsetup{options=chunk}
\renewcommand{\thechunk}{Chunk~\thesection.\arabic{chunk}}
\makeatletter
\@addtoreset{chunk}{section}
\makeatother

Since the environment used for chunks is not a floating type we declare a new one, named chunk. The option name is left blank since we already redefine \thechunk in the next line by prepending the word Chunk (play with the name option and see what happens).

The chunks should be enumerated by section and so we tell tex to reset the counter each time a new section begins.

If you do not use section numbering (by setting the YAML option), then replace the line

\renewcommand{\thechunk}{Chunk~\thesection.\arabic{chunk}}

by

\renewcommand{\thechunk}{Chunk~\arabic{chunk}}
  1. Modify the knitr source hook in your rmarkdown document

library(knitr)
oldSource <- knit_hooks$get("source")
knit_hooks$set(source = function(x, options) {
  x <- oldSource(x, options)
  x <- ifelse(!is.null(options$ref), paste0("\\label{", options$ref,"}", x), x)
  ifelse(!is.null(options$codecap), paste0("\\captionof{chunk}{", options$codecap,"}", x), x)
})

Here we make use of two new chunk options ref and codecap. If either one is not NULL, a corresponding label or caption is generated using the the commands \label or \captionof.

MWE:

---
title: "Cross-referencing Code Chunks"
output: 
  pdf_document: 
    includes:
      in_header: header.tex
    number_sections: true
---

```{r, echo=FALSE}
library(knitr)
oldSource <- knit_hooks$get("source")
knit_hooks$set(source = function(x, options) {
  x <- oldSource(x, options)
  x <- ifelse(!is.null(options$ref), paste0("\\label{", options$ref,"}", x), x)
  ifelse(!is.null(options$codecap), paste0("\\captionof{chunk}{", options$codecap,"}", x), x)
})
```

# Foo

Jump to \ref{TheBarChunk}

```{r Foo, ref = "TheFooChunk", codecap = "My Chunk"}
print("Foo!")
```

\newpage

# Bar

```{r Bar, ref = "TheBarChunk", codecap = "My second chunk"}
print("Bar!")
```

Head back to \ref{TheFooChunk}

Here is the output (of both pages):

enter image description here

enter image description here

Adding the caption below the code chunk

If you'd prefer to add the caption below the code chunk, instead of above, this can be achieved by altering the above knitr hook to read:

oldSource <- knit_hooks$get("source")
knit_hooks$set(source = function(x, options) {
  x <- oldSource(x, options)
  x <- ifelse(!is.null(options$codecap), paste0(x, "\\captionof{chunk}{", options$codecap,"}"), x)
  ifelse(!is.null(options$ref), paste0(x, "\\label{", options$ref,"}"), x)
})

Comments:

You could improve the code by checking what output type is desired so that the new source hook is only used for pdf output (skipped since it is lunch time).

like image 55
Martin Schmelzer Avatar answered Oct 16 '22 15:10

Martin Schmelzer