Skip to contents

group_rows() names the structural columns whose runs of identical values define the table's row hierarchy, ordered outer to inner. List only the keys that drive the structure — the section headers and any hidden break keys; the visible row-label column (e.g. the statistic stub) stays an ordinary cols() column and is indented automatically. It is the row-structure counterpart of sort_rows(): one declaration per table, replaced wholesale on a repeat call.

Usage

group_rows(.spec, by, display = "section", skip = TRUE)

Arguments

.spec

The tabular_spec to attach the grouping plan to. <tabular_spec>: required.

by

Structural grouping key columns, ordered outer to inner. <character>: required. Names at least one column of data; duplicates are rejected. List only the section-header and break-only keys, not the visible label column.

Interaction: A subgroup()(by = ) partition column may also be a grouping key; within each partition the key is constant and auto-hidden, so the combination composes.

display

How the keys' values render in the body. <character(1)>: default "section". One value, applied to every key:

  • "section" (default) — each unique value emits a section header row spanning the visible columns; the key column is hidden from the body. The canonical submission shape.

  • "collapse" — the key column stays visible; repeated values are suppressed so only the first row of each run shows the label. The classic listing shape.

  • "repeat" — the key column stays visible and every row repeats the value. The export / QC shape, where every row must be self-describing.

Tip: for a hidden break-only key, set col_spec(visible = FALSE) on it rather than a display mode.

skip

Which keys get a blank spacer row between their groups. <TRUE | FALSE | character>: default TRUE. A logical flag or an explicit character set (the readr::read_csv(col_names = ) pattern):

  • TRUE (default) — derive: a "section" key or a break-only (visible = FALSE) key breaks with a blank line; a visible "collapse" / "repeat" key runs continuous.

  • FALSE — no spacer rows anywhere.

  • <character> — exactly these by keys break, e.g. skip = "param" (blank line between params, none between visits). Every name must be in by; character(0) is equivalent to FALSE.

Value

<tabular_spec>. A new spec with @row_groups replaced; pipe into the remaining build verbs or emit().

Details

One plan per table. A second group_rows() call replaces the first (the sort_rows() contract); levels never accumulate across calls.

Structural keys only. Nesting is just listing the header keys: by = c("param", "visit") renders param as the outer section header and visit as the indented sub-header, and the first visible column beneath (the label stub) is auto-indented one level per header. You do not put the label column in by.

Break-only keys use visible = FALSE. A key you mark col_spec(visible = FALSE) renders nothing and contributes only group transitions — the blank spacer between blocks (skip) and the decimal-alignment reset — exactly what a hidden sort/break key needs. There is no separate display mode for it.

See also

Column display: cols() / col_spec() for labels, alignment, and visibility of the key columns.

Row order: sort_rows() — sort so each key's runs are contiguous before grouping.

Pagination: paginate() — the grouping keys form the default panel stub; keep_together protects runs across page breaks independently of grouping.

Examples

# ---- Example 1: Demographics with section headers and a stat column ----
#
# The canonical demographics shape: `variable` is the one structural
# key. The defaults do all the work -- `display = "section"` renders
# one section header row per parameter (Age, Sex, ...) and hides the
# key column; `skip = TRUE` derives a blank spacer between sections.
# `stat_label` is NOT a grouping key -- it stays an ordinary column
# and is auto-indented one level under each section header.
n <- stats::setNames(cdisc_saf_n$n, cdisc_saf_n$arm_short)

tabular(
  cdisc_saf_demo,
  titles = c("Table 14.1.1", "Demographics", "Safety Population")
) |>
  cols(
    variable = "Parameter",
    stat_label = "Statistic",
    placebo = "Placebo\nN={n['placebo']}",
    drug_50 = "Drug 50\nN={n['drug_50']}",
    drug_100 = "Drug 100\nN={n['drug_100']}",
    Total = "Total\nN={n['Total']}"
  ) |>
  cols_apply(
    c("placebo", "drug_50", "drug_100", "Total"),
    col_spec(align = "decimal")
  ) |>
  group_rows(by = "variable")

 

Table 14.1.1

Demographics

Safety Population

 

StatisticPlacebo
N=86
Drug 50
N=96
Drug 100
N=72
Total
N=254
Age (years)
n86         96         72         254         
Mean (SD)75.2 (8.59)76.0 (8.11)73.8 (7.94) 75.1 (8.25)
Median76.0       78.0       75.5        77.0       
Q1, Q369.2, 81.8 71.0, 82.0 70.5, 79.0  70.0, 81.0 
Min, Max52  , 89   51  , 88   56  , 88    51  , 89   
 
Sex, n (%)
F53 (61.6)  55 (57.3)  35 (48.6)  143 (56.3)  
M33 (38.4)  41 (42.7)  37 (51.4)  111 (43.7)  
 
