Subgroups in gt()

I know one can split a gt() table into groups by factor level, but can these groups be further sub-divided into sub-groups? For example, using this mock data:

data <- data.frame(
  rowname = rep(c("Row1", "Row2", "Row3", "Row4"), times = 2),
  Season = rep(c("Spring", "Fall"), each = 4),
  Value = c(10, 20, 30, 40, 15, 25, 35, 45)
)

And this table...

library(gt)
library(dplyr)

data %>%
  gt(rowname_col = "rowname",  # Specify the column to use for row names
     groupname_col = "Season") %>%  # Specify the column to use for grouping
  
  tab_header(
    title = "Grouped Table with Custom Row Names"
  )

Can I split the groups for each level in "Season" into two parts? As in, "Spring" has 2 parts: one part for when the row names = "Row1" and "Row2" specifically, and a second for the other values. I tried using this code below with tab_row_group, but it overrides the first grouping structure (Season) and just creates a 3rd group level.

  tab_row_group(
  label = "Season",
  rows = rowname %in% c("Row1")
  )

Hi @Nate_L,

Does the following approach work for you? It involves creating a second grouping variable, which I've called season_part, grouping the data by both Season and season_part before passing to gt().

library(dplyr)
library(gt)

data <- data.frame(
  rowname = rep(c("Row1", "Row2", "Row3", "Row4"), times = 2),
  Season = rep(c("Spring", "Fall"), each = 4),
  Value = c(10, 20, 30, 40, 15, 25, 35, 45)
)

data |> 
  as_tibble() |> 
  mutate(
    season_part = case_match(
      rowname,
      c('Row1', 'Row2') ~ 'Part 1',
      .default = 'Part 2'
    )
  ) |> 
  group_by(Season, season_part) |> 
  gt() |> 
  tab_header(title = 'Grouped Table with Custom Row Names')
Grouped Table with Custom Row Names
Value
Spring - Part 1
Row1 10
Row2 20
Spring - Part 2
Row3 30
Row4 40
Fall - Part 1
Row1 15
Row2 25
Fall - Part 2
Row3 35
Row4 45

Created on 2024-09-02 with reprex v2.1.0

Hi @craig.parylo,

Not quite, but thank you!

I was hoping that Season would only be broken into 2 parts, while the rows would indented and split into 2 groups. Something like this:

Spring
Group 1
       Row1
       Row2
Group 2
       Row3
       Row4          
Fall
Group 1
       Row1
       Row2
Group 2
       Row3
       Row4

Hi @Nate_L ,

Thank you for the clarification. Unfortunately, I don't think nested groups is currently supported by gt(), though there is an open ticket for this: Feature Request: Allow Nested Row Groups · Issue #399 · rstudio/gt · GitHub.

If the above approach doesn't suit your need, then the nearest alternative I can think of is to create multiple gt tables within a gt_group().

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

# create the subgroup variable and nest by Season
data_nest <- data |> 
  mutate(
    season_part = case_match(
      rowname,
      c('Row1', 'Row2') ~ 'Group 1',
      .default = 'Group 2'
    )
  ) |> 
  nest_by(Season, .keep = T)

# produce individual gt tables for each season with row groups
data_subgrouped <- purrr::map2(
  .x = data_nest$data,
  .y = data_nest$Season,
  .f = \(.data, .season) {
    .data |> 
      select(-Season) |> 
      group_by(season_part) |> 
      gt() |> 
      tab_header(title = .season)
  }
)

# combine the individual gt tables into a gt_group 
table_group <- gt_group(
  data_subgrouped[[1]],
  data_subgrouped[[2]]
)

# output the result
table_group

The output is technically two gt tables displayed one after the other but with the right styling they could look like a single table.

Fall
Group 1
Row1 15
Row2 25
Group 2
Row3 35
Row4 45
Spring
Group 1
Row1 10
Row2 20
Group 2
Row3 30
Row4 40

That works, thanks again!

This topic was automatically closed 7 days after the last reply. New replies are no longer allowed.

If you have a query related to it or one of the replies, start a new topic and refer back with a link.