4

This is presumably related to latex kable side-by-side tables "Not in outer par mode" but the solution identified by the author, to use latex_options = c("Hold_position") is not changing the outcome for me when I try to knit to PDF. The author's full comment reads:

I got the tables to display side-by-side by adding kable_styling(latex_options = c("striped", "Hold_position")).

Here is a minimal example that works fine:

---
title: "Example Document"
date: "Last compiled on `r format(Sys.time(), '%d %B, %Y at %H:%M ')`"
output: pdf_document
---

```{r setup, include=FALSE, echo=FALSE}
library(tidyverse)
library(kableExtra)
```

``` {r species}  
kable(caption = "Species",
      starwars %>%
        count(species) %>%
        filter(n > 1)
) %>% kable_styling(latex_options = c("striped", "Hold_position"))    
```

``` {r planet} 
 kable(caption = "Homeworld",
      starwars %>%
        count(homeworld) %>%
        filter(n > 1)
    )%>% kable_styling(latex_options = c("striped", "Hold_position"))
```

When I use knitr::kables to combine them into a pair of side-by-side tables, I can run the code chunk and knit to HTML just fine, but I'm still getting a "not in outer par mode" error:

! LaTeX Error: Not in outer par mode.

Error: LaTeX failed to compile 10_knit_doesnt.tex. See https://yihui.org/tinytex/r/#debugging for debugging tips. See 10_knit_doesnt.log for more info.
Execution halted

The actual code chunk is this:

``` {r side by side} 

knitr::kables(list(
  kable(caption = "Species",
    starwars %>%
      count(species) %>%
      filter(n > 1)
    ) %>% kable_styling(),
    kable(caption = "Homeworld",
      starwars %>%
        count(homeworld) %>%
        filter(n > 1)
    ) %>% kable_styling()
    
  )
) %>% kable_styling(latex_options = c("striped", "Hold_position"))
```

I've tried moving the styling (kable_styling(latex_options = c("striped", "Hold_position")) ) into the individual tables, but that doesn't seem to have any impact.

knitr::kables(list(
  kable(caption = "Species",
    starwars %>%
      count(species) %>%
      filter(n > 1)
    ) %>% kable_styling(latex_options = c("striped", "Hold_position")),
    kable(caption = "Homeworld",
      starwars %>%
        count(homeworld) %>%
        filter(n > 1)
    ) %>% kable_styling(latex_options = c("striped", "Hold_position"))
    
  )
) %>% kable_styling()

Can I knit to PDF while using side-by-side tables?

Amanda
  • 12,099
  • 17
  • 63
  • 91

1 Answers1

0

Yes, you can knit to PDF while using side-by-side tables. The following code results in side by side tables of your example data. Explanation and sample .rmd below.

```{r working solution, results = "asis"}
library(tidyverse)
library(knitr)
library(kableExtra)

species.table = kbl(format = "latex",  booktabs = TRUE,
  starwars %>%
    count(species) %>%
    filter(n > 1)
) %>% kable_styling(latex_options = c("striped", "Hold_position"))

planet.table = kbl(format = "latex", booktabs = TRUE,
  starwars %>%
    count(homeworld) %>%
    filter(n > 1)
)%>% kable_styling(latex_options = c("striped", "Hold_position"))

species.table = substr(species.table, start = 25, stop = nchar(species.table) - 11)
planet.table = substr(planet.table, start = 25, stop = nchar(planet.table) - 11)

# The following code is from a similar SO question: 
# https://stackoverflow.com/a/38037481/15293705

cat(c("\\begin{table}[!htb]
  \\begin{minipage}{.5\\linewidth}
    \\caption{Species Table}
    \\centering",
    species.table,
  "\\end{minipage}%
  \\begin{minipage}{.5\\linewidth}
    \\centering
    \\caption{Planets Table}",
    planet.table,
  "\\end{minipage}
  \\end{table}"
  ))
```

The sample code errors out because your initial tables are being wrapped in their own \begin{table}->\end{table} environments, and then kables comes in and tries to wrap both of them in its own table environment. Latex sees something like \begin{table}->\begin{table} and errors out.

Stripping the \begin{table} and \end{table} (and a loose \centering) commands from both inner tables allows us to use a previous SO solution to output the tables.

The following .rmd file demonstrates and walks through how this solution was obtained.

---
title: "Solved Example Document"
author: "Carbiner"
date: "`r Sys.Date()`"
output: pdf_document
---

```{r setup, include=FALSE, echo=FALSE}
library(tidyverse)
library(knitr)
library(kableExtra)
```

Let's take a look at what our tables actually look like, under the hood. Note that I've changed the format to "latex", because the solution to this problem works best when it's directly specified. 

``` {r species}  
species.table = kbl(format = "latex",  booktabs = TRUE,
  starwars %>%
    count(species) %>%
    filter(n > 1)
) %>% kable_styling(latex_options = c("striped", "Hold_position"))

print(species.table)

```


Looks fine. The table has a table enviornment, which is centered, and a tabular enviornment. 

``` {r planet} 
planet.table = kbl(format = "latex", booktabs = TRUE,
  starwars %>%
    count(homeworld) %>%
    filter(n > 1)
    )%>% kable_styling(latex_options = c("striped", "Hold_position"))

print(planet.table)
```

Same thing here. All looks good. These tables both output normally.

But what does `kables` do?

```{r no good}

no.good = kables(list(species.table, planet.table))

print(no.good)

```

`kables` puts the both planets and species into an overarching table environment. The double `\begin{table} \begin{table}` is what seems to kill latex. The first is coming from `kables`, the second comes from the species table. 

`kables` works for latex output when the original table doesn't wrap everything in a table environment. Wrapping things in a table environment seems to happen when certain formatting options (such as `striped`) are used. 

A solution is to strip out the commands that create the inner table environments. Because these are internally character vectors, we can use substring to slice out the commands we don't want. 

Doing this stops kables from working properly (not that it was), so we're going to borrow some other SO code to make them output. 

```{r hacky hacky, results = "asis"}

# 25 characters in is after the initial \begin{table} 
# and \centering commands, which we don't want to include.

# The last 11 characters are the \end{table} command
# which we also don't want to include. 

species.table = substr(species.table, start = 25, stop = nchar(species.table) - 11)
planet.table = substr(planet.table, start = 25, stop = nchar(planet.table) - 11)

# The following code is from a similar SO question: 
# https://stackoverflow.com/a/38037481/15293705

cat(c("\\begin{table}[!htb]
  \\begin{minipage}{.5\\linewidth}
    \\caption{Species Table}
    \\centering",
    species.table,
  "\\end{minipage}%
  \\begin{minipage}{.5\\linewidth}
    \\centering
    \\caption{Planets Table}",
    planet.table,
  "\\end{minipage}
  \\end{table}"
  ))

```

This should output the tables properly. I haven't tested if all formatting commands still work, but `booktabs`, `striped` do. 

It should be noted that this solution relies on string subsetting, which is greatly aided by setting the table format to "latex" when creating them. String subsetting is also...hacky, and relies entirely on the behavior of kable and kables not being fixed.

This works great for latex tables going to PDF. If you intend to output to multiple formats, or do not want to use latex, you might have to find another workaround.

Carbiner
  • 11
  • 3