Skip to contents

Demography Table

For this demography table we are going to use data_demog, an example analysis results dataset found in the package, which is based on the CDISC pilot data. This dataset has two different row label columns, rowlbl1 and rowlbl2 because we are building a table with group and row labels. There are also two order columns which will be used to set the row order of the output. There is a single column to define our table’s columns (multiple column columns are used when there is column spanning). Finally there is a param column, a value column and an additional grouping column, grp, which we can use for more complex formatting.

#> # A tibble: 6 × 8
#> # Groups:   rowlbl1 [1]
#>   rowlbl1 rowlbl2 param grp    ord1  ord2 column                 value
#>   <chr>   <chr>   <chr> <chr> <dbl> <dbl> <chr>                  <dbl>
#> 1 Age (y) n       n     cont      1     1 Placebo               86    
#> 2 Age (y) n       n     cont      1     1 Xanomeline Low Dose   84    
#> 3 Age (y) n       n     cont      1     1 Xanomeline High Dose  84    
#> 4 Age (y) n       n     cont      1     1 Total                254    
#> 5 Age (y) n       p     cont      1     1 p-value                0.593
#> 6 Age (y) Mean    Mean  cont      1     2 Placebo               75.2

The mock we are going to match looks like this:

Placebo Xanomeline Low Dose Xanomeline High Dose Total p-value
Age (y) n               xxx          xxx          xxx          xxx          x.xxx
Mean            xxx.x        xxx.x        xxx.x        xxx.x             
SD              xxx.xx       xxx.xx       xxx.xx       xxx.xx            
Median          xxx.x        xxx.x        xxx.x        xxx.x             
Min             xxx.x        xxx.x        xxx.x        xxx.x             
Max             xxx.x        xxx.x        xxx.x        xxx.x             
                                                                         
<65 yrs         xxx (xx.x %) xxx (xx.x %) xxx (xx.x %) xxx (xx.x %) x.xxx
65-80 yrs       xxx (xx.x %) xxx (xx.x %) xxx (xx.x %) xxx (xx.x %)      
>80 yrs         xxx (xx.x %) xxx (xx.x %) xxx (xx.x %) xxx (xx.x %)      
                                                                         
Sex n               xxx          xxx          xxx          xxx          x.xxx
Male            xxx (xx.x %) xxx (xx.x %) xxx (xx.x %) xxx (xx.x %)      
Female          xxx (xx.x %) xxx (xx.x %) xxx (xx.x %) xxx (xx.x %)      
                                                                         
Race (Origin) n               xxx          xxx          xxx          xxx          x.xxx
Caucasian       xxx (xx.x %) xxx (xx.x %) xxx (xx.x %) xxx (xx.x %)      
African Descent xxx (xx.x %) xxx (xx.x %) xxx (xx.x %) xxx (xx.x %)      
Hispanic        xxx (xx.x %) xxx (xx.x %) xxx (xx.x %) xxx (xx.x %)      
Other           xxx (xx.x %) xxx (xx.x %) xxx (xx.x %) xxx (xx.x %)      
                                                                         
MMSE n               xxx          xxx          xxx          xxx          x.xxx
Mean            xxx.x        xxx.x        xxx.x        xxx.x             
SD              xxx.xx       xxx.xx       xxx.xx       xxx.xx            
Median          xxx.x        xxx.x        xxx.x        xxx.x             
Min             xxx.x        xxx.x        xxx.x        xxx.x             
Max             xxx.x        xxx.x        xxx.x        xxx.x             
                                                                         
Duration of disease n               xxx          xxx          xxx          xxx          x.xxx
Mean            xxx.x        xxx.x        xxx.x        xxx.x             
SD              xxx.xx       xxx.xx       xxx.xx       xxx.xx            
Median          xxx.x        xxx.x        xxx.x        xxx.x             
Min             xxx.x        xxx.x        xxx.x        xxx.x             
Max             xxx.x        xxx.x        xxx.x        xxx.x             
                                                                         
<12 months      xxx (xx.x %) xxx (xx.x %) xxx (xx.x %) xxx (xx.x %) x.xxx
>=12 months     xxx (xx.x %) xxx (xx.x %) xxx (xx.x %) xxx (xx.x %)      
                                                                         
