Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to set background colors for the cells of multiple columns based on string contents #863

Closed
ahbon123 opened this issue Jan 18, 2022 · 5 comments · Fixed by #1108
Closed

Comments

@ahbon123
Copy link

Hello, say I have a small dataset as follows:

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")
df <- data.frame(id, res1, res2)

df %>% 
  gt()

For columns res1 and res2, let's say if value content are trues, I'll need to highlight that cell with red background color, if falses, highlight with green color, for other cases, keep their colors as original.

Is it possible to achieve that using gt package?

@rich-iannone
Copy link
Member

We need an easier way to set basic style attributes based on values. I think a new function for this should be the way to do it. The sub_values() function provides a nice (and forgiving) way to target values so I believe the new function ought to be modeled on that.

@ahbon123
Copy link
Author

ahbon123 commented Nov 3, 2022

Thank you very much, I believe this function will have lots of application scenarios.

@jthomasmock
Copy link
Collaborator

Tagging on to this, there are a few requests I've seen on Twitter and gtExtras re: color the background of column 1 based on column 2. Right now, data_color() only operates on the current column, text_transform() only works on the current column (although this can be "abused"), and to properly color the background of a column you end up needing to use tab_style() multiple times.

I have a prototype that works like below:

set.seed(37)
base_tab <- head(mtcars) |>
  dplyr::slice_sample(n = 6) |>
  dplyr::arrange(desc(mpg)) |>
  gt::gt()

base_tab |>
  gt_color_by_col(mpg, cyl, domain = range(gtExtras::gt_index(base_tab, mpg)))

image

Essentially it loops through the column, values, and rows to apply a tab_style() with the minimal snippets of code below:

fn_data_clr_by_col <- function(gt_object, col2, value, row_id, color_add){

  gt_object |>
    tab_style(
      style = list(
        cell_fill(color = color_add),
        cell_text(color = gt:::ideal_fgnd_color(color_add))
      ),
      locations = cells_body({{ col2 }}, rows = row_id)
    )

}
for (i in 1:length(full_vals)){
    gt_object <- fn_data_clr_by_col(gt_object, {{ col2 }}, full_vals[i], i, color_add[i])
  }
  return(gt_object)

Full code:

Full Code
fn_data_clr_by_col <- function(gt_object, col2, value, row_id, color_add){

  gt_object |>
    tab_style(
      style = list(
        cell_fill(color = color_add),
        cell_text(color = gt:::ideal_fgnd_color(color_add))
      ),
      locations = cells_body({{ col2 }}, rows = row_id)
    )

}

gt_color_by_col <- function(
    gt_object, col1, col2, ..., domain = NULL, direction = 1, type = "continuous",
    palette = c("#af8dc3", "#e7d4e8", "#f7f7f7", "#d9f0d3", "#7fbf7b")){

  stopifnot("Table must be of class 'gt_tbl'" = "gt_tbl" %in% class(gt_object))

  full_vals <- gtExtras::gt_index(gt_object = gt_object, {{ col1 }})

  rng_vals <- range(full_vals, na.rm = TRUE)

  if(is.null(domain)){

    domain <- rng_vals
    warning(
      "Domain not specified, defaulting to observed range within each specified column.",
      call. = FALSE
    )
  }

  color_add <- scales::col_numeric(
    palette = if(grepl(x = palette[1], pattern = "::")){
      paletteer::paletteer_d(
        palette = palette,
        direction = direction,
        type = pal_type
      ) %>% as.character()
    } else {
      if(direction == -1){
        rev(palette)
      } else {
        palette
      }
    },
    ...,
    domain = domain
  )(full_vals)

  for (i in 1:length(full_vals)){
    gt_object <- fn_data_clr_by_col(gt_object, {{ col2 }}, full_vals[i], i, color_add[i])
  }
  return(gt_object)
}

@rich-iannone
Copy link
Member

rich-iannone commented Nov 10, 2022

@jthomasmock if it doesn't already exist could you transfer your comments/ideas to a new issue? There's some great stuff there and it's such a common problem that I don't want to lose track of this.

@jthomasmock
Copy link
Collaborator

If it doesn't already exist could you transfer your comments/ideas to a new issue? There's some great stuff there and it's such a common problem that I don't want to lose track of this.

Done! I've moved it to: #1119 with some of the public requests I've seen

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment