How should I format across rows of a gt table efficiently in R?

A generalisable approach to achieve this is to set up a wrapper which loops through the format_specs dataframe and applies the format rules row by row. For the looping part I make use of purrr::reduce but a simple for-loop should also work:

library(dplyr)
library(purrr)
library(gt)

#create small dataset
gtcars_8 <-
  gtcars %>%
  dplyr::group_by(ctry_origin) %>%
  dplyr::top_n(2) %>%
  dplyr::ungroup() %>%
  dplyr::filter(ctry_origin != "United Kingdom")
#> Selecting by msrp

#transpose data
row_labels <- colnames(gtcars_8)
gtcars_8_t <- as.data.frame(t(as.matrix(gtcars_8)))
gtcars_8_t$row_labels <- row_labels
my_column_names <- colnames(gtcars_8_t)[1:8]

#format data

format_specs <- data.frame(row = row_labels[1:10]) # Name column with row labels
format_specs$type     <- c("c","c","n","c","c","n","n","n","n","p")
format_specs$decimals <- c( 0 , 0 , 0 , 0 , 0 , 1 , 2 , 2 , 1 , 2 )

myfmt <- function(data, cols, row_spec) {
  reduce(row_spec$row, function(x, y) {
    row_spec <- filter(row_spec, row == y)
    fmt(x, columns = cols,
        rows = which(x[["_data"]][["row_labels"]] == y), 
        fns = function(x) switch(row_spec$type,
                                 n = scales::number(as.numeric(x), accuracy = 10^(-row_spec$decimals), big.mark = ""),
                                 p = scales::percent(as.numeric(x), scale = 1, accuracy = 10^(-row_spec$decimals))))
        }, .init = data)
}

gtcars_8_t %>%
  slice(1:10) %>% 
  gt() %>% 
  cols_move_to_start("row_labels") %>% 
  myfmt(vars(my_column_names), format_specs)

Created on 2020-06-12 by the reprex package (v0.3.0)

Results in this table:

enter image description here

Tags:

Format

R

Gt