rlatexr-markdownkableextra

R Markdown latex/pdf output conditional formatting with kableExtra outputting latex commands without evaluating them


Hard to come up with a handy short title for this question, sorry.

Background and Goal

I'm working on a PDF report using RMarkdown, and have need to conditionally format one of my tables. I've managed to get this to work just fine with HTML conditional formatting, but I am running into problems with conditional formatting for PDF export.

The goal is to conditionally format the background of a cell if the value in the cell is 0, and leave the background blank if the value is not. The custom colours in the MWE below are from my preamble.tex, so that's not the problem I'm running into.

MWE chunks are below, with both sample data and the kable arguments.

MWE


``` {r packages, message = FALSE, echo = FALSE}
## Load required packages
library(tidyverse)
library(kableExtra)
```
``` {r mwe-data}
## Create MWE Data Example
mwe_data <- tibble(
  proj_na = rep(paste("PROJECT", 1:10), 5),
  proj_yr = rep(2020:2024, each = 10),
  proj_st = sample(rep(c(0, 1), each = 10), 50, replace = TRUE)
)

## Kable Output
mwe_data %>% 
  mutate(
    proj_st = cell_spec(
      proj_st,
      format     = "latex",
      bold       = TRUE,
      background = case_when(
        proj_st == 0 ~ "mpsred!50",
        TRUE         ~ "mpswine!0"
      )
    )
  ) %>% 
  pivot_wider(
    names_from  = proj_yr,
    values_from = proj_st
  ) %>% 
  kable(
    format    = "latex",
    booktabs  = TRUE,
    align     = "lccccc",
  ) %>% 
  kable_styling(latex_options = c("HOLD_position", "repeat_header")) %>% 
  row_spec(row = 0, color = "mpswine", align = "c")

```

Outputs and Errors

First Attempt

When I knit the document with the above code chunks, I get a PDF output that looks like the following:

LaTeX code showing in table output

Obviously, this is not what I want. That said, it is correctly adding \cellcolor{mpsred!50} and \cellcolor{mpswine!0} to the correct cells, so that's good. After some googling and searching around stack overflow, I found that I should add the escape=FALSE argument to my kable().

Second Attempt

I added the escape=FALSE argument to kable() and tried to knit the document. Unfortunately, the document won't knit with escape=FALSE. I get the following error in the console:

! Missing $ inserted. $ l.113 ...icolumn{1}{c}{\textcolor{mpswine}{proj_na}} & \multicolumn{1}{c}> {\tex...

Try to find the following text in testing.Rmd: ...icolumn{1}{c}{\textcolor{mpswine}{proj_na}}

You may need to add $ $ around a certain inline R expression r in testing.Rmd (see the above hint). See https://github.com/rstudio/rmarkdown/issues/385 for more info. Error: LaTeX failed to compile testing.tex. See https://yihui.org/tinytex/r/#debugging for debugging tips. See testing.log for more info. Execution halted

The .log file shows the same error, but it did keep the .tex file it tried to generate. The table from the .tex file looks like this:

\begin{table}[H]
\centering
\begin{tabular}{lccccc}
\toprule
\multicolumn{1}{c}{\textcolor{mpswine}{proj_na}} & \multicolumn{1}{c}{\textcolor{mpswine}{2020}} & \multicolumn{1}{c}{\textcolor{mpswine}{2021}} & \multicolumn{1}{c}{\textcolor{mpswine}{2022}} & \multicolumn{1}{c}{\textcolor{mpswine}{2023}} & \multicolumn{1}{c}{\textcolor{mpswine}{2024}}\\
\midrule
PROJECT 1 & \cellcolor{mpswine!0}{\textbf{1}} & \cellcolor{mpswine!0}{\textbf{1}} & \cellcolor{mpsred!50}{\textbf{0}} & \cellcolor{mpswine!0}{\textbf{1}} & \cellcolor{mpsred!50}{\textbf{0}}\\
PROJECT 2 & \cellcolor{mpsred!50}{\textbf{0}} & \cellcolor{mpswine!0}{\textbf{1}} & \cellcolor{mpswine!0}{\textbf{1}} & \cellcolor{mpswine!0}{\textbf{1}} & \cellcolor{mpsred!50}{\textbf{0}}\\
PROJECT 3 & \cellcolor{mpswine!0}{\textbf{1}} & \cellcolor{mpsred!50}{\textbf{0}} & \cellcolor{mpsred!50}{\textbf{0}} & \cellcolor{mpswine!0}{\textbf{1}} & \cellcolor{mpswine!0}{\textbf{1}}\\
PROJECT 4 & \cellcolor{mpsred!50}{\textbf{0}} & \cellcolor{mpswine!0}{\textbf{1}} & \cellcolor{mpsred!50}{\textbf{0}} & \cellcolor{mpswine!0}{\textbf{1}} & \cellcolor{mpswine!0}{\textbf{1}}\\
PROJECT 5 & \cellcolor{mpswine!0}{\textbf{1}} & \cellcolor{mpswine!0}{\textbf{1}} & \cellcolor{mpsred!50}{\textbf{0}} & \cellcolor{mpsred!50}{\textbf{0}} & \cellcolor{mpswine!0}{\textbf{1}}\\
\addlinespace
PROJECT 6 & \cellcolor{mpsred!50}{\textbf{0}} & \cellcolor{mpswine!0}{\textbf{1}} & \cellcolor{mpsred!50}{\textbf{0}} & \cellcolor{mpsred!50}{\textbf{0}} & \cellcolor{mpsred!50}{\textbf{0}}\\
PROJECT 7 & \cellcolor{mpsred!50}{\textbf{0}} & \cellcolor{mpsred!50}{\textbf{0}} & \cellcolor{mpswine!0}{\textbf{1}} & \cellcolor{mpsred!50}{\textbf{0}} & \cellcolor{mpsred!50}{\textbf{0}}\\
PROJECT 8 & \cellcolor{mpswine!0}{\textbf{1}} & \cellcolor{mpswine!0}{\textbf{1}} & \cellcolor{mpsred!50}{\textbf{0}} & \cellcolor{mpsred!50}{\textbf{0}} & \cellcolor{mpsred!50}{\textbf{0}}\\
PROJECT 9 & \cellcolor{mpswine!0}{\textbf{1}} & \cellcolor{mpswine!0}{\textbf{1}} & \cellcolor{mpsred!50}{\textbf{0}} & \cellcolor{mpsred!50}{\textbf{0}} & \cellcolor{mpsred!50}{\textbf{0}}\\
PROJECT 10 & \cellcolor{mpswine!0}{\textbf{1}} & \cellcolor{mpsred!50}{\textbf{0}} & \cellcolor{mpsred!50}{\textbf{0}} & \cellcolor{mpsred!50}{\textbf{0}} & \cellcolor{mpswine!0}{\textbf{1}}\\
\bottomrule
\end{tabular}
\end{table}

The table looks mostly correctly formatted for latex, though I'm assuming the & is what's breaking the knitting at this point.

Third Attempt

I thought maybe escape=FALSE might belong in the cell_spec() call, but that doesn't work either. I get the document to knit, but I get the same output as in the screenshot above.

Fourth Attempt

I did some digging, and the new documentation on kableExtra says to use column_spec() for conditional formatting, rather than cell_spec(), so I tried the following code:

``` {r mwe-test2}

mwe_data1 <- mwe_data %>% 
  pivot_wider(
    names_from  = proj_yr,
    values_from = proj_st
  ) 

mwe_data1 %>% 
  kable(
    format    = "latex",
    booktabs  = TRUE,
    align     = "lccccc",
  ) %>%
  kable_styling(latex_options = c("HOLD_position", "repeat_header")) %>%
  row_spec(row = 0, color = "mpswine", align = "c") %>% 
  column_spec(
    column = 2:6,
    bold = TRUE,
    background = case_when(
      mwe_data1$`2020` == 0 ~ "mpsred!50",
      mwe_data1$`2021` == 0 ~ "mpsred!50",
      mwe_data1$`2022` == 0 ~ "mpsred!50",
      mwe_data1$`2023` == 0 ~ "mpsred!50",
      mwe_data1$`2024` == 0 ~ "mpsred!50",
      TRUE ~ "mpswine!0"
    )
  )

```

This knit just fine, but the output is not conditionally formatted as expected:

Latex table with formatting, but not conditional formatting

Help :]

