knitr::opts_chunk$set( collapse = TRUE, comment = "#>" ) library(knitrdrawio)
It feels natural and intuitive to use knitrdrawio as part of a Continuous Integration / Continuous Deployment (CI/CD) workflow, for example to automatically your document or book, each time you push a commit.
However, CI/CD typically runs in a headless environment, a server without a graphical display, and/or in Docker containers.
knitrdrawio requires additional dependencies to work in such environments, because of known limitations of the draw.io executable. Being an Electron-based application, draw.io expects and requires a graphical display, and needs to be tricked into thinking there is one available.
Note: if your system is mis-configured, knitrdrawio might believe to
be in a headless environment, and complain!
In this case, you must make sure that your $DISPLAY
environment variable
is correctly set, so that knitrdrawio (and, more importantly, drawio itself)
may find your display.
In particular, if the $DISPLAY
variable is empty, there certainly is a problem.
Two methods are available:
knitrdrawio provides a complete Docker image which already contains all necessary dependencies, such as R, knitr, pandoc, draw.io, etc.
This image is automatically built against the latest release of knitrdrawio, so you can safely use it in your workflows, or reuse it as a base for your own images.
This image can be accessed as ghcr.io/rchaput/knitrdrawio:master
, e.g.,
FROM ghcr.io/rchaput/knitrdrawio:master RUN apt install <your-custom-dependencies> RUN R -e 'rmarkdown::render("your_document.Rmd")'
Note: this image is inspired from rocker/r-rmd, which includes every dependency for rendering documents, including a TeX distribution (for PDF output). It was meant as a ready-to-use tool, for which you do not have to worry: simply bring your own custom dependencies (if any), and let the image do the job for you. However, this results in a very large image size (several GBs).
You may also manually install the dependencies: knitrdrawio internally has support for some tools and workarounds to make draw.io work when these tools are available.
First, you need to install on the system the following dependencies:
These system dependencies can be simply installed through your distribution's
package manager, e.g., apt
for Ubuntu and Debian-derivatives systems.
Please check with your package manager for the appropriate packages, the
name might differ.
Then, you may simply render your document: everything will work, thanks to knitrdrawio's internal detection and workaround.
To summarize, assuming an Ubuntu (or Debian) based environment:
sudo apt update
sudo apt install libdrm2 libgbm1 libasound2 xvfb
R -e 'rmarkdown::render("your_document.Rmd")'
However, please note that the previously described steps induce a small
overhead: knitrdrawio internally relies on xvfb-run
to create a "fake"
graphical server each time a diagram should be rendered. This process takes
an additional time, and, as the number of diagrams in the document increases,
the overhead might become noticeable.
To avoid this and optimize for performance, an additional step can be performed, using the same dependencies. This method creates a virtual server before knitrdrawio is launched, using the same virtual server for all diagrams. Thus, the overhead of starting a virtual server is paid only once.
To do so, before rendering your document, choose a display number, which must
be unique on the machine. Usually, 99
should work.
Set the $DISPLAY
environment variable to :<your number>
, e.g.,
export DISPLAY=:99
(do not forget the :
part).
Then, start the virtual server with Xvfb &
.
You can now render your document: the virtual server, as a background process, will make knitrdrawio (and, ultimately, draw.io) believe there is a graphical server available.
The complete workflow should look like this, assuming an Ubuntu (or Debian) based distribution:
sudo apt update sudo apt install libdrm2 libgbm1 libasound2 xvfb export DISPLAY=:99 Xvfb & R -e 'rmarkdown::render("your_document.Rmd")'
Note that the first two lines (apt update
and apt install
) are the same
as previously, and need to be executed only once. The following two
(export DISPLAY
and Xvfb &
) need to be executed once in a session, i.e.,
until your close your terminal. Finally, the last line performs the rendering,
and can be executed as much as desired. As long as the background process is
available, the rendering will work.
By default, knitrdrawio tries to detect whether the current system is
headless, by relying on the xrandr
tool, or, if it is not available, the
$DISPLAY
environment variable.
If, for some reason, this detection does not work, or you want to increase performance by avoiding this check every time a chunk is rendered, the detection can be bypassed by setting a global option:
```r options("knitrdrawio.headless" = FALSE) ```
This option is applied to all subsequent calls to the knitrdrawio engine,
and should thus be placed as early as possible.
A common place for global options is the .Renv
file, which is loaded by R
at the beginning of a session.
Using a .Renv
file makes it easy to have different configurations for a local
development system versus a CI/CD headless workflow.
The following values are recognized:
NULL
(default): perform the headless-detection each time.FALSE
: assume the system is not headless, do not perform the detection.TRUE
: assume the system is headless, do not perform the detection, and
always apply the "headless workaround" through xvfb
.Warning: drawio will fail if the system is headless but no workaround, such
as xvfb
, is set up. You may also use the FALSE
value to disable
knitrdrawio's built-in workaround, if you prefer to manually set up another
one.
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.