Skip to contents

Loading the package

After installation (using remotes::install_github("stopsack/rifttable")), load the package with:

Loading example data

The cancer dataset from survival package is used here:

data(cancer, package = "survival")

cancer <- cancer %>%
  tibble::as_tibble() %>%
  dplyr::mutate(
    # The exposure (here, 'sex') must be categorical
    sex = factor(
      sex,
      levels = 1:2,
      labels = c("Male", "Female")),
    time = time / 365.25,
    status = status - 1)

cancer
#> # A tibble: 228 × 10
#>     inst  time status   age sex    ph.ecog ph.karno pat.karno meal.cal wt.loss
#>    <dbl> <dbl>  <dbl> <dbl> <fct>    <dbl>    <dbl>     <dbl>    <dbl>   <dbl>
#>  1     3 0.838      1    74 Male         1       90       100     1175      NA
#>  2     3 1.25       1    68 Male         0       90        90     1225      15
#>  3     3 2.77       0    56 Male         0       90        90       NA      15
#>  4     5 0.575      1    57 Male         1       90        60     1150      11
#>  5     1 2.42       1    60 Male         0      100        90       NA       0
#>  6    12 2.80       0    74 Male         1       50        80      513       0
#>  7     7 0.849      1    68 Female       2       70        60      384      10
#>  8    11 0.988      1    71 Female       2       60        80      538       1
#>  9     1 0.597      1    53 Male         1       70        80      825      16
#> 10     7 0.454      1    61 Male         2       70        70      271      34
#> # ℹ 218 more rows

Example 1: Basic use with binary outcomes

Set the table design:

design1 <- tibble::tibble(
  label = c(
    "Outcomes",
    "Total",
    "Outcomes/Total",
    "Risk",
    "Risk (CI)",
    "Outcomes (Risk)",
    "Outcomes/Total (Risk)",
    "RR",
    "RD")) %>%
  dplyr::mutate(
    type = label,
    exposure = "sex",
    outcome = "status")

Generate rifttable:

rifttable(
  design = design1, 
  data = cancer)
#> # A tibble: 9 × 3
#>   sex                   Male              Female              
#>   <chr>                 <chr>             <chr>               
#> 1 Outcomes              112               53                  
#> 2 Total                 138               90                  
#> 3 Outcomes/Total        112/138           53/90               
#> 4 Risk                  0.81              0.59                
#> 5 Risk (CI)             0.81 (0.74, 0.87) 0.59 (0.49, 0.68)   
#> 6 Outcomes (Risk)       112 (0.81)        53 (0.59)           
#> 7 Outcomes/Total (Risk) 112/138 (0.81)    53/90 (0.59)        
#> 8 RR                    1 (reference)     0.73 (0.60, 0.88)   
#> 9 RD                    0 (reference)     -0.22 (-0.34, -0.10)

Example 2: Formatted output

This example uses the design of Example 1 above. So far, the tables produced when just running the code shown had an appearance like output in the R console. To obtain formatted tables in HTML and other output documents, pipe the output of rifttable() to a table formatting function such as

  • knitr::kable(): works well with all output formats, but supports only limited formatting. Add to the YAML header a statement df_print: kable to print all tables using kable.
  • gt::gt(): supports more advanced formatting but output is no longer human-readable.

The rifttable package provides the rt_gt() wrapper function. When knitting to HTML, PDF, or Word, it functions as a wrapper for gt::gt(), passing along indentations from the label of the table design. When knitting to a Markdown document (.md), such as github_document (in RMarkdown) or gfm (in Quarto), rt_gt() will automatically provide plain table output using the kable package.

rifttable(
  design = design1, 
  data = cancer) %>% 
  rt_gt()
sex Male Female

Outcomes

112 53

Total

138 90

Outcomes/Total

112/138 53/90

Risk

0.81 0.59

Risk (CI)

0.81 (0.74, 0.87) 0.59 (0.49, 0.68)

Outcomes (Risk)

112 (0.81) 53 (0.59)

Outcomes/Total (Risk)

112/138 (0.81) 53/90 (0.59)

RR

1 (reference) 0.73 (0.60, 0.88)

RD

0 (reference) -0.22 (-0.34, -0.10)

Example 3: Swap rows and columns

To use the design as columns instead of rows, showing only three types:

rifttable(
  design = design1 %>%
    dplyr::filter(label %in% c(
      "Outcomes/Total (Risk)",
      "RR", 
      "RD")),
  data = cancer,
  layout = "cols") %>% 
  rt_gt()
sex Outcomes/Total (Risk) RR RD

Male

112/138 (0.81) 1 (reference) 0 (reference)

Female

53/90 (0.59) 0.73 (0.60, 0.88) -0.22 (-0.34, -0.10)

Example 4: Survival outcomes, effect modifier, and confounder

Survival outcomes use the time and event variables in the design (and type2, with late entry, as in survival::Surv()), rather than the outcome variable used for binary, categorical, or continuous outcomes.

Set table design:

design2 <- tibble::tribble(
  # Elements that vary by row:
  ~label,                       ~stratum, ~confounders, ~type,
  "**Overall**",                NULL,     "",           "blank",
  "  Events",                   NULL,     "",           "events",
  "  Person-years",             NULL,     "",           "time",
  "  Rate/1000 py (95% CI)",    NULL,     "",           "rate (ci)",
  "  Unadjusted HR (95% CI)",   NULL,     "",           "hr",
  "  Age-adjusted HR (95% CI)", NULL,     "+ age",      "hr",
  "",                           NULL,     "",           "blank",
  "**Stratified models**",      NULL,     "",           "",
  "*ECOG PS1* (events/N)",      1,        "",           "events/total",
  "  Unadjusted",               1,        "",           "hr",
  "  Age-adjusted",             1,        "+ age",      "hr",
  "*ECOG PS2* (events/N)",      2,        "",           "events/total",
  "  Unadjusted",               2,        "",           "hr",
  "  Age-adjusted",             2,        "+ age",      "hr",
  "",                           NULL,     "",           "",
  "**Joint model**, age-adj.",  NULL,     "",           "",
  "  ECOG PS1",                 1,        "+ age",      "hr_joint",
  "  ECOG PS2",                 2,        "+ age",      "hr_joint") %>%
  # Elements that are the same for all rows:
  dplyr::mutate(
    exposure = "sex",
    event = "status",
    time = "time",
    effect_modifier = "ph.ecog")

Generate rifttable:

rifttable(
  design = design2,
  data = cancer %>% 
    dplyr::filter(ph.ecog %in% 1:2)) %>% 
  rt_gt(md = 1)
sex Male Female

Overall

Events

82 44

Person-years

70 59

Rate/1000 py (95% CI)

1164.8 (938.1, 1446.3) 746.7 (555.7, 1003.4)

Unadjusted HR (95% CI)

1 (reference) 0.60 (0.41, 0.86)

Age-adjusted HR (95% CI)

1 (reference) 0.60 (0.41, 0.86)

Stratified models

ECOG PS1 (events/N)

54/71 28/42

Unadjusted

1 (reference) 0.53 (0.33, 0.85)

Age-adjusted

1 (reference) 0.53 (0.33, 0.85)

ECOG PS2 (events/N)

28/29 16/21

Unadjusted

1 (reference) 0.70 (0.37, 1.30)

Age-adjusted

1 (reference) 0.68 (0.34, 1.36)

Joint model, age-adj.

ECOG PS1

1 (reference) 0.55 (0.35, 0.88)

ECOG PS2

1.54 (0.98, 2.44) 1.10 (0.62, 1.98)

Example 5: Two estimates using type and type2

design3 <- tibble::tribble(
  ~label,     ~stratum, ~type,          ~type2,
  "ECOG PS1", 1,        "events/total", "hr",
  "ECOG PS2", 2,        "events/total", "hr") %>%
  dplyr::mutate(
    exposure = "sex",
    event = "status",
    time = "time",
    confounders = "+ age",
    effect_modifier = "ph.ecog")

rifttable(
  design = design3,
  data = cancer %>% 
    dplyr::filter(ph.ecog %in% 1:2)) %>% 
  rt_gt()
sex Male Female

ECOG PS1

54/71 28/42
1 (reference) 0.53 (0.33, 0.85)

ECOG PS2

28/29 16/21
1 (reference) 0.68 (0.34, 1.36)

With estimate type as columns:

rifttable(
  design = design3,
  data = cancer %>% 
    dplyr::filter(ph.ecog %in% 1:2),
  layout = "cols", 
  type2_layout = "cols") %>% 
  rt_gt()
sex ECOG PS1 ECOG PS1 ECOG PS2 ECOG PS2

Male

54/71 1 (reference) 28/29 1 (reference)

Female

28/42 0.53 (0.33, 0.85) 16/21 0.68 (0.34, 1.36)

Example 6: Continuous outcomes, rounding, and trend (slope)

Request rounding to 1 decimal digit in some cases; add a continuous trend, i.e., the slope per one unit of the trend variable:

tibble::tribble(
  ~label,                   ~stratum, ~type,        ~digits,
  "Marginal mean (95% CI)", NULL,     "mean (ci)",  1,
  "  Male",                 "Male",   "mean",       NA,
  "  Female",               "Female", "mean",       NA,
  "",                       NULL,     "",           NA,
  "Stratified model",       NULL,     "",           NA,
  "  Male",                 "Male",   "diff",       1,
  "  Female",               "Female", "diff",       1,
  "",                       NULL,     "",           NA,
  "Joint model",            NULL,     "",           NA,
  "  Male",                 "Male",   "diff_joint", NA,
  "  Female",               "Female", "diff_joint", NA) %>%
  dplyr::mutate(
    exposure = "ph.ecog_factor",
    trend = "ph.ecog",
    outcome = "age",
    effect_modifier = "sex") %>%
  rifttable(
    data = cancer %>%
      dplyr::filter(ph.ecog < 3) %>%
      dplyr::mutate(ph.ecog_factor = factor(ph.ecog))) %>% 
  rt_gt()
ph.ecog_factor 0 1 2 Trend

Marginal mean (95% CI)

61.2 (58.8, 63.5) 61.5 (59.8, 63.1) 66.2 (64.0, 68.5)

Male

63.00 62.79 65.00

Female

58.70 59.19 67.90

Stratified model

Male

0 (reference) -0.2 (-3.9, 3.5) 2.0 (-2.5, 6.5) 0.9 (-1.3, 3.2)

Female

0 (reference) 0.5 (-3.5, 4.5) 9.2 (4.5, 13.9) 4.4 (2.0, 6.7)

Joint model

Male

0 (reference) -0.21 (-3.75, 3.33) 2.00 (-2.32, 6.32) 0.93 (-1.33, 3.19)

Female

-4.30 (-8.70, 0.11) -3.81 (-7.74, 0.12) 4.90 (0.15, 9.66) 4.36 (1.97, 6.75)