1

Based on the code and data from this link, we can set background colors for the cells of multiple columns based on string contents using gt package:

library(gt)
library(tidyverse)

id <- c(1,2,3,4,5)
res1 <- c("true", "true", "false", "true", "false")
res2 <- c("false", NA, NA, "true", "true")
res3 <- c("true", NA, NA, "true", "true")
df <- data.frame(id, res1, res2, res3)

df %>% 
  gt() %>% 
  data_color(
    columns = c("res1", "res2", 'res3'),
    colors = c("green", "red", 'gray'),
    apply_to = "fill",
    autocolor_text = FALSE)

enter image description here

But as you may noticed, for res3, the color for true is green instead of red as in other two columns. If I hope to set red for true, green for false and gray for NA, for these 3 columns, if in case, they have other values such as yes, no, etc., just keep as original.

How could we solve this problem? Many thanks at advance.

Update1: an alternative solution with tab_style(), but not concise:

df %>% 
  gt() %>% 
  tab_style(
    style = list(
      cell_fill(color = 'red')
    ),
    locations = cells_body(
      columns = res1,
      rows = res1 == "true"
    )
  ) %>% 
  tab_style(
    style = list(
      cell_fill(color = 'red')
    ),
    locations = cells_body(
      columns = res2,
      rows = res2 == "true"
    )
  ) %>% 
  tab_style(
    style = list(
      cell_fill(color = 'red')
    ),
    locations = cells_body(
      columns = res3,
      rows = res3 == "true"
    )
  ) %>% 
  tab_style(
    style = list(
      cell_fill(color = 'green')
    ),
    locations = cells_body(
      columns = res1,
      rows = res1 == "false"
    )
  ) %>% 
  tab_style(
    style = list(
      cell_fill(color = 'green')
    ),
    locations = cells_body(
      columns = res2,
      rows = res2 == "false"
    )
  ) %>% 
  tab_style(
    style = list(
      cell_fill(color = 'green')
    ),
    locations = cells_body(
      columns = res3,
      rows = res3 == "false"
    )
  ) %>% 
  tab_style(
    style = list(
      cell_fill(color = 'gray')
    ),
    locations = cells_body(
      columns = res1,
      rows = res1 == NA
    )
  ) %>% 
  tab_style(
    style = list(
      cell_fill(color = 'gray')
    ),
    locations = cells_body(
      columns = res2,
      rows = res2 == NA
    )
  ) %>% 
  tab_style(
    style = list(
      cell_fill(color = 'gray')
    ),
    locations = cells_body(
      columns = res3,
      rows = res3 == NA
    )
  )

enter image description here

Update2: How to correctly set gray color for NA cells?

cols <- c('res1', 'res2', 'res3')
df %>% 
  # mutate_each_(funs(factor(.)), cols)
  mutate_at(cols, factor) %>% 
  gt() %>% 
  data_color(
    columns = cols,
    colors = scales::col_factor(
      palette = c('green', 'red', 'gray'),
      domain = c('false', 'true', NA)
    ),
    apply_to = "fill",
    autocolor_text = FALSE
  )

enter image description here

Update3: I set palette = c("green", "red", 'yellow'), domain = c("false", "true", '-'), why it's not shown green for false, red for true, and yellow for -?

id <- c(1, 2, 3, 4, 5)
res1 <- c("true", "true", "false", "true", "false")
res2 <- c("false", NA, NA, "true", "-")
res3 <- c("true", NA, NA, "true", "true")
df <- data.frame(id, res1, res2, res3)

df %>% 
  mutate_at(cols, factor) %>% 
  gt() %>% 
  data_color(
    columns = cols,
    colors = scales::col_factor(
      palette = c("green", "red", 'yellow'),
      domain = c("false", "true", '-'),
      na.color = 'gray'
    ),
    apply_to = "fill",
    autocolor_text = FALSE
  )

enter image description here

References:

Set background color if one cell's (of multiple columns) content is specific string using gt package

ah bon
  • 9,293
  • 12
  • 65
  • 148

2 Answers2

1

It's not a good idea to store your logical values as character strings. If you use TRUE and FALSE values instead, gt() works as designed to give you the table coloring you want.

id <- c(1,2,3,4,5)
res1 <- c(TRUE, TRUE, FALSE, TRUE, FALSE)
res2 <- c(FALSE, NA, NA, TRUE, TRUE)
res3 <- c(TRUE, NA, NA, TRUE, TRUE)
df2 <- data.frame(id, res1, res2, res3)

df2 %>% 
  gt() %>% 
  data_color(
    columns = c(res1, res2, res3),
    colors = scales::col_factor(
      palette = c("green", "red"),
      domain = c(FALSE, TRUE)
    ),
    apply_to = "fill",
    autocolor_text = FALSE
  )

If there's some reason you have to have the logicals as character strings you'll need to convert them to a factor and adjust the domain argument in data_color().

rdelrossi
  • 1,114
  • 1
  • 7
  • 17
  • Thanks for answering my question, `col_factor` is the function I'm looking for. – ah bon Feb 18 '22 at 01:15
  • You're welcome. I had only read about `data_color()` so it was a good way to dig into it. – rdelrossi Feb 18 '22 at 01:20
  • Sorry to confuse u with `true`, `false`, in my real data it's character strings, maybe I should use for example `yes`, `no` instead of `true`, `false`. – ah bon Feb 18 '22 at 01:23
  • If you decide to stick with the character strings just use factors and change `data_color` to `domain = c("false", "true")` (or whatever words you want). – rdelrossi Feb 18 '22 at 01:26
  • I added new code and output in the end of question, I didn't succeed in setting `gray` color for `NA` cells, do u mind have a look? – ah bon Feb 18 '22 at 01:37
  • After converting `NA` to factor, it become ``, but I set `domain = c('false', 'true', NA)` or `domain = c('false', 'true', )`, it didn't work out. – ah bon Feb 18 '22 at 01:39
  • 1
    I'll have a look. – rdelrossi Feb 18 '22 at 02:11
1

With regard to Update 2, the version with character strings, this should work:

df %>% 
  mutate_at(cols, factor) %>% 
  gt() %>% 
  data_color(
    columns = cols,
    colors = scales::col_factor(
      palette = c("green", "red"),
      domain = c("false", "true")
    ),
    apply_to = "fill",
    autocolor_text = FALSE
  )
rdelrossi
  • 1,114
  • 1
  • 7
  • 17
  • Thanks, let's say if I wanna set `yellow` color for `NA`s? How could we do that? – ah bon Feb 18 '22 at 02:48
  • 1
    Just add `na.color = "yellow"` to the `col_factor` call. – rdelrossi Feb 18 '22 at 03:11
  • Rather than color names use hex values (i.e., `"#FFFF00"` for "yellow"). Can you post a sample of your real data? – rdelrossi Feb 18 '22 at 07:17
  • Sorry for this late reply, after I carefully re-check my code, I found I've made a mistake in the code. However I find a new issue which I added as **update3** in the question, which is, the color palette and domain's orders are not coordinated. It's quite confusing. – ah bon Feb 18 '22 at 15:29
  • Are there four values now? TRUE, FALSE, NA and "-"? – rdelrossi Feb 18 '22 at 16:54
  • Yes. `c('true', 'false', NA, '-')`. – ah bon Feb 19 '22 at 02:54