knitr has support for executing tikz blocks in a Rmarkdown/quarto document and can even output an svg for html using the following block syntax.
```{R, engine = "tikz"}
#| fig-ext: svg
\begin{tikzpicture}[scale=2]
\node (A) at (0,0) {Hello};
\node (B) at (1,0.5) {Entire};
\node (C) at (1,-0.5) {World};
\draw[->] (A) -- (B);
\draw[->] (A) -- (C);
\end{tikzpicture}
```The only issue when using svg output is that we cannot access system fonts using fontspec. From knitr/R/engine.R in the knitr::eng_tikz function, knitr calls tinytex::latexmk with the latex backend since neither xelatex or lualatex support dvi output, and then feeds the dvi output to dvisvgm to convert to the final svg product.
ext = dev2ext(options)
to_svg = ext == 'svg'
outf = if (to_svg) tinytex::latexmk(texf, 'latex') else tinytex::latexmk(texf)
fig = fig_path(if (to_svg) '.dvi' else '.pdf', options)
dir.create(dirname(fig), recursive = TRUE, showWarnings = FALSE)
file.rename(outf, fig)
fig2 = with_ext(fig, ext)
if (to_svg) {
# dvisvgm needs to be on the path
# dvisvgm for windows needs ghostscript bin dir on the path also
if (Sys.which('dvisvgm') == '') tinytex::tlmgr_install('dvisvgm')
if (system2('dvisvgm', c(
options$engine.opts$dvisvgm.opts, '-o', shQuote(fig2), fig
)) != 0) stop('Failed to compile ', fig, ' to ', fig2)
} else {
# convert to the desired output-format using magick
if (ext != 'pdf') magick::image_write(do.call(magick::image_convert, c(
list(magick::image_read_pdf(fig), ext), options$engine.opts$convert.opts
)), fig2)
}Unfortunately, fontspec doesn’t support latex. But, dvisvgm does accept xdv (extended dvi) input, which we can create using xelatex. This isn’t currently supported by knitr so either patch the eng_tikz function or create a standalone TeX document for each diagram. For example, we could have a file diagram.tex.
\documentclass[12pt,tikz,dvisvgm]{standalone}
\usepackage{fontspec}
\usepackage{tikz}
\setmainfont{Jost-400-Book.otf}
\begin{document}
\begin{tikzpicture}[scale=2]
\node (A) at (0,0) {Hello};
\node (B) at (1,0.5) {Entire};
\node (C) at (1,-0.5) {World};
\draw[->] (A) -- (B);
\draw[->] (A) -- (C);
\end{tikzpicture}
\end{document}Compile to xdv by disabling pdf output with xelatex and then convert using dvisvgm with the bonus that we can embed our font into the svg.
$ xelatex -no-pdf diagram.tex
$ dvisvgm -c 3 --font-format=woff2 diagram.xdvFinally, we can embed this in a markdown document.
