Search code examples
rgt

How to customize background colors based on (characters, NA) contents in multiple columns using gt


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


Solution

  • 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
      )