Plane Wryter
Plane Wryter

Reputation: 1369

A Way in Knitr to Copy a Chunk?

Knitr Mavens,

Background: Using knitr to report a report with many embedded graphs. In the body of the report, all that's appropriate is the graph, not the code.

For example:

```{r graph_XYZ_subset, echo = FALSE, message = TRUE, 
                        fig.cap = "Text that explains the graph"}

graph.subset <- ggplot() + ...

```

This part works just fine.

However, there is a need to display the key parts of the code (e.g., key statistical analyses and key graph generations)...but in an Addendum.

Which leads to this question: is there a way to copy a knitr chunk from the early parts of a script to a later part?

To ensure accuracy, it's ideal that the code in the Addendum list (display) all the code that was actually executed in the report.

For example:

# ADDENDUM - Code Snippets

### Code to Generate Subset Graph

\\SOMEHOW COPY the code from graph_XYZ_subset to here without executing it.

### Code to Compute the Mean of Means of the NN Factors

\\Copy another knitr chunk which computes the mean of means, etc.

### And So On...

\\Copy chunks till done

* * * * * * * * 

Any ideas? Is there a way in knitr to perform these types of chunk copies?

Upvotes: 4

Views: 963

Answers (1)

CL.
CL.

Reputation: 14957

There are several options, four of them listet and shortly explained below. Yihui's explanations in How to reuse chunks might also help.

\documentclass{article}
\begin{document}

\section{Output}
<<mychunk, echo = FALSE>>=
  print("Hello World!")
@

\section{Source code}
Option 1: Use an empty chunk with the same label.
<<mychunk, eval = FALSE>>=
@

Option 2: Embed in other chunk (no advantage in this case). Note that there is no equality sign and no at for the inner chunk.
<<myOtherChunk, eval = FALSE>>=
<<mychunk>>
@

Option 3: Use \texttt{ref.label}.
<<ref.label = "mychunk", eval = FALSE>>=
@

Option 4: Define the chunk in an external file you read in using \texttt{read\_chunk}. Then use Option 1--3 to execute the chunk (with \texttt{eval = TRUE}; default) or show it's code (with \texttt{eval = FALSE}).
\end{document}

Output

I usually prefer Option 4. This allows you to separate the programming logic from writing the document.

At the place mychunk is to be exectued and the graph will appear in the PDF, you only have <<mychunk>>= in your Rnw file and don't have to bother with all the code that generates your graph. Developing your code is also easier, because in an interactive session you have all your code at one spot and don't have to scroll through all the text of the report when going from one chunk to the next one.

EDIT: The options mentioned above have in common that you need to manually maintain a list of the chunks to show in the appendix. Here two options to avoid this; unfortunately, both have some drawbacks:

Option 1: Automatically create a list of all chunks that have been executed and show their code.

This can be achieved using a chunk hook that registers all chunk names. Include the following chunk before all other chunks in the document:

<<echo = FALSE>>=
library(knitr)
myChunkList <- c()

listChunks <- function(before, options, envir) {
  if (before) {
    myChunkList <<- c(myChunkList, options$label)
  }
  return(NULL)
}

knit_hooks$set(recordLabel = listChunks) # register the new hook
opts_chunk$set(recordLabel = TRUE) # enable the new hook by default
@

Where you want to show the code (for example in the appendix), insert the following chunk:

<<showCode, ref.label = unique(myChunkList), eval = FALSE>>=
@

Unfortunately, there will be no margin or any other visual separation between the chunks.

Option 2: Using the chunk hook is not always necessary because there is the function all_labels() that returns a list of all chunk labels. However, there might be chunks in your file that don't get executed and you probably don't want to see their code. Moreover, option 1 allows skipping certain chunks simply by setting recordLabel = FALSE in their chunk options.

Upvotes: 2

Related Questions