Tables in R using {tfrmt}

ARDS ๐Ÿค Tables: A Dynamic Duo

Objectives

  • By the end of this tables section you will have:
    • Developed an understanding of how tfrmt supports table creation in multiple phases of the reporting process
    • Seen examples of demographic and AE summary table formatting
    • Gained an awareness of utilities for the transition from cards to tfrmt input data

Play by Play to achieve our Objectives

  • ๐Ÿ•™ 10 mins: The possibilities of tfrmt

  • ๐Ÿ•ฅ 15 mins: Step-by-step formatting a display

  • ๐Ÿ•š 10 mins: cards-to-tfrmt helpers

  • ๐Ÿ•ฆ 10 mins: Exercise

ARD-first Tables with {tfrmt}

  • Metadata-driven table formatting

  • Easily create new and modify existing tables

  • Input: ARD with raw, numeric values ({cards}!)

  • Output: Formatted table via {gt}

Thereโ€™s also an app!

The {tfrmt} object

  • Pre-define the non-data components of your table
  • Pre-define how the data will be handled once added

A quick tour of the many uses of {tfrmt}

Use #1: Study planning (mocks)

library(tfrmt)

print_mock_gt(
  tfrmt = tfrmt_demog, # tfrmt
  .data = ard_demog_mock # sample ARD
)|> 
   gt_style_slides()
Demographics Table
Placebo
N = xx
Low Dose
N = xx
High Dose
N = xx
Age (y)     


  Mean       xxx.x        xxx.x        xxx.x       
  SD         xxx.xx       xxx.xx       xxx.xx      
  Median     xxx.x        xxx.x        xxx.x       
  Min        xxx.x        xxx.x        xxx.x       
  Max        xxx.x        xxx.x        xxx.x       
  <65 yrs    xxx (xx.x %) xxx (xx.x %) xxx (xx.x %)
  65-80 yrs  xxx (xx.x %) xxx (xx.x %) xxx (xx.x %)
  >80 yrs    xxx (xx.x %) xxx (xx.x %) xxx (xx.x %)
Sex         


  Male       xxx (xx.x %) xxx (xx.x %) xxx (xx.x %)
  Female     xxx (xx.x %) xxx (xx.x %) xxx (xx.x %)
Baseline BMI


  Mean       xxx.x        xxx.x        xxx.x       
  SD         xxx.xx       xxx.xx       xxx.xx      
  Median     xxx.x        xxx.x        xxx.x       
  Min        xxx.x        xxx.x        xxx.x       
  Max        xxx.x        xxx.x        xxx.x       
  <25        xxx (xx.x %) xxx (xx.x %) xxx (xx.x %)
  25-<30     xxx (xx.x %) xxx (xx.x %) xxx (xx.x %)
  >=30       xxx (xx.x %) xxx (xx.x %) xxx (xx.x %)
  • If no data is supplied, {tfrmt} will generate some under the hood

Use #2: Final analysis

library(tfrmt)

print_to_gt(
  tfrmt = tfrmt_demog,
  .data = ard_demog # true ARD
)|> 
   gt_style_slides()
Demographics Table
Placebo
N = 86
Low Dose
N = 84
High Dose
N = 84
Age (y)     


  Mean       75.2        75.7        74.4       
  SD          8.59        8.29        7.89      
  Median     76.0        77.5        76.0       
  Min        52.0        51.0        56.0       
  Max        89.0        88.0        88.0       
  <65 yrs    14 (16.3 %)  8 ( 9.5 %) 11 (13.1 %)
  65-80 yrs  42 (48.8 %) 47 (56.0 %) 55 (65.5 %)
  >80 yrs    30 (34.9 %) 29 (34.5 %) 18 (21.4 %)
Sex         


  Male       33 (38.4 %) 34 (40.5 %) 44 (52.4 %)
  Female     53 (61.6 %) 50 (59.5 %) 40 (47.6 %)
Baseline BMI


  Mean       23.6        25.1        25.3       
  SD          3.67        4.27        4.16      
  Median     23.4        24.3        24.8       
  Min        15.1        17.7        13.7       
  Max        33.3        40.1        34.5       
  <25        59 (68.6 %) 47 (56.0 %) 44 (52.4 %)
  25-<30     21 (24.4 %) 27 (32.1 %) 28 (33.3 %)
  >=30        6 ( 7.0 %) 10 (11.9 %) 12 (14.3 %)
  • Full reuse of the original {tfrmt} object = reduced rework!

