Blogdown

Plus other RMarkdown-derived scholarly blogging systems

August 26, 2020 — July 9, 2023

academe
doing internet
faster pussycat
how do science
plain text
workflow

Assumed audience:

Aspirational bloggers who want to include nerdy stuff in their posts

Figure 1

Blogdown is the academic blogging system that I use. It constructs a website using pages made from Rmarkdown to write a blog with embedded diagrams and code. In its default state, all the things that academics want (citations, equations, plots) just work, which is rare and precious. However, there are a few frictions, which I attempt to find fancy workarounds for. Both basic blogdown and excessively fancy options are discussed here.

I suspect that quarto is more active currently than blogdown, although it is not strictly superior; rather it has a different set of annoyances.

1 Blogdown classic

Blogdown might be the most popular option now, especially if you want to access the mind-share of other academics, such as the rbind community. This is what I currently use for this site. I recommend it because although it is not free from shortcomings, it does most things right by default, including things that only academics care about. It is built upon, per default, hugo which is an elegant and popular blogging platform. It is a great option. You can also use some alternative options such as jekyll, although I do not know what benefit that would bring, and it would certainly lead you down an overgrown path.

See the blogdown-book for an introduction to this tool.

One point of friction is that hugo is well integrated with its own internal markdown processor, goldmark and much of the hugo documentation reflects that. However, blogdown bypasses goldmark, using instead rmarkdown (which uses pandoc internally) to render workbooks direct to HTML+images. This leads to pluses (equation and citation support) and minuses (many hugo tricks, notably shortcodes) do not work.

One could possibly work around some frictions by rendering to markdown, or using hugodown or quarto which support that. Then you have a different set of problems, notably the hugo markdown+maths problems.

UPDATE: Alison Hill points out that blogdown as of 2021 supports some more pure-markdown style workflows via the .RMarkdown format which augments the .Rmd format with an alternative processing of R Markdown so that … you know what? Just go and read her post. It is clear and has animations in. Does this do what we want?

See the blogdown-book, or the various academic intros, e.g. by Emi Tanaka or Rob Hyndman. Some themes have been tested against blogdown.

Also What to know before you adopt Hugo/blogdown.

1.1 Pro tip: Cascading

Hugo’s cascade configuration works in blogdown too. Setting that key in an _index file passes config down to all descendants. For example, here is how I set the default post quality in this blog:

cascade:
  certainty: 0
  novelty: 0
  usefulness: 0
  polish: 0

NB there is a subtlety here: Hugo will correctly propagate this information through the blog when it renders the content to the site. However, it does not appear to be propagated at the markup handling stage, at least not for the blogdown config. So I cannot pass e.g. reference handling options to pandoc this way, but I can pass options to page templates this way.

1.2 Pro tip: Setting classes on plots is ugly

Want to set classes for R-generated plots? Try this:

knitr::knit_hooks$set(class = function(before, options, envir) {
  if(before){
    sprintf("<div class='%s'>", options$class)
  }else{
    "</div>"
  }
})

Then in the chunk, we can use the new hook thusly:

```{r example-plot, class="blue-outline"}
plot(1:10, pch=21, bg="blue")
```

🤮

1.3 Pro-tip: double code fences

Wondering how I got the previous line of code to print? It was not quite obvious. See the double code fences trick. tl;dr uses the code type {verbatim}.

1.4 Pro-tip: comments

We can comment-out sections of the document by making them into fenced code blocks with type {comment}. That is also included in the double code fences trick.

In hugo templates it is different; {/* a comment */} is the syntax.

1.5 Pro tip: Archetypes

Firstly, hugo archetypes automate some menial work if you have many posts of similar type (e.g. meeting minutes).

1.6 Pro tip: postprocessing

Maëlle Salmon writes about how to create smart code and figures using postprocessing hooks.

1.7 Pro tip: VS Code config