Years of education n               xxx          xxx          xxx          xxx          x.xxx
Mean            xxx.x        xxx.x        xxx.x        xxx.x             
SD              xxx.xx       xxx.xx       xxx.xx       xxx.xx            
Median          xxx.x        xxx.x        xxx.x        xxx.x             
Min             xxx.x        xxx.x        xxx.x        xxx.x             
Max             xxx.x        xxx.x        xxx.x        xxx.x             
                                                                         
Baseline weight(kg) n               xxx          xxx          xxx          xxx          x.xxx
Mean            xxx.x        xxx.x        xxx.x        xxx.x             
SD              xxx.xx       xxx.xx       xxx.xx       xxx.xx            
Median          xxx.x        xxx.x        xxx.x        xxx.x             
Min             xxx.x        xxx.x        xxx.x        xxx.x             
Max             xxx.x        xxx.x        xxx.x        xxx.x             
                                                                         
Baseline height(cm) n               xxx          xxx          xxx          xxx          x.xxx
Mean            xxx.x        xxx.x        xxx.x        xxx.x             
SD              xxx.xx       xxx.xx       xxx.xx       xxx.xx            
Median          xxx.x        xxx.x        xxx.x        xxx.x             
Min             xxx.x        xxx.x        xxx.x        xxx.x             
Max             xxx.x        xxx.x        xxx.x        xxx.x             
                                                                         
Baseline BMI n               xxx          xxx          xxx          xxx          x.xxx
Mean            xxx.x        xxx.x        xxx.x        xxx.x             
SD              xxx.xx       xxx.xx       xxx.xx       xxx.xx            
Median          xxx.x        xxx.x        xxx.x        xxx.x             
Min             xxx.x        xxx.x        xxx.x        xxx.x             
Max             xxx.x        xxx.x        xxx.x        xxx.x             
                                                                         
<25             xxx (xx.x %) xxx (xx.x %) xxx (xx.x %) xxx (xx.x %) x.xxx
25-<30          xxx (xx.x %) xxx (xx.x %) xxx (xx.x %) xxx (xx.x %)      
>=30            xxx (xx.x %) xxx (xx.x %) xxx (xx.x %) xxx (xx.x %)      
                                                                         

For this table, we have three columns for each of the treatment groups, a total column for all groups combined, and a p-value column. The table also contains a mix of categorical and continuous analysis.

The first thing we are going to do when building out the tfrmt is specify all our columns

tfrmt(
  # specify columns in the data
  group = c(rowlbl1,grp),
  label = rowlbl2,
  column = column, 
  param = param,
  value = value,
  sorting_cols = c(ord1, ord2)) %>% 
  print_to_gt(data_demog) %>% 
  tab_options(
    container.width = 900
  )
ord1 ord2 Placebo Xanomeline Low Dose Xanomeline High Dose Total p-value
Age (y)






  cont






    n 1 1 86 84 84 254 0.593435775283097
    Mean 1 2 75.2093023255814 75.6666666666667 74.3809523809524 75.0866141732283 NA
    SD 1 3 8.59016712714193 8.28605059954093 7.88609384869824 8.24623389621606 NA
    Median 1 4 76 77.5 76 77 NA
    Min 1 5 52 51 56 51 NA
    Max 1 6 89 88 88 89 NA
  cat






    <65 yrs 1 7 14, 16.2790697674419 8, 9.52380952380952 11, 13.0952380952381 33, 12.992125984252 0.143917025502502
    65-80 yrs 1 8 42, 48.8372093023256 47, 55.9523809523809 55, 65.4761904761905 144, 56.6929133858268 NA
    >80 yrs 1 9 30, 34.8837209302326 29, 34.5238095238095 18, 21.4285714285714 77, 30.3149606299213 NA
Sex






  cat






    n 2 1 86 84 84 254 0.140859828596478
    Male 2 2 33, 38.3720930232558 34, 40.4761904761905 44, 52.3809523809524 111, 43.7007874015748 NA
    Female 2 3 53, 61.6279069767442 50, 59.5238095238095 40, 47.6190476190476 143, 56.2992125984252 NA
