- This post was updated with advanced tips (at the bottom) 2/12/2016
For scientific projects we often using knitr and R markdown in RStudio to share results and code either in HTML or PDF format. These are great tools for reproducible research. We find, however, that keeping all of our R code in an R markdown (.Rmd) file creates two problems. First, you need to completely re-run the report to evaluate new bits of R code and secondly the .Rmd file can become unwieldy very quickly. Fortunately, there is an easy way to make use of external code.
1. Create your external R script
You would create an R script as normal and, within the R script, you create ‘chunks’ using the ## @knitr
syntax. So, in this example, we create a new R script entitled example.R
with two chunks (variablesXY
and plotXY
) that looks like this:
# This is our external R script called example.R
# We're adding two chunks variablesXY and plotXY
## @knitr variablesXY
x<-1:100
y<-x+rnorm(100)
head(data.frame(x,y))
## @knitr plotXY
plot(x,y)
2. Create your R markdown script and refer to the external R script
Now you can create your R markdown (.Rmd) file. In order to read your external file you use the function read_chunk
and then you can reference individual chunks using the <<chunkname>>
syntax. So, continuing with our example, we can create a new file called myreport.Rmd, read the external file and reference/run the code chunks:
# read chunk (does not run code)
```{r echo=FALSE}
read_chunk('example.R')
```
# run the variablesXY chunk and use the variables it creates
```{r first}
<<variablesXY>>
head(data.frame(x,y))
```
# run the plotXY chunk and create the plot
```{r second}
<<plotXY>>
```
3. Alternative syntax
Although we usually use the syntax above which allows us to easily re-use chunks and flexibly name the R markdown chunks, there is an alternative syntax you can use. You can move all of the R code to the chunks in the external file and refer to those chunks in the R markdown chunk headers. For example, to produce exactly the same output as that above you can use the following for the example.R
:
## @knitr variablesXY
x<-1:100
y<-x+rnorm(100)
head(data.frame(x,y))
## @knitr plotXY
plot(x,y)
And then the myreport.Rmd
can be simplified to look like:
```{r echo=FALSE}
read_chunk('example.R')
```
```{r variablesXY}
```
```{r plotXY}
```
In either case, the output would look like this:
Advanced tips:
Run and show external code but leave off the comments
This was a tip provided by Bob Rudis. My external code often has comments that I don't want included in my final report but including code and excluding comments is tricky. To do this you add a couple of arguments to your code chunk, one is tidy=TRUE
which tells R to tidy up the code (but leaves comments intact). The second is an argument to tidy.opts
setting comment=FALSE
. To a certain extent this is covered in Yihui's post on chunk options but the various setting available in tidy.opts
are not spelled out there.
```{r, echo=TRUE,tidy=TRUE, tidy.opts=list(comment=FALSE)}
<<variablesXY>>
```
Run or show all code from an external script
I occasionally have a situation where I want to echo the code from a script but I don't want to run it. The simplest way to do this would be to copy and paste the code into a code chunk (and set eval=FALSE
) but, of course, you would need to re-cut and paste if your code changes. An alternative to this, explained by Yihui at the bottom of this page, would be to use the code
argument and readLines
. So, as an example, to echo the code (but don't run it) from an external script called myscript.R
in your Rmarkdown you can use:
```{r, code=readLines("myscript.R")}
```
Thank you and the Lord for being one of the few people using R who actually knows how to explain something with, gasp!!!!!, actual examples!!! Seriously, you are a rare human in the messed up world of R where creating confusion via the lack of basic communication skills seem the norm.
Thanks for this, I wish I had found this 10 hours ago!
Externalization seems like it should be at the top of the list but all the basic intros give at best a passing mention of it (and little in the way of how to do it).
This is much appreciated!
Thanks!
Thanks for sharing this! I clueless the ‘code’ argument existed. No more copying and pasting. I echo Michale’s comment about this area being an afterthought.
Note, like in the example, the script name must be wrapped in double quotes. I default to using single quotes and the document wouldn’t compile.
Thanks again!
Hi, I am trying to replicate this example. But I get the following error when ever I try to read the chunk in the Rmarkdown file: Error: unexpected input in “<<" . Could you kindly advise on how I can correct this.
There are a number of reasons why this could be. You need to set up the external file properly and reference it properly. If you create a stackoverflow question with your reproducible code and send me the link I can take a look.
I think that is because knitr is not loaded. Put “`library(knitr)“` in the myreport.Rmd file.
Thank you so much!
I have a question. If you have more than one plot in a script chunk, could you reference a specific plot in the markdown script?
off-hand I don’t know. Why not just use another code chunk?
I use a loop to draw two different kinds of plots for several subjects, and want to format the output to show two plots for each subject. Also, I want to make the code reproducible for different set of subjects, so I want to know how to reference specific plot.
I’d need to see the code, you should post at stackoverflow and provide a link.
The “code” option can also be used in python chunk for py files
Thank you for this! I’m a little confused in the examples because think the two example.R scripts are the same. It appears the only difference between the two methods is one calls the variable from the chunk name and the other calls it using kintr’s “<>” syntax. Is that correct? The description leads one to believe there’s more to the difference than that.
I think you’re right! Thanks for spotting this.
great post, thank you!
the official doco never showed any example of how this feature works in Rmd files, and I was beginning to think it doesn’t.
Hi! Thank you for the very informative post. I’d like to make one small recommendation to your last point. If you would like to simply echo the code, and not run the external script, set eval=FALSE.
This will run the script:
“`{r, code=readLines(“myscript.R”)}
“`
While this will not run, but echo the script:
“`{r, code=readLines(“myscript.R”), eval=FALSE}
“`
Weird enough, this never worked for me. I actually copied the text here verbatim, but I could never ever get an output from the external script.