gt icon indicating copy to clipboard operation
gt copied to clipboard

`data_color()` vector applies wrong color

Open jthomasmock opened this issue 5 years ago • 3 comments
trafficstars

Problem:

To specify colors of a column from another column you can in theory specify an equal length character vector of colors. This works nicely for some examples, but fails under some other constraints.

gt version 0.2.1

library(gt)

# create a tibble of letters, numbers
# and a column to "scale" or generate the colors from

dfx <- dplyr::tibble(
  text = letters[1:5],
  numbers = 1:5,
  scale = c(1,2,3,2,1)
)

dfx

#    # A tibble: 5 x 3
#     text  numbers scale
#    <chr>   <int>  <dbl>
#   1 a         1     1
#   2 b         2     2
#   3 c         3     3
#   4 d         4     2
#   5 e         5     1

# create a vector of colors to apply the color from
# should be c(red, blue, green, blue, red)

col_all <- (scales::col_factor(
    palette = c("red", "blue", "green"),
    domain = NULL)(dfx$scale))

scales::show_col(col_all)


# Apply the colors via data_color()
dfx %>% 
  gt() %>% 
  # expected colors
  data_color(
    columns = "text",
    colors = col_all
  ) %>% 
  # expected colors
  data_color(
    columns = "numbers",
    colors = col_all
  ) %>% 
  # applies incorrect color for rows 3, 4, and 5
  data_color(
    columns = "scale",
    colors = col_all
  )

jthomasmock avatar Aug 06 '20 21:08 jthomasmock

Shoot, I led you astray.

The colors parameter in data_color doesn't work the way I implied on Slack. You cannot pass a vector of colors and expect them to be applied to the cells in the specified order. Instead, when you pass a vector of colors it means "these are colors I'd like to use, do something sensible with them". For numeric columns, that means "use these colors to form a numeric color scale (scales::col_numeric) and then apply that scale to the cell values"; for characters and factors, it means the same thing but with scales::col_factor.

dfx %>% gt() %>% data_color(columns = TRUE, colors = c("blue", "red"))

image

That the "text" and "numbers" columns even looked the same is just a coincidence due to the particulars of this example. Here I've modified the example slightly:

library(gt)

dfx <- dplyr::tibble(
  text = letters[1:5],
  numbers = sample.int(5, 5),
  scale = c(1,2,3,2,1)
)

# RColorBrewer::brewer.pal(5, "Spectral")
colors <- c("#D7191C", "#FDAE61", "#FFFFBF", "#ABDDA4", "#2B83BA")

gt(dfx) %>%
  data_color(columns = TRUE, colors = colors)

image

jcheng5 avatar Aug 06 '20 21:08 jcheng5

It would be totally reasonable to ALSO have a way to specify the colors directly. Either through a new data_color_manual function, or a new parameter to data_color that is mutually exclusive to the color parameter, or a new parameter that modifies the interpretation of color, etc.

jcheng5 avatar Aug 06 '20 21:08 jcheng5

Just as an aside - you can accomplish this upstream of gt by building your own HTML. Probably not ideal, but it's possible today without any changes to gt.

Inspired by Christophe's example on Community. Technically the fill is also a HTML created color-bar inspired from formattable.

library(dplyr)
library(gt)

dat <- tibble(
  group = c("a","b","c"),
  success = c(0, 25, 50),
  attempts = c(50, 50, 50)
) %>% 
  mutate(
    percentage = success / attempts,
    proportion = paste(success, attempts, sep = "/")
  )

dat %>% 
  mutate(
    color = scales::col_numeric(c("white", "red"), domain = c(0,1))(percentage),
    prop_fill = glue::glue('<span style=\"display: inline-block; direction: ltr; border-radius: 4px; padding-right: 2px; background-color: {color}; width: 100%\"> {proportion} </span>'),
    prop_color = glue::glue('<span style="color:{color}"> {proportion} </span>'),
    prop_fill = map(prop_fill, ~gt::html(as.character(.x))),
    prop_color = map(prop2, ~gt::html(as.character(.x)))
    ) %>% 
  select(-color) %>% 
  gt()

Screen Shot 2020-09-08 at 11 16 46 AM

jthomasmock avatar Sep 08 '20 16:09 jthomasmock