Use #3: Repurposed final table

library(tfrmt)

tfrmt_demog |> 
  layer_tfrmt(
    tfrmt_demog_custom  
  )|> 
  print_to_gt( 
    .data = ard_demog
  ) |> 
  gt::grp_pull(1)|> 
   gt_style_slides()
Demographics Table
Safety Population
High Dose
(N = 84)
Low Dose
(N = 84)
Placebo
(N = 86)
Age (y)    


  Mean      74.4        75.7        75.2       
  SD         7.89        8.29        8.59      
  Median    76.0        77.5        76.0       
  Min       56.0        51.0        52.0       
  Max       88.0        88.0        89.0       
                                               
  <65 yrs   11 (13.1 %)  8 ( 9.5 %) 14 (16.3 %)
  65-80 yrs 55 (65.5 %) 47 (56.0 %) 42 (48.8 %)
  >80 yrs   18 (21.4 %) 29 (34.5 %) 30 (34.9 %)
                                               
Sex        


  Male      44 (52.4 %) 34 (40.5 %) 33 (38.4 %)
  Female    40 (47.6 %) 50 (59.5 %) 53 (61.6 %)
                                               
Data collected at Screening Visit
  • Layering allows for custom tweaks while preserving the original metadata

Templates: the possibilities

  • Organization standards can be capture as templates
# create a template as a function
tfrmt_demog_org <- function(tfrmt_obj){
  
  tfrmt_demog_org <- tfrmt( 
    # define standard formatting for org
  )
  
  layer_tfrmt(x = tfrmt_obj, y = tfrmt_demog_ta)
}

# Make a standard table
tfrmt_demog_org() |>  
  print_to_gt(
    .data = ard_demog
  )

Templates: the possibilities

  • Organization standards can be capture as templates

  • With layering, teams can customize only the bits that need changing

# create a template as a function
tfrmt_demog_ta <- function(tfrmt_obj){
  
  tfrmt_demog_ta <- tfrmt( 
    # define the formatting specific to the therapeutic area
  )
  
  layer_tfrmt(x = tfrmt_obj, y = tfrmt_demog_ta)
}

# Layering multiple templates
tfrmt_demog_org() |> 
  tfrmt_demog_ta() |>  
  print_to_gt(
    .data = ard_demog
  )

Templates: the possibilities

  • Organization standards can be capture as templates

  • With layering, teams can customize only the bits that need changing

# create a template as a function
tfrmt_demog_study <- function(tfrmt_obj){
  
  tfrmt_demog_study <- tfrmt( 
    # define the formatting specific to the study
  )
  
  layer_tfrmt(x = tfrmt_obj, y = tfrmt_demog_study)
}

# Layering multiple templates
tfrmt_demog_org() |> 
  tfrmt_demog_ta() |>  
  tfrmt_demog_study() |> 
  print_to_gt(
    .data = ard_demog
  )

Save metadata for reuse

library(tfrmt)