I feel like I'm missing something fairly obvious here, but my google-fu and searching through stack overflow haven't yielded anything terribly useful for this purpose. Most of what I'm seeing is just "add escape=FALSE and all will be well," except that isn't working. What am I missing?


Solution

  • Looking at the error

    Missing $ inserted. $ l.95 ...column{1}{c}{\textcolor{mpswine}{proj_na}} & \multicolumn{1}{c}{\tex... I've inserted a begin-math/end-math symbol since I think you left one out. Proceed, with fingers crossed.

    Try to find the following text in bgCells.Rmd: ...column{1}{c}{\textcolor{mpswine}{proj_na}}

    You may need to add $ $ around a certain inline R expression r in bgCells.Rmd (see the above hint). See https://github.com/rstudio/rmarkdown/issues/385 for more info. Fehler: LaTeX failed to compile bgCells.tex. See https://yihui.org/tinytex/r/#debugging for debugging tips. See bgCells.log for more info.

    you can see that LaTeX has a problem with column proj_na because it has an underscore which is interpreted as math mode subscripts. So it specifically fails, trying to apply your textcolor mpswine from the code piece row_spec(row = 0, color = "mpswine", align = "c").

    To prevent this, simply add rename("Project Name" = proj_na) to remove the underscore from the problematic column.

    Full Code

    Note: I tried to recreate your custom colors, since you did not specify them using header-includes and this, although it's not necessary to recreate the issue and might detract.

    ---
    title: "Untitled"
    output:
      pdf_document: default
    header-includes:
      - \definecolor{mpswine}{RGB}{106, 107, 143}
      - \definecolor{mpswine!0}{RGB}{255, 255, 255}
      - \definecolor{mpsred!50}{RGB}{223, 153, 147}
      
    ---
    
    ```{r table, echo = FALSE, warning = FALSE, message = FALSE}
    library(kableExtra)
    library(tidyverse)
    
    set.seed(123)  # For reproducibility
    tibble(
      proj_na = rep(paste("PROJECT", 1:10), 5), # or remove underscore here
      proj_yr = rep(2020:2024, each = 10),
      proj_st = sample(rep(c(0, 1), each = 10), 50, replace = TRUE)
    ) %>% 
      mutate(
        proj_st = cell_spec(
          proj_st,
          format     = "latex",
          bold       = TRUE,
          background = case_when(
            proj_st == 0 ~ "mpsred!50",
            TRUE         ~ "mpswine!0"
          )
        )
      ) %>% 
      pivot_wider(
        names_from  = proj_yr,
        values_from = proj_st
      ) %>% 
      rename("Project Name" = proj_na) %>% 
      kable(
        format = "latex",
        booktabs  = TRUE,
        align     = "lccccc",
        escape = FALSE
      ) %>% 
      kable_styling(latex_options = c("HOLD_position", "repeat_header")) %>% 
      row_spec(row = 0, color = "mpswine", align = "c")
    ```
    

    and it works:

    out