Outils pour une science reproductible, ouverte et communicable

Diplôme Universitaire Public Health Data Science

Auteur
Date de publication

25 octobre 2026

Avant-propos et instructions

Note🎯 Objectifs pédagogiques

À la fin de ce cours vous saurez :

  1. Expliquer pourquoi la reproductibilité est essentielle en science, et identifier ses principaux obstacles.
  2. Organiser un projet d’analyse de données de façon à ce que tout collègue (y compris votre futur vous) puisse le ré-exécuter de zéro.
  3. Rédiger un document dynamique complet et reproductible avec Quarto mêlant narration, code et résultats.
  4. Produire des visualisations prêtes pour publication avec ggplot2 () ou plotnine (), et les sauvegarder de manière programmatique.
  5. Auditer votre propre projet selon une check-list de reproductibilité avant de le partager.

Instructions : comment naviguer dans ce cours

Ce cours s’articule en 4 Parties (augmentées par cette introduction, ainsi qu’un résumé conclusif). Tout au long de votre session, vous rencontrerez trois types d’activités, identifiées par les icônes ci-dessous :

Icône Type Objectif
📖 Lecture ciblée Une courte ressource externe à lire (~5–10 min). Suivez les liens — ne les ignorez pas.
💡 Définition de concept Idées clés avec illustrations et exemples résolus.
🧑‍💻 Exercice pratique VOUS écrivez et exécutez le code vous-même. Les chunks ne sont pas pré-exécutés dans ce cas.

Choisissez R ou python , les deux langages sont présentés dans les exercices via des onglets, mais vous n’avez besoin d’en faire qu’un seul (au choix, selon votre préférence initiale).

Temps total nécessaire : environ ~3 heures. N’hésitez pas à faire une courte pause entre chaque partie !


⚙️ Configuration (avant de commencer le cours)

Installez la dernière version de → https://cran.r-project.org/
Installez la dernière version de RStudio → https://posit.co/download/rstudio-desktop/

Exécuter ensuite les lignes ci-dessous dans la console :

install.packages(c(
  "tidyverse",    # ggplot2, dplyr, readr, …
  "gapminder",    # notre jeu de données principal
  "renv",         # gestion des dépendances
  "here",         # chemins de fichiers portables
  "quarto",       # compilation des .qmd depuis R
  "knitr",        # moteur de compilation
  "sessioninfo"   # documenter votre environnement logiciel
))

Vérifiez que Quarto est bien installé et accessible depuis le terminal : dans l’onglet Terminal de RStudio, tapez quarto --version.
La commande doit renvoyer un numéro de version si tout fonctionne correctement (par exemple ≥ 1.4).

Installez Python ≥ 3.10 → https://www.python.org/downloads/
Installez VS Code → https://code.visualstudio.com/ (avec l’extension Python)
ou utilisez JupyterLab : pip install jupyterlab

Créez et activez un environnement virtuel, puis installez les packages nécessaires à l’aide des commandes suivantes :

# Créer le dossier du projet et l'environnement virtuel
mkdir repro-phds && cd repro-phds
python -m venv .venv

# Activer (choisissez la ligne correspondant à votre OS)
source .venv/bin/activate       # pour macOS ou Linux
# .venv\Scripts\activate       # pour Windows (PowerShell)

# Installer les bibliothèques Python
pip install pandas plotnine jupyterlab quarto-cli pyprojroot

Vérifiez que Quarto est bien installé et accessible en exécutant quarto --version dans le terminal. La commande doit renvoyer un numéro de version si tout fonctionne correctement).

Avertissement⏱ Avant de commencer

Si vous rencontrez des erreurs d’installation, recherchez le message d’erreur sur le web : le débogage est une compétence fondamentale en data science ! La plupart des erreurs ont une solution rapidement identifiable sur Stack Overflow par exemple… Les chatbots d’IA générative, comme Vibe de Mistral AI par exemple, peuvent également être très utiles.


1 Reproductibilité : qu’est-ce que c’est et pourquoi est-ce important ?

⏱ ~45 minutes

1.1 📖 Lectures : la crise de la reproductibilité

Note📖 Lectures ciblées (~10 min)

Avant de lire plus avant, posez-vous la question : Avez-vous déjà essayé de ré-exécuter une analyse et obtenu des chiffres différents ? Avez-vous lu la section Material and Methods d’un article en vous disant « Je n’ai finalement aucune idée de comment ils ont réellement fait telle ou telle étape » ?

  1. Lisez l’article de Nature News intitulé « 1,500 scientists lift the lid on reproducibility » (Baker, 2016).
    Concentrez-vous sur le graphique intitulé « What Factors Contribute to Irreproducible Research? » et la section « The cause » :
    👉 https://www.nature.com/news/1-500-scientists-lift-the-lid-on-reproducibility-1.19970
    (~5 min)

  2. Consultez la page de présentation de The Turing Way, et en particulier la rubrique « Why this is important » ainsi que la liste des obstacles :
    👉 https://book.the-turing-way.org/reproducible-research/overview
    (~5 min)

Réflexion : En santé publique, les enjeux sont particulièrement importants : des résultats non reproductibles peuvent influencer des recommandations cliniques ou des décisions politiques. Vous rappelez-vous d’une étude publiée à propos du traitement de la COVID-19 en 2020 au début de la pandémie et qui a dû être rétractée ou substantiellement corrigée ? (Indice : cherchez « Surgisphere hydroxychloroquine Lancet » ou « Hydroxychloroquine and azithromycin Gautret Raoult International Journal of Antimicrobial Agents »)


1.2 💡 La reproductibilité sous tous ses angles

Le terme « reproductible » est parfois employé de façon imprécise, et plusieurs définitions coexistent dans différents domaines scientifiques. Dans ce cours, nous utiliserons la définition ci-dessous, centrée sur la reproductibilité computationnelle :

Mêmes données ? Même code/méthode ? Ce qui est évalué
Reproductible ✅ ✅ Peut-on ré-exécuter l’analyse et obtenir exactement les mêmes chiffres ?
Réplicable ❌ ✅ La même méthode se généralise-t-elle à de nouvelles données ?
Robuste ✅ ❌ Des choix analytiques différents aboutissent-ils à la même conclusion ?
Généralisable ❌ ❌ Le résultat tient-il au-delà du contexte original ?

Le diagramme ci-dessous (extrait de The Turing Way) illustre ces quatre définitions :

Une matrice 2x2 montrant la recherche reproductible, réplicable, robuste et généralisable selon les axes mêmes/différentes données et même/différent code

Matrice de reproductibilité. The Turing Way / Scriberia — CC-BY 4.0. Source : https://book.the-turing-way.org

1.3 💡 Pourquoi la reproductibilité est importante

Quelle est la valeur d’un article non reproductible ?
Si ce n’est pas reproductible, est-ce de la science ?
Devrait-on simplement se faire confiance mutuellement ?