tfrmt_demog |> 
  tfrmt_to_json()
{
  "group": ["rowlbl1", "grp"],
  "label": ["rowlbl2"],
  "param": ["param"],
  "value": ["value"],
  "column": ["column"],
  "title": ["Demographics Table"],
  "body_plan": [
    {
      "group_val": [".default"],
      "label_val": [".default"],
      "param_val": ["n", "pct"],
      "frmt_combine": {
        "expression": ["{n} {pct}"],
        "frmt_ls": {
          "n": {
            "frmt": {
              "expression": ["xxx"],
              "missing": {},
              "scientific": {},
              "transform": {}
            }
          },
          "pct": {
            "frmt_when": {
              "frmt_ls": {
                "==100": [""],
                "==0": [""],
                "TRUE": {
                  "frmt": {
                    "expression": ["(xx.x %)"],
                    "missing": {},
                    "scientific": {},
                    "transform": {}
                  }
                }
              },
              "missing": {}
            }
          }
        },
        "missing": {}
      }
    },
    {
      "group_val": [".default"],
      "label_val": ["n"],
      "param_val": [".default"],
      "frmt": {
        "expression": ["xxx"],
        "missing": {},
        "scientific": {},
        "transform": {}
      }
    },
    {
      "group_val": [".default"],
      "label_val": ["Mean", "Median", "Min", "Max"],
      "param_val": [".default"],
      "frmt": {
        "expression": ["xxx.x"],
        "missing": {},
        "scientific": {},
        "transform": {}
      }
    },
    {
      "group_val": [".default"],
      "label_val": ["SD"],
      "param_val": [".default"],
      "frmt": {
        "expression": ["xxx.xx"],
        "missing": {},
        "scientific": {},
        "transform": {}
      }
    }
  ],
  "col_style_plan": [
    {
      "cols": [
        ["Placebo"],
        ["Low Dose"],
        ["High Dose"]
      ],
      "align": [".", ",", " "],
      "type": ["char"],
      "width": {}
    },
    {
      "cols": [
        ["rowlbl1"],
        ["rowlbl2"]
      ],
      "align": ["left"],
      "type": ["char"],
      "width": {}
    }
  ],
  "col_plan": {
    "col_plan": {
      "dots": [
        ["-grp"],
        ["-starts_with(\"ord\")"]
      ],
      ".drop": [false]
    }
  },
  "sorting_cols": ["ord1", "ord2"],
  "big_n": {
    "param_val": ["bigN"],
    "n_frmt": {
      "expression": ["<br>N = xx"],
      "missing": {},
      "scientific": {},
      "transform": {}
    },
    "by_page": [false]
  }
} 
  • Create a language-agnostic JSON file

  • Load JSON back into R and recreate the table with json_to_tfrmt()

Saving display

Now, letโ€™s format a display, 1 piece at a time

Creating a {tfrmt} table step-by-step

Demographic Table
Safety Population
Placebo
N = xx
Xanomeline
N = xx1
Age (years)

  Median   xx.x           xx.x        
  [Q1, Q3] [xx.x, xx.x]   [xx.x, xx.x]  
Age Group

  18-64     xx (xx.x%)     xx (xx.x%)
  >64     xx (xx.x%)     xx (xx.x%)
Sex

  F     xx (xx.x%)     xx (xx.x%)
  M     xx (xx.x%)     xx (xx.x%)
1 Pooled High and Low Dose

Ensure placement of all values (Main)

print(ard_demog)
# A tibble: 24 ร— 7
   ARM2    stat_variable stat_name   stat label     ord1  ord2
   <chr>   <chr>         <chr>      <dbl> <chr>    <dbl> <dbl>
 1 Placebo Age (years)   median    76     Median       1    NA
 2 Placebo Age (years)   p25       69     [Q1, Q3]     1    NA
 3 Placebo Age (years)   p75       82     [Q1, Q3]     1    NA
 4 Placebo Age Group     n         72     >64          2     2
 5 Placebo Age Group     p          0.837 >64          2     2
 6 Placebo Age Group     n         14     18-64        2     1
 7 Placebo Age Group     p          0.163 18-64        2     1
 8 Placebo Sex           n         53     F            3    NA
 9 Placebo Sex           p          0.616 F            3    NA
10 Placebo Sex           n         33     M            3    NA
# โ„น 14 more rows
Demographic Table
Safety Population
Placebo
N = xx
Xanomeline
N = xx1
Age (years)

  Median   xx.x           xx.x        
  [Q1, Q3] [xx.x, xx.x]   [xx.x, xx.x]  
Age Group

  18-64     xx (xx.x%)     xx (xx.x%)
  >64     xx (xx.x%)     xx (xx.x%)
Sex

  F     xx (xx.x%)     xx (xx.x%)
  M     xx (xx.x%)     xx (xx.x%)
1 Pooled High and Low Dose

Ensure placement of all values (Main)

tfrmt_demog <- tfrmt(
  group = stat_variable, 
  label = label, 
  column = ARM2,
  param = stat_name,
  value = stat, 
  sorting_cols = c(ord1, ord2) 
)

print_to_gt(
  tfrmt = tfrmt_demog,
  .data = ard_demog
) |> 
   gt_style_slides()
ord1 ord2 Placebo Xanomeline
Median 1 NA 76 77
[Q1, Q3] 1 NA 69, 82 71, 81
18-64 2 1 14, 0.162790697674419 19, 0.113095238095238
>64 2 2 72, 0.837209302325581 149, 0.886904761904762
F 3 NA 53, 0.616279069767442 90, 0.535714285714286
M 3 NA 33, 0.383720930232558 78, 0.464285714285714
NA NA NA 86 168

Ensure placement of all values (Big N)

tfrmt_demog <- tfrmt_demog |>
  tfrmt(
    big_n = big_n_structure(
      param_val = "bigN",
      n_frmt = frmt("<br>N = xx")
      )
  )

print_to_gt(
  tfrmt = tfrmt_demog, 
  .data = ard_demog
  )|> 
   gt_style_slides()
ord1 ord2 Placebo
N = 86
Xanomeline
N = 168
Age (years)



  Median 1 NA 76 77
  [Q1, Q3] 1 NA 69, 82 71, 81
Age Group



  18-64 2 1 14, 0.162790697674419 19, 0.113095238095238
  >64 2 2 72, 0.837209302325581 149, 0.886904761904762
Sex



  F 3 NA 53, 0.616279069767442 90, 0.535714285714286
  M 3 NA 33, 0.383720930232558 78, 0.464285714285714

Select and reorder columns

tfrmt_demog <- tfrmt_demog |>
  tfrmt(
    col_plan = col_plan(
      Placebo,
      Xanomeline,
      - starts_with("ord")
    )
  )

print_to_gt(
  tfrmt = tfrmt_demog, 
  .data = ard_demog
)|> 
   gt_style_slides()
Placebo
N = 86
Xanomeline
N = 168
Age (years)

  Median 76 77
  [Q1, Q3] 69, 82 71, 81
Age Group

  18-64 14, 0.162790697674419 19, 0.113095238095238
  >64 72, 0.837209302325581 149, 0.886904761904762
Sex

  F 53, 0.616279069767442 90, 0.535714285714286
  M 33, 0.383720930232558 78, 0.464285714285714

Format the data values - Basic

tfrmt_demog <- tfrmt_demog |>
  tfrmt(
    body_plan = body_plan(
      frmt_structure(
        group_val = ".default", 
        label_val = ".default", 
        frmt("x.xx"))
    )
  )

print_to_gt(
  tfrmt = tfrmt_demog, 
  .data = ard_demog
) |> 
   gt_style_slides()
Placebo
N = 86
Xanomeline
N = 168
Age (years)

  Median 76.00 77.00
  [Q1, Q3] 69.00, 82.00 71.00, 81.00
Age Group

  18-64 14.00, 0.16 19.00, 0.11
  >64 72.00, 0.84 149.00, 0.89
Sex

  F 53.00, 0.62 90.00, 0.54
  M 33.00, 0.38 78.00, 0.46

Format the data values - Advanced

tfrmt_demog <- tfrmt_demog |>
  tfrmt(
    body_plan = body_plan(
      frmt_structure(
        group_val = ".default", 
        label_val = ".default",
        frmt_combine("{n} ({p}%)",
                     n = frmt("xx"),
                     p = frmt("xx.x", transform = ~ . *100)
                     
        )
      )
    )
  )

print_to_gt(
  tfrmt = tfrmt_demog, 
  .data = ard_demog
  ) |> 
   gt_style_slides()
Placebo
N = 86
Xanomeline
N = 168
Age (years)

  Median 76.00 77.00
  [Q1, Q3] 69.00, 82.00 71.00, 81.00
Age Group

  18-64 14 (16.3%) 19 (11.3%)
  >64 72 (83.7%) 149 (88.7%)
Sex

  F 53 (61.6%) 90 (53.6%)
  M 33 (38.4%) 78 (46.4%)

Format the data values - Advanced

