Skip to contents

Introduction

The chevron R package has a collection of functions that create standard tables, listings, and graphs (TLGs). These functions are referred in chevron as TLG-functions. A subset of these TLG-functions create tables. Tables are created using the rtables package. rtables has the context of table layouts, i.e. pre-data table cell-derivation instructions. For example:

library(rtables)
#> Loading required package: magrittr
#> Loading required package: formatters

lyt <- basic_table() %>%
  split_cols_by("ARM") %>%
  analyze("AGE", mean)

lyt
#> A Pre-data Table Layout
#> 
#> Column-Split Structure:
#> ARM (lvls) 
#> 
#> Row-Split Structure:
#> AGE (** analysis **)

These layout contain all the cell-value derivation information and can be used and reused for different data

adsl <- data.frame(
  ARM = factor(sample(c("ARM A", "ARM B"), 100, TRUE)),
  AGE = runif(100, 20, 90),
  COUNTRY = factor(sample(c("CHN", "USA", "BRA", "RUS"), 100, TRUE))
)

build_table(lyt, adsl)
#>             ARM A              ARM B     
#> —————————————————————————————————————————
#> mean   53.8729145839655   51.919801786847

build_table(lyt, adsl[adsl$COUNTRY == "RUS", ])
#>             ARM A              ARM B     
#> —————————————————————————————————————————
#> mean   44.9912354815751   50.841894256459

Hence these layouts define a table pre-data. That is, the layout functions in chevron do never take any data as an argument. Note that pruning and sorting are currently not performed in the layout space in rtables but rather on the actual table objects.

Also, layouts allow for certain queries such as which variables are required to build the table using the given layout:

rtables::vars_in_layout(lyt)
#> [1] "ARM" "AGE"

So in chevron when creating tables we always do the explicit layout creation in the *_lyt functions. For example for aet02_1 we have the layout function:

library(chevron)
#> Registered S3 method overwritten by 'tern':
#>   method   from 
#>   tidy.glm broom
aet02_1_lyt
#> function (armvar = .study$actualarm, lbl_overall = .study$lbl_overall, 
#>     lbl_aebodsys = "MedDRA System Organ Class", lbl_aedecod = "MedDRA Preferred Term", 
#>     deco = std_deco("AET02"), .study = list(actualarm = "ACTARM", 
#>         lbl_overall = NULL)) 
#> {
#>     basic_table_deco(deco) %>% split_cols_by(var = armvar) %>% 
#>         add_colcounts() %>% ifneeded_add_overall_col(lbl_overall) %>% 
#>         summarize_num_patients(var = "USUBJID", .stats = c("unique", 
#>             "nonunique"), .labels = c(unique = "Total number of patients with at least one adverse event", 
#>             nonunique = "Overall total number of events")) %>% 
#>         split_rows_by("AEBODSYS", child_labels = "visible", labels_var = "AEBODSYS", 
#>             nested = FALSE, indent_mod = -1L, split_fun = drop_split_levels, 
#>             label_pos = "topleft", split_label = lbl_aebodsys) %>% 
#>         summarize_num_patients(var = "USUBJID", .stats = c("unique", 
#>             "nonunique"), .labels = c(unique = "Total number of patients with at least one adverse event", 
#>             nonunique = "Total number of events")) %>% count_occurrences(vars = "AEDECOD", 
#>         .indent_mods = -1L) %>% append_topleft(paste0("  ", lbl_aedecod))
#> }
#> <bytecode: 0x556d34ef0860>
#> <environment: namespace:chevron>

Note that the aet02_1_lyt function returns a concise description on how tern and rtables can be used to create the cell values of the tables. The table creation function then does then use the *_lyt function and builds the table using build_table and the data given in adam_db as shown next:

aet02_1_main
#> function (adam_db, armvar = .study$actualarm, lbl_overall = .study$lbl_overall, 
#>     prune_0 = TRUE, deco = std_deco("AET02"), .study = list(actualarm = "ACTARM", 
#>         lbl_overall = NULL)) 
#> {
#>     dbsel <- get_db_data(adam_db, "adsl", "adae")
#>     lyt <- aet02_1_lyt(armvar = armvar, lbl_overall = lbl_overall, 
#>         deco = deco)
#>     tbl <- build_table(lyt, dbsel$adae, alt_counts_df = dbsel$adsl)
#>     if (prune_0) {
#>         tbl <- smart_prune(tbl)
#>     }
#>     tbl_sorted <- tbl %>% sort_at_path(path = c("AEBODSYS"), 
#>         scorefun = cont_n_allcols) %>% sort_at_path(path = c("AEBODSYS", 
#>         "*", "AEDECOD"), scorefun = score_occurrences)
#>     tbl_sorted
#> }
#> <bytecode: 0x556d26b809e0>
#> <environment: namespace:chevron>

Summary

  • Layouts specify a tabulation an cell-values derivation pre-data
  • these layouts are useful to understand how table is created and what variables are required in the data to create a table using the layout
  • the table creation functions focus the main part of their code on building, sorting and pruning the table
  • Headers and footers are taken by default from the standards. They can be specified with the deco argument. Note that we currently do not have all of the data base for standard headers and footers imported in chevron.