Hide extraneous crap using the following configuration:

  "files.watcherExclude": {
    "**/output/**": true
  },
  "files.exclude": {
    "content/**/*.html": true
  },
  "files.exclude": {
    "blogdown/*": true  # content hashes
  }

1.8 Pro tip: cleaning up

Beware! blogdown will silently fail to render updates if there are lockfiles hanging around. It is easy to accumulate lockfiles if rendering crashes, which does happen from time to time. For me this seems to arise in pandoc errors, e.g. if there are errors in the bibliography/citation workflow. As long as no other rendering job is currently running, the fix is this:

find content -name "*.lock~" -delete

1.9 Outside RStudio

Many blogdown intros assume you are an RStudio user. RStudio is …fine. It does not incite enthusiasm in me, but it gets the job done.

If you are using VS code, Tianyi Shi’s excellent RMarkdown extension is useful; it allows you to compile the document from inside VSCode and other useful things.

Some of the design choices are explained well in blogdown: Knit on Save, or Save on Knit?.

From the command-line I find it best to build incrementally:

#!/usr/bin/env Rscript
library(blogdown)
options(blogdown.files_filter = blogdown::timestamp_filter)
blogdown::build_site(build_rmd = TRUE)

In version 1.0+ this becomes:

#!/usr/bin/env Rscript
library(blogdown)
blogdown::build_site(build_rmd = "timestamp")

In vs code Tianyi Shi’s excellent RMarkdown all-in-one extension is useful. An in-app browser preview can be useful.

As for running the server, this works:

#!/usr/bin/env Rscript
library(blogdown)
blogdown::build_site(build_rmd = "timestamp")
blogdown::serve_site()

On one hand it does not seem to automatically pick up changes to .Rmd files and thus save me a build step.

Alternatively I can manually run system hugo to serve the blogdown output eils

hugo serve --buildDrafts --poll 3000&

The --poll argument waits 3 seconds for my R build-script to finish before doing anything and thus is counterintuitively faster than an instant rebuild (which in practice is 10 different hugo rebuilds or something, each of which cases my browser to refresh and takes more than 3 seconds).

The blogdown-native methods run hugo behind the scenes, but ensure it is the correct version etc.

Either way I need to trigger .Rmd compilation manually. Maybe that part works better from inside RStudio.

Since I am already off the blogdown piste at this point maybe I should be running the netlify dev server.

netlify dev --live

It has many features including draft deployments and ssh tunnel configuration for private preview.

1.10 Alternative markdown parsing settings

If I need alternate pandoc markdown settings… Finding the documentation of the exact configuration of the markdown parser is tricky from google for some reason, and in fact I have already lost the link. For my reference, I found the following _output.yml configuration options useful:

blogdown::html_page:
  toc: true
  dev: "svg"
  smartypants: false
  variant: markdown+citations+tex_math_single_backslash+backtick_code_blocks+emoji+footnotes+inline_notes-smart+pipe_tables
  md_extensions: +citations+tex_math_single_backslash+backtick_code_blocks+emoji+footnotes+inline_notes-smart+pipe_tables

I am not sure which of variant and md_extensions is the configuration I need to pass my preferred options to pandoc. I should work that out one day.

2 Bookdown

If the website you are writing is more naturally a book than a blog or a report or a journal article, possibly bookdown is the better backend.

The bookdown package is built on top of RMarkdown, and inherits the simplicity of the Markdown syntax (you can learn the basics in five minutes), as well as the possibility of multiple types of output formats (PDF/HTML/Word/…). It has also added features like multi-page HTML output, numbering and cross-referencing figures/tables/sections/equations, inserting parts/appendices, and imported the GitBook style to create elegant and appealing HTML book pages. This book itself is an example of how you can produce a book from a series of R Markdown documents, and both the printed version and the online version can look professional. You can find more examples at bookdown.org.

It defines “book” broadly — it could output a word document or a PDF or a navigable website with chapter headings and cross references etc.