tfrmt_demog <- tfrmt_demog |>
  tfrmt(
    body_plan = body_plan(
      
      frmt_structure(
        group_val = ".default", 
        label_val = "Median",
        frmt("xx.x")
      ),
      
      frmt_structure(
        group_val = ".default",
        label_val = ".default",
        frmt_combine(
          expression = "[{p25}, {p75}]",                
          p25 = frmt("xx.x"),                     
          p75 = frmt("xx.x")                      
        )
      )
      
    )
  )
  
print_to_gt(
  tfrmt = tfrmt_demog, 
  .data = ard_demog
  ) |> 
   gt_style_slides()
Placebo
N = 86
Xanomeline
N = 168
Age (years)

  Median 76.0 77.0
  [Q1, Q3] [69.0, 82.0] [71.0, 81.0]
Age Group

  18-64 14 (16.3%) 19 (11.3%)
  >64 72 (83.7%) 149 (88.7%)
Sex

  F 53 (61.6%) 90 (53.6%)
  M 33 (38.4%) 78 (46.4%)

Align the columns

tfrmt_demog <- tfrmt_demog |>
  tfrmt(
    col_style_plan = col_style_plan(
      col_style_structure(
        col = c("Placebo", 
                "Xanomeline"),
        align = " "
      )
    )
  )
  
print_to_gt(
  tfrmt = tfrmt_demog, 
  .data = ard_demog
  ) |> 
   gt_style_slides()
Placebo
N = 86
Xanomeline
N = 168
Age (years)

  Median   76.0           77.0        
  [Q1, Q3] [69.0, 82.0]   [71.0, 81.0]  
Age Group

  18-64     14 (16.3%)     19 (11.3%)
  >64     72 (83.7%)    149 (88.7%)
Sex

  F     53 (61.6%)     90 (53.6%)
  M     33 (38.4%)     78 (46.4%)

Add footnotes

tfrmt_demog <- tfrmt_demog |>
  tfrmt(
    footnote_plan = footnote_plan(
      footnote_structure(
        "Pooled High and Low Dose",
        column_val = "Xanomeline"
      )
    )
  )
  
print_to_gt(
  tfrmt = tfrmt_demog, 
  .data = ard_demog
  ) |> 
   gt_style_slides()
Placebo
N = 86
Xanomeline
N = 1681
Age (years)

  Median   76.0           77.0        
  [Q1, Q3] [69.0, 82.0]   [71.0, 81.0]  
Age Group

  18-64     14 (16.3%)     19 (11.3%)
  >64     72 (83.7%)    149 (88.7%)
Sex

  F     53 (61.6%)     90 (53.6%)
  M     33 (38.4%)     78 (46.4%)
1 Pooled High and Low Dose

Add titles

tfrmt_demog <- tfrmt_demog |>
  tfrmt(
    title = "Demographic Table",
    subtitle = "Safety Population"
  )
  
print_to_gt(
  tfrmt = tfrmt_demog, 
  .data = ard_demog
  ) |> 
   gt_style_slides()
Demographic Table
Safety Population
Placebo
N = 86
Xanomeline
N = 1681
Age (years)

  Median   76.0           77.0        
  [Q1, Q3] [69.0, 82.0]   [71.0, 81.0]  
Age Group

  18-64     14 (16.3%)     19 (11.3%)
  >64     72 (83.7%)    149 (88.7%)
Sex

  F     53 (61.6%)     90 (53.6%)
  M     33 (38.4%)     78 (46.4%)
1 Pooled High and Low Dose

Other features include:

  • Transform values in the formatting

  • Row group formatting

  • Pagination

  • Multi-positional column alignment

  • Templating

cards to tfrmt - How did we get here?

cards to tfrmt helpers

  • {tfrmt} includes several helper functions to transform native {cards} output to display-ready data.
  • We need to get from the cards output on the left to the data frame on the right

Current data (cards output)

{cards} data frame: 28 x 11
   group1 group1_level variable variable_level stat_name stat_label  stat
1    ARM2      Placebo      AGE                   median     Median    76
2    ARM2      Placebo      AGE                      p25         Q1    69
3    ARM2      Placebo      AGE                      p75         Q3    82
4    ARM2      Placebo   AGEGR1            >64         n          n    72
5    ARM2      Placebo   AGEGR1            >64         p          % 0.837
6    ARM2      Placebo   AGEGR1          18-64         n          n    14
7    ARM2      Placebo   AGEGR1          18-64         p          % 0.163
8    ARM2      Placebo      SEX              F         n          n    53
9    ARM2      Placebo      SEX              F         p          % 0.616
10   ARM2      Placebo      SEX              M         n          n    33
โ„น 18 more rows
โ„น Use `print(n = ...)` to see more rows
โ„น 4 more variables: context, fmt_fun, warning, error

Goal data (tfrmt input)

# A tibble: 24 ร— 7
   ARM2    stat_variable stat_name   stat label     ord1  ord2
   <chr>   <chr>         <chr>      <dbl> <chr>    <dbl> <dbl>
 1 Placebo Age (years)   median    76     Median       1    NA
 2 Placebo Age (years)   p25       69     [Q1, Q3]     1    NA
 3 Placebo Age (years)   p75       82     [Q1, Q3]     1    NA
 4 Placebo Age Group     n         72     >64          2     2
 5 Placebo Age Group     p          0.837 >64          2     2
 6 Placebo Age Group     n         14     18-64        2     1
 7 Placebo Age Group     p          0.163 18-64        2     1
 8 Placebo Sex           n         53     F            3    NA
 9 Placebo Sex           p          0.616 F            3    NA
10 Placebo Sex           n         33     M            3    NA
# โ„น 14 more rows

cards to tfrmt

First, letโ€™s โ€œshuffleโ€ the results into a tidy data frame:

ard_demog_00 |> 
  tfrmt::shuffle_card(fill_overall = "Overall") 
# A tibble: 28 ร— 9
   ARM2    AGE    AGEGR1 SEX   context stat_variable stat_name stat_label   stat
   <chr>   <chr>  <chr>  <chr> <chr>   <chr>         <chr>     <chr>       <dbl>
 1 Placebo Overaโ€ฆ <NA>   <NA>  summary AGE           median    Median     76    
 2 Placebo Overaโ€ฆ <NA>   <NA>  summary AGE           p25       Q1         69    
 3 Placebo Overaโ€ฆ <NA>   <NA>  summary AGE           p75       Q3         82    
 4 Placebo <NA>   >64    <NA>  categoโ€ฆ AGEGR1        n         n          72    
 5 Placebo <NA>   >64    <NA>  categoโ€ฆ AGEGR1        p         %           0.837
 6 Placebo <NA>   18-64  <NA>  categoโ€ฆ AGEGR1        n         n          14    
 7 Placebo <NA>   18-64  <NA>  categoโ€ฆ AGEGR1        p         %           0.163
 8 Placebo <NA>   <NA>   F     categoโ€ฆ SEX           n         n          53    
 9 Placebo <NA>   <NA>   F     categoโ€ฆ SEX           p         %           0.616
10 Placebo <NA>   <NA>   M     categoโ€ฆ SEX           n         n          33    
# โ„น 18 more rows
Demographic Table
Safety Population
Placebo
N = xx
Xanomeline
N = xx1
Age (years)

  Median   xx.x           xx.x        
  [Q1, Q3] [xx.x, xx.x]   [xx.x, xx.x]  
Age Group

  18-64     xx (xx.x%)     xx (xx.x%)
  >64     xx (xx.x%)     xx (xx.x%)
Sex

  F     xx (xx.x%)     xx (xx.x%)
  M     xx (xx.x%)     xx (xx.x%)
1 Pooled High and Low Dose
  • Notice that our variables have been spread wide and are no longer named group1, group1_level, etc.
  • But we want to get all of our row variables (AGE, AGEGR1, SEX) into a single, stacked column

cards to tfrmt

  • We want to get all of our row variables (AGE, AGEGR1, SEX) into a single, stacked column
  • We can collapse them into a single column named variable_level
ard_demog_00 |> 
  tfrmt::shuffle_card(fill_overall = "Overall") |> 
  tfrmt::prep_combine_vars(c("AGE","AGEGR1","SEX"))