Race, n (%)
WHITE78 (90.7)  90 (93.8)  62 (86.1)  230 (90.6)  
BLACK OR AFRICAN AMERICAN 8 ( 9.3)   6 ( 6.2)   9 (12.5)   23 ( 9.1)  
ASIAN 0          0          0           0         
AMERICAN INDIAN OR ALASKA NATIVE 0          0          1 ( 1.4)    1 ( 0.4)  
# ---- Example 2: Nested parameter / visit with a hidden break key ---- # # `param` and `visit` nest as section headers (outer then indented # sub-header) just by listing both -- no per-key modes. `paramcd` # never renders: col_spec(visible = FALSE) makes it a break-only key # whose transitions reset the decimal-alignment sections. `skip = # "param"` puts a blank line between parameters but not between # visits within a parameter. tabular(cdisc_saf_vital, titles = "Vital Signs by Parameter and Visit") |> cols( paramcd = col_spec(visible = FALSE), param = "Parameter", visit = "Visit", stat_label = "Statistic", placebo = "Placebo\nN={n['placebo']}", drug_50 = "Drug 50\nN={n['drug_50']}", drug_100 = "Drug 100\nN={n['drug_100']}" ) |> cols_apply( c("placebo", "drug_50", "drug_100"), col_spec(align = "decimal") ) |> group_rows(by = c("param", "visit"), skip = "param")

 

Vital Signs by Parameter and Visit

 

StatisticPlacebo
N=86
Drug 50
N=96
Drug 100
N=72
Diastolic Blood Pressure (mmHg)
Baseline
n340         384         288         
Mean (SD) 77.1 (10.7) 76.6 ( 9.8) 78.2 (10.3)
Median 77.7        76.7        78.8       
Min, Max 40  , 110   48  , 108   51  , 108  
Week 8
n292         240         224         
Mean (SD) 75.2 ( 9.1) 75.4 (10.6) 77.4 ( 9.1)
Median 76.0        74.0        78.3       
Min, Max 49  , 101   52  , 100   54  , 98   
Week 16
n272         168         148         
Mean (SD) 75.1 (10.9) 75.2 (10.0) 76.0 ( 9.0)
Median 76.0        75.7        77.3       
Min, Max 49  , 98    55  , 98    50  , 92   
End of Treatment
n222         177         168         
Mean (SD) 74.4 (10.7) 76.0 (11.2) 76.0 ( 9.9)
Median 73.5        76.0        78.0       
Min, Max 49  , 104   50  , 100   56  , 98   
 
Pulse Rate (beats/min)
Baseline
n340         384         288         
Mean (SD) 73.5 (11.6) 72.1 (10.8) 72.4 (9.7) 
Median 72.3        70.0        71.7       
Min, Max 51  , 134   50  , 104   52  , 100  
Week 8
n292         240         224         
Mean (SD) 71.8 ( 9.0) 72.6 (11.1) 74.0 (8.9) 
Median 72.0        72.0        73.2       
Min, Max 52  , 102   49  , 104   50  , 104  
Week 16
n272         168         148         
Mean (SD) 70.6 ( 8.8) 68.8 ( 9.4) 73.2 (9.5) 
Median 70.2        68.0        72.0       
Min, Max 50  , 90    48  , 104   51  , 96   
End of Treatment
n222         177         168         
Mean (SD) 75.2 (11.5) 74.1 ( 9.4) 73.6 (9.6) 
Median 74.0        75.0        73.0       
Min, Max 51  , 106   50  , 94    50  , 98   
 
Systolic Blood Pressure (mmHg)
Baseline
n340         384         288         
Mean (SD)136.8 (17.6)137.9 (18.5)137.8 (17.2)
Median136.3       138.0       138.0       
Min, Max 80  , 184  100  , 194  100  , 192  
Week 8
n292         240         224         
Mean (SD)136.3 (17.0)134.9 (17.8)135.1 (15.5)
Median136.5       132.3       134.0       
Min, Max 90  , 189   92  , 200   91  , 198  
Week 16
n272         168         148         
Mean (SD)134.6 (18.3)132.5 (14.3)133.7 (16.0)
Median134.0       130.0       132.0       
Min, Max 76  , 190  100  , 168   99  , 186  
End of Treatment
n222         177         168         
Mean (SD)132.7 (15.4)133.0 (17.1)132.3 (15.6)
Median131.0       130.0       131.0       
Min, Max 78  , 172   92  , 178  100  , 177  
 
