1
votes

This is a follow-on question to this. I'm aware that the canonical method for cross-referencing figures and tables in a PDF produced by knitr is to use bookdown::pdf_document2 (details here).

This is awesome! But suppose that I want to send my Rmd to a user who doesn't have bookdown already installed? How can I ensure that the document will render if knitted in an environment in which bookdown is not already installed? I want to have everything self-contained in a single Rmd file. The consumer of the document might be someone with little or no prior experience of R, and has just installed R and RStudio but no packages. How can I ensure that if they click knit that they will get the PDF with cross-references? Alternatively, what if Binder or similar provide the means to execute (or, better still, knit to PDF) Rmd files in much the same way as is done with Jupyter Notebooks -- I'd like to be able to bundle everything that is needed for rendering the PDF in an automated way in the Rmd file itself.

An example document looks like this:

---
title: "Cross-refs test"
author: "Me"
date: "13 December 2017"
output:
  bookdown::pdf_document2:
    citation_package: natbib
    fig_caption: yes
    keep_tex: yes
---

```{r setup, include=FALSE}
knitr::opts_chunk$set(echo = TRUE)
```

## Title

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

You may refer to it using `\@ref(eq:binom)`, e.g., see Equation \@ref(eq:binom).

So if this Rmd file is downloaded and knit by a brain-dead zombie, or by Binder, how can I make sure that this doesn't happen:

Error in loadNamespace(name) : there is no package called 'bookdown'
Calls: <Anonymous> ... tryCatch -> tryCatchList -> tryCatchOne -> <Anonymous>
Execution halted

I can't assume that a consumer of my Rmd will know what to do in this situation, nor any automated process that I don't control that renders a PDF from the Rmd that it grabs from a repo somewhere (like what Binder does).

If there are no cross-references, I can specify pdf_document as the output format and RStudio will read the YAML and if knitr and rmarkdown are not installed, installation of these will be triggered automatically (the user/brain-dead zombie just has to click on "OK" to accept installation) and the PDF will be rendered. So if these two packages are missing: no problem, at least when using RStudio. User gets Rmd, installs R and Rstudio, knits the Rmd, and the PDF appears. The same is not true if using bookdown to get cross-referencing.

It seems the YAML is interpreted before R code is executed, so the same kind of logic as this that is used to print the current time in a document (date: "`r Sys.time()`") doesn't work. Otherwise, I'd r install.packages("bookdown") here.

So, is there a method to do cross-referencing without bookdown, but as simply and as elegantly as with bookdown, or is there someway of triggering knitr to install bookdown such that rendering won't crash when encountering bookdown::pdf_document2?

Basically, what I want is cross-references in a knitted PDF with minimal user intervention to make it happen -- 'cos my user might be a brain-dead zombie or robot.

I want to avoid hard-coding cross-refs. And I'd rather not use LaTeX. Just pure R Markdown and some knitr magic, if possible.

1
I don't remember if rmarkdown is also installed by default in Rstudio, but this is the same problem. Maybe the only solution is to create an associated R script, you put it in your github for instance, and ask the person to copy-paste the command in the console like source("https://github.com/.../myfile.R"). Then, he can knit.Sébastien Rochette
Thanks, that's a solution that I'm aware of, but I explicitly want to avoid requiring the users to copy-paste code to render the documents. Here's why: I'm trying to encourage reproducible research in my field. There is incredible resistence in my community to learning a new tool to facilitate reproducible research. If I say, "just copy-paste this line" --- they've already tuned out. Not that they're lazy, per se, just that people have absolutely no spare brain capacity for "just type this line". Please assume my users are lazy brain-dead zombies. The solution must be that simple.Andrew John Lowe
Then why do you think they'll be able to open and modify a Rmd, and then knit it ! Learn them how to install packages with the click menu. Show them how nice it is to be able to output the document in pdf, html, and doc at the same time. Before speaking about reproducible science, try to show how easy it is to produce nice document. Etc... Good luck.Sébastien Rochette
I explictly do not want them to modify the Rmd. My users do not want to learn another tool. They are academics who are already working +80 hours a week and have absolutely no spare capacity to learn a new tool -- that's time that they would be spending instead on writing grant applications, papers, and things that improve their chances of getting tenure. That's the reality, which is why the solution must be as simple as possible, and not require them to learn anything -- at least until they've seen that it's worth investing their time in.Andrew John Lowe
I perfectly know what is academics ! I only tried to find a better way to help you. I do not have other ideas for the moment... ;-)Sébastien Rochette

1 Answers

2
votes

There are a couple of ways to go:

  1. The easiest way to avoid technical problems is that you preinstall everything "on the cloud" and let your users use the "cloud". For example, you can install RStudio Server, and preinstall all packages required to build your documents. Then all your users need is a web browser. If you ask them to install packages locally on their computers, it is already complicated enough to install R, RStudio, and LaTeX, and I'm not convinced they would cry over one more thing to install: install.packages('bookdown').

  2. If they have to install everything locally, and a command install.packages('bookdown') turns out to be still a huge pain, what you could do is create an RStudio project with packrat enabled (or enable packrat in an existing project). This should make sure all necessary R packages are available when users work with this project.

For more background on why I don't want to backport this feature to the rmarkdown package, see this Github issue.