Fathom Data is working on a project to reproduce the figures from the CORE textbook The Economy using R and {ggplot2}
. There’s a strict style guide which specifies the figure aesthetics including colours and font. We’re a team of seven people working on as many different setups. The principle challenges have been package versions and fonts.
We’ve solved the problem by creating a custom Docker image, which provides both packages and fonts. In retrospect, we should have done this much earlier.
Dockerfile
This is the Dockerfile
describing the image.
FROM rocker/verse:4.0.4
RUN apt-get update -qq && \
apt-get install -y -qq ttf-ubuntu-font-family && \
apt-get -y purge fonts-roboto fonts-roboto-unhinted fonts-lmodern fonts-texgyre && \
# Clean up after apt.
rm -rf /var/lib/apt/lists/*
RUN install2.r -e \
extrafont \
ggnewscale \
ggtext \
googledrive \
gridExtra \
here \
htmlwidgets \
janitor \
patchwork \
plotly \
readxl \
rsvg \
showtext \
gdtools
RUN wget https://cran.r-project.org/src/contrib/Archive/svglite/svglite_1.2.3.2.tar.gz && \
R CMD INSTALL svglite_1.2.3.2.tar.gz && \
rm svglite_1.2.3.2.tar.gz
# Install Google Fonts.
#
ARG GOOGLE_TTF=/usr/share/fonts/truetype/google-fonts
#
RUN git clone git://github.com/google/fonts.git && \
mkdir -p $GOOGLE_TTF && \
find fonts -regex '.*Asap-[a-zA-Z]+\.ttf$' -exec install -Dm644 {} $GOOGLE_TTF \; && \
rm -rf fonts/ && \
fc-cache -f > /dev/null
RUN R -e "library(extrafont); font_import(prompt = FALSE); loadfonts(quiet = FALSE)"
COPY core ./core
RUN cd core && \
R -e "devtools::build(); devtools::install(dependencies = FALSE)"
ENV PASSWORD CORE
Here are the key points:
- It’s based on the 4.0.4 version of the
rocker/verse
image, which means that it immediately includes the most recent version of R, RStudio, all of the{tidyverse}
as well as TeX and other publishing-related packages. - Google Fonts are cloned from their GitHub repository, but only Asap is retained.
- All of the R packages that we’re using are baked into the image.
- To get a specific (older) version of
{svglite}
we download and install from the.tar.gz
archive. - The
{extrafont}
package is used to import system TTF fonts into R. - The
{core}
package (a submodule on our repository), built and maintained by Megan Beckett, is copied across onto the image, built and installed. Specifydependencies = FALSE
to ensure that{svglite}
is not updated! - A default password is set. There’s probably no harm in this since the image will only be used locally.
Running
Create a volume to persist work between sessions.
docker volume create core
Run the image, mounting the volume and exposing port 8787.
docker run -it --rm \
--name rcore \
-p 8787:8787 \
--mount source=core,target=/home/rstudio \
rcore:latest
And access at 127.0.0.1:8787. 🚀
Validation
Validating that the requirements are satisfied.
First check that we have the required version of {svglite}
.
> packageVersion("svglite")
[1] ‘1.2.3.2’
Looks good.
What about fonts?
> library(extrafont)
> fonts()
[1] "Asap" "Asap Medium" "Asap SemiBold" "DejaVu Sans"
[5] "DejaVu Sans Mono" "DejaVu Serif" "Ubuntu" "Ubuntu Light"
[9] "Ubuntu Thin" "Ubuntu Condensed" "Ubuntu Mono"
Yup, everything that we need is there.
Authentication
All of the data for the figures are stored in Google Sheets. An important component of the workflow is authenticating with Google. We wanted this to occur immediately upon loading the {core}
package and the authentication details to be persisted between sessions. Matt Dennis implemented this using the use_oob
option to googledrive::drive_auth()
, checking first for an interactive session to ensure that it wasn’t triggered during package build.
.onLoad <- function(libname, pkgname) {
if (interactive()) {
googledrive::drive_auth(use_oob = TRUE)
}
}
With this setup we have everything we need to create the figures in a stable, reproducible environment. No need to install fonts or packages. Rather than worrying about technical issues, we can focus on the figures.
📢 Thanks to the maintainers of the version-stable Rocker images, which made putting this together a lot easier.