28  Produire des rapports automatisés avec R Markdown

28.1 Tâches concernées et recommandations

L’utilisateur souhaite réaliser l’une des tâches suivantes :

  • produire un rapport automatisé, reproductible et facile à actualiser en cas de modification des données ;
  • produire de nombreux rapports automatisés sur un même modèle en faisant varier certains paramètres.
Tâche concernée et recommandation

Il est recommandé d’utiliser R Markdown pour produire ce type de rapports. Si vous ne connaissez pas R Markdown, il est indispensable de lire au préalable la fiche R Markdown.

28.2 Les rapports automatisés

28.2.1 Introduction

Un rapport automatisé est un document qui contient du texte et des informations (graphiques, tableaux…) produites en exécutant un code, appelé code source. Un rapport automatisé peut prendre plusieurs formes :

  • une page internet (un fichier html) ;
  • un document texte (Word, writer, LaTeX) ;
  • une présentation (slides) ;
  • une carte.

Les rapports automatisés présentent deux grands avantages. Premièrement, ils sont reproductibles, car le code source contient toutes les instructions nécessaires à la production des informations contenues dans le rapport. Deuxièmement, ils sont faciles à actualiser en cas de modification des données.

Dans le cas de R Markdown, le code source est un fichier texte portant l’extension .Rmd. Il rassemble en un même endroit les instructions de traitement des données, mais aussi les commentaires associés sous forme de texte, des images, des cartes… Le document final (ou output) est produit après une étape de compilation, par exemple en cliquant sur le bouton Knit de RStudio.

Note

Les instructions de traitement de données sont généralement rédigées en R, mais il est possible d’utiliser R Markdown avec d’autres langages (par exemple python).

28.2.2 Quelques bonnes pratiques

Cette section détaille les bonnes pratiques à adopter pour réaliser des rapports automatisés. Le principal conseil tient en une phrase : tous les réglages du rapport paramétré doivent être regroupés au début du code source.

28.2.3 Remplir l’en-tête

Le code source d’un rapport automatisé commence toujours par un en-tête YAML qui doit contenir au minimum un titre et un format de sortie. Voici un exemple d’en-tête :

---
title: "Titre du rapport"
date: '11 March 2024'
output: pdf_document
author: "Anne Onyme"
description: "Une description vraiment utile"
---

L’en-tête permet de paramétrer finement le document de sortie : format du document, présence d’une table des matières, d’une bibliographie…

Il existe un nombre considérable d’options, dont certaines sont spécifiques à un format de sortie (pdf, html, …). La liste des options est détaillée sur le site de la documentation officielle de R Markdown et sur l’antisèche et le guide de référence de R Markdown, accessibles depuis RStudio via le menu Help puis Cheatsheets.

Tip

Si vous souhaitez construire un rapport automatisé que vous utiliserez régulièrement, il est vivement conseillé de prendre le temps de définir un en-tête qui corresponde précisément à ce que vous voulez produire.

28.2.4 Configurer le fonctionnement de knitr

Dans un deuxième temps, il est souhaitable de configurer le comportement par défaut de knitr. La fiche R Markdown détaille les principales options. Dans le cas des rapports automatisés, la configuration de knitr doit porter au minimum sur les deux points suivants :

  • la position et taille des figures ;
  • l’affichage ou non des instructions R dans le fichier de sortie.

La méthode la plus simple pour configurer knitr consiste à inclure un chunk de configuration au début du fichier R Markdown (juste après l’en-tête). Ce chunk de configuration utilise la fonction knitr::opts_chunk$set() pour définir les options par défaut applicables à tous les chunks du code source. La fonction opts_chunk$set permet de définir de nombreux paramètres, dont la liste complète est disponible sur https://yihui.org/knitr/options. Voici un exemple de chunk de configuration :

```{r configuration, include=FALSE}
knitr::opts_chunk$set(echo = FALSE,
                      warning = FALSE,
                      message = FALSE,
                      error = TRUE,
                      fig.align = "center",
                      out.width = "75%")
```