Les chercheurs et chercheuses sont comptables de leurs résultats scientifiques. La crédibilité scientifique et le professionnalisme de chacun reposent sur cette capacité à rendre des comptes. Travailler de manière reproductible, en rendant ses méthodes et ses résultats vérifiables, contribue à répondre à ces enjeux.

  • 📙 Les revues scientifiques exigent un certain niveau de reproductibilité : les pairs ne se contentent plus de relire et d’évaluer les manuscrits, ils vérifient aussi désormais le code, les données et les workflows/pipelines computationnels avant l’acceptation finale pour publication.
  • 🛡️ La reproductibilité constitue un bouclier méthodologique : elle réduit la probabilité d’erreurs non détectées et de résultats fallacieux.
  • 🇪🇺🇫🇷 Droit institutionnel : l’Union Européenne, l’Agence Nationale de la Recherche (ANR), et le Haut Conseil de l’évaluation de la recherche et de l’enseignement supérieur (Hcéres) notamment imposent tous un certain niveau de reproductibilité pour les recherches qu’elles financent.
  • 🧱 Impact accru : les articles reproductibles sont davantage cités et réutilisés (ils constituent des bases plus fiables pour les travaux ultérieurs).

En santé publique, la reproductibilité revêt une importance particulière :

  • Des décisions politiques sont prises à partir de résultats publiés. Un résultat erroné ou non reproductible peut ainsi nuire à un grand nombre de patients ou de populations.
  • La recherche financée par des fonds publics doit rendre des comptes: si le public a financé l’étude, le code et les données devraient (dans la mesure du possible) être accessibles au public. Cette idée est étroitement liée à la science ouverte, un concept connexe à celui de la reproductibilité, mais distinct (➡️🌐 plus de détails ici)

Obstacles, motivations et solutions

Obstacle Exemple concret Solution pratique
Culturel « Mon directeur de thèse ne fait jamais ça » Le présenter comme un investissement de carrière, non comme une contrainte supplémentaire
Technique La simulation met plus de 3 jours à tourner Stocker des résultats intermédiaires pré-calculés ; prévoir un mode d’exécution rapide réduit
Légal Données patients sous RGPD Générer des données synthétiques de structure identique ; accorder un accès temporaire restreint à un auditeur
Temps « Je nettoierai le code plus tard » Commencer tôt : cela représente plus de travail et de temps au départ, mais en économise énormément lors des révisions suivantes

La reproductibilité représente un atout, une garantie, et n’est pas un frein

La reproductibilité et ses gages renforcent de la confiance. En effet, les scientifiques qui font attention à la reproductibilité de leurs travaux gagnent en efficacité sur le long terme : ils peuvent plus facilement s’appuyer sur leurs propres travaux passés.

La reproductibilité bénéficie à la science à plusieurs niveaux :

Les bénéfices scientifiques de la reproductibilité sur trois niveaux
🌍 Domaine scientifique 🏥 Groupe de recherche 🧑‍🔬 Vous-même
Crédibilité méthodologique renforcée Transmission plus rapide aux collaborateurs Finalisation & révisions d’articles plus rapides
Connaissances cumulatives et extensibles Réduction de la dette technique Transparent & fiable pour l’audience
Risque d’erreurs publiées réduit Archivage clair et opposable Compétences techniques & workflow efficace
Plus de citations
Important🔑 Points clés à retenir
  • La reproductibilité est une exigence scientifique : un résultat scientifique qui ne peut pas être reproduit n’a que très peu (voire aucune) de valeur. Dans ce cours, nous nous concentrons sur la reproductibilité computationnelle, qui n’est qu’une des couches nécessaires à la reproductibilité de la recherche scientifique (il y a aussi la génération des données par exemple).
  • La reproductibilité est un continuum : la reproductibilité universelle, absolue et permanente est un idéal hors d’atteinte. Néanmoins, nous devons nous efforcer d’améliorer concrètement la reproductibilité en pensant à la réutilisation de nos travaux et à la façon dont nous établissons la confiance dans nos résultats scientifiques.

1.4 🧑‍💻 Exercice 1 : Créer le squelette de votre projet reproductible

Astuce🧑‍💻 Exercice 1 : Configuration du projet (25 min)

Objectif : Créer un projet bien organisé et portable, sur lequel vous vous appuierez ensuite tout au long de ce cours.


Étape 1 : Créer un projet

  1. Ouvrez RStudio → File → New Project… → New Directory → New Project

  2. Nommez-le repro-phds, choisissez un dossier dont vous vous souviendrez

  3. ✅ Cochez « Utiliser renv avec ce projet » — cela configure automatiquement le suivi des dépendances

  4. Cliquez sur Créer le projet

  5. Dans la console du nouveau projet, rendez-y disponibles les packages installés lors de la configuration (la bibliothèque renv du projet est vide au départ) :

    renv::hydrate(c("tidyverse", "gapminder", "here", "quarto", "knitr", "rmarkdown", "sessioninfo"))

Repérez le fichier .Rproj dans l’onglet Files. Lorsque vous l’ouvrez, RStudio définit automatiquement le répertoire de travail à la racine du projet. Rien que cela permet d’éliminer la grande majorité des problèmes liés aux chemins.

# Si vous ne l'avez pas encore fait, créez le répertoire et l'environnement virtuel ci-dessous
mkdir repro-phds && cd repro-phds

# Créer et activer un environnement virtuel
python -m venv .venv
source .venv/bin/activate        # macOS/Linux – exécutez la ligne correspondant à votre OS
.venv\Scripts\activate           # Windows – exécutez la ligne correspondant à votre OS

# Démarrer Python
python

Étape 2 : Créer une structure de dossiers standard

Exécutez ceci dans votre console (à l’intérieur du projet) :

dirs <- c(
  "data/raw",           # Données originales — NE JAMAIS écraser
  "data/processed",     # Données nettoyées / transformées
  "R",                  # Fonctions R réutilisables
  "analysis",           # Les scripts .qmd vont ici
  "output/figures",     # Figures sauvegardées → fig01_..., fig02_...
  "output/tables"       # Tableaux exportés → tab01_..., tab02_...
)

invisible(lapply(dirs, dir.create, recursive = TRUE, showWarnings = FALSE))
cat("✅ Dossiers créés !\n")

Exécutez le code python suivant (avec .venv actif, dans repro-phds/) :

import os

dirs = [
    "data/raw",
    "data/processed",
    "src",               # Fichiers source Python / modules
    "analysis",          # Notebooks ou scripts
    "output/figures",
    "output/tables"
]

for d in dirs:
    os.makedirs(d, exist_ok=True)

print("✅ Dossiers créés !")

À ce stade, la structure de votre projet devrait ressembler à ceci :

repro-phds/
├── data/
│   ├── raw/          ← données originales  (à traiter comme en lecture seule)
│   └── processed/    ← données nettoyées
├── R/  (ou src/)     ← fonctions / modules réutilisables
├── analysis/         ← vos scripts et notebooks
├── output/
│   ├── figures/      ← fig01_nom.pdf, fig01_nom.png, ...
│   └── tables/       ← tab01_nom.csv, ...
└── README.md         ← vous l'écrirez à l'étape suivante

Étape 3 : Rédiger un README.md

Créez README.md à la racine du projet. Le fichier README est souvent la première chose que consulte une personne qui s’intéresse au projet (y compris votre futur vous). Il doit notamment permettre de répondre à deux questions : À quoi sert ce code et comment l’exécuter ?

Copiez le modèle ci-dessous dans README.md, puis complétez les champs laissés vides :