Race (Origin)






  cat






    n 3 1 86 84 84 254 0.647674941661787
    Caucasian 3 2 75, 87.2093023255814 72, 85.7142857142857 71, 84.5238095238095 218, 85.8267716535433 NA
    African Descent 3 3 8, 9.30232558139535 6, 7.14285714285714 9, 10.7142857142857 23, 9.05511811023622 NA
    Hispanic 3 4 3, 3.48837209302326 6, 7.14285714285714 3, 3.57142857142857 12, 4.7244094488189 NA
    Other 3 5 NA, NA NA, NA 1, 1.19047619047619 1, 0.393700787401575 NA
MMSE






  cont






    n 4 1 86 84 84 254 0.59465975941027
    Mean 4 2 18.046511627907 17.8690476190476 18.5119047619048 18.1417322834646 NA
    SD 4 3 4.2727783404855 4.22208696726523 4.15800591577738 4.21032874412179 NA
    Median 4 4 19.5 18 20 19 NA
    Min 4 5 10 10 10 10 NA
    Max 4 6 23 24 24 24 NA
Duration of disease 






  cont






    n 5 1 86 84 84 254 0.152960564175341
    Mean 5 2 42.65 48.6916666666667 40.5071428571429 43.9393700787402 NA
    SD 5 3 30.241571504451 29.5841711516636 24.6935472070355 28.3973156262964 NA
    Median 5 4 35.3 40.25 35.95 36.25 NA
    Min 5 5 7.2 7.8 2.2 2.2 NA
    Max 5 6 183.1 130.8 135 183.1 NA
  cat






    <12 months 5 7 5, 5.81395348837209 3, 3.57142857142857 4, 4.76190476190476 12, 4.7244094488189 0.788536928535063
    >=12 months 5 8 81, 94.1860465116279 81, 96.4285714285714 80, 95.2380952380952 242, 95.2755905511811 NA
Years of education






  cont






    n 6 1 86 84 84 254 0.38750874992316
    Mean 6 2 12.5813953488372 13.1666666666667 12.5119047619048 12.751968503937 NA
    SD 6 3 2.94843973206596 4.14738510544312 2.91854910157261 3.3829227112292 NA
    Median 6 4 12 12 12 12 NA
    Min 6 5 6 3 6 3 NA
    Max 6 6 21 24 20 24 NA
Baseline weight(kg)






  cont






    n 7 1 86 83 84 253 0.00304006274608553
    Mean 7 2 62.7593023255814 67.2795180722892 70.0047619047619 66.6478260869565 NA
    SD 7 3 12.7715435329253 14.1235986486909 14.6534333717795 14.1314255372792 NA
    Median 7 4 60.55 64.9 69.2 66.7 NA
    Min 7 5 34 45.4 41.7 34 NA
    Max 7 6 86.2 106.1 108 108 NA
Baseline height(cm)






  cont






    n 8 1 86 84 84 254 0.126217916960126
    Mean 8 2 162.573255813953 163.433333333333 165.820238095238 163.931496062992 NA
    SD 8 3 11.5223611185188 10.4192400034262 10.1313515524819 10.7604472686284 NA
    Median 8 4 162.6 162.6 165.1 162.85 NA
    Min 8 5 137.2 135.9 146.1 135.9 NA
    Max 8 6 185.4 195.6 190.5 195.6 NA
Baseline BMI






  cont






    n 9 1 86 83 84 253 0.0133190726378392
    Mean 9 2 23.6360465116279 25.0626506024096 25.347619047619 24.6723320158103 NA
    SD 9 3 3.67192569419556 4.27050893303881 4.15826876019846 4.09218492698334 NA
    Median 9 4 23.4 24.3 24.8 24.2 NA
    Min 9 5 15.1 17.7 13.7 13.7 NA
    Max 9 6 33.3 40.1 34.5 40.1 NA
  cat






    <25 9 7 59, 68.6046511627907 47, 55.9523809523809 44, 52.3809523809524 150, 59.0551181102362 0.232621461976889
    25-<30 9 8 21, 24.4186046511628 27, 32.1428571428571 28, 33.3333333333333 76, 29.9212598425197 NA
    >=30 9 9 6, 6.97674418604651 10, 11.9047619047619 12, 14.2857142857143 28, 11.0236220472441 NA