Dans cet exemple, il est demandé à R Markdown de ne pas inclure les instructions R dans le document de sortie (echo = FALSE). Les warnings et les messages d’informations n’apparaîtront pas non plus dans le fichier de sortie. En revanche, les erreurs apparaîtront (error = TRUE). Les figures sont centrées (fig.align = "center") et ont une largeur de 75% de la largeur du texte (out.width = "75%").

Tip

Une attention particulière doit être portée à l’utilisation de l’option cache. L’option cache = TRUE permet de signaler à R Markdown de ne pas ré-exécuter du code n’ayant pas été modifié depuis la dernière compilation. Ceci peut faire gagner beaucoup de temps, notamment pour les chunks d’importation de données volumineuses, mais peut conduire à des comportements non souhaités, notamment lorsque les données que vous utilisez dans votre rapport ont été actualisées. Si vous utilisez l’option cache = TRUE, et si aucun élément du code source n’a été modifié, alors les données ne seront pas réimportées lorsque vous recompilerez le rapport.

28.2.5 Charger les packages et les données au début du code source

Il est recommandé d’intégrer au début de votre code source (par exemple juste après la configuration des options de knitr) un chunk qui charge les packages utilisés dans le rapport, puis un chunk qui importe l’ensemble des données manipulées dans le rapport. L’intérêt de cette approche est qu’elle permet de voir facilement quels packages et quelles données sont utilisées par votre rapport.

Dans la mesure du possible, il est préférable d’utiliser des chemins relatifs pour les fichiers (exemple : ./donnees/mesdonnees.csv), plutôt que des chemins absolus (exemple : D:/chemin/vers/les/donnees/mesdonnees.csv).

A titre d’exemple, les deux chunks qui chargent les packages et les données pourraient ressembler à ceci :

```{r packages, include = FALSE}
library(doremifasolData)
library(data.table)
library(ggplot2)
```
```{r donnees, include = FALSE}
donnees <- fread("./donnees/mesdonnees.csv")
```
Note

Il peut arriver qu’il soit difficile d’accéder à des fichiers en utilisant uniquement des chemins relatifs. Une solution de repli consiste à définir le chemin absolu du dossier à un seul endroit dans le code source du rapport, puis à l’utiliser de façon relative dans les fonctions d’importation. Voici un exemple :

```{r donnees, include = FALSE}
# Définir UNE SEULE FOIS le répertoire des données
dossier_donnees <- "D:/chemin/vers/les/donnees/"

# Charger les données avec un chemin composé
donnees1 <- fread(paste0(dossier_donnees, "mesdonnees1.csv"))
donnees2 <- fread(paste0(dossier_donnees, "mesdonnees2.csv"))
```

28.2.6 Nommer les chunks

Il est important de donner un nom à tous les chunks, car cela facilite grandement la résolution des problèmes, en particulier si votre rapport est long. En effet, si la compilation du code source génère une erreur, R Markdown vous indiquera le nom du chunk où se trouve l’erreur. Le nom du chunk se positionne immédiatement avant les éventuelles options, par exemple :

```{r nom_du_chunk, include = FALSE}
resultat <- 1 + 1
```

28.3 Les rapports paramétrés

28.3.1 Définition

Un rapport paramétré est une forme particulière de rapport automatisé. Il a donc les mêmes avantages que ce dernier (reproductible et simple à actualiser). Il permet en outre de générer différents outputs à partir du même code source, mais en distinguant les traitements selon un ou plusieurs paramètres définis dans l’en-tête YAML.

Par exemple, on peut créer un rapport paramétré qui produit des statistiques descriptives sur un département, dont le numéro est un paramètre de l’en-tête YAML du code source. Il suffit alors de changer le numéro du département dans l’en-tête pour produire un rapport sur un autre département, sans modifier le code source.

Par conséquent, un même modèle de rapport “générique” (appelé template) peut être utilisé pour produire de multiples rapports sur différents territoires, différentes périodes, différents secteurs…

28.3.2 Paramétrer un rapport