Temperature (C)
Baseline
n172         190         144         
Mean (SD) 36.6 (0.4)  36.5 (0.4)  36.6 (0.4) 
Median 36.7        36.6        36.6       
Min, Max 35  , 37    35  , 37    36  , 37   
Week 8
n146         118         112         
Mean (SD) 36.6 (0.4)  36.6 (0.4)  36.6 (0.4) 
Median 36.6        36.7        36.7       
Min, Max 36  , 37    36  , 37    36  , 37   
Week 16
n136          82          74         
Mean (SD) 36.7 (0.3)  36.6 (0.4)  36.6 (0.4) 
Median 36.7        36.6        36.7       
Min, Max 36  , 37    36  , 37    36  , 37   
End of Treatment
n 74          59          56         
Mean (SD) 36.7 (0.4)  36.6 (0.4)  36.6 (0.4) 
Median 36.8        36.7        36.7       
Min, Max 35  , 37    35  , 38    36  , 37   
# ---- Example 3: Listing shape with a visible, collapsed key column ---- # # The same vitals data as a continuous listing: `display = "collapse"` # keeps `param` and `visit` as visible columns and suppresses repeated # values, so only the first row of each run shows the label; `skip = # FALSE` removes every blank spacer. Use `display = "repeat"` instead # to print the value on every row -- the export / QC shape. tabular(cdisc_saf_vital, titles = "Vital Signs Listing") |> cols( paramcd = col_spec(visible = FALSE), param = "Parameter", visit = "Visit", stat_label = "Statistic", placebo = "Placebo\nN={n['placebo']}", drug_50 = "Drug 50\nN={n['drug_50']}", drug_100 = "Drug 100\nN={n['drug_100']}" ) |> cols_apply( c("placebo", "drug_50", "drug_100"), col_spec(align = "decimal") ) |> group_rows(by = c("param", "visit"), display = "collapse", skip = FALSE)

 

Vital Signs Listing

 

ParameterVisitStatisticPlacebo
N=86
Drug 50
N=96
Drug 100
N=72
Diastolic Blood Pressure (mmHg)Baselinen340         384         288         
Mean (SD) 77.1 (10.7) 76.6 ( 9.8) 78.2 (10.3)
Median 77.7        76.7        78.8       
Min, Max 40  , 110   48  , 108   51  , 108  
Week 8n292         240         224         
Mean (SD) 75.2 ( 9.1) 75.4 (10.6) 77.4 ( 9.1)
Median 76.0        74.0        78.3       
Min, Max 49  , 101   52  , 100   54  , 98   
Week 16n272         168         148         
Mean (SD) 75.1 (10.9) 75.2 (10.0) 76.0 ( 9.0)
Median 76.0        75.7        77.3       
Min, Max 49  , 98    55  , 98    50  , 92   
End of Treatmentn222         177         168         
Mean (SD) 74.4 (10.7) 76.0 (11.2) 76.0 ( 9.9)
Median 73.5        76.0        78.0       
Min, Max 49  , 104   50  , 100   56  , 98   
Pulse Rate (beats/min)Baselinen340         384         288         
Mean (SD) 73.5 (11.6) 72.1 (10.8) 72.4 ( 9.7)
Median 72.3        70.0        71.7       
Min, Max 51  , 134   50  , 104   52  , 100  
Week 8n292         240         224         
Mean (SD) 71.8 ( 9.0) 72.6 (11.1) 74.0 ( 8.9)
Median 72.0        72.0        73.2       
Min, Max 52  , 102   49  , 104   50  , 104  
Week 16n272         168         148         
Mean (SD) 70.6 ( 8.8) 68.8 ( 9.4) 73.2 ( 9.5)
Median 70.2        68.0        72.0       
Min, Max 50  , 90    48  , 104   51  , 96   
End of Treatmentn222         177         168         
Mean (SD) 75.2 (11.5) 74.1 ( 9.4) 73.6 ( 9.6)
Median 74.0        75.0        73.0       
Min, Max 51  , 106   50  , 94    50  , 98   
Systolic Blood Pressure (mmHg)Baselinen340         384         288         
Mean (SD)136.8 (17.6)137.9 (18.5)137.8 (17.2)
Median136.3       138.0       138.0       
Min, Max 80  , 184  100  , 194  100  , 192  
Week 8n292         240         224         
Mean (SD)136.3 (17.0)134.9 (17.8)135.1 (15.5)
Median136.5       132.3       134.0       
Min, Max 90  , 189   92  , 200   91  , 198  
Week 16n272         168         148         
Mean (SD)134.6 (18.3)132.5 (14.3)133.7 (16.0)
Median134.0       130.0       132.0       
Min, Max 76  , 190  100  , 168   99  , 186  
End of Treatmentn222         177         168         
Mean (SD)132.7 (15.4)133.0 (17.1)132.3 (15.6)
Median131.0       130.0       131.0       
Min, Max 78  , 172   92  , 178  100  , 177  
Temperature (C)Baselinen172         190         144         
Mean (SD) 36.6 ( 0.4) 36.5 ( 0.4) 36.6 ( 0.4)
Median 36.7        36.6        36.6       
Min, Max 35  , 37    35  , 37    36  , 37   
Week 8n146         118         112         
Mean (SD) 36.6 ( 0.4) 36.6 ( 0.4) 36.6 ( 0.4)
Median 36.6        36.7        36.7       
Min, Max 36  , 37    36  , 37    36  , 37   
Week 16n136          82          74         
Mean (SD) 36.7 ( 0.3) 36.6 ( 0.4) 36.6 ( 0.4)
Median 36.7        36.6        36.7       
Min, Max 36  , 37    36  , 37    36  , 37   
End of Treatmentn 74          59          56         
Mean (SD) 36.7 ( 0.4) 36.6 ( 0.4) 36.6 ( 0.4)
Median 36.8        36.7        36.7       
Min, Max 35  , 37    35  , 38    36  , 37