save_kable() in R does not compile LaTeX table

Viewed 356

I'm working on a convenience function in R that prints a publication quality LaTeX table from some common model objects. It all works just great for me on my Mac, but I've built it largely for a colleague who's on a PC, for whom the file writing fails when calling save_kable() from the kableExtra package.

We get no output whatsoever from this. No pdf and no error messages.

A simple reproducible example, which fails in the same way, is as follows:

library(knitr)
library(here)
library(kableExtra)

outfile = here("test_table.png")
table = head(iris)
latex =  kable(x = table, format = "html")
save_kable(x = latex, file = outfile)

When using as_image(), we get the following "cannot find file" error:

Error in include_graphics(temp_png, dpi = img_dpi) : Cannot find the file(s): "C:/R Projects/export-anova/test.pdf"

which has been talked about before in the context of blogdown. But that's not our context.

Other potentially relevant tidbits:

  1. We can save table images with format = 'html', but they are not formatted properly. We want booktabs.
  2. If we use the above to output LaTeX code, rather than a file, then Knit with RMarkdown, we do get the correct output, but it's a full page document that needs to be cropped.
  3. Same results with extensions .pdf, .png, and .jpeg

Running Windows 10, R version 4.1.2, and kableExtra version 1.3.4. The LaTeX settings in RStudio are below.

Any ideas? Seems like we're so close!

enter image description here

1 Answers

The problem turned out to be missing LaTeX dependencies. The kableExtra package creates a .tex file with a long list of required packages (see below), but MikTex, the Tex distribution we were using, was unable to automatically install them, and the errors didn't propagate through to R. Here is a post with some useful details.

There are a number of solutions, each for a different distribution.

  1. Use TexLive, rather than MikTex. I use TexLive on my Mac, and it appears to have no trouble locating and installing the dependencies. The downside is that it's gigantic (>7GB to MikTex's <1GB).

  2. For MikTex, you can get the packages downloaded with a combination of two approaches. First, set keep_tex = TRUE in kableExtra::save_kable(), which should produce the .tex file for compilation. Next, compile it at the command line with xelatex yourtable.tex. You can't use latex yourtable.tex, since this compiler can't work with the required fontspec package. This may download all that you need. If it doesn't, check the log file for a missing .sty file: we needed to manually download the tabu package. You can manually install the missing files from MikTex Console: Packages > Search for "tabu" > "+" to install. Rinse, repeat until you have all the packages you need. You could do this for all the dependencies, but there are a lot, so might as well let the compiler do as much work as possible first, then backfill as needed.

  3. Compile with TinyTex in R. Create the .tex file as above (`keep_tex = TRUE'). Then:

install.packages("tinytex")
tinytex::install_tinytex()
tinytex::xelatex("mytable.tex")

TinyTex will automatically download the required packages and should compile a pdf. The benefit is that you don't need a beefy Tex distro, but you need the added step of creating the tex file, then manually compiling.

Here's the .tex file generated for the example above:

\documentclass[border=1mm, preview]{standalone}
\usepackage[active,tightpage]{preview}
\usepackage{varwidth}
\usepackage{amssymb, amsmath}
\usepackage{ifxetex,ifluatex}
\usepackage{fixltx2e}
\usepackage{polyglossia}
\usepackage{booktabs}
\usepackage{longtable}
\usepackage{array}
\usepackage{multirow}
\usepackage{wrapfig}
\usepackage{float}
\usepackage{colortbl}
\usepackage{pdflscape}
\usepackage{tabu}
\usepackage{threeparttable}
\usepackage{threeparttablex}
\usepackage[normalem]{ulem}
\usepackage[utf8]{inputenc}
\usepackage{makecell}
\usepackage{xcolor}
\usepackage{graphicx}
\usepackage{xltxtra,xunicode}
\usepackage{xcolor}
\begin{document}

\begin{tabular}{rrrrl}
\toprule
Sepal.Length & Sepal.Width & Petal.Length & Petal.Width & Species\\
\midrule
5.1 & 3.5 & 1.4 & 0.2 & setosa\\
4.9 & 3.0 & 1.4 & 0.2 & setosa\\
4.7 & 3.2 & 1.3 & 0.2 & setosa\\
4.6 & 3.1 & 1.5 & 0.2 & setosa\\
5.0 & 3.6 & 1.4 & 0.2 & setosa\\
5.4 & 3.9 & 1.7 & 0.4 & setosa\\
\bottomrule
\end{tabular}
\end{document}
Related