How to Make R Markdown Snow
Last year, I tweeted about how to spread holiday cheer by letting your R Markdown documents snow. After all, what better to put people in the holiday spirit than to add a random 5% probability that whatever part of a document they are trying to read will be covered?
No one:
--- Emily Riederer (@EmilyRiederer) December 10, 2020
Absolutely no one:
Me: SO, I know we can\'t have a holiday party this year, but we CAN make our \#rstats R Markdown reports snow before we send them to each other https://t.co/SSBzlgb3TV
HT to https://t.co/c7c5c5csMK for the heavy lifting pic.twitter.com/hIu7z0knR4
I make no promises that this will amuse your recipients, but at least it seemed to strike a cord with other R Markdown creators. This year, I decided to write it up step-by-step. As silly as the example is, I think it demonstrates (through slight abuse) some useful features of R Markdown. Much like ice sculpting, we will apply the powertool that is R Markdown to achieve our rather fanciful end.
If you want to skip the discussed, you can check out the full project, the main R Markdown file, or the rendered output. The rendered output is also shown below:
In the rest of this post, I’ll touch on three R Markdown tricks and their fanciful uses:
- Using child documents… to add snowflake
- Including raw HTML and custom CSS style… to animate them
- Evaluating chunks conditionally… to keep things seasonal
We will see how to dress up this very important business R Markdown
Much more useful applications of these same features are discussed in the linked sections of the R Markdown Cookbook.
Child documents
Child documents allow R Markdown authors to combine multiple R Markdown files into a single final output rendered in a consistent environment. This helps create a more manageable, modular workflow if you are working on a long project or anaylsis with many distinct parts or if there are some pieces of boilerplate text or analysis that you wish to inject into many projects.
To add child documents, we create an empty R code chunk, and use the child
chunk option to pass the path to the R Markdown file that we wish to include. In our case, we reference our snow.Rmd
file.
```{r child = "snow.Rmd"}
```
Of course, since child documents are functionally the same as including files in the same document, we could have included this material in the same file. However, since snowflakes should clearly only be placed in very important documents, it is good to use best practices and take a modular approach. Tactically, this also makes it easier to “turn them on an off” at will or swap them our for New Years fireworks, Valentine’s Day hearts, and more.
Including HTML and CSS
So, what is in the
snow.Rmd
file?
First, we have to bring in the snowflakes themselves.
<div class="snowflakes" aria-hidden="true">
<div class="snowflake">
❅
</div>
<!-- many more snowflakes... -->
</div>
Because this R Markdown will render to an HTML document, we are free to include raw HTML text the same way we include narrative, English-language text. Here, I wrap unicode snowflakes in <divs>
so I can attach CSS classes to them.
Similarly, R Markdowns that will be rendered to HTML can use all the benefits of web technology like CSS and JavaScript.
Custom CSS can be included either with the css
language engine or a reference in the YAML header to an external .css
file. For compactness, I go with the former.
A css
chunk adds CSS code used to animate the snowflake divs. This is taken nearly verbatim from
this CodePen. Since this is rather lengthy, we can also use the echo = FALSE
chunk option to not output all of the CSS in our final document.
```{css echo = FALSE}
<<css goes here>>
```
For more tips on writing CSS for R Markown, check out my post on finding the right selectors.
Conditional chunk evaluation
The above two tricks are as for as my demo goes since I only planned to render it once. However, if you are creating automated reports and fear your recipients have limited patience for animated snowflakes, we can also use R Markdown chunk options with variables as arguments to only allow these snowflakes to appear during a certain time period.
So, for example instead of:
```{r child = "snow.Rmd"}
```
We might type:
```{r child = "snow.Rmd", eval = (substr(Sys.Date(), 6, 7) == 12)}
```
To only allow the child document to be included in December.
If we had chosen not to use child documents, we could also use chunks to achieve conditional evaluation using the
asis
engine.