Voici un exemple de situation dans laquelle les rapports paramétrés sont utiles. Un utilisateur souhaite produire pour chaque département français un rapport donnant le nombre de communes de ce département.

Une première approche consiste à créer un rapport R Markdown par département (fichier_Ain.Rmd, fichier_Aisne.Rmd…). Si elle peut convenir lorsque le nombre de documents à produire est réduit, cette approche n’est clairement pas adaptée lorsqu’il est question de réaliser plusieurs dizaines de rapports.

Une solution est d’introduire le département comme paramètre du rapport :

---
title: "Titre du rapport"
output: html_document
params:
  codeDpt: "01"
---

Il faut ensuite remplacer dans les différents chunks le code du département par params$codeDpt. Une fois ces 2 modifications (en-tête et chunks) effectués, il n’est plus besoin de changer le département qu’à un seul endroit.

28.3.3 Utiliser un modèle de rapport paramétré

Une fois que le modèle de rapport paramétré est défini, il est possible de l’utiliser pour publier facilement des rapports. La compilation du code source avec la commande rmarkdown::render("rapportParametre.Rmd") générera le document suivant :

Vous pouvez remarquer que ce rapport porte sur le département “01”, car le paramètre codeDpt prend par défaut la valeur “01” d’après l’en-tête du modèle de rapport. Si l’utilisateur souhaite produire le même type de document pour un autre département, il devra passer explicitement le paramètre params = list(codeDpt = "XX") à la fonction render. Par exemple, le code suivant produit un rapport sur le département “02” (l’Aisne).

rmarkdown::render(
  input = "rapportParametre.Rmd", 
  params = list(codeDpt = "02")
)

Dans cet exemple, l’output ressemblera à ceci :

28.3.4 Automatiser la génération de rapports paramétrés

La dernière étape de l’utilisation des rapports paramétrés consiste à en automatiser la production avec une fonction. Voici comment définir une fonction qui génère automatiquement un rapport à partir du modèle de rapport présenté ci-dessus :

GenererRapport <- function(codeDpt) {
    rmarkdown::render(
      input = "rapportParametre.Rmd",
      params = list(codeDpt = codeDpt),
      envir = new.env(),
      output_file = paste0("Rapport_", codeDpt, ".html")
    )
}

Une fois la fonction définie, il est possible de générer automatiquement un rapport paramétré pour le département “31” (Haute-Garonne) en exécutant la commande GenererRapport(codeDpt = "31"). Par défaut, le fichier de sortie s’appellera Rapport_31.html, mais il est possible de choisir un autre nom avec l’argument output_file.

Enfin, cette fonction peut être utilisée dans une boucle for ou un appel à la fonction lapply pour produire un grand nombre de rapports.

28.3.5 Un exemple complet de rapport

Le modèle de rapport paramétré suivant répond au besoin de l’utilisateur. Vous pouvez noter que cet exemple minimal contient tous les éléments d’un rapport paramétré : un en-tête renseigné qui contient la liste des paramètres (il n’y en a qu’un seul : codeDpt), un chunk de configuration, des chunks qui importent les packages et les données, du texte, et des chunks manipulant des données.

---
title: "Mon rapport"
date: "`r Sys.Date()`"
author: "Un agent de l'Insee"
output: html_document
params:
  codeDpt: "01"
---
  
```{r config, include=FALSE}
knitr::opts_chunk$set(echo = FALSE,
                      warning=FALSE,
                      message=FALSE,
                      error = TRUE,
                      fig.align = "center",
                      out = '75%')
```

```{r load-packages}
library(doremifasolData)
library(data.table)
```

```{r importData}
cog_com_2019 <- as.data.table(doremifasolData::cog_com_2019)
```

```{r selectData}
monDpt <- cog_com_2019[dep %in% params$codeDpt]
```

Voici un rapport paramétré très intéressant. Il porte sur le département `r params$codeDpt`.

```{r tableData}
table(monDpt$dep)
```
Note

Vous pouvez télécharger le fichier Rmd de cet exemple sur cette page.

28.4 Pour en savoir plus