While this makes a table, it isn’t a very nice table and definitely doesn’t match the mock. So let’s start with formatting all the numbers. To do this we are going to build a body_plan to add to our tfrmt. This will be a fairly quick explanation of body_plans but if you would like more information see vignettes("Body Plan")

Body plans are made up of a series of frmt_stuctures where each frmt_stucture represents the formatting of a cell within the table. The order of the frmt_structures matter; they are always applied latest to oldest. This means the first frmt_stucture in the body_plan should be the most generic. You can use the groups, labels and parameters to specify which formatting applies to which values.

To start, we are going to use all the rows that are “n (%)” as the default. This way we don’t need to list out every row that is an “n (%)” row. These rows are made up of two different values, so we will need to use frmt_combine. Next, we can format the continuous variables, which is just a straightforward one value per row so we can just use the label to filter and frmt to define the look. Finally, we want to format the p-values. This is a bit more complicated, since the p-value sits in the same row as other parameters; therefore the group and label value are not specific enough and we need something more granular. As such, we will need to specify the parameter in the frmt_structure like so: frmt_structure(group_val = ".default", label_val = ".default", p = frmt("x.xx"). Further, we also need to make sure it never displays a rounded p-value of 0 or 1. So we can use frmt_when to specify the formatting based on the value.

tfrmt(
  # specify columns in the data
  group = c(rowlbl1,grp),
  label = rowlbl2,
  column = column, 
  param = param,
  value = value,
  sorting_cols = c(ord1, ord2),
  # specify value formatting 
  body_plan = body_plan(
    frmt_structure(group_val = ".default", label_val = ".default", frmt_combine("{n} ({pct} %)", 
                                                                                n = frmt("xxx"),
                                                                                pct = frmt("xx.x"))),
    frmt_structure(group_val = ".default", label_val = "n", frmt("xxx")),
    frmt_structure(group_val = ".default", label_val = c("Mean", "Median", "Min","Max"), frmt("xxx.x")),
    frmt_structure(group_val = ".default", label_val = "SD", frmt("xxx.xx")),
    frmt_structure(group_val = ".default", label_val = ".default", p = frmt_when(">0.99" ~ ">0.99",
                                                                                 "<0.001" ~ "<0.001",
                                                                                 TRUE ~ frmt("x.xxx", missing = "")))
  )) %>% 
  print_to_gt(data_demog) %>% 
  tab_options(
    container.width = 900
  )
ord1 ord2 Placebo Xanomeline Low Dose Xanomeline High Dose Total p-value
Age (y)






  cont






    n 1 1  86  84  84 254 0.593
    Mean 1 2  75.2  75.7  74.4  75.1
    SD 1 3   8.59   8.29   7.89   8.25
    Median 1 4  76.0  77.5  76.0  77.0
    Min 1 5  52.0  51.0  56.0  51.0
    Max 1 6  89.0  88.0  88.0  89.0
  cat






    <65 yrs 1 7  14 (16.3 %)   8 ( 9.5 %)  11 (13.1 %)  33 (13.0 %) 0.144
    65-80 yrs 1 8  42 (48.8 %)  47 (56.0 %)  55 (65.5 %) 144 (56.7 %)
    >80 yrs 1 9  30 (34.9 %)  29 (34.5 %)  18 (21.4 %)  77 (30.3 %)
Sex






  cat






    n 2 1  86  84  84 254 0.141
    Male 2 2  33 (38.4 %)  34 (40.5 %)  44 (52.4 %) 111 (43.7 %)
    Female 2 3  53 (61.6 %)  50 (59.5 %)  40 (47.6 %) 143 (56.3 %)
Race (Origin)






  cat






    n 3 1  86  84  84 254 0.648
    Caucasian 3 2  75 (87.2 %)  72 (85.7 %)  71 (84.5 %) 218 (85.8 %)
    African Descent 3 3   8 ( 9.3 %)   6 ( 7.1 %)   9 (10.7 %)  23 ( 9.1 %)
    Hispanic 3 4   3 ( 3.5 %)   6 ( 7.1 %)   3 ( 3.6 %)  12 ( 4.7 %)
    Other 3 5   1 ( 1.2 %)   1 ( 0.4 %)
MMSE






  cont






    n 4 1  86  84  84 254 0.595
    Mean 4 2  18.0  17.9  18.5  18.1
    SD 4 3   4.27   4.22   4.16   4.21
    Median 4 4  19.5  18.0  20.0  19.0
    Min 4 5  10.0  10.0  10.0  10.0
    Max 4 6  23.0  24.0  24.0  24.0
Duration of disease 






  cont






    n 5 1  86  84  84 254 0.153
    Mean 5 2  42.6  48.7  40.5  43.9
    SD 5 3  30.24  29.58  24.69  28.40
    Median 5 4  35.3  40.2  36.0  36.2
    Min 5 5   7.2   7.8   2.2   2.2
    Max 5 6 183.1 130.8 135.0 183.1
  cat






    <12 months 5 7   5 ( 5.8 %)   3 ( 3.6 %)   4 ( 4.8 %)  12 ( 4.7 %) 0.789
    >=12 months 5 8  81 (94.2 %)  81 (96.4 %)  80 (95.2 %) 242 (95.3 %)
Years of education






  cont






    n 6 1  86  84  84 254 0.388
    Mean 6 2  12.6  13.2  12.5  12.8
    SD 6 3   2.95   4.15   2.92   3.38
    Median 6 4  12.0  12.0  12.0  12.0
    Min 6 5   6.0   3.0   6.0   3.0
    Max 6 6  21.0  24.0  20.0  24.0
Baseline weight(kg)






  cont






    n 7 1  86  83  84 253 0.003
    Mean 7 2  62.8  67.3  70.0  66.6
    SD 7 3  12.77  14.12  14.65  14.13
    Median 7 4  60.5  64.9  69.2  66.7
    Min 7 5  34.0  45.4  41.7  34.0
    Max 7 6  86.2 106.1 108.0 108.0
Baseline height(cm)






  cont






    n 8 1  86  84  84 254 0.126
    Mean 8 2 162.6 163.4 165.8 163.9
    SD 8 3  11.52  10.42  10.13  10.76
    Median 8 4 162.6 162.6 165.1 162.8
    Min 8 5 137.2 135.9 146.1 135.9
    Max 8 6 185.4 195.6 190.5 195.6
Baseline BMI






  cont






    n 9 1  86  83  84 253 0.013
    Mean 9 2  23.6  25.1  25.3  24.7
    SD 9 3   3.67   4.27   4.16   4.09
    Median 9 4  23.4  24.3  24.8  24.2
    Min 9 5  15.1  17.7  13.7  13.7
    Max 9 6  33.3  40.1  34.5  40.1
  cat






    <25 9 7  59 (68.6 %)  47 (56.0 %)  44 (52.4 %) 150 (59.1 %) 0.233
    25-<30 9 8  21 (24.4 %)  27 (32.1 %)  28 (33.3 %)  76 (29.9 %)
    >=30 9 9   6 ( 7.0 %)  10 (11.9 %)  12 (14.3 %)  28 (11.0 %)

Now that all the numbers look correct, we can drop the order columns and the grp column (note that while we do not want to display the grp column, it plays a role behind the scenes, which will be addressed in the next step). To do this we use a col_plan which uses tidy-select nomenclature to drop/move columns.

tfrmt(
  # specify columns in the data
  group = c(rowlbl1,grp),
  label = rowlbl2,
  column = column, 
  param = param,
  value = value,
  sorting_cols = c(ord1, ord2),
  # specify value formatting 
  body_plan = body_plan(
    frmt_structure(group_val = ".default", label_val = ".default", frmt_combine("{n} {pct}", 
                                                                                n = frmt("xxx"),
                                                                                pct = frmt_when("==100" ~ "",
                                                                                                "==0" ~ "",
                                                                                                TRUE ~ frmt("(xx.x %)")))),
    frmt_structure(group_val = ".default", label_val = "n", frmt("xxx")),
    frmt_structure(group_val = ".default", label_val = c("Mean", "Median", "Min","Max"), frmt("xxx.x")),
    frmt_structure(group_val = ".default", label_val = "SD", frmt("xxx.xx")),
    frmt_structure(group_val = ".default", label_val = ".default", p = frmt("")),
    frmt_structure(group_val = ".default", label_val = c("n","<65 yrs","<12 months","<25"), p = frmt_when(">0.99" ~ ">0.99",
                                                                                 "<0.001" ~ "<0.001",
                                                                                 TRUE ~ frmt("x.xxx", missing = "")))
  ),
  # remove extra cols
  col_plan = col_plan(-grp, 
                      -starts_with("ord") )) %>% 
  print_to_gt(data_demog) %>% 
  tab_options(
    container.width = 900
  )
Placebo Xanomeline Low Dose Xanomeline High Dose Total p-value
Age (y)




  n  86  84  84 254 0.593
  Mean  75.2  75.7  74.4  75.1
  SD   8.59   8.29   7.89   8.25
  Median  76.0  77.5  76.0  77.0
  Min  52.0  51.0  56.0  51.0
  Max  89.0  88.0  88.0  89.0
  <65 yrs  14 (16.3 %)   8 ( 9.5 %)  11 (13.1 %)  33 (13.0 %) 0.144
  65-80 yrs  42 (48.8 %)  47 (56.0 %)  55 (65.5 %) 144 (56.7 %)
  >80 yrs  30 (34.9 %)  29 (34.5 %)  18 (21.4 %)  77 (30.3 %)
Sex




  n  86  84  84 254 0.141
  Male  33 (38.4 %)  34 (40.5 %)  44 (52.4 %) 111 (43.7 %)
  Female  53 (61.6 %)  50 (59.5 %)  40 (47.6 %) 143 (56.3 %)
Race (Origin)




  n  86  84  84 254 0.648
  Caucasian  75 (87.2 %)  72 (85.7 %)  71 (84.5 %) 218 (85.8 %)
  African Descent   8 ( 9.3 %)   6 ( 7.1 %)   9 (10.7 %)  23 ( 9.1 %)
  Hispanic   3 ( 3.5 %)   6 ( 7.1 %)   3 ( 3.6 %)  12 ( 4.7 %)
  Other   1 ( 1.2 %)   1 ( 0.4 %)
MMSE




  n  86  84  84 254 0.595
  Mean  18.0  17.9  18.5  18.1
  SD   4.27   4.22   4.16   4.21
  Median  19.5  18.0  20.0  19.0
  Min  10.0  10.0  10.0  10.0
  Max  23.0  24.0  24.0  24.0
Duration of disease 




  n  86  84  84 254 0.153
  Mean  42.6  48.7  40.5  43.9
  SD  30.24  29.58  24.69  28.40
  Median  35.3  40.2  36.0  36.2
  Min   7.2   7.8   2.2   2.2
  Max 183.1 130.8 135.0 183.1
  <12 months   5 ( 5.8 %)   3 ( 3.6 %)   4 ( 4.8 %)  12 ( 4.7 %) 0.789
  >=12 months  81 (94.2 %)  81 (96.4 %)  80 (95.2 %) 242 (95.3 %)
Years of education




  n  86  84  84 254 0.388
  Mean  12.6  13.2  12.5  12.8
  SD   2.95   4.15   2.92   3.38
  Median  12.0  12.0  12.0  12.0
  Min   6.0   3.0   6.0   3.0
  Max  21.0  24.0  20.0  24.0
Baseline weight(kg)




  n  86  83  84 253 0.003
  Mean  62.8  67.3  70.0  66.6
  SD  12.77  14.12  14.65  14.13
  Median  60.5  64.9  69.2  66.7
  Min  34.0  45.4  41.7  34.0
  Max  86.2 106.1 108.0 108.0
Baseline height(cm)




  n  86  84  84 254 0.126
  Mean 162.6 163.4 165.8 163.9
  SD  11.52  10.42  10.13  10.76
  Median 162.6 162.6 165.1 162.8
  Min 137.2 135.9 146.1 135.9
  Max 185.4 195.6 190.5 195.6
Baseline BMI




  n  86  83  84 253 0.013
  Mean  23.6  25.1  25.3  24.7
  SD   3.67   4.27   4.16   4.09
  Median  23.4  24.3  24.8  24.2
  Min  15.1  17.7  13.7  13.7
  Max  33.3  40.1  34.5  40.1
  <25  59 (68.6 %)  47 (56.0 %)  44 (52.4 %) 150 (59.1 %) 0.233
  25-<30  21 (24.4 %)  27 (32.1 %)  28 (33.3 %)  76 (29.9 %)
  >=30   6 ( 7.0 %)  10 (11.9 %)  12 (14.3 %)  28 (11.0 %)

Now this table looks just about right. There are two problems, (1) alignment and (2) spacing between the continuous and categorical values. To take care of the alignment we are going to add a col_style_plan which accepts a series of col_style_structures. This allows columns to be aligned differently if needed. For this table, we want all the columns to align on either “.”, “,” or ” ” so our col_style_structure looks like col_style_structure(align = c(".",","," "), col = vars(everything())). After the alignment is sorted we can move on to the spacing. In order to match the spacing of the mock we need to use the extra grp column from our data. If we look at our data, we can see we want a space any time either of the groups change.

data_demog %>% 
  distinct(rowlbl1,grp)
#> # A tibble: 12 × 2
#> # Groups:   rowlbl1 [9]
#>    rowlbl1                grp  
#>    <chr>                  <chr>
#>  1 "Age (y)"              cont 
#>  2 "Age (y)"              cat  
#>  3 "Sex"                  cat  
#>  4 "Race (Origin)"        cat  
#>  5 "MMSE"                 cont 
#>  6 "Duration of disease " cont 
#>  7 "Duration of disease " cat  
#>  8 "Years of education"   cont 
#>  9 "Baseline weight(kg)"  cont 
#> 10 "Baseline height(cm)"  cont 
#> 11 "Baseline BMI"         cont 
#> 12 "Baseline BMI"         cat

This means that we can use a row_grp_plan with just a ".default" as the group value and it should handle all of the spacing. In addition to the spacing, row_grp_plan will let us move the spanning group labels to a separate column by changing the label_loc to “column”.

tfrmt(
  # specify columns in the data
  group = c(rowlbl1,grp),
  label = rowlbl2,
  column = column, 
  param = param,
  value = value,
  sorting_cols = c(ord1, ord2),
  # specify value formatting 
  body_plan = body_plan(
    frmt_structure(group_val = ".default", label_val = ".default", frmt_combine("{n} {pct}", 
                                                                                n = frmt("xxx"),
                                                                                pct = frmt_when("==100" ~ "",
                                                                                                "==0" ~ "",
                                                                                                TRUE ~ frmt("(xx.x %)")))),
    frmt_structure(group_val = ".default", label_val = "n", frmt("xxx")),
    frmt_structure(group_val = ".default", label_val = c("Mean", "Median", "Min","Max"), frmt("xxx.x")),
    frmt_structure(group_val = ".default", label_val = "SD", frmt("xxx.xx")),
    frmt_structure(group_val = ".default", label_val = ".default", p = frmt("")),
    frmt_structure(group_val = ".default", label_val = c("n","<65 yrs","<12 months","<25"), p = frmt_when(">0.99" ~ ">0.99",
                                                                                 "<0.001" ~ "<0.001",
                                                                                 TRUE ~ frmt("x.xxx", missing = "")))
  ),
  # remove extra cols
  col_plan = col_plan(-grp, 
                      -starts_with("ord") ),
  # Specify column styling plan
  col_style_plan = col_style_plan(
    col_style_structure(align = c(".",","," "), col = c("Placebo", "Xanomeline Low Dose",
                                                        "Xanomeline High Dose", "Total", "p-value")),
    col_style_structure(align = "left", col = c("rowlbl1","rowlbl2"))
  ),
  
    # Specify row group plan
  row_grp_plan = row_grp_plan(
    row_grp_structure(group_val = ".default", element_block(post_space = " ")),
    label_loc = element_row_grp_loc(location = "column")
  )
  
  ) %>% 
  print_to_gt(data_demog) %>% 
  tab_options(
    container.width = 900
  )
Placebo Xanomeline Low Dose Xanomeline High Dose Total p-value
Age (y) n                86           84           84          254          0.593
Mean             75.2         75.7         74.4         75.1             
SD                8.59         8.29         7.89         8.25            
Median           76.0         77.5         76.0         77.0             
Min              52.0