Make paired bar chart into table

Published

November 3, 2023

Create a fake data set

library(tidyverse)
library(reactable)
library(reactablefmtr)
library(htmltools)
frameworks_data <- tribble(
  ~framework, ~stars, ~forks, ~watchers,
  'React.js', 170000, 35000, 5000,
  'Vue', 182000, 30000, 5000,
  'Angular', 75000, 20000, 2000,
  'jQuery', 55000, 20000, 2000,
  'Meteor', 42000, 3000, 1000,
  'Aurelia', 10000, 1000, 1000
)

Define helpers for building bar charts into reactable

# Render a bar chart
# See also: 
# https://glin.github.io/reactable/articles/cookbook/cookbook.html#bar-charts
bar_chart <- 
  function(
    label, width = "100%", height = "1rem", 
    fill = "#00bfc4", background = NULL
  ) {
  bar <- div(
    style = list(background = fill, width = width, height = height)
  )
  chart <- div(
    style = list(
      flexGrow = 1, 
      marginLeft = "0.5rem", 
      background = background
    ), 
    bar
  )
  div(
    style = list(display = "flex", alignItems = "center"), 
    div(
      style = list(width = '50px', `text-align` = 'right'), 
      number_formatter(label)
    ), 
    chart
  )
}

number_formatter <- scales::label_number(
  scale_cut = scales::cut_short_scale()
)
column_label_size <- '24px'
number_col_widhts <- 200

Build the table

frameworks_data |> 
  reactable(
    columns = list(
      framework = colDef(
        name = 'Framework',
        maxWidth = 175,
        headerStyle = htmltools::css(
          font_size = column_label_size
        )
      ),
      stars = colDef(
        name = 'Stars',
        align = 'left',
        cell = function(value) {
          width <- paste0(value / max(frameworks_data$stars) * 100, "%")
          bar_chart(value, width = width, fill = '#E69F00')
        }, 
        maxWidth = number_col_widhts,
        headerStyle = htmltools::css(
          color = '#E69F00', 
          font_size = column_label_size
        )
      ),
     forks = colDef(
        name = 'Forks',
        align = 'left',
        cell = function(value) {
          width <- paste0(value / max(frameworks_data$stars) * 100, "%")
          bar_chart(value, width = width, fill = '#0072B2')
        }, 
        maxWidth = number_col_widhts,
        headerStyle = htmltools::css(
          color = '#0072B2', 
          font_size = column_label_size
        )
      ),
      watchers = colDef(
        name = 'Watchers',
        align = 'left',
        cell = function(value) {
          width <- paste0(value / max(frameworks_data$stars) * 100, "%")
          bar_chart(value, width = width, fill = '#009E73')
        }, 
        maxWidth = number_col_widhts,
        headerStyle = htmltools::css(
          color = '#009E73', 
          font_size = column_label_size
        )
      )
    ),
    style = htmltools::css(
      font_family = "Source Sans Pro",
      font_size = '20px',
      color = '#333333'
    ),
    width = 775
  ) |> 
  reactablefmtr::add_source(
    source = 'This is a remake of a chart from Christopher Chin',
    align = 'left',
    font_size = 14,
    margin = margin(t = 6)
  ) |> 
  google_font(font_family = "Source Sans Pro")


Enjoyed this code snippet?

You may also like my weekly 3-minute newsletter. Reading time: 3 minutes or less.

Or you can check out previous editions of the newsletter at 3mw.albert-rapp.de