2.1 Pro-tip: Header stuff

How to include Google Analytics in an RMarkdown generated GitHub Page?:

output:
  html_document:
    includes:
       in_header: header.html

Also works for favicons.

2.2 Pro-tip: better theorem syntax

The New theorem syntax is IMO nicer than the previous code-block thing, which IIRC is the one mentioned in the manual:

::: {.theorem #pyth name="Pythagorean theorem"}
For **a right triangle**, if $c$ denotes the length of the hypotenuse
and $a$ and $b$ denote the lengths of the other two sides, we have
$$a^2 + b^2 = c^2$$
:::

2.3 Pro-tip: Equation references

If I follow the UX hints I end up using the wrong syntax for aligned referenced equations. The canonical method is, in fact, to use a naked align environment, like so:

Ordinary text before naked LaTeX.

\begin{align}
  f\left(k\right) = \binom{n}{k} p^k\left(1-p\right)^{n-k}
  (\#eq:binom)
\end{align}

An equation reference is \@ref(eq:binom)

This seems like it will not work during the writing because RStudio equation preview is broken for naked mathematical block environments, but in fact other candidate options (e.g. wrapping the {align} environment in $$ will work in preview but produce no output, or broken output, in the various backends.

3 distill for R

Rmarkdown can alternatively target the Distill Web framework. The R binding was formerly called radix. The R package to use Distill is now also called distill. This was confusing to me, because it was not easy to discern from the documentation at the time the relationship between the two projects. I think I understand now?

Distill-for-R is not actually blogdown, but a different way of publishing Rmarkdown to the web than blogdown. The combination is an academic writing system that overlaps in features and toolkit with blogdown but is oriented towards journal article-style typography. As befits such an origin story, it has lavish article and citation metadata support. Emi Tanaka’s comparison makes the points of difference clear. (tl;dr; if you are writing a journal choose distill, if you are writing a blog choose blogdown.)

4 quarto

Quarto is not a blogdown variant, but a re-do which implements many similar features and skips some misfeatures. Probably if I were starting over I would be using it now.

5 hugodown

hugodown is another twist on blogdown. I think it has been essentially eclipsed by quarto.

Hugodown is an experimental package that aims to facilitate the use of RMarkdown and hugo together. It’s similar to blogdown, but is focused purely on Hugo websites, and enforces a stricter partitioning of roles: hugodown is responsible for transforming .Rmd to .md, and hugo is responsible for transforming .md to .html. …it strives to provide the best of blogdown’s two Rmarkdown variants: .Rmd and .Rmarkdown.

Feature hugodown .Rmd blogdown .Rmd blogdown .Rmarkdown
Output .md .html .markdown
Runs R code y y y
Table of contents y n y
Bibliography y y n
MathJax y y ?
HTML widgets y y n
Cross-references n y y
devtools::install_github("r-lib/hugodown")

The documentation is not great — I think this is mostly an internal theme for the Rstudio blog and in particular tidymodels. Source is here. Speed run is here.

The main win over blogdown is the consistent rendering across different posts, particularly of the Table of Contents, and a less flaky preview server.

If something breaks, best steal the working tricks from the default theme from hugo-graphite.

A recommended configuration is using Wowchemy extensions to hugo.

5.1 Pro-tip: hugodown outside RStudio

What is not obvious is the command to compile a page (the manual tells you to click a button, which presumes you are using RStudio, which I do not personally enjoy.) It seems to be

knitr::knit("PATH/TO/FILE", "hugodown::md_document")

but this compiles the output in the wrong place per default. TBC.

5.2 Pro-tip: CSL is not configurable

CSL configuration is not quite done.

5.3 Pro-tip: Shortcodes broken

shortcode support is broken. A pity. That would have been a real win in terms of opening up brainshare from the hugo ecosystem.

6 Bibliographies

I do citation management mainly via zotero, and a custom script.