Demographic Tables avec flextable

Introduction

Les études cliniques commencent souvent par un tableau récapitulatif des caractéristiques démographiques des patients inclus dans l’étude afin de démontrer un équilibre entre les traitements et autres sous-groupes. Ce tableau se nomme “Demographic Tables”.

Le format est standard et peut être réalisé avec flextable en enchaînant 3 opérations.

Les trois étapes de la création de ces tableaux sont les suivantes :

  1. résumer l’information avec la fonction flextable::summarizor(). Elle calcule par groupes et pour chaque variables un ensemble de statistiques. Elle retourne un data.frame prêt à être consommé par flextable::tabulator().
  2. Appeler flextable::tabulator() en précisant comment disposer les lignes et colonnes et comment formater les contenus.
  3. Enfin créer le flextable avec la fonction as_flextable() et le personnaliser éventuellement avec les fonctions de ‘flextable’.

Données d’exemple

library(flextable)
library(officer)
library(tidyverse)
library(safetyData)

use_df_printer()

set_flextable_defaults(
  border.color = "#AAAAAA", font.family = "Arial",
  font.size = 11, padding = 2, line_spacing = 1.3
)
adsl <- select(adam_adsl, AGE, SEX, BMIBLGR1, DURDIS, ARM)
adsl

Résumé de l’information

Tout d’abord, on réalise un comptage de lignes par groupes de traitements afin de pouvoir les afficher dans le tableau plus tard.

arm_cpt <- count(adsl, ARM)
arm_cpt

On va utiliser la fonction flextable::summarizor(). Elle produit un data.frame agrégé et structuré d’une façon idéale pour flextable::tabulator().

dat <- summarizor(adsl, by = "ARM") %>% 
  mutate(variable = factor(variable, levels = c("AGE", "SEX", "BMIBLGR1", "DURDIS")))
dat

Création du flextable

On souhaite un affichage où les traitements sont répartis en colonnes et où le contenu des paragraphes est assez souple pour permettre la création du tableau.

tab_object <- dat %>% 
  tabulator(
    rows = c("variable", "stat"),
    columns = "ARM",
    content_cell = as_paragraph(
      fmt_2stats(
        stat = stat, 
        num1 = value1, num2 = value2, 
        cts = cts, pcts = percent 
      )
    )
  )

Le nom content_cell n’a pas d’intérêt ici, ces noms ne s’affichent que s’ils conduisent à afficher différentes statistiques par croisement possible.

On utilise la fonction fmt_2stats() qui est spécialement écrite pour fonctionner avec la sortie de summarizor().

On obtient facilement un premier tableau avec as_flextable().

as_flextable(tab_object)

Ajout des libellés

Cette partie va permettre de récupérer un ensemble de libellés que nous allons utiliser pour remplacer certains textes affichés dans le flextable.

La fonction à utiliser est labelizor(), elle prend un simple argument sous forme de vecteur nommé, les noms sont les valeurs à remplacer, les valeurs sont les valeurs de remplacement.

On doit d’abord préparer les entêtes des colonnes où on aimerait ajouter la contingence contenues dans arm_cpt.

arm_cpt <- mutate(arm_cpt, label = paste0(ARM, "\n", "(N=", n, ")"))
arm_labels <- set_names(arm_cpt$label, arm_cpt$ARM)
arm_labels
##                        Placebo           Xanomeline High Dose 
##              "Placebo\n(N=86)" "Xanomeline High Dose\n(N=84)" 
##            Xanomeline Low Dose 
##  "Xanomeline Low Dose\n(N=84)"

On va aussi récupérer les labels des colonnes stockées dans le tableau d’origine.

col_labels <- map_chr(adsl, function(x) attr(x, "label"))
col_labels
##                            AGE                            SEX 
##                          "Age"                          "Sex" 
##                       BMIBLGR1                         DURDIS 
##  "Pooled Baseline BMI Group 1" "Duration of Disease (Months)" 
##                            ARM 
##   "Description of Planned Arm"

On va les empiler dans un seul vecteur avec quelques autres labels définis manuellement.

labs <- c(
    arm_labels,
    col_labels,
    stat = "",
    mean_sd = "Mean (SD)", median_iqr = "Median (IQR)",
    range = "Range", missing = "Missing",
    AGE = "Age (Years)",
    SEX = "Sex, n (%)"
  )
labs
##                        Placebo           Xanomeline High Dose 
##              "Placebo\n(N=86)" "Xanomeline High Dose\n(N=84)" 
##            Xanomeline Low Dose                            AGE 
##  "Xanomeline Low Dose\n(N=84)"                          "Age" 
##                            SEX                       BMIBLGR1 
##                          "Sex"  "Pooled Baseline BMI Group 1" 
##                         DURDIS                            ARM 
## "Duration of Disease (Months)"   "Description of Planned Arm" 
##                           stat                        mean_sd 
##                             ""                    "Mean (SD)" 
##                     median_iqr                          range 
##                 "Median (IQR)"                        "Range" 
##                        missing                            AGE 
##                      "Missing"                  "Age (Years)" 
##                            SEX 
##                   "Sex, n (%)"
ft <- as_flextable(
    x = tab_object,
    sep_w = 0,
    separate_with = "variable",
    spread_first_col = TRUE) %>%
  labelizor(j = "stat", labels = labs, part = "all") %>% 
  labelizor(
    j = tabulator_colnames(
      tab_object, 
      columns = "content_cell", 
      type = "columns"), 
    labels = labs, part = "all")
ft

On va aussi ajouter un caption et une note dans le bas du tableau et quelques paramétrages supplémentaires.

ft <- ft %>%
  set_caption(
    caption = as_paragraph(
          "Demographic Characteristics",
          "\nx.x: Study Subject Data"
        )
  ) %>% 
  add_footer_lines("Source: ADaM adsl data frame from r package 'safetyData'") %>% 
  fix_border_issues() %>% 
  set_table_properties(layout = "autofit")

ft

Ajout dans un document Word

On va préparer le tableau pour un export dans Word en ajoutant une ligne d’entête comportant le numéro de page. Le caption va être auto-numéroté et aligné à gauche dans le document.

ft %>%
  add_header_lines("Page ") %>%
  append_chunks(i = 1, part = "header", j = 1, as_word_field(x = "Page")) %>% 
  set_caption(
    autonum = officer::run_autonum(seq_id = "tab", bkm = "demo_tab", bkm_all = FALSE),
    caption = as_paragraph(
      "Demographic Characteristics",
      "\nx.x: Study Subject Data"
    ), 
    fp_p = fp_par(text.align = "left", line_spacing = 2),
    align_with_table = FALSE) %>% 

  save_as_docx(path = "adsl.docx")

Le document Word produit peut être téléchargé ici : adsl.docx. La miniature ci-dessous montre le document attendu.

miniatures du document Word produit