prevent knitr/Rmarkdown from interleaving chunk output with code - r

When I use knitr to build an HTML document out of the following code:
Chunk Output
========================================================
Outside a chunk.
```{r chunk1, results='asis'}
cat('Inside a chunk\n\n')
for (i in 1:3) {
cat('* Inside loop #', i, '\n')
}
cat('Outside a loop, but still inside the first chunk')
```
Between chunks.
```{r chunk2, results='asis'}
cat('Inside second chunk')
```
I get output where the code in chunk1 is interleaved with the output of the cat statements. Interestingly, the output within the for loop is output as a single block.
I would prefer to have all of the code from chunk1 to appear first, followed by all of the output from chunk1. Is there a way to ask Rmarkdown/knitr to avoid the more granular interweaving that it's currently doing?

Here is the solution I proposed
Chunk Output
========================================================
Outside a chunk.
```{r chunk1, results='hide'}
cat('Inside a chunk\n\n')
for (i in 1:3) {
cat('* Inside loop #', i, '\n')
}
cat('Outside a loop, but still inside the first chunk')
```
```{r ref.label = 'chunk1', results = 'asis', echo = F}
```
In the latest version of knitr, #yihui has added a new chunk option results = "hold", which automatically holds printing of all output to the end. Accordingly, we can just write
Chunk Output
========================================================
Outside a chunk.
```{r chunk1, results='hold'}
cat('Inside a chunk\n\n')
for (i in 1:3) {
cat('* Inside loop #', i, '\n')
}
cat('Outside a loop, but still inside the first chunk')
```

Related

How to reproducibly include R code in Word documents with Rmarkdown?

I have some R code in a package. I don't want to copy that code, but I want to display it in a pretty way in Word with syntax highlighting without any manual steps.
I looked at styler::style_text in combination of capture.output and that looks nice in the browser, but all the formatting is lost when knitting to Word. Is there some way to preserve it? I'm thinking the best thing would be to have Word native styling but the next best (acceptable) thing would be to somehow render the output to an image and include that. Has anyone done these things to document their code in a report?
show_code = function (fun) {
stopifnot(is.function(fun))
out = capture.output(fun)
n = length(out)
without_bytecode_and_env_lines = -1*c(n-1, n)
code = paste(out[without_bytecode_and_env_lines], collapse = "\n")
styler::style_text(code)
}
I believe you are trying to use syntax highlighting on the output of show_code and to do that, you simply need to use the options comment="" and class.output="r" and syntax highlighting will apply to the output.
---
title: "Source Code highlighting"
output:
word_document:
highlight: kate
---
```{r setup, include=FALSE}
knitr::opts_chunk$set(echo = TRUE)
```
## R Markdown
```{r echo=FALSE}
show_code = function (fun) {
stopifnot(is.function(fun))
out = capture.output(fun)
n = length(out)
without_bytecode_and_env_lines = c(n-1, n)
code = paste0(out[-without_bytecode_and_env_lines], collapse = "\n")
styler::style_text(code)
}
```
### The source code for `lm`
```{r comment='', echo=FALSE, class.output = "r"}
show_code(lm)
```

Chopped up output using message() in an R Markdown / knitr report

I recently submitted a package to rOpenSci, and they prefer the use of message() rather than cat() for user-side console output. When I made the switch for my package, I noticed a disconcerting change in the formatting of the rendered vignettes. I have reproduced the problem in the following R Markdown report.
---
title: "MWE"
author: "Will Landau"
date: "11/20/2017"
output: html_document
---
```{r testcat}
for(x in LETTERS[1:3]){
cat(x, "\n")
}
```
```{r testmessage}
for(x in LETTERS[1:3]){
message(x)
}
```
```{r testmessage2}
for(x in LETTERS[1:3]){
message(x, "\n", appendLF = FALSE)
}
```
For the first code chunk, I get the desired output: all three lines string together in a single gray box.
## A
## B
## C
But for the second and third chunks, each line is given its own separate gray box.
## A
.
## B
.
## C
How do I keep using message() without chopping up the knitr output like this?
I think I solved it: knitr has a collapse chunk option. All I needed was to put this chunk before any of the other chunks.
```{r setup}
knitr::opts_chunk$set(collapse = TRUE)
```
The output is more condensed than I expected, but after some touching up, the formatting actually looks much better now.
You can try and build the string and put the message function outside the loop, like this:
```{r testmessage}
single_message <- c()
for(x in LETTERS[1:3]){
single_message <- paste(single_message , x, sep = "\n")
}
message(single_message )
```
Note that this example does add a newline at the start, you can prevent this with an extra if, or use the first element outside the loop to initialize single_message.

