39
votes

I am using knitr to parse an R Markdown document . Is there a way to conditionally display a block of text in R Markdown depending on a variable in the environment I pass into knitr?

For instance, something like:

`r if(show.text) {`
  la la la
`r }`

Would print "la la la" in the resulting doc if show.text is true.

8
Unfortunately I am not sure about knitr, but you can do that easily with pander and the <% ... %> type of tags: rapporter.github.io/pander/#brew-to-pandoc - daroczig

8 Answers

64
votes

You need a complete R expression, so you cannot break it into multiple blocks like you show, but if the results of a block are a text string then it will be included as is (without quotes), so you should be able to do something like:

`r if(show.text){"la la la"}`

and it will include the text if and only if show.text is TRUE.

35
votes

You can do this using the "eval" chunk option. See http://yihui.name/knitr/options/.

```{r setup, echo=FALSE}
show_text <- FALSE
````

```{r conditional_block, eval=show_text}
print("this will only print when show.text is TRUE")
```

I've been using YAML config files to parameterize my markdown reports which makes them more reusable.

```{r load_config}
library(yaml)
config <- yaml.load_file("config.yaml")
```

...

```{r conditional_print, eval=config$show_text}
print("la la la")
````
29
votes

I find it easiest to do this by putting all of my text into a separate file and then include it from the main file with:

```{r conditional_print, child='text.Rmd', eval = show_text}
```

This has the advantage that you can still put inline R statements or other chunks into the child file, so that if you change your mind about what counts as optional text, you don't have to refactor your project.

22
votes

Here's a tweak to Paul Boardman's approach that gives proper markup in the output.

```{r setup, echo=FALSE}
show_text <- FALSE
```

```{r conditional_block, echo=FALSE, results='asis', eval=show_text}
cat("## Hey look, a heading!

lorem ipsum dolor emet...")
```

Even better, if we invoke the python engine to generate our output, we can use triple quoting to easily handle text that contains single or double quotes without needing to do anything fancy:

```{python, conditional_block_py, echo=FALSE, results='asis', eval=show_cond_text}
print("""
## Still a heading

Block of text with 'single quotes' and "double quotes"
""")
```
6
votes

The solutions above may be a little clunky for larger blocks of text and not great for certain situations. Let's say I want to create a worksheet for students with some questions and also use the same .Rmd file to generate a file with solutions. I used basic LaTeX flow control:

``` {r, include = F}
# this can be e.g., in a parent .Rmd and the below can be in child
solution <- TRUE 
```
\newif\ifsol
\sol`r ifelse(solution, 'true', 'false')`

Then I can do:

What is $2 + 2$

\ifsol
4
\fi

This way you can also create alternative blocks of text using

\ifsol
Alternative 1
\else
Alternative 2
\fi
2
votes

Another way to add markdown text conditionally is below. It uses the block "engine" which seems to run fine although I'm not sure how to make inline R evaluation working.

Note that I use the view_all switch defined in the YAML metadata to control whether or not the block is visible.

Also, note that both eval and include chunk options are needed. The first prevents errors during regular Run All in RStudio. The second prevents output with Knit.

---
title: "Conditional Output"
params:
  view_all: false
output:
  html_document: default
  pdf_document: default
---

```{block eval=FALSE, include=params$view_all}
# Some simple markdown.

Some things work: $2 + 2^2 = 3\cdot2$

Other does not: 2 + 2 = `r 2+2`
```
2
votes

The accepted answer above works well for inline content.

For block content (one of several paragraphs of Markdown text), knitr contains a asis engine that allow to include Markdown content conditionnally depending if chunk option echo = FALSE or echo = TRUE

Example from the doc https://bookdown.org/yihui/rmarkdown-cookbook/eng-asis.html

```{r}
getRandomNumber <- function() {
  sample(1:6, 1)
}
```

```{asis, echo = getRandomNumber() == 4}
According to https://xkcd.com/221/, we just generated
a **true** random number!
```

If you need to include more complexe content , like piece of a R Markdown document with e.g code block, then child document could be useful. See https://bookdown.org/yihui/rmarkdown-cookbook/child-document.html

1
votes

I tried to define a function my.render(), which preprocesses the Rmd file, and depending on the commentout argument, either keeps the HTML commenting code (TRUE) in the Rmd file or removes them (FALSE). Then writes the preprocessed Rmd file into tmp.Rmd, and uses the usual render() function.

my.render <- function(input, commentout=FALSE, ...) {
  if (commentout == FALSE) {
    ## Delete the HTML comment lines from code
    txt <- readLines(input)
    txt[grepl(" *<!-- *| *--> *", txt)] <- ""
    write.table(txt, file="tmp.Rmd", sep="\n", quote=FALSE, row.names=FALSE, col.names=FALSE)
    render("tmp.Rmd", output_file=sub("Rmd","html",input), ...)
  } else {
    render(input, output_file=sub("Rmd","html",input), ...)
  }
}

It seemed to work. E.g.

<!--
This text with formulas $\alpha+\beta$ is visible, when commentout=FALSE.
-->