The hardware and bandwidth for this mirror is donated by dogado GmbH, the Webhosting and Full Service-Cloud Provider. Check out our Wordpress Tutorial.
If you wish to report a bug, or if you are interested in having us mirror your free-software or open-source project, please feel free to contact us at mirror[@]dogado.de.

End-to-End Example

This vignette walks through a program in a fuller context. Here we’re going to create a simple demographics table.

First we’ll start by preparing the data. We’ll use our other package {Tplyr} to take care of the summaries.

library(clinify)
library(Tplyr)
library(dplyr)
#> 
#> Attaching package: 'dplyr'
#> The following objects are masked from 'package:stats':
#> 
#>     filter, lag
#> The following objects are masked from 'package:base':
#> 
#>     intersect, setdiff, setequal, union

tplyr_adsl <- tplyr_adsl |>
  mutate(
    SEX = recode(SEX, M = "Male", F = "Female"),
    RACE = factor(
      RACE,
      c(
        "AMERICAN INDIAN OR ALASKA NATIVE",
        "ASIAN",
        "BLACK OR AFRICAN AMERICAN",
        "NATIVE HAWAIIN OR OTHER PACIFIC ISLANDER",
        "WHITE",
        "MULTIPLE"
      )
    )
  )

t <- tplyr_table(tplyr_adsl, TRT01P) |>
  add_layer(
    group_count(SEX, by = "Sex n (%)") |>
      set_missing_count(f_str("xx", n), Missing = NA, denom_ignore = TRUE)
  ) |>
  add_layer(
    group_desc(AGE, by = "Age (Years)")
  ) |>
  add_layer(
    group_count(AGEGR1, by = "Age Categories n (%)") |>
      set_missing_count(f_str("xx", n), Missing = NA, denom_ignore = TRUE)
  ) |>
  add_layer(
    group_count(RACE, by = "Race n (%)") |>
      set_missing_count(f_str("xx", n), Missing = NA, denom_ignore = TRUE) |>
      set_order_count_method("byfactor")
  ) |>
  add_layer(
    group_count(ETHNIC, by = "Ethnicity n (%)") |>
      set_missing_count(f_str("xx", n), Missing = NA, denom_ignore = TRUE)
  ) |>
  add_layer(
    group_desc(HEIGHTBL, by = "Height at Baseline")
  ) |>
  add_layer(
    group_desc(WEIGHTBL, by = "Weight at Baseline")
  )

# Apply some conditional formatting for blanking out 0's.
dat <- build(t) |>
  mutate(
    across(
      starts_with("var"),
      ~ if_else(
        ord_layer_index %in% c(1, 3:5),
        apply_conditional_format(
          string = .,
          format_group = 2,
          condition = x == 0,
          replacement = ""
        ),
        .
      )
    )
  )

# Sort all the row values out, add row masks and breaks
dat <- dat |>
  arrange(ord_layer_index, ord_layer_1, ord_layer_2) |>
  apply_row_masks() |>
  select(
    starts_with("row_label"),
    var1_Placebo,
    `var1_Xanomeline Low Dose`,
    `var1_Xanomeline High Dose`,
    ord_layer_index
  )

# Grab the header Ns for column header help
header_n <- t$header_n$n
names(header_n) <- t$header_n$TRT01P

Great - our data are presentation ready now. Using {clinify} we’ll get everything ready. Looking at some of these sections:

ct <- clintable(dat) |>
  # Use group changes to let Word naturally split pages
  clin_auto_page("ord_layer_index", drop = TRUE) |>
  # Add padding to changes within the group
  # By using `notempty`, paging groups are determined by populated
  # values of `row_label1`
  clin_group_pad('row_label1', when = "notempty") |>
  # Assign column headers with spanning rows
  clin_column_headers(
    row_label1 = "",
    row_label2 = "",
    var1_Placebo = sprintf("Placebo\n(N=%s)", header_n["Placebo"]),
    `var1_Xanomeline Low Dose` = c(
      "Xanomeline",
      sprintf("Low Dose\n(N=%s)", header_n["Xanomeline Low Dose"])
    ),
    `var1_Xanomeline High Dose` = c(
      "Xanomeline",
      sprintf("High Dose\n(N=%s)", header_n["Xanomeline High Dose"])
    )
  ) |>
  # Use flextable functions directly to set all of the alignment
  flextable::align(align = "center", part = "header") |>
  flextable::align(
    j = c(
      "var1_Placebo",
      "var1_Xanomeline Low Dose",
      "var1_Xanomeline High Dose"
    ),
    align = "center"
  ) |>
  # Set column widths as proportion of the total document width
  clin_col_widths(
    row_label1 = .17,
    row_label2 = .3,
    var1_Placebo = .176,
    `var1_Xanomeline Low Dose` = .176,
    `var1_Xanomeline High Dose` = .176
  ) |>
  # Add titles here is using new_header_footer to allow flextable functions
  # to customize the titles block
  clin_add_titles(
    list(
      # We'll add tools to automate paging
      c("Protocol: CDISCPILOT01", "Page {PAGE} of {NUMPAGES}"),
      c("Table 14-2.01"),
      c("Summary of Demographic and Baseline Characteristics")
    )
  ) |>
  clin_add_footnotes(
    list(
      c(
        "Source: /my/file/path.R",
        format(Sys.time(), "%H:%M %A, %B %d, %Y")
      )
    )
  )

print(ct)

Protocol: CDISCPILOT01

Page of

Table 14-2.01

Summary of Demographic and Baseline Characteristics

 

Xanomeline

Xanomeline

Placebo
(N=86)

Low Dose
(N=84)

High Dose
(N=84)

Sex n (%)

Female

53 ( 61.6%)

50 ( 59.5%)

40 ( 47.6%)

Male

33 ( 38.4%)

34 ( 40.5%)

44 ( 52.4%)

Missing

 0

 0

 0

Age (Years)

n

 86

 84

 84

Mean (SD)

75.2 ( 8.59)

75.7 ( 8.29)

74.4 ( 7.89)

Median

76.0

77.5

76.0

Q1, Q3

69.2, 81.8

71.0, 82.0

70.8, 80.0

Min, Max

52, 89

51, 88

56, 88

Missing

  0

  0

  0

Age Categories n (%)

65-80

42 ( 48.8%)

47 ( 56.0%)

55 ( 65.5%)

<65

14 ( 16.3%)

 8 (  9.5%)

11 ( 13.1%)

>80

30 ( 34.9%)

29 ( 34.5%)

18 ( 21.4%)

Missing

 0

 0

 0

Race n (%)

AMERICAN INDIAN OR ALASKA NATIVE

 0        

 0        

 1 (  1.2%)

ASIAN

 0        

 0        

 0        

Source: /my/file/path.R

13:38 Monday, July 07, 2025

With everything ready to go, we can write our table out to its destination using write_clindoc().

write_clindoc(ct, "demo_table.docx")

These binaries (installable software) and packages are in development.
They may not be fully stable and should be used with caution. We make no claims about them.
Health stats visible at Monitor.