purl() within knit() duplicate label error

I am knitting a .Rmd file and want to have two outputs: the html and a purl'ed R script each time I run knit. This can be done with the following Rmd file:
---
title: "Purl MWE"
output: html_document
---
```{r}
## This chunk automatically generates a text .R version of this script when running within knitr.
input = knitr::current_input() # filename of input document
output = paste(tools::file_path_sans_ext(input), 'R', sep = '.')
knitr::purl(input,output,documentation=1,quiet=T)
```
```{r}
x=1
x
```
If you do not name the chunk, it works fine and you get html and .R output each time you run knit() (or click knit in RStudio).
However, if you name the chunk it fails. For example:
title: "Purl MWE"
output: html_document
---
```{r}
## This chunk automatically generates a text .R version of this script when running within knitr.
input = knitr::current_input() # filename of input document
output = paste(tools::file_path_sans_ext(input), 'R', sep = '.')
knitr::purl(input,output,documentation=1,quiet=T)
```
```{r test}
x=1
x
```
It fails with:
Quitting from lines 7-14 (Purl.Rmd)
Error in parse_block(g[-1], g[1], params.src) : duplicate label 'test'
Calls: <Anonymous> ... process_file -> split_file -> lapply -> FUN -> parse_block
Execution halted
If you comment out the purl() call, it will work with the named chunk. So there is something about how the purl() call is also naming chunks which causes knit() to think there are duplicate chunk names even when there are no duplicates.
Is there a way to include a purl() command inside a .Rmd file so both outputs (html and R) are produced? Or is there a better way to do this? My ultimate goal is to use the new rmarkdown::render_site() to build a website that updates the HTML and R output each time the site is compiled.
You can allow duplicate labels by including options(knitr.duplicate.label = 'allow') within the file as follows:
title: "Purl MWE"
output: html_document
---
```{r GlobalOptions}
options(knitr.duplicate.label = 'allow')
```
```{r}
## This chunk automatically generates a text .R version of this script when running within knitr.
input = knitr::current_input() # filename of input document
output = paste(tools::file_path_sans_ext(input), 'R', sep = '.')
knitr::purl(input,output,documentation=1,quiet=T)
```
```{r test}
x=1
x
```
This code isn't documented on the knitr website, but you can keep track with the latest changes direct from Github: https://github.com/yihui/knitr/blob/master/NEWS.md
A related approach to #ruaridhw solution would be to wrap the knitr::purl() in callr::r(). See function below that saves the R chunks from a specified R markdown file to a temporary .R file:
# RMD to local R temp file
# inspiration: https://gist.github.com/noamross/a549ee50e8a4fd68b8b1
rmd_chunks_to_r_temp <- function(file){
temp <- tempfile(fileext=".R")
# needed callr so can use when knitting -- else can bump into "duplicate chunk
# label" errors when running when knitting
callr::r(function(file, temp){
knitr::purl(file, output = temp)
},
args = list(file, temp))
}
This function also exists in funspotr:::rmd_chunks_to_r_temp() at brshallo/funspotr.
You can avoid this error with a bash chunk that calls purl in a separate R session. That way there's no need to allow duplicate labels.
An example use case is an Rmd file where the code is run (and not echo'd) throughout the report and then all the code chunks are shown with chunks names and code comments in an Appendix. If you don't require that additional functionality then you would only need up until the bash chunk.
The idea is that report_end signifies where to stop purl such that the appendix code isn't considered "report code". Then read_chunk reads the entire R file into one code chunk which can then be echo'd with syntax highlighting if required.
---
title: "Purl MWE"
output: html_document
---
These code chunks are used in the background of the report however
their source is not shown until the Appendix.
```{r test1, echo=FALSE}
x <- 1
x
```
```{r test2, echo=FALSE}
x <- x + 1
x
```
```{r test3, echo=FALSE}
x <- x + 1
x
```
# Appendix
```{r, eval=TRUE}
report_end <- "^# Appendix"
temp <- tempfile(fileext = ".R")
Sys.setenv(PURL_IN = shQuote("this_file.Rmd"), # eg. knitr::current_input()
PURL_OUT = shQuote(temp),
PURL_END = shQuote(report_end))
```
```{bash, include=FALSE}
Rscript -e "lines <- readLines($PURL_IN, warn = FALSE)" \
-e "knitr::purl(text = lines[1:grep($PURL_END, lines)], output = $PURL_OUT, documentation = 1L)"
```
```{r, include=FALSE}
knitr::read_chunk(temp, labels = "appendix")
unlink(temp)
```
```{r appendix, eval=FALSE, echo=TRUE}
```

How to include a header based on a condition in knitr

I have a header followed by a code chunk in an Rmd file. I only want to include this header and the chunk followed by it, if a condition is met. I know how to do that with the chunk, since it's in the body of the code, but how do I do the former?
```{r}
print_option <- TRUE
```
## My header
```{r}
if(print_option==TRUE) {
print (x)
}
```
The chunk option eval and asis_output() provide a simple solution.
Assuming that print_option is a boolean indicating whether to show the header (and whether to execute other code like print(1:10) in chunk example1):
```{r setup}
library(knitr)
print_option <- TRUE
```
```{r, eval = print_option}
asis_output("## My header\\n") # Header that is only shown if print_option == TRUE
print(1:10) # Other stuff that is only executed if print_option == TRUE
```
Text that is shown regardless of `print_option`.
```{r setup2}
print_option <- FALSE
```
Now `print_option` is `FALSE`. Thus, the second header is not shown.
```{r, eval = print_option}
asis_out("## Second header\\n")
```
Output:
For longer conditional outputs (of text/markdown, without embedded R code) the engine asis can be helpful, see this answer (it's long, but the solution at the end is very concise).
Addendum
Why is ## `r Title` with Title set to "My header" or "" as suggested in this answer a bad idea? Because it creates an "empty header" in the second case. This header is not visible in the rendered HTML/markdown output, but it is still there. See the following example:
```{r, echo = FALSE}
title <- ""
```
## `r title`
This generates the following markdown ...
##
... and HTML:
<h2></h2>
Besids being semantically nonsense it might lead to layout issues (depending on the style sheet) and disrupts the document outline.
I figured it out :)
```{r, echo=FALSE, include=FALSE}
x<- FALSE
if ( x ) {
Title <- "My header"
} else {Title=""}
```
## `r Title`
```{r, echo=FALSE}
if(x) {
print(1:10)
}
```

Load and print every table in new page by R markdown and knitr

I have about 60 .Rdata files in the same directory. The object name in all those .Rdata are same. I want to write some code to load and print all 60 .Rdata file and each file in the new page. For example, if the file name is file_1.rdata, file_2.rdata and file_3.rdata. The object name in all three .Rdata files is table. The following knitr code showed exactly what I want,
>\```{r,echo=FALSE}
>load("file_1.rdata")
>print(table)
>\```
>\pagebreak
>\```{r,echo=FALSE}
>load("file_2.rdata")
>print(table)
>\```
>\pagebreak
>\```{r,echo=FALSE}
>load("file_3.rdata")
>print(table)
>```
>\pagebreak
But I have more than 60 files, it is really hard to write all the code by hand. I can write for loop in R block, however, how can I make a new page for each .rdata file?
The for loop will be
>\```{r,echo=FALSE}
>names <- c("file_1.rdata","file_2.rdata","file_3.rdata")
>for(i in 1:length(names)){
> current_object <- names[i]
> load(current_object)
> print(table)
>}
>\```
You can try adding in cat("\n\n\\pagebreak\n") inside your for loop, and results='asis' to your chunk call:
```{r,echo=FALSE, results='asis'}
names <- c("file_1.rdata","file_2.rdata","file_3.rdata")
for(i in 1:length(names)){
current_object <- names[i]
load(current_object)
print(table)
cat("\n\n\\pagebreak\n")
}
```
It works for me with mtcars:
---
title: "test"
output: pdf_document
---
```{r, echo=FALSE, results='asis'}
for (i in 1:3) {
print(mtcars)
cat("\n\n\\pagebreak\n")
}
```
NB you might want to look into the function kable to format your tables more nicely. Or using library(xtable):
```{r, echo=FALSE, results='asis'}
for (i in 1:3) {
print(xtable::xtable(mtcars), type = "latex")
cat("\n\n\\pagebreak\n")
}
```

Resources