# A tibble: 28 ร— 7
   ARM2    variable_level context     stat_variable stat_name stat_label   stat
   <chr>   <chr>          <chr>       <chr>         <chr>     <chr>       <dbl>
 1 Placebo Overall        summary     AGE           median    Median     76    
 2 Placebo Overall        summary     AGE           p25       Q1         69    
 3 Placebo Overall        summary     AGE           p75       Q3         82    
 4 Placebo >64            categorical AGEGR1        n         n          72    
 5 Placebo >64            categorical AGEGR1        p         %           0.837
 6 Placebo 18-64          categorical AGEGR1        n         n          14    
 7 Placebo 18-64          categorical AGEGR1        p         %           0.163
 8 Placebo F              categorical SEX           n         n          53    
 9 Placebo F              categorical SEX           p         %           0.616
10 Placebo M              categorical SEX           n         n          33    
# โ„น 18 more rows
Demographic Table
Safety Population
Placebo
N = xx
Xanomeline
N = xx1
Age (years)

  Median   xx.x           xx.x        
  [Q1, Q3] [xx.x, xx.x]   [xx.x, xx.x]  
Age Group

  18-64     xx (xx.x%)     xx (xx.x%)
  >64     xx (xx.x%)     xx (xx.x%)
Sex

  F     xx (xx.x%)     xx (xx.x%)
  M     xx (xx.x%)     xx (xx.x%)
1 Pooled High and Low Dose
  • Notice the row labels in the mock. Itโ€™s a combination of variable_level and stat_label for categorical and continuous variables, respectively

cards to tfrmt

Next, we create a row label (โ€œlabelโ€ column) for the table that is either the category (i.e. variable_level) for categorical variables, or the stat name for continuous variables.

ard_demog_00 |> 
  tfrmt::shuffle_card(fill_overall = "Overall") |> 
  tfrmt::prep_combine_vars(c("AGE","AGEGR1","SEX")) |> 
  tfrmt::prep_label()
# A tibble: 28 ร— 8
   ARM2   variable_level context stat_variable stat_name stat_label   stat label
   <chr>  <chr>          <chr>   <chr>         <chr>     <chr>       <dbl> <chr>
 1 Placeโ€ฆ Overall        summary AGE           median    Median     76     Mediโ€ฆ
 2 Placeโ€ฆ Overall        summary AGE           p25       Q1         69     Q1   
 3 Placeโ€ฆ Overall        summary AGE           p75       Q3         82     Q3   
 4 Placeโ€ฆ >64            categoโ€ฆ AGEGR1        n         n          72     >64  
 5 Placeโ€ฆ >64            categoโ€ฆ AGEGR1        p         %           0.837 >64  
 6 Placeโ€ฆ 18-64          categoโ€ฆ AGEGR1        n         n          14     18-64
 7 Placeโ€ฆ 18-64          categoโ€ฆ AGEGR1        p         %           0.163 18-64
 8 Placeโ€ฆ F              categoโ€ฆ SEX           n         n          53     F    
 9 Placeโ€ฆ F              categoโ€ฆ SEX           p         %           0.616 F    
10 Placeโ€ฆ M              categoโ€ฆ SEX           n         n          33     M    
# โ„น 18 more rows
Demographic Table
Safety Population
Placebo
N = xx
Xanomeline
N = xx1
Age (years)

  Median   xx.x           xx.x        
  [Q1, Q3] [xx.x, xx.x]   [xx.x, xx.x]  
Age Group

  18-64     xx (xx.x%)     xx (xx.x%)
  >64     xx (xx.x%)     xx (xx.x%)
Sex

  F     xx (xx.x%)     xx (xx.x%)
  M     xx (xx.x%)     xx (xx.x%)
1 Pooled High and Low Dose

cards to tfrmt

Take a look at our โ€œbig Nโ€ (i.e. population counts) rows:

# A tibble: 6 ร— 8
  ARM2   variable_level context stat_variable stat_name stat_label    stat label
  <chr>  <chr>          <chr>   <chr>         <chr>     <chr>        <dbl> <chr>
