Search code examples
rbar-chartfillreactable

How to fill bar charts in reactable table using a vector of colors?


I have the below example code (inspired by the Demo Cookbook) that creates my bar charts for each column of data in my reactable table.

library(tidyverse)
library(htmltools)
library(reactable)

data <- tibble(
  a = c(9.175783855, 11.81526856, 0.958313222, 5.616405204, 2.52481891,
        1.781139798, 1.440104888, 2.40162111, 5.144542917,8.254753493,
        6.651080016, 4.44758866, 2.714855098, 2.35523782, 2.20347958,
        6.761000611),
  b = c(3.87414355, 10.75733095, 6.823421855, 10.11946139, 3.677263099,
        4.287000085, 4.993322574, 2.691458126, 7.013314446, 4.900493424,
        8.649965459, 1.482655707, 0.20604618, 0.32892486, 2.161339902,
        4.55948858)
)

bar_style <- function(width = 1, fill = "#e6e6e6", height = "75%", align = c("left", "right"), color = NULL) {
  align <- match.arg(align)
  if (align == "left") {
    position <- paste0(width * 100, "%")
    image <- sprintf("linear-gradient(90deg, %1$s %2$s, transparent %2$s)", fill, position)
  } else {
    position <- paste0(100 - width * 100, "%")
    image <- sprintf("linear-gradient(90deg, transparent %1$s, %2$s %1$s)", position, fill)
  }
  list(
    backgroundImage = image,
    backgroundSize = paste("100%", height),
    backgroundRepeat = "no-repeat",
    backgroundPosition = "center",
    color = color
  )
}

reactable(
  data,
  columns = list(
    a = colDef(align = "right",
               format = colFormat(digits = 1),
               style = function(value) {
                 bar_style(width = value / max(data$a), align = "right")
                         }),
    b = colDef(align = "left",
               format = colFormat(digits = 1),
               style = function(value) {
                 bar_style(width = value / max(data$b), align = "left")
               })
  ))

I'd like to know how I can fill each bar chart based on the color codes below. Essentially, I'd like to have a different fill for each row for columns a and b.

a_fill <- c("#97233f", "#241773", "#0b162a", "#fb4f14", "#002244",
            "#002244", "#203731", "#000000", "#002244", "#008e97",
            "#4f2683", "#203731", "#004953", "#000000", "#002244",
            "#aa0000")

b_fill <- c("#002244", "#a5acaf", "#002244", "#e31837", "#d50a0a",
            "#0b2265", "#9f8958", "#03202f", "#773141", "#002244",
            "#000000", "#0085ca", "#a71930", "#00338d", "#002c5f",
            "#005a8b")

Is anyone able to help me with this?

Thank you.


Solution

  • Here is one option where we create a function with two arguments, 'value', 'index' and the 'index' will be used for subsetting the corresponding color vector value for each 'bar'

    reactable(
      data,
      columns = list(
        a = colDef(align = "right",
                   format = colFormat(digits = 1),
                   style = function(value, index) {
                     
                     color <- a_fill[index]
                     width = value / max(data$b)
                     bar_style(width = width, fill = color, align = "right")
                     
                   }),
               
        b = colDef(align = "left",
                   format = colFormat(digits = 1),
                   style = function(value, index) {
                     width = value / max(data$b)
                     color <- b_fill[index]
                     bar_style(width = width, fill = color, align = "left")
                   })
      ))
    

    -output

    enter image description here