# repro-phds — Pratique de la reproductibilité (Santé Publique)

## Description
Un projet d'analyse de données autonome produit lors du cours
« Outils pour la Science Reproductible » (DU Public Health Data Science, [Année]).

## Comment reproduire tous les résultats

1. Ouvrez `repro-phds.Rproj` dans RStudio
   (ou, en Python, créez puis activez l'environnement virtuel :
   `python -m venv .venv` puis `source .venv/bin/activate`).
2. Restaurez les dépendances :
   - R : exécutez `renv::restore()` dans la console
   - Python : `pip install -r requirements.txt`
3. Rendez le rapport principal :
   ouvrez `analysis/report.qmd` et cliquez sur **Render**,
   ou exécutez `quarto render analysis/report.qmd`.

## Durée d'exécution estimée
< 1 minute sur un ordinateur portable standard.

## Informations de session
(Collez ici la sortie de `sessioninfo::session_info()` pour R, ou la sortie de `pip freeze` pour python, **après** avoir terminé l'Exercice 4 en partie 4.)

Étape 4 : Verrouiller les dépendances

renv a normalement déjà été initialisé lors de la création du projet.
Après avoir installé ou mis à jour des packages, enregistrez les versions exactes utilisées :

renv::snapshot()
# → "renv.lock has been updated."

Ce fichier est une protection contre les problèmes du type « cela fonctionnait l’année dernière ».
Un collaborateur qui exécute renv::restore() obtiendra exactement les mêmes version de package.

Dans le terminal, exécutez les commandes suivantes :

pip freeze > requirements.txt

# Vérifier qu'il a bien été créé
cat requirements.txt

Une autre personne peut alors recréer cet environnement à l’identique à l’aide de la commande suivante :

pip install -r requirements.txt

✅ Auto-évaluation

Avant de continuer vers la partie suivante, vérifiez que vous avez bien réalisé les quatre étapes suivantes, et que vous en comprenez l’intérêt et le rôle :

  • getwd() () ou os.getcwd() () renvoie le chemin vers repro-phds/
  • Les six sous-dossiers existent dans l’explorateur de fichiers
  • README.md est à la racine du projet et comporte les trois sections
  • renv.lock () ou requirements.txt () a été créé
  • Fermer et rouvrir le projet fonctionne correctement

Réflexions supplémentaires : Pourquoi le dossier data/raw/ devrait-il être traité comme un dossier en lecture seule ? Que se passerait-il si vous écrasiez accidentellement le fichier de données original avec une version modifiée ?


2 Programmation lettrée avec Quarto

⏱ ~45 minutes

2.1 📖 Lectures : Un document pour les gouverner tous

Note📖 Lectures ciblées (5 min)

Donald Knuth a introduit la programmation lettrée dans les années 1980 : plutôt que d’écrire du code accompagné de commentaires destinés principalement aux ordinateurs, on rédige un document narratif qui contient le code et qui est d’abord destiné aux humains. Le document produit constitue lui-même l’analyse et son compte-rendu.

  1. Lisez le guide « Hello, Quarto ». Essayez de générer le document à partir de l’exemple, si vous le pouvez :
    👉 https://quarto.org/docs/get-started/hello/rstudio.html

  2. Gardez la fiche mémo Quarto à portée de main tout au long de cette partie :
    👉 https://rstudio.github.io/cheatsheets/quarto.pdf

L’idée centrale : lorsque les figures et les valeurs sont calculées directement dans votre fichier .qmd, il n’y a aucune étape de copier-coller où une valeur devenue obsolète pourrait être copiée par erreur. Réexécutez le document et chaque valeur se met à jour automatiquement.


2.2 💡 Anatomie d’un fichier .qmd

Un fichier Quarto comporte trois éléments principaux :

┌─────────────────────────────────────────────────────────┐
│  1. En-tête YAML    -> titre, auteur, type de sortie... │
│─────────────────────────────────────────────────────────│
│  2. Texte Markdown  -> prose, titres, listes, liens     │
│─────────────────────────────────────────────────────────│
│  3. Blocs de code   -> code R ou Python + sa sortie     │
└─────────────────────────────────────────────────────────┘

Schéma Quarto

Une illustration colorée montrant des sorciers lançant des sorts pour transformer du code R en beaux documents de sortie

Figure 1: Quarto (comme son prédécesseur, Rmarkdown) permet de combiner du code et du texte narratif dans un seul document dynamique. Illustration par Allison Horst — CC-BY 4.0.

1. L’en-tête YAML

Un en-tête YAML se trouve au tout début du document, entre deux lignes contenant uniquement --- qui le délimitent. Il définit notamment les paramètres de sortie et le format général du document. En voici un exemple. Attention : l’indentation est importante en YAML.

---
title: "Tendances mondiales de santé — Données Gapminder"
author: "Votre Nom"
date: today                   # remplit automatiquement la date du jour
format:
  html:
    toc: true                 # table des matières
    code-fold: true           # masquer le code par défaut (le lecteur peut le déplier)
    embed-resources: true     # fichier `HTML` autonome (portable)
execute:
  echo: true                  # afficher le code dans la sortie par défaut
  warning: true               # continuer à afficher les avertissements
  message: false              # supprimer les messages (ex. lors du chargement des packages)
---

2. Texte Markdown

Entre les chunks de code, le texte narratif est rédigé en Markdown (.md), un langage de balisage léger. Voici quelques éléments de syntaxe courants :

# Titre de niveau 1
## Titre de niveau 2

Un paragraphe. Mettez le texte en **gras**, *italique*, ou `style code`.

- Élément de liste à puces 1
- Élément de liste à puces 2

1. Élément numéroté 1
2. Élément numéroté 2

[Texte descriptif du lien](https://url.com)
![Texte alternatif de l'image](chemin/vers/image.png){width=50%}

3. chunks de code

Ces chunks sont délimités par des triples apostrophes inversées ```, suivies de {r} ou {python} (par exemple) pour spécifier l’interpréteur du langage de programmation à utiliser. Les options spécifiques au chunk sont indiquées en attribuant des valeurs à des mots-clés spécifiques au début du chunk avec la syntaxe suivante : #| mot-clé: valeur (pouvant changer les valeurs par défaut définies en tête si besoin). Voici un exemple de chunk, suivi de sa sortie :

```{r}
#| label: summary-table-r
#| echo: true
#| eval: true

library(gapminder)
head(gapminder)
```
# A tibble: 6 × 6
  country     continent  year lifeExp      pop gdpPercap
  <fct>       <fct>     <int>   <dbl>    <int>     <dbl>
1 Afghanistan Asia       1952    28.8  8425333      779.
2 Afghanistan Asia       1957    30.3  9240934      821.
3 Afghanistan Asia       1962    32.0 10267083      853.
4 Afghanistan Asia       1967    34.0 11537966      836.
5 Afghanistan Asia       1972    36.1 13079460      740.
6 Afghanistan Asia       1977    38.4 14880372      786.

Principales options des chunks (écrites après #| à l’intérieur du chunk) :

Option Défaut Effet
echo true Afficher le code dans la sortie
eval true Exécuter le code
include true Inclure la sortie du chunk
message true Afficher les messages de chargement des packages
warning true Afficher les avertissements
cache false Mettre en cache les résultats (utile pour le code lent)
label — Nom pour le référencement croisé des figures / tableaux
fig-cap — Légende de la figure
fig-width / fig-height — Dimensions de la figure (en pouces)

Code inline

Vous pouvez également insérer dans le texte des valeurs calculées automatiquement en utilisant `r ` ou `{python} ` :

Le jeu de données couvre `r length(unique(gapminder$country))` pays de `r min(gapminder$year)` à `r max(gapminder$year)`

Après la compilation, le texte affiché est :

Le jeu de données couvre 142 pays de 1952 à 2007

✨ Pas de copier-coller, pas de chiffres obsolètes, pas de mise à jour manuelle !


2.3 🧑‍💻 Exercice 2 : Votre premier rapport Quarto

Astuce🧑‍💻 Exercice 2 : Premier rapport Quarto (25 min)

Objectif : Rédiger un rapport .qmd reproductible qui charge des données, calcule des résumés avec des valeurs inline, et génère un fichier HTML.

Nous utiliserons le jeu de données Gapminder, qui contient notamment l’espérance de vie, la population et le PIB par habitant pour 142 pays entre 1952 et 2007. L’espérance de vie est un indicateur important en santé publique, elle synthétise la mortalité à tous les âges et reflète la performance globale du système de santé.


Étape 1 : Créer le fichier

Dans RStudio : File → New File → Quarto Document….
Supprimez tout le contenu du modèle. Enregistrez le fichier sous analysis/report.qmd.

Collez l’en-tête YAML ci-dessous correspondant au langage que vous utilisez ( ou ) :

---
title: "Tendances mondiales de santé — Analyse Gapminder"
author: "Votre Nom"
date: today
format:
  html:
    toc: true
    code-fold: true
    theme: flatly
    embed-resources: true
execute:
  echo: true
  warning: false
  message: false
---
---
title: "Tendances mondiales de santé — Analyse Gapminder"
author: "Votre Nom"
date: today
format:
  html:
    toc: true
    code-fold: true
    theme: flatly
    embed-resources: true
execute:
  echo: true
  warning: false
  message: false
jupyter: python3
---

Étape 2 : chunk de configuration (toujours le tout premier chunk !)

Un chunk de configuration s’exécute silencieusement avant tout le reste. C’est notamment à cet endroit que vous pouvez définir la graine aléatoire par exemple.

```{r}
#| label: setup-r
#| include: false

set.seed(20260401)      # ← assure la reproductibilité de tout code reposant sur la génération de nombre pseudo-aléatoires

library(ggplot2)
library(dplyr)
library(gapminder)
library(here)
library(knitr)
```
```{python}
#| label: setup-py
#| include: false

import urllib.request
import numpy as np
import pandas as pd
from pyprojroot import here

np.random.seed(20260401)

# Télécharger Gapminder dans data/raw/ (puis le lire depuis ce dossier)
url = "https://raw.githubusercontent.com/jennybc/gapminder/main/inst/extdata/gapminder.tsv"
raw_file = here("data/raw/gapminder.tsv")
if not raw_file.exists():
    urllib.request.urlretrieve(url, raw_file)
gapminder = pd.read_csv(raw_file, sep="\t")
```

Étape 3 : Section “Données”, avec calcul de valeurs inline

## Les données

Le jeu de données **Gapminder** est une base de données mondiale sur le développement compilée 
par la Fondation Gapminder. Il couvre des indicateurs de santé, de population et de richesse 
pour **`r length(unique(gapminder$country))` pays** 
sur **`r length(unique(gapminder$year))` points temporels**
(de `r min(gapminder$year)` à `r max(gapminder$year)`).

```{r}
#| label: tbl-preview-r
#| tbl-cap: "Les 6 premières lignes du jeu de données Gapminder."

head(gapminder) |> knitr::kable()
```
## Les données

Le jeu de données **Gapminder** est une base de données mondiale sur le développement compilée 
par la Fondation Gapminder. Il couvre des indicateurs de santé, de population et de richesse 
pour **`{python} gapminder["country"].nunique()` pays** 
sur **`{python} len(sorted(gapminder["year"].unique()))` points temporels**
(de `{python} int(gapminder["year"].min())` à `{python} int(gapminder["year"].max())`).

```{python}
#| label: tbl-preview-py

gapminder.head(6)
```

Étape 4 : Section “Statistiques descriptives”

## Statistiques descriptives

```{r}
#| label: tbl-continent-2007-r
#| tbl-cap: "Espérance de vie et PIB par habitant par continent en 2007."

gapminder |>
  filter(year == 2007) |>
  group_by(continent) |>
  summarise(
    `N pays`                  = n(),
    `Esp. vie moy.`           = round(mean(lifeExp), 1),
    `Esp. vie méd.`           = round(median(lifeExp), 1),
    `PIB/hab. moyen`          = round(mean(gdpPercap), 0)
  ) |>
  knitr::kable(format.args = list(big.mark = ","))
```

En 2007, l'espérance de vie mondiale moyenne était de
**`r round(mean(dplyr::filter(gapminder, year == 2007)$lifeExp), 1)` ans**,
avec des valeurs allant de
`r round(min(dplyr::filter(gapminder, year == 2007)$lifeExp), 1)` à
`r round(max(dplyr::filter(gapminder, year == 2007)$lifeExp), 1)` ans.
## Statistiques descriptives

```{python}
#| label: tbl-continent-2007-py

gapminder.query("year == 2007") \
.groupby("continent") \
.agg(
    n_countries=("country", "nunique"),
    mean_lifeExp=("lifeExp", "mean"),
    median_lifeExp=("lifeExp", "median"),
    mean_gdpPercap=("gdpPercap", "mean")
) \
.round(1) \
.reset_index() \
.rename(columns={
    "continent": "Continent",
    "n_countries": "N Pays",
    "mean_lifeExp": "Esp. vie moy.",
    "median_lifeExp": "Esp. vie méd.",
    "mean_gdpPercap": "PIB/hab. moyen"
})
```

Étape 5 : Compilation !

Cliquez sur le bouton bleu Render (en haut du volet éditeur), ou appuyez sur Ctrl+Shift+K / Cmd+Shift+K.

Ou encore depuis la console :

quarto::quarto_render("analysis/report.qmd")

Dans le terminal

quarto render analysis/report.qmd

Dans votre navigateur, ouvrez le fichier report.html généré, puis vérifiez les points suivants :

  • Les valeurs calculées inline insérées dans le texte (nombre de pays, plage d’années) apparaissent correctement
  • Le tableau de résumé a bien un titre
  • Le bouton « Code » (issu de code-fold: true) fonctionne correctement pour chaque chunk

✅ Auto-évaluation

  • Le fichier HTML se génère sans erreurs
  • Les valeurs inline dans le texte correspondent aux valeurs du tableau
  • Changer year == 2007 en year == 1997 et re-générer met bien à jour les valeurs automatiquement
  • Vous pouvez ouvrir report.html sans RStudio ni aucun logiciel (il est auto-suffisant)

Bonus : Pour aller plus loin, ajoutez une section ## Introduction avant ## Les données, avec deux ou trois phrases expliquant pourquoi l’espérance de vie est un indicateur pertinent en santé publique. Essayez aussi d’ajouter une note de bas de page (avec la syntaxe [^1]) et une citation à l’aide d’un fichier bibliographique .bib associé à un fichier de style .csl (contrôlant le format des citations).


3 Visualisation des données

⏱ ~40 minutes

3.1 📖 Lectures : la grammaire des graphiques

Note📖 Lectures ciblées (5 min)

Plutôt que de mémoriser des dizaines de types de graphiques, vous découvrez une grammaire graphique, c’est-à-dire un ensemble de règles que l’on peut combiner. Tout graphique statistique peut être décrit comme des données mises en correspondance avec des propriétés visuelles (position, couleur, taille, forme), représentées par des objets géométriques dans un système de coordonnées.

  1. Parcourez la page d’accueil ggplot2 et le premier exemple « Quick start » :
    👉 https://ggplot2.tidyverse.org/
    (Si vous utilisez , consultez plutôt l’introduction à plotnine, qui reprend la même grammaire :
    👉 https://plotnine.org/guide/introduction.html)

  2. Lisez le résumé de The Grammar of Graphics de Wilkinson par Hadley Wickham présenté ici :
    👉 https://vita.had.co.nz/papers/layered-grammar.html (lisez uniquement les sections « Abstract » et « Introduction »)

Idée clé : Une fois que vous comprenez cette grammaire, vous pouvez construire presque n’importe quel graphique en composant des couches (rapidement modulables). Vous n’avez plus besoin de chercher « comment faire un graphique en violon en ? » (par exemple) à chaque tentative de modification.


3.2 💡 Construire des graphiques couche par couche

Les sept couches

Composant Dans ggplot2 Exemple
Données ggplot(data = ...) gapminder |> filter(year == 2007)
Esthétiques aes(x, y, colour, size, shape) aes(x = gdpPercap, y = lifeExp, colour = continent)
Géométrie geom_*() geom_point(), geom_line(), geom_boxplot()
Échelles scale_*() scale_x_log10(), scale_colour_viridis_d()
Facettes facet_wrap() / facet_grid() facet_wrap(~ continent)
Thème theme_*() theme_minimal()
Étiquettes labs() labs(title = "...", x = "...", caption = "...")

Une illustration artistique d'un personnage construisant un graphique ggplot2 en couches

Chaque graphique ggplot2 est construit en superposant ces composants. Illustration par Allison Horst — CC-BY 4.0.

Exemple complet

library(ggplot2)
library(gapminder)
library(dplyr)

gap_2007 <- gapminder |> filter(year == 2007)

ggplot(
  data = gap_2007,
  aes(x = gdpPercap, y = lifeExp,
      colour = continent,
      size   = pop)          # taille des bulles = population
) +
  geom_point(alpha = 0.7) +
  scale_x_log10(labels = scales::dollar_format()) +   # axe PIB en log
  scale_colour_viridis_d(option = "plasma") +         # palette accessible aux daltoniens
  scale_size(range = c(2, 14), guide = "none") +
  labs(
    title    = "Richesse et santé en 2007",
    subtitle = expression("Chaque bulle est un pays ; taille" %prop% "population"),
    x        = "PIB par habitant (échelle log, USD)",
    y        = "Espérance de vie (années)",
    colour   = "Continent",
    caption  = "Source : Fondation Gapminder"
  ) +
  theme_minimal(base_size = 13)
from plotnine import (ggplot, aes, geom_point, scale_x_log10, scale_size,
                      scale_colour_cmap_d, labs, theme_minimal)
from mizani.labels import label_dollar

gap_2007 = gapminder[gapminder["year"] == 2007]

(
    ggplot(gap_2007,
           aes(x="gdpPercap", y="lifeExp",
               colour="continent",
               size="pop"))                                    # taille des bulles = population
    + geom_point(alpha=0.7)
    + scale_x_log10(labels=label_dollar(precision=0, big_mark=","))  # axe PIB en log
    + scale_colour_cmap_d("plasma")                            # palette accessible aux daltoniens
    + scale_size(range=(2, 14), guide=None)
    + labs(
        title="Richesse et santé en 2007",
        subtitle="Chaque bulle est un pays ; taille ∝ population",
        x="PIB par habitant (échelle log, USD)",
        y="Espérance de vie (années)",
        colour="Continent",
        caption="Source : Fondation Gapminder"
    )
    + theme_minimal(base_size=13)
)

Sauvegarder les figures de manière programmatique

Avertissement⚠️ N’utilisez jamais le bouton « Export »

L’enregistrement manuel d’une figure (par clic droit ou à l’aide du bouton « Export » dans le volet Plots) n’est pas reproductible : la taille, la résolution et le format varient à chaque fois, et cette opération n’est pas consignée dans le code (cette étape reste invisible).

Enregistrez toujours les figures depuis votre script, avec des dimensions et une résolution fixes.

# 1. Assigner votre graphique à une variable nommée
p <- ggplot(gap_2007, aes(...)) + ...

# 2. Sauvegarder : fournir un format vectoriel (par exemple `.PDF`) ou un raster (par exemple `.PNG`) selon la nature de votre graphique
ggsave(
  filename = here::here("output", "figures", "fig01_richesse_sante_2007.pdf"),
  plot     = p,
  width    = 10, height = 6, units = "in"
)
ggsave(
  filename = here::here("output", "figures", "fig01_richesse_sante_2007.png"),
  plot     = p,
  width    = 10, height = 6, units = "in",
  dpi      = 300          # 300 dpi = qualité publication
)
from pyprojroot import here

# 1. Assigner votre graphique à une variable nommée
p = ggplot(gap_2007, aes(...)) + ... 
    ... votre code de graphique ...

# 2. Enregistrer dans un format vectoriel (par exemple `.PDF`) ou un raster (par exemple `.PNG`) selon la nature de votre graphique
p.save(
    here("output/figures/fig01_richesse_sante_2007.pdf"),
    width=10, height=6, units="in", verbose=False
)
p.save(
    here("output/figures/fig01_richesse_sante_2007.png"),
    width=10, height=6, units="in",
    dpi=300, verbose=False      # 300 dpi = qualité publication
)

Convention de nommage des fichiers : utilisez un préfixe numérique cohérent avec l’ordre des figures et des tableaux dans votre document — fig01_, fig02_, …, tab01_, tab02_, …

Choisir des palettes de couleurs accessibles

Environ 8 % des hommes ont une forme de déficience de la vision des couleurs en France (d’après la Société Française d’Ophtalmologie). Voici quelques palettes conçues pour être perceptuellement uniformes et plus accessibles aux personnes daltoniennes :

Palette Package /library Cas d’usage
viridis, plasma, magma viridis (intégré dans ggplot2) Séquentiel / continu
scale_colour_viridis_d() ggplot2 Catégoriel discret
scale_colour_brewer(palette = "Set2") ggplot2 Catégoriel (jusqu’à 8 groupes)
scale_colour_cmap_d("viridis") plotnine Catégoriel discret
scale_colour_cmap("viridis") plotnine Mapping de couleur continu

3.3 🧑‍💻 Exercice 3 : Figures

Astuce🧑‍💻 Exercice 3 : Votre première figure (20 min)

Objectif : Produire et ajouter deux figures avec une qualité adaptée à la publication à votre document analysis/report.qmd, et les enregistrer de manière programmatique dans output/figures/.


Figure 1 : Évolution de l’espérance de vie au fil du temps

Ajoutez une nouvelle section ## Tendances au fil du temps à votre document .qmd :

## Tendances au fil du temps

L'espérance de vie s'est améliorée dans tous les continents depuis 1952 (voir @fig-trends-r),
mais de grandes disparités persistent.

```{r}
#| label: fig-trends-r
#| fig-cap: "Espérance de vie médiane par continent, 1952–2007. Les rubans indiquent l'intervalle interquartile."
#| fig-width: 10
#| fig-height: 5

p_trends <- gapminder |>
  group_by(continent, year) |>
  summarise(
    med  = median(lifeExp),
    q25  = quantile(lifeExp, 0.25),
    q75  = quantile(lifeExp, 0.75),
    .groups = "drop"
  ) |>
  ggplot(aes(x = year, y = med,
             colour = continent, fill = continent)) +
  geom_ribbon(aes(ymin = q25, ymax = q75), alpha = 0.2, colour = NA) +
  geom_line(linewidth = 1.1) +
  geom_point(size = 2.2) +
  scale_colour_viridis_d(option = "plasma") +
  scale_fill_viridis_d(option = "plasma") +
  labs(
    title   = "Tendances de l'espérance de vie par continent (1952–2007)",
    x       = "Année",
    y       = "Espérance de vie (années)",
    colour  = "Continent", fill = "Continent",
    caption = "Source : Gapminder. Les rubans indiquent l'intervalle inter-quartile (IQR)."
  ) +
  theme_minimal(base_size = 13) +
  theme(legend.position = "bottom")

p_trends

ggsave(
  here::here("output", "figures", "fig02_tendances_par_continent.pdf"),
  plot = p_trends, width = 10, height = 5
)
```
## Tendances au fil du temps

```{python}
#| label: fig-trends-py
#| fig-cap: "Espérance de vie médiane par continent, 1952–2007."

from plotnine import (ggplot, aes, geom_ribbon, geom_line, geom_point,
                      scale_colour_cmap_d, scale_fill_cmap_d, labs,
                      theme_minimal, theme)

trend = (
    gapminder
    .groupby(["continent", "year"])["lifeExp"]
    .agg(med="median",
         q25=lambda x: x.quantile(0.25),
         q75=lambda x: x.quantile(0.75))
    .reset_index()
)

p_trends = (
    ggplot(trend, aes(x="year", y="med",
                      colour="continent", fill="continent"))
    + geom_ribbon(aes(ymin="q25", ymax="q75"), alpha=0.2, colour="none")
    + geom_line(size=1.1)
    + geom_point(size=2.2)
    + scale_colour_cmap_d("plasma")
    + scale_fill_cmap_d("plasma")
    + labs(
        title="Tendances de l'espérance de vie par continent (1952–2007)",
        x="Année",
        y="Espérance de vie (années)",
        colour="Continent", fill="Continent",
        caption="Source : Gapminder. Les rubans indiquent l'intervalle inter-quartile (IQR)."
    )
    + theme_minimal(base_size=13)
    + theme(legend_position="bottom", figure_size=(10, 5))
)

p_trends.save(
    here("output/figures/fig02_tendances_par_continent.pdf"),
    width=10, height=5, verbose=False
)

p_trends
```

Figure 2 : Distribution de l’espérance de vie en 2007

Ajoutez une nouvelle section ## Distribution en 2007 à votre fichier .qmd :

## Distribution en 2007

En 2007, la distribution de l'espérance de vie varie largement au sein
de chaque continent (voir @fig-dist-r).

```{r}
#| label: fig-dist-r
#| fig-cap: "Espérance de vie par continent en 2007. Violon = densité ; points = pays individuels ; barre blanche = médiane."
#| fig-width: 9
#| fig-height: 5

p_dist <- gapminder |>
  filter(year == 2007) |>
  ggplot(aes(
    x      = reorder(continent, lifeExp, FUN = median),
    y      = lifeExp,
    fill   = continent,
    colour = continent
  )) +
  geom_violin(alpha = 0.35, linewidth = 0.4) +
  geom_jitter(width = 0.12, alpha = 0.8, size = 2.2) +
  stat_summary(fun = median, geom = "crossbar",
               width = 0.45, colour = "white", linewidth = 0.9) +
  scale_fill_viridis_d(option = "plasma") +
  scale_colour_viridis_d(option = "plasma") +
  labs(
    title   = "Distribution de l'espérance de vie par continent en 2007",
    x       = "Continent (ordonné par espérance de vie médiane)",
    y       = "Espérance de vie (années)",
    caption = "Source : Gapminder. Chaque point = un pays."
  ) +
  theme_minimal(base_size = 13) +
  theme(legend.position = "none")

p_dist

ggsave(
  here::here("output", "figures", "fig03_distribution_2007.pdf"),
  plot = p_dist, width = 9, height = 5
)
```
## Distribution en 2007

En 2007, la distribution de l'espérance de vie varie largement au sein
de chaque continent (voir @fig-dist-py).

```{python}
#| label: fig-dist-py
#| fig-cap: "Espérance de vie par continent en 2007."

import numpy as np
from plotnine import (ggplot, aes, geom_violin, geom_jitter, stat_summary,
                      scale_fill_cmap_d, scale_colour_cmap_d, labs,
                      theme_minimal, theme)

gap_2007 = gapminder[gapminder["year"] == 2007]

p_dist = (
    ggplot(gap_2007, aes(
        x="reorder(continent, lifeExp, np.median)",
        y="lifeExp",
        fill="continent",
        colour="continent"
    ))
    + geom_violin(alpha=0.35, size=0.4)
    + geom_jitter(width=0.12, alpha=0.8, size=2.2)
    + stat_summary(fun_y=np.median, fun_ymin=np.median, fun_ymax=np.median,
                   geom="crossbar", width=0.45, colour="white", size=0.9)
    + scale_fill_cmap_d("plasma")
    + scale_colour_cmap_d("plasma")
    + labs(
        title="Distribution de l'espérance de vie par continent en 2007",
        x="Continent (ordonné par espérance de vie médiane)",
        y="Espérance de vie (années)",
        caption="Source : Gapminder. Chaque point = un pays."
    )
    + theme_minimal(base_size=13)
    + theme(legend_position="none", figure_size=(9, 5))
)

p_dist.save(
    here("output/figures/fig03_distribution_2007.pdf"),
    width=9, height=5, verbose=False
)

p_dist
```

Références croisées dans le texte narratif

Dans votre document .qmd, faites référence aux figures à l’aide de leur identifiant (remplacez @fig-trends-r par @fig-trends-py si vous utilisez ) :

L'espérance de vie a considérablement progressé depuis 1952 (voir @fig-trends-r),
bien que de larges disparités persistent entre et au sein des continents
(@fig-dist-r).

✅ Auto-évaluation

  • Les deux figures apparaissent dans le HTML généré
  • Deux fichiers PDF existent dans output/figures/ avec des noms descriptifs
  • Les noms de fichiers suivent la convention de préfixe fig01_, fig02_
  • Les deux figures utilisent une palette accessible aux daltoniens
  • Chaque figure a une légende informative fig-cap

Défi bonus : Ajoutez une 3e figure : un nuage de points, pour l’Afrique uniquement, montrant la relation entre le PIB par habitant et l’espérance de vie, par décennie. La relation est-elle la même qu’à l’échelle mondiale ? Évolue-t-elle dans le temps ?


4 Partage & checklist de reproductibilité

⏱ ~35 minutes

4.1 📖 Lectures : audit de reproductibilité par les revues scientifiques

Note📖 Lectures ciblées (5 min)

Le Biometrical Journal, une revue de biostatistique, réalise un audit de reproductibilité pour chaque article accepté. Chaque manuscrit est évalué à l’aide d’une checklist et ne peut être publié que lorsque tous les points sont validés (à moins de perdre le badge “Fully reproducible”). C’est une pratique de plus en plus répandue dans les revues scientifiques.

  1. Lisez l’encadré 1 et l’introduction de :
    Hejblum et al. (2020). Realistic and robust reproducible research for biostatistics.
    👉 https://www.biorxiv.org/content/10.1101/2020.01.15.907485v1
    (~5 min, concentrez-vous sur les 10 points de la checklist)

  2. Consultez la rubrique de The Turing Way consacrée à « Making Research Reproducible » :
    👉 https://book.the-turing-way.org/reproducible-research/reproducible-research

Demandez-vous : Si vous soumettez votre projet repro-phds à un audit concernant sa reproductibilité, quels points, parmi les 10 de la checklist ci-dessus, ne pourriez-vous pas encore cocher ?

4.2 💡 Outils pour partager et archiver

Une chaîne d’outils complète pour la reproductibilité

Passer de « ça fonctionne sur ma machine » à « n’importe qui peut l’exécuter » nécessite de combiner plusieurs outils complémentaires :

📁  Organisation du projet      Projets RStudio / structure de dossiers standard
🔒  Gestion des dépendances     `renv`  (R)  /  `venv` + requirements.txt  (Python)
📝  Document lettré             `Quarto` (.qmd)
🎲  Graines aléatoires          `set.seed()` / `np.random.seed()`
🗂️  Contrôle de version         `git`
🌐  Hébergement distant         GitHub
📦  Archivage permanent         Zenodo  →  DOI citable dans un article

renv sous et environnements virtuels sous

renv crée une bibliothèque de packages propre au projet et consigne dans le fichier de verrouillage renv.lock les versions exactes des packages telles qu’utilisées.

renv::snapshot()    # mettre à jour le fichier de verrouillage après installation/modification de packages
renv::restore()     # commande pour le collaborateur : installer exactement les mêmes versions
renv::status()      # vérifier si le fichier de verrouillage et l'état actuel concordent

À la fin de votre document .qmd, enregistrez toujours votre environnement logiciel :

sessioninfo::session_info()

Cette commande affiche la version de , le système d’exploitation, et les versions exactes des packages chargés.

Dans le terminal, comme mentionné dans la Section 1.

pip freeze > requirements.txt       # sauvegarder les versions exactes

# Configuration pour le collaborateur
python -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt

À la fin de votre notebook :

## Dépendances

```{python}
import sys, importlib.metadata
print(f"Python {sys.version}")
for pkg in ["pandas", "numpy", "plotnine"]:
    print(f"  {pkg}: {importlib.metadata.version(pkg)}")
```

git et GitHub : l’essentiel

Pourquoi utiliser git et GitHub ?

🎖 Sauvegarde distante : si votre ordinateur tombe en panne, rien n’est perdu
🎖 Historique complet : vous pouvez remonter dans le temps, jusqu’à n’importe quelle version précédente, sans craindre d’avoir supprimé par inadvertance du code que vous pourriez réutiliser plus tard
🎖 Collaboration : les autres peuvent contribuer facilement, sans s’envoyer des fichiers par e-mail
🎖 Intégration avec Zenodo (attribution de DOI citables)

  • git est un système de contrôle de version qui permet de suivre les modifications de tous les fichiers d’un projet, et de synchroniser les modifications entre plusieurs ordinateurs et faciliter le travail à plusieurs.
  • GitHub est une plateforme en ligne de Microsoft fournissant l’intégration de git avec l’hébergement cloud.

Vous n’avez pas besoin d’être un expert git , trois commandes couvrent la majeure partie des usages quotidiens :

git add .                                                 # indexer toutes les modifications
git commit -m "Ajout analyse espérance de vie et figures" # messages décrivant les modifications indexées
git push                                                  # envoyer vers GitHub
Note🐙 Configuration initiale de git
git config --global user.name  "Votre nom d'utilisateur"
git config --global user.email "vous@domaine.ext"

Dans RStudio : Tools → Global Options… → Git/SVN — pointez vers l’exécutable git . En cas de problème de configuration de git dans RStudio, vous pouvez consulter le livre en ligne Happy git with R.

Zenodo : un DOI pérenne pour votre code (et vos données, le cas échéant)

Zenodo est une archive en ligne hébergée par le CERN (Organisation européenne pour la recherche nucléaire), qui permet d’attribuer un DOI (Digital Object Identifier, un identifiant permanent et citable), à une version de votre code et/ou à vos données . Ce DOI peut par exemple être mentionné dans la section Data availability des manuscrits scientifiques.

Fonctionnement simple en trois étapes :

  1. Vérifiez que le dépôt GitHub hébergeant votre projet est bien public
  2. Connectez votre compte GitHub à Zenodo depuis https://zenodo.org/account/settings/github
  3. Créez une release GitHub (ex. v1.0) => Zenodo archive cette version automatiquement et lui attribue un DOI

Votre article peut ensuite facilement citer (en remplaçant XXXXXXX par le DOI réel) :
> « L’ensemble du code d’analyse est disponible sur https://doi.org/10.5281/zenodo.XXXXXXX »

Le fait qu’il possède un DOI, et qu’il soit hébergé en Europe, le rend beaucoup plus pérenne qu’un simple dépôt GitHub (d’autant qu’ils ne sont pas exclusifs l’un de l’autre).

4.3 🧑‍💻 Exercice 4 : Auto-audit de la checklist de la Recherche Reproductible et préparation au partage

Astuce🧑‍💻 Exercice 4 : Vérifier la checklist de la Recherche Reproductible (20 min)

Objectif : Évaluer la reproductibilité de votre propre projet repro-phds de manière systématique selon la checklist ci-dessous, corriger les lacunes, et le préparer au partage.


Étape 1 : La checklist

Examinez chaque point. Pour chaque élément manquant, ajoutez-le maintenant :

🗂️ README & exécution

  • README.md décrit le projet en un paragraphe
  • Le README donne des instructions précises pour reproduire tous les résultats (quel fichier, quelle commande)
  • Une seule commande ré-exécute tout (quarto render analysis/report.qmd)
  • La durée d’exécution est documentée (ex. « < 1 minute sur un ordinateur portable standard »)

📦 Dépendances

  • renv.lock () ou requirements.txt () est présent et à jour
  • sessioninfo::session_info() () ou la sortie Python équivalente est affichée dans le rapport

📊 Données & code

  • Tous les scripts nécessaires pour reproduire les résultats sont à l’intérieur du projet
  • Les données sont soit dans data/raw/, soit téléchargées via une URL stable dans le code
  • Aucun chemin absolu nulle part dans le code (/home/alice/… ou C:…)

🎲 Aléatoire

  • set.seed() () ou np.random.seed() () est défini dans le chunk de configuration

📁 Sortie

  • Toutes les figures sont sauvegardées de manière programmatique dans output/figures/
  • Les noms de fichiers de figures utilisent la convention de préfixe fig01_, fig02_ correspondant au rapport
  • Au moins un tableau est sauvegardé dans output/tables/

Étape 2 : Ajouter les informations de session au README

Ajoutez la sortie de la commande décrivant votre environnement logiciel à la fin du fichier README.md :

# Exécuter dans la console et coller la sortie dans README.md
sessioninfo::session_info()
# Exécuter dans le terminal et coller dans README.md
python -c "import sys; print(sys.version)"
python -m pip list

Étape 3 : Enregistrer un tableau de résultats depuis le rapport

Ajoutez une nouvelle section ## Export des résultats à votre fichier analysis/report.qmd, juste avant les informations sur l’environnement logiciel. Le tableau est ainsi régénéré à chaque compilation, comme les figures.

## Export des résultats

```{r}
#| label: export-tab01-r

library(readr)

summary_2007 <- gapminder |>
  filter(year == 2007) |>
  group_by(continent) |>
  summarise(
    n_countries    = n(),
    mean_lifeExp   = round(mean(lifeExp), 2),
    median_lifeExp = round(median(lifeExp), 2),
    mean_gdpPercap = round(mean(gdpPercap), 0)
  )

write_csv(summary_2007,
          here("output", "tables", "tab01_continent_summary_2007.csv"))
```
## Export des résultats

```{python}
#| label: export-tab01-py

summary_2007 = (
    gapminder.query("year == 2007") \
    .groupby("continent") \
    .agg(
        n_countries=("country", "nunique"),
        mean_lifeExp=("lifeExp", "mean"),
        median_lifeExp=("lifeExp", "median"),
        mean_gdpPercap=("gdpPercap", "mean")
    ) \
    .round(2) \
    .reset_index()
)

summary_2007.to_csv(here("output/tables/tab01_continent_summary_2007.csv"),
                    index=False)
```

Étape 4 : Instantané final des dépendances et compilation depuis un environnement propre

# Mettre à jour le fichier de verrouillage
renv::snapshot()

# Le test final: redémarrer R complètement, puis compiler le fichier `.qmd` à partir de zéro
# Session → Redémarrer R  (ou Ctrl+Shift+F10)
renv::restore()
quarto::quarto_render("analysis/report.qmd")
pip freeze > requirements.txt

# Désactiver et réactiver l'environnement virtuel, puis rendre
deactivate
source .venv/bin/activate
pip install -r requirements.txt
quarto render analysis/report.qmd

Étape 5 (Bonus) — Pusher sur GitHub, et archiver sur Zenodo

# 1. Initialiser Git (à ignorer si c'est déjà fait)
git init
git add .
git commit -m "Analyse reproductible initiale — Espérance de vie Gapminder"

# 2. Créer un nouveau dépôt sur https://github.com/new, puis exécutez les commandes suivantes dans le terminal (remplacer VOTRE_NOM dans l'url ci-dessous par votre propre *username* sur GitHub):
git remote add origin https://github.com/VOTRE_NOM/repro-phds.git
git branch -M main
git push -u origin main

# 3. Allez sur https://zenodo.org/account/settings/github
#    Activez le dépôt dans Zenodo → la création d'une release déclenchera la création automatique d'un DOI

# 4. Créer une release sur GitHub (cliquez "Releases" → "Create a new release")
#    Étiquetez-la : "v1.0.0"

✅ Vérification finale

Le test ultime de reproductibilité :
Demandez à un camarade de cloner ou télécharger votre dépôt, de suivre exactement vos instructions README, et d’essayer de reproduire vos figures sans vous demander quoi que ce soit.

Si c’est possible — vous avez un projet reproductible. 🎉

  • Les 13 points de la checklist ci-dessus sont cochés
  • Le projet se rend à partir d’une session /Python propre
  • Un camarade peut reproduire vos figures à partir des seules instructions du README
  • (Bonus) Le projet est sur GitHub avec un DOI Zenodo

Questions de réflexion :

  1. Quel était le point de la checklist le plus difficile à satisfaire — et pourquoi ?
  2. Grossièrement, combien de temps supplémentaire la mise en place reproductible vous a-t-elle coûté, comparé à « juste écrire du code » ?
  3. Imaginez une situation réelle en santé publique dans laquelle cet investissement supplémentaire serait clairement justifié.

🏆 Résumé et conclusion

Ce que nous avons appris :

🎖 Adopter une structure claire et portable pour une navigation aisée dans votre projet
🎖 Tout exécuter de bout en bout à l’aide d’une seule commande
🎖 Enregistrer les figures et les tableaux de résultats de manière programmatique
🎖 Figer les versions des dépendances utilisées, pour que l’environnement logiciel soit également reproductible
🎖 Insérer des valeurs calculées inline directement dans le texte
🎖 Satisfaire aux exigences d’une checklist de reproductibilité telle qu’utilisée par les revues scientifiques

La règle d’or

Commencez petit, commencez maintenant. La reproductibilité est un idéal ; chaque petit pas en avant vous en rapproche.

Outils clés

Outil Problème résolu Une commande à retenir
RStudio Project Plus de chemins absolus ; espace de travail autonome Ouvrir .Rproj
Quarto Code + prose en un seul document ; pas de copier-coller de valeurs quarto render
renv / venv Versions exactes des packages — assurance « ça marchait l’année dernière » renv::snapshot()
here / pyprojroot Chemins de fichiers portables fonctionnant sous tous les OS here::here(“output”,“fig.pdf”) / here(“output/fig.pdf”)
ggplot2 / plotnine Figures programmatiques, cohérentes et exportables ggsave() / p.save()
Git + GitHub Historique des versions, collaboration, sauvegarde hors site git add . && git commit && git push
Zenodo DOI permanent pour citer le code dans les articles Connecter GitHub dans les paramètres Zenodo

Pour aller plus loin

Ressource À quoi ça sert
The Turing Way Guide complet et maintenu par la communauté pour la recherche reproductible
R for Data Science (2e) Ouvrage en ligne gratuit consacré à tidyverse, ggplot2 et Quarto
What They Forgot to Teach You About R Organisation des projets, conventions de nommage, chemins de fichiers
Documentation Quarto Tout sur Quarto
ggplot2 book (3e) Présentation approfondie de la grammaire des graphiques
Python Data Science Handbook NumPy, pandas, Matplotlib, scikit-learn
Hejblum et al. (2020) Recherche reproductible en biostatistique
Hornung et al. (2026) Surmonter les obstacles à la reproductibilité computationnelle dans la publication scientifique
Ouvrir la Science Guides et passeports de science ouverte publiés par le gouvernement français (MESRI)