tobin_lab
tobin_lab

Reputation: 305

Conditional colouring with kableExtra() fails with NAs in column

I use the kableExtra()-package for conditional formatting of tables in an PDF-output Rmarkdown report. All works pretty much fine, but fails if in one column is a NA present.

The original report contains columns with percentage agreement on a specific variable (e.g. 21% (but % not in the cell)) , however it will show NA if the value is based on less than 10 answers for protection of subjects answers, therefore I will have potential NAs in the table.

Here is a small reprex for a case when it works (no NA):

---
output: pdf_document
---

```{r setup}
knitr::opts_chunk$set(echo = TRUE)
# load packages
library(tidyverse)
library(kableExtra)


# example when no NA are resent
df1 <- mtcars %>% select(mpg, cyl, disp)
df1 <- head(df1, 10)
# kable
df1 %>%
  mutate(cyl = cell_spec(cyl, color = if_else(cyl == 8, "teal",
                                              if_else(cyl == 6, "orange", 
                                                      if_else(is.na(cyl), "black", "red"))))) %>%
    kable("latex", escape = F, booktabs = TRUE, linesep = "")

```

here is the other one, when NAs are present:

```{r, eval=T}
# example when NA is present
df2 <- mtcars %>% select(mpg, cyl, disp)
df2 <- head(df2, 10)
df2$cyl[df2$cyl == 4] <- NA

# kable
df2 %>%
  mutate(cyl = cell_spec(cyl, color = if_else(cyl == 8, "teal",
                                              if_else(cyl == 6, "orange", "red")))) %>%
    kable("latex", escape = F, booktabs = TRUE, linesep = "")


```

the error running the chunk is :

Error in if (substr(color, 1, 1) != "#") { : missing value where 
TRUE/FALSE needed

the error when knitting is:

enter image description here

I also tried adding a third if_else() which evaluates to is.na() - the errors stay the same:

# kable
df2 %>%
  mutate(cyl = cell_spec(cyl, color = if_else(cyl == 8, "teal",
                                              if_else(cyl == 6, "orange", 
                                                      if_else(is.na(cyl), "black","red"))))) %>%
    kable("latex", escape = F, booktabs = TRUE, linesep = "")

My session.info:

R version 3.5.2 (2018-12-20)
Platform: x86_64-apple-darwin15.6.0 (64-bit)
Running under: macOS Mojave 10.14.2

Matrix products: default
BLAS: /System/Library/Frameworks/Accelerate.framework/Versions/A/Frameworks/vecLib.framework/Versions/A/libBLAS.dylib
LAPACK: /Library/Frameworks/R.framework/Versions/3.5/Resources/lib/libRlapack.dylib

locale:
[1] en_US.UTF-8/en_US.UTF-8/en_US.UTF-8/C/en_US.UTF-8/en_US.UTF-8

attached base packages:
[1] stats     graphics  grDevices utils     datasets  methods   base     

other attached packages:
 [1] naniar_0.4.1       shurp2018_0.0.9000 kableExtra_1.0.1   forcats_0.3.0      stringr_1.3.1      dplyr_0.8.0        purrr_0.3.0       
 [8] readr_1.3.1        tidyr_0.8.2        tibble_2.0.99.9000 ggplot2_3.1.0      tidyverse_1.2.1 

Upvotes: 0

Views: 1476

Answers (1)

JBGruber
JBGruber

Reputation: 12420

It seems that you have two problems:

First, I think that by default, no color value is set. Yet it is also not overwritten when for some cells color = NA. So you could solve it by setting color = NULL (any other color would be concatenated with the ones assigned in the next step, which causes trouble).So this works somewhat for me:

```{r}
# kable
df2 %>%
  mutate(cyl = cell_spec(cyl, color = NULL)) %>% 
  mutate(cyl = cell_spec(cyl, color = if_else(cyl == 8, "teal",
                                              if_else(cyl == 6, "orange", "red")))) %>%
    kable("latex", escape = F, booktabs = TRUE, linesep = "")
```

The problem is that the color of NA is red now instead of black.

The second problem is that your ifelse evaluations do not work correctly

You can also check what happens in your ifelse function separately to get a better understanding of this problem:

> with(df2,  if_else(cyl == 8, "teal",
+                    if_else(cyl == 6, "orange", 
+                            if_else(is.na(cyl), "black","red"))))
 [1] "orange" "orange" NA       "orange" "teal"   "orange" "teal"   NA       NA       "orange"

But you can make it work by evaluating is.na(cyl) first instead of last:

df2 %>%
  mutate(cyl = cell_spec(cyl, color = if_else(is.na(cyl), "black", 
                                              if_else(cyl == 8, "teal",
                                                      if_else(cyl == 6, "orange", "red"))))) %>%
  kable("latex", escape = F, booktabs = TRUE, linesep = "")

Upvotes: 2

Related Questions