0

I am sorry, I already asked 2 similar questions, but I guess they werent clear enough.

My problem: I have a dataframe with a very wide range of numbers. Since I have numbers that are 300x higher than the average, I cant use a normal color scheme, since most of the colors would be the same. I also want to see the differences in the smaller numbers aswell.

I saw this question, similar to mine, but only with 2 different color palettes. Set asymmetric midpoint for data_color in gt table

Now I have created color-palettes on my own and wrote that function. It works perfectly with only 2 color-palettes. But I am struggling to do it with 4. The ifelse-statement doesnt work there and I cant think of any other alternative.

emerald = c("#d3f2a3","#97e196","#6cc08b","#4c9b82","#217a79","#105965","#074050")
oryel = c("#ecda9a","#efc47e","#f3ad6a","#f7945d","#f97b57","#f66356","#ee4d5a")
sunshort = c("#dc3977","#b9257a","#7c1d6f")
toplevel = c("#6c2167", "#541f3f")



pal <- function(x) {
  f_neg <- scales::col_numeric(
    palette = c(emerald),
    domain = c(min(test), 0))
  f_pos1 <- scales::col_numeric(
    palette = c(oryel),
    domain = c(0, 300))
  f_pos2 <- scales::col_numeric(
      palette = c(sunshort),
      domain = c(300, 500))
  f_pos3 <- scales::col_numeric(
    palette = c(toplevel),
    domain = c(500, max(test))
  
  ifelse(x < 0, f_neg(x), f_pos1(x))}

library(gt)
    gt(test)%>%
      data_color(columns = c(1,2),
               colors = pal)


structure(list(Delta_p = c(-19.98, 51.22, NA, 57.61, -17.01, 
    27.76, NA, 43.7, 25.75, NA, NA, 28.72, NA, 52.07, 45.12, NA, 
    -41.56, -16.81, 14.35, -20.09, -35.17, NA, 23.91, 54.09, NA, 
    NA, 10.53, NA, 28.97, 36.76, -11.25, 48.61, 99.01, -20, 137.5, 
    NA, 29.19, 26.71, -29.74, -18, 57.66, -41.91, 25.5, 29.01, 12.47, 
    NA, 22.19, -52.42, 19.01, 32.71, 43.39, NA, 123.88, 76.71, 45.96, 
    105.85, 47.71, 51.72, NA, 43.7, -38.04, -25.05, 45.96, NA, 71.93, 
    12.77, NA, -33.59, 577.78, 52.2, 24.44, 27.06, 127.27, -35.53, 
    -21.34, NA, 8.33, 22.46, 27.65, 93.1, 37.87, 58.9, -19.67, -25.53, 
    -24.35, 27.21, NA, -57.4, 16.62, 16.48, 14.71, 24.81, -30.33, 
    40.79, 45.02, 70.13, 68.65, 29.6, 13.28, -11.87), Delta_n = c(32.25, 
    NA, -20.49, 43.61, -22.97, 26.87, 46.58, 28.69, 46.56, 94.12, 
    36.67, 96.05, 50.15, 59.35, 24.95, 47.93, NA, NA, 28.26, 59.56, 
    -17.03, 89.47, -26.11, 35.5, 29.76, 69.09, NA, 27.75, -13.47, 
    43.58, NA, 72.22, 52.28, -24.95, NA, -16.4, 65.49, 51.58, 23.94, 
    -19.1, -21.1, 70.97, NA, -26.96, 22.39, -21.74, 20.47, 27.33, 
    41.44, 24.69, 32.33, 68.16, -23.7, NA, -19.9, NA, NA, -19.9, 
    -19.71, 24.91, NA, 24.85, 30.38, 23.72, 89.67, NA, 69.05, NA, 
    NA, 35.07, 37.39, -32.13, 90.91, 28.08, -13.34, 24.23, -20.49, 
    NA, -15.04, 100.86, NA, NA, -18.1, 16.85, NA, 18.38, 276.83, 
    22.82, 36, -9.78, NA, 20.83, NA, 21.54, 52.36, -23.95, NA, 12.74, 
    NA, 20.36)), row.names = c(2117L, 2609L, 200L, 340L, 1576L, 1353L, 
    1710L, 832L, 1530L, 895L, 1980L, 92L, 273L, 884L, 1784L, 452L, 
    2610L, 2109L, 733L, 261L, 2277L, 1447L, 1588L, 1803L, 1989L, 
    275L, 2192L, 2500L, 1876L, 2077L, 1637L, 2536L, 971L, 2596L, 
    283L, 360L, 1316L, 83L, 1310L, 2000L, 529L, 2201L, 2189L, 563L, 
    1486L, 487L, 2046L, 97L, 98L, 1554L, 1769L, 2318L, 782L, 1845L, 
    196L, 802L, 2414L, 198L, 1712L, 2220L, 1201L, 2480L, 2491L, 2237L, 
    2539L, 2207L, 2537L, 1432L, 73L, 730L, 2477L, 582L, 1209L, 2291L, 
    2336L, 737L, 1853L, 2409L, 1281L, 426L, 1054L, 1205L, 566L, 1299L, 
    129L, 2069L, 948L, 846L, 1723L, 1148L, 208L, 490L, 2269L, 6L, 
    1187L, 1184L, 2091L, 2143L, 1439L, 1703L), class = "data.frame")

UPDATE

pal <- function(x) {
  f_neg <- scales::col_numeric(
    palette = c(emerald),
    domain = c(min_delta, 0))
  f_pos1 <- scales::col_numeric(
    palette = c(oryel),
    domain = c(0, 300))
  f_pos2 <- scales::col_numeric(
    palette = c(sunshort),
    domain = c(300, 500))
  f_pos3 <- scales::col_numeric(
    palette = c(toplevel),
    domain = c(500, max_delta))
  
  dplyr::case_when(
    x < 0 ~ f_neg(x),
    x < 300 ~ f_pos1(x),
    x < 500 ~ f_pos2(x),
    x < max_delta+1 ~ f_pos3(x),
    .default = "#808080")}

It gives me this error when plotting the table:

   data_color(columns = c(Delta_p, Delta_n),
              colors = pal) %>% 

Error in `dplyr::case_when()`:
! Case 5 (`x < 0 ~ f_neg(x)`) must be a two-sided formula, not a character vector.
Run `rlang::last_error()` to see where the error occurred.
Essi
  • 761
  • 3
  • 12
  • 22
  • 1
    You could extend the if else statement to include 4 groups instead of 2: `if(conditon1) f_neg(x) else if(condition2) f_pos1(x) else if(conditon3) f_pos2(x) else f_pos3(x)` – mfg3z0 Mar 10 '23 at 04:24
  • Thx! I tried it: if(x<=0) f_neg(x) else if(x>0 & x<300) f_pos1(x) else if(x >= 300 & x<500) f_pos2(x) else f_pos3(x) , but I am getting this error message: Error in if (x <= 0) f_neg(x) else if (x > 0 & x < 300) f_pos1(x) else if (x >= : the condition has length > 1 – Essi Mar 10 '23 at 16:21

1 Answers1

1

You could use e.g. dplyr::case_when. And as you data contains NAs I added na.rm=TRUE when computing the min and max values. Finally, I used a more minimal example dataset.

library(gt)

pal <- function(x) {
  f_neg <- scales::col_numeric(
    palette = c(emerald),
    domain = c(min(test, na.rm = TRUE), 0)
  )
  f_pos1 <- scales::col_numeric(
    palette = c(oryel),
    domain = c(0, 300)
  )
  f_pos2 <- scales::col_numeric(
    palette = c(sunshort),
    domain = c(300, 500)
  )
  f_pos3 <- scales::col_numeric(
    palette = c(toplevel),
    domain = c(500, max(test, na.rm = TRUE))
  )

  dplyr::case_when(
    x < 0 ~ f_neg(x),
    x < 300 ~ f_pos1(x),
    x < 500 ~ f_pos2(x),
    .default = f_pos3(x)
  )
}

test <- data.frame(
  Delta_p = seq(-100, 600, length.out = 10),
  Delta_n = rev(seq(-100, 600, length.out = 10))
)

gt(test) %>%
  data_color(
    columns = c(1, 2),
    colors = pal
  )

enter image description here

stefan
  • 90,330
  • 6
  • 25
  • 51
  • Thanks a lot! I had to adjust a bit, since I got some errors for the last condition. Now it works! Thank you very much! – Essi Mar 10 '23 at 16:29
  • dplyr::case_when( x < 0 ~ f_neg(x), x < 300 ~ f_pos1(x), x < 500 ~ f_pos2(x), x < max_delta+1 ~ f_pos3(x)) – Essi Mar 10 '23 at 16:30
  • Oh, I tried it now on my entire dataframe. There is an issue with na -values: Error in `html_color()`: ! No values supplied in `colors` should be `NA`. Run `rlang::last_error()` to see where the error occurred. – Essi Mar 10 '23 at 16:36
  • 1
    I just have had a look. The issue is most likely that your dropped the `.default` from my code. As a consequence no color code is assigned to the NAs. To fix that, you could add a `.default` value which assigns a color to the NAs using `case_when(...., .default = "#808080")` (this assign the default NA color used by gt). – stefan Mar 10 '23 at 16:54
  • It doesnt work :(. Look in my updated question. I added the code and error message now – Essi Mar 10 '23 at 17:03
  • From the euro message I would guess (unfortunately I can not run your code as I miss min_delta and max_delta) that you do not use the most recent version of `dplyr`, i.e. the `.default` argument was introduced in dplyr 1.1.0. Option 1: Try with updating dplyr, Option 2: Use the "old-way" to provide a default: `case_when(...., TRUE ~ "#808080")` – stefan Mar 10 '23 at 17:08
  • 1
    Oh ok, max_delta = 3633.33, min_delta = -69.53 I will try the 2 things you mentioned. Thanks! – Essi Mar 10 '23 at 17:16
  • Thx for providing the missing pieces. Now I can confirm that the code runs fine on my side. – stefan Mar 10 '23 at 17:18
  • Please, help again. I just cant get it right. The sample you provided works also for me. But when I apply it on my real data, I get this error: Error in FUN(X[[i]], ...) : The length of the unique elements must match the palette length – Essi Mar 11 '23 at 16:49