1 Placeโ€ฆ <NA>           tabulaโ€ฆ ARM2          n         n           86     <NA> 
2 Placeโ€ฆ <NA>           tabulaโ€ฆ ARM2          N         N          254     <NA> 
3 Placeโ€ฆ <NA>           tabulaโ€ฆ ARM2          p         %            0.339 <NA> 
4 Xanomโ€ฆ <NA>           tabulaโ€ฆ ARM2          n         n          168     <NA> 
5 Xanomโ€ฆ <NA>           tabulaโ€ฆ ARM2          N         N          254     <NA> 
6 Xanomโ€ฆ <NA>           tabulaโ€ฆ ARM2          p         %            0.661 <NA> 
  • First, we only need the counts themselves (โ€˜nโ€™), not denominators or percentages (โ€˜Nโ€™, โ€˜%โ€™) to display in the column headers.
  • Second, we need to give these a unique stat name to distinguish them for the big_n_structure in {tfrmt}.

cards to tfrmt

  • First, we only need the counts themselves (โ€˜nโ€™), not denominators or percentages (โ€˜Nโ€™, โ€˜%โ€™).
  • Second, we need to give these a unique stat name to distinguish them for the big_n_structure in {tfrmt}.
ard_demog_display <- ard_demog_00 |> 
  tfrmt::shuffle_card(fill_overall = "Overall") |> 
  tfrmt::prep_combine_vars(c("AGE","AGEGR1","SEX")) |> 
  tfrmt::prep_label() |> 
  tfrmt::prep_big_n(vars = "ARM2")

ard_demog_display |> 
  dplyr::filter(stat_variable %in% c("ARM2", "..ard_total_n.."))
# A tibble: 2 ร— 8
  ARM2     variable_level context stat_variable stat_name stat_label  stat label
  <chr>    <chr>          <chr>   <chr>         <chr>     <chr>      <dbl> <chr>
1 Placebo  <NA>           tabulaโ€ฆ ARM2          bigN      n             86 <NA> 
2 Xanomelโ€ฆ <NA>           tabulaโ€ฆ ARM2          bigN      n            168 <NA> 
Demographic Table
Safety Population
Placebo
N = xx
Xanomeline
N = xx1
Age (years)

  Median   xx.x           xx.x        
  [Q1, Q3] [xx.x, xx.x]   [xx.x, xx.x]  
Age Group

  18-64     xx (xx.x%)     xx (xx.x%)
  >64     xx (xx.x%)     xx (xx.x%)
Sex

  F     xx (xx.x%)     xx (xx.x%)
  M     xx (xx.x%)     xx (xx.x%)
1 Pooled High and Low Dose

cards to tfrmt

Finally, we can do any other necessary manipulations like relabeling or adding order variables before passing to tfrmt().

ard_demog_display <- ard_demog_display |> 
  
   # give Q1/Q3 the same row label so they appear on the same row
  dplyr::mutate(label = dplyr::case_when(
    stat_name %in% c("p25","p75") ~ "[Q1, Q3]",
    TRUE ~ label
  ),
  
  # make variable names look nice
  stat_variable = dplyr::case_match(
    stat_variable,
    "AGE" ~ "Age (years)",
    "AGEGR1" ~ "Age Group",
    "SEX" ~ "Sex"
  ) ) |> 
  
  # remove unnecessary variables
  dplyr::select(-c(context, stat_label, variable_level)) |>
  
  # create order variables
  dplyr::mutate(ord1 = as.numeric(
    factor(stat_variable, 
           levels = c("Age (years)", "Age Group", "Sex"))),
    ord2 = as.numeric(
      factor(label, levels = c("18-64",">64"))))

print_to_gt(tfrmt_demog, ard_demog_display)|> 
  gt_style_slides()|> 
  gt::tab_options(
    table.font.size = 15
  )
Demographic Table
Safety Population
Placebo
N = 86
Xanomeline
N = 1681
Age (years)

  Median   76.0           77.0        
  [Q1, Q3] [69.0, 82.0]   [71.0, 81.0]  
Age Group

  18-64     14 (16.3%)     19 (11.3%)
  >64     72 (83.7%)    149 (88.7%)
Sex

  F     53 (61.6%)     90 (53.6%)
  M     33 (38.4%)     78 (46.4%)
1 Pooled High and Low Dose

Exercise ๐Ÿƒโ€โžก๏ธ (Together!)

  1. Navigate to Posit Cloud script exercises/05-tables-tfrmt.R

  2. Create and modify the AE table as described.

  3. Add the โ€œcompletedโ€ sticky note to your laptop when complete.

10:00