kableExtra::landscape() LaTeX Error: Environment landscape undefined

rmarkdown
rstudio
latex

#1

Hi,

I'm trying to directly produce a PDF report from an R script using rmarkdown::render() and wanted to place a wide table onto it's own landscape orientated page. I was happy to find a solution using the kableextra package, as described here:

Rotate a table from R markdown in pdf

However, when I try to render the R script to produce the PDF file, I get the following error:

LaTeX Error: Environment landscape undefined.

System:
R version 3.5.0 (2018-04-23)
Platform: x86_64-w64-mingw32/x64 (64-bit)
Running under: Windows >= 8 x64 (build 9200)

Below is example code that will produce the error on my machine:

#' ---
#' title: "Test title"
#' author: "Pirates"
#' date: "`r format(Sys.time(), '%Y-%m-%d')`"
#' ---

library(knitr)
library(kableExtra)

dt <- mtcars[1:5, 1:6]

knitr::kable(dt, "latex", caption = "Demo Table (Landscape)[note]", booktabs = T) %>%
  kable_styling (latex_options = c("hold_position")) %>%
  add_header_above( c(" ", "Group 1[note]" = 3, "Group 2[note]" = 3)) %>%
  add_footnote( c  ("This table is from mtcars",
                    "Group 1 contains mpg, cyl and disp",
                    "Group 2 contains hp, drat and wt"),
                notation = "symbol") %>%
  group_rows("Group 1", 4, 5) %>%
  landscape()

Compiling the report with:

rmarkdown::render("test_kableextra_landscape_bad.R", "pdf_document")

producing the error:

LaTeX Error: Environment landscape undefined.

There is a second strange problem. If I do not include any meta-data and execute only R code, then the latex error does not occur and it produces a table on a landscape orientated page. However, this only works if I start in a fresh RStudio session without trying to render() the above bad code (that produced the error).

The R code below has no meta-data comments. It will compile only if the above example and resulting error is NOT run. Once the above example is run, then the below code will produce the same error.

It would appear the pandoc/latex build process is corrupted in some way to affect the compiling of other R documents.

library(knitr)
library(kableExtra)

dt <- mtcars[1:5, 1:6]

knitr::kable(dt, "latex", caption = "Demo Table (Landscape)[note]", booktabs = T) %>%
  kable_styling (latex_options = c("hold_position")) %>%
  add_header_above( c(" ", "Group 1[note]" = 3, "Group 2[note]" = 3)) %>%
  add_footnote( c  ("This table is from mtcars",
                    "Group 1 contains mpg, cyl and disp",
                    "Group 2 contains hp, drat and wt"),
                notation = "symbol") %>%
  group_rows("Group 1", 4, 5) %>%
  landscape()

Compiling using the following command:

rmarkdown::render("test_kableextra_landscape_good.R", "pdf_document")

I could only find the following example of the problem in the wild.

How to knit to landscape() using kableExtra?

However, the only solution was to drop the kableextra::landscape() function.. whilst I'd like a solution.

Thanks!


#2

If you're using pdflatex you should add the pdflscape package to your preamble:

\usepackage{pdflscape}

#3

Thanks, I'm using MikTex 2.9 and pdflscape is already installed via the oberdiek bundle.

The pdflscape package appears to be working correctly because the compiled R script that has no meta-data produces the correctly formatted PDF. However, once I compile the R script with meta-data ( e.g. #' title: "Test title" it fails with the previously described problems.


#4

Have you explicitly added pdflscape to your preamble as suggested? You can (I think) do it like this:

header-includes:
   - \usepackage{pdflscape}

or alternatively:

        includes:
            in_header: filename.tex

where filename.tex is a file with some usepackage statements.


#5

Thank you @hughjonesd for your help.

Maybe I should be more clear. I'm not actually choosing to use pdflscape as such. All I'm trying to do is use kableExtra::landscape() which in turn calls miktex behind the scenes. So I'm not making any choices regarding tex coding.

I had assumed that kableExtra would import the necessary packages for it to work. Unless there is something wrong with my environment.

I tried what you have suggested, but it produced the same error unfortunately.

#' ---
#' title: "Test title"
#' author: "Pirates"
#' date: "`r format(Sys.time(), '%Y-%m-%d')`"
#' output: 
#'   always_allow_html: yes
#'   pdf_document:
#'     fig_caption: yes
#'     latex_engine: xelatex
#' includes: 
#'   in_header: test_header.tex
#' ---

library(knitr)
library(kableExtra)

dt <- mtcars[1:5, 1:6]

knitr::kable(dt, "latex", caption = "Demo Table (Landscape)[note]", booktabs = T) %>%
  kable_styling (latex_options = c("hold_position")) %>%
  add_header_above( c(" ", "Group 1[note]" = 3, "Group 2[note]" = 3)) %>%
  add_footnote( c  ("This table is from mtcars",
                    "Group 1 contains mpg, cyl and disp",
                    "Group 2 contains hp, drat and wt"),
                notation = "symbol") %>%
  group_rows("Group 1", 4, 5) %>%
  landscape()

Where, test_header.tex contains:

\usepackage{pdflscape}

Executing the command:

rmarkdown::render("test_kableextra_landscape_bad.R", "pdf_document")

Produces the same error:

LaTeX Error: Environment landscape undefined.

pdflscape is installed in Miktex 2.9 becauase oberdiek](https://miktex.org/packages/oberdiek) is installed.

Why would a package available in Miktex not be available to latex called within RStudio?


#6

Not exactly answering your question but if you can, I'd highly suggest uninstalling Miktex and installing tinytex instead.

If I use tinytex, your script knits just fine without any header configuration nonsense (note that I didn't need to specify the latex engine or anything).

---
title: "Cool Example Bro"
output: pdf_document
---

```{r}
library(kableExtra)

dt <- mtcars[1:5, 1:6]

knitr::kable(dt, "latex", caption = "Demo Table (Landscape)[note]", booktabs = T) %>%
  kable_styling (latex_options = c("hold_position")) %>%
  add_header_above( c(" ", "Group 1[note]" = 3, "Group 2[note]" = 3)) %>%
  add_footnote( c  ("This table is from mtcars",
                    "Group 1 contains mpg, cyl and disp",
                    "Group 2 contains hp, drat and wt"),
                notation = "symbol") %>%
  group_rows("Group 1", 4, 5) %>%
  landscape()


#7

Thanks @rywhale, I uninstalled Miktex and installed TinyTex via the R package. (I had permission problems relating to the temp directory for some reason, but running the install command tinytex::install_tinytex( force = T, dir = "c:\Data\user1234\Program Files\TinyTex") twice fixed it..??)

The example now works!!! So it was a problem with Miktex. Thanks for the heads up, I had never heard of TinyTex, it looks to be a great idea.