Journal Préparation de figures avec R : automatiser l'ajout d'annotations manuelles

Posté par  . Licence CC By‑SA.
17
18
sept.
2021

Sommaire

R est un outil libre destiné aux statistiques utilisé pour l'analyse de données et la production de figures scientifiques. Une bonne reproductibilité des résultats peut être obtenue en utilisant des scripts R et un logiciel de gestion de version comme Git. Néanmoins, il est parfois pratique d'ajouter quelques annotations à la main sur une figure, ce qui va à l'encontre de la reproductibilité désirée.

Ce journal présente une approche permettant d'incorporer ces annotations manuelles dans une figure de manière automatique et reproductible. J'espère qu'il pourra être utile aux lectrices et lecteurs de LinuxFr qui utilisent R et qui ont pu rencontrer ce problème par le passé !

Le contexte en détail

R est très utilisé en recherche pour analyser des données ainsi que pour réaliser des figures à partir de ces données. Un (ou plusieurs) script R peut contenir toutes les étapes de nettoyage des données brutes, d'analyse statistique, et finalement de préparation des tableaux de résultats et des figures destinés à la publication dans des revues scientifiques.

L'utilisation de script(s) est très utile pour reproduire les analyses de manière fiable, par exemple lorsque le jeu de données original est mis à jour : il suffit de relancer le ou les scripts pour automatiquement mettre à jour toutes les étapes en aval, y compris les tableaux et les figures finals.

Un léger problème survient assez souvent lors de la préparation de figures élaborées : même si R permet de dessiner pratiquement n'importe quelle figure, il peut être plus rapide pour certaines annotations (typiquement des éléments de légende) d'utiliser un logiciel tierce comme Inkscape pour ajouter à la main quelques éléments au fichier svg ou pdf produit par R, plutôt que de les définir laborieusement avec du code R.

Cette étape manuelle implique que la génération des figures n'est plus 100% automatique : après une mise à jour des données, il faudra répéter l'étape d'annotation manuelle de la figure. Si ce n'est pas un problème à faire une fois ou deux, cela devient plus ennuyeux si le jeu de données est amené à être mis à jour souvent, ou si l'analyse fait partie d'un pipeline plus important géré par un Makefile1 par exemple.

Dans cette situation, il peut être intéressant d'automatiser cette dernière étape manuelle. Ce journal propose une approche simple pour ajouter des annotations manuelles de manière automatique à une figure générée par R.

L'approche proposée

En quelques mots, l'idée est de sauvegarder les annotations faites à la main dans un fichier svg séparé, et d'utiliser quelques lignes de code pour superposer le contenu de ce fichier à la figure produite par R.

Dans la figure ci-dessous, l'approche de gauche est celle dans laquelle l'intervention manuelle est nécessaire à chaque exécution du pipeline ; celle de droite est l'approche présentée dans ce journal, où l'étape manuelle n'a lieu qu'une seule fois.

Vue générale de l'approche proposée pour fusionner des annotations SVG dans une figure générée avec R

Comparaison de deux approches possibles pour ajouter des annotations manuelles dans une figure générée avec R. Celle de droite, présentée ici, a l'avantage de ne pas nécessiter une étape manuelle à chaque exécution.

Notons que dans l'approche proposée à droite, l'ensemble du travail peut être intégralement suivi par Git : le script R qui sert à générer la figure incomplète, le fichier svg d'Inkscape qui est un fichier texte, et le script R qui sert à fusionner les deux fichiers svg (la figure générée par R et celle avec les annotations manuelles).

Un exemple détaillé

1 - Préparation de la figure de base avec R

Imaginons que l'on souhaite dessiner une figure présentant la taille de certaines grandes villes françaises. Chaque ville est représentée par un rectangle dont les dimensions sont judicieusement calculées afin de donner une idée de la taille des villes à la fois du point de vue du nombre d'habitants et de celui de la superficie occupée.

Le code ci-dessous prépare les données et enregistre une figure au format svg sous le nom figure-de-base.svg:

library(tibble)

# Données
z <- tibble::tribble(
           ~ville,  ~lat,  ~lon, ~superficie_km2, ~habitants,
          "Paris", 48.86,  2.35,           105.4,    2175601,
      "Marseille",  43.3,  5.37,          240.62,     868277,
           "Lyon", 45.76,  4.83,           47.87,     518635,
       "Toulouse",  43.6,  1.44,           118.3,     486828,
           "Nice",  43.7,  7.27,           71.92,     341032,
         "Nantes", 47.22, -1.55,           65.19,     314138,
    "Montpellier", 43.61,  3.88,           56.88,     290053,
     "Strasbourg", 48.57,  7.75,           78.26,     284677,
       "Bordeaux", 44.84, -0.58,           49.36,     257068,
          "Lille", 50.64,  3.06,           34.51,     233098,
         "Rennes", 48.11, -1.68,           50.39,     217728,
          "Reims", 49.26,  4.03,           47.02,     182211,
         "Toulon", 43.12,  5.93,           42.84,     176198,
  "Saint-Étienne", 45.43,  4.39,           79.97,     173089,
       "Le Havre", 49.49,   0.1,           46.95,     169733,
          "Brest", 48.39, -4.49,           49.51,     139602,
       "Biarritz", 43.48, -1.56,           11.66,      25532
  )
z$densite <- z$habitants / z$superficie_km2

# Figure sauvegardée dans un fichier svg
svg("figure-de-base.svg", width = 8, height = 5, family = "serif")
# Pour laisser de la place aux annotations manuelles sur le côté
par(fig = c(0, 0.7, 0, 1))
# plot() avec 'asp = 1.6' pour avoir un aspect correct à cette latitude
plot(NA, type = "n", xlab = "Longitude", ylab = "Latitude",
     xlim = c(-6, 10), ylim = c(42, 52), asp = 1.6, las = 1, bty = "n")
# ADJ_W et ADJ_H permettent d'ajuster les dimensions des villes à la volée
ADJ_W <- 8e-3    
ADJ_H <- 1.5e-4
# Dessin d'un rectangle par ville (i.e. par ligne du tableau `z`)
for (i in seq_len(nrow(z))) {
    x0 <- z$lon[i]
    y0 <- z$lat[i]
    w <- z$superficie_km2[i] * ADJ_W
    h <- z$densite[i] * ADJ_H
    points(x0, y0, pch = 4)
    rect(x0 - w/2, y0, x0 + w/2, y0 + h, col = grey(0.8))
    text(x0, y0, z$ville[i], pos = 1)
}
# Fermeture du fichier graphique
dev.off()

Figure de base sans annotations

Figure de base générée par R, sans la légende manuelle. Le code qui produit cette figure est écrit de manière à laisser de l'espace sur la droite pour l'ajout ultérieur des annotations.

2 - Préparation des annotations manuelles avec Inkscape

À présent que l'on dispose de la figure de base générée par R, on peut l'ouvrir avec Inkscape et ajouter à la main les éléments nécessaires. Dans l'exemple ci-dessous, j'ai ajoutée une légende qui explique comment interpréter les dimensions des rectangles représentant les villes:

Figure de base avec annotations ajoutées à la main

Ajout manuel d'une légende avec Inkscape, en se basant sur la figure de base générée par R un peu plus tôt.

Une fois que la légende est complète, on efface tous les éléments qui avaient été créés par R afin de ne garder que les annotations ajoutées à la main. Ces annotations sont alors sauvegardées dans un nouveau fichier svg avec Inkscape (annotations-manuelles.svg, ci-dessous). Ce fichier peut être suivi par Git.

Fichier svg avec uniquement les annotations ajoutées à la main
Fichier svg sauvegardé avec Inkscape, contenant uniquement les annotations manuelles.

Une note importante : il est probable que la figure générée par R possède un rectangle blanc en arrière-plan. Il est important de bien penser à effacer cet arrière-plan avant d'enregistrer annotations-manuelles.svg, sinon il occultera la figure de base lorsque annotations-manuelles.svg sera superposé à la figure générée par R (voir ci-dessous).

3 - Automatisation de l'ajout des annotations manuelles à la figure générée par R

À ce stade, on dispose de deux fichiers svg:

  • Le fichier figure-de-base.svg, généré par le script R et facilement mis à jour si les données changent (il suffit d'exécuter le script R à nouveau avec les nouvelles données).
  • Le fichier annotations-manuelles.svg, créé à la main avec Inkscape et suivi par Git. Si les annotations doivent être modifiées dans le futur, elles le seront avec Inkscape et les modifications seront consignées dans l'historique de Git.

La dernière étape consiste à réaliser l'incorporation du fichier annotations-manuelles.svg par-dessus figure-de-base.svg avec quelques lignes de code en R, de manière à ce que l'ensemble des opérations soient scriptées :

library(rsvg)
library(grImport2)
# Conversion du fichier svg avec les annotations manuelles vers le format cairo
# svg reconnu par grImport2
# ("tmp-annotations-cairo.svg" est un fichier temporaire qui sera effacé)
rsvg::rsvg_svg("annotations-manuelles.svg", "tmp-annotations-cairo.svg")
# Chargement de la figure de base
f_base <- grImport2::readPicture("figure-de-base.svg")
# Chargement des annotations (au format cairo svg)
f_ann <- grImport2::readPicture("tmp-annotations-cairo.svg")
# Sauvegarde de la figure finale au format pdf par exemple
cairo_pdf("figure-finale.pdf", width = 8, height = 5, family = "serif")
grImport2::grid.picture(f_base, expansion = 0)
grImport2::grid.picture(f_ann, expansion = 0)
dev.off()
# Nettoyage du fichier temporaire
file.remove("tmp-annotations-cairo.svg")

Et voici la figure finale au format pdf :

Figure finale
Figure finale, avec à la fois la figure de base générée par R et les annotations manuelles créées via Inkscape.

À présent, si les données changent, on peut simplement exécuter à nouveau le script R qui produit la figure de base, puis le script R qui fusionne cette figure de base avec le fichier svg des annotations manuelles. Et si les annotations manuelles doivent être changées, on peut juste modifier le fichier svg des annotations à la main, le consigner dans l'historique de Git, et relancer le script R pour la fusion des fichiers graphiques !

Conclusion

R est un outil très souple et on peut faire énormément avec, y compris les légendes les plus tarabiscotées. Mais parfois il est indéniablement plus simple et plus rapide d'ouvrir Inkscape et de réaliser les annotations en quelques secondes plutôt qu'avec du code.

J'espère que ce journal aura permis de réconcilier les gens qui, comme moi, sont de fermes partisans de l'approche "100% codé en R pour être reproductible" avec l'idée d'ajouter quelques annotations à la main !

Et pour finir, quelques remarques :

  • L'approche proposée ici marche très bien pour les annotations fixes, qui ne changent pas de place lorsque la figure est mise à jour, et qui sont simplement ajoutées à la figure. Par contre, cela ne sera pas une solution si un élément graphique produit par R doit être modifié ou supprimé : dans ce cas, il vaut mieux se donner un peu de mal avec R pour ne pas avoir à modifier cet élément en dehors du script, ou alors omettre son inclusion avec R et l'ajouter dans le fichier svg des annotations manuelles.
  • Je recommande de faire attention à être cohérent dans les dimensions des fichiers graphiques, c'est à dire de s'assurer que les fichiers svg en entrée (figure-de-base.svg et annotations-manuelles.svg) ainsi que le fichier final en sortie (figure-finale.pdf) aient la même taille, afin de ne pas avoir de mauvaise surprise quand les images sont superposées.

Amusez-vous bien avec vos figures maintenant 100% reproductibles :)

  • # Reproductibilité

    Posté par  . Évalué à 4 (+2/-0). Dernière modification le 19/09/21 à 06:37.

    D'abord, merci pour le partage, c'est sympa et j'adore R :)

    Quelques points (oui, je pinaille un peu, mais j'espère que ce ne sera pas mal pris) :

    Perso, je n'inclue pas le rapport dans la notion de reproductibilité. Il s'agit simplement d'une présentation de résultats (qui eux sont en revanche intéressants à reproduire). S'il s'agit de permettre à n'importe quel contributeur de fournir la version "paper ready" de la publication, vu que git est déjà utilisé, autant brancher un jenkins, et zou, c'est lui qui fait foi…

    Ensuite, tu utilise des packages, et ça, c'est pas très bon pour la reproductibilité. Ici, ce sont des packages graphiques, donc à nouveau, pas trop de problème à mon sens, puisque ça n'en fait pas partie. Mais dans ce cas, pourquoi ne pas aller directement vers ggplot2 ? Ça me semblerait à première vue pouvoir résoudre les soucis de taille de fichiers d'entrée… mais je n'ai pas creusé pour être honnête.

    Un autre moyen que j'ai testé pour partager des résultats (dans un autre contexte et avec d'autres objectifs, ça n'est pas du tout pareil), c'est shiny. En gros, je voulais présenter des résultats légèrement interactifs à ma direction. Interactifs car il s'agissait de "fixer" des seuils, qu'ils ne savaient pas fixer (et beaucoup trop de possibilités pour être exhaustif). Autre contrainte m'ayant fait opter pour cette option : les calculs intermédiaires étaient super longs et volumineux une fois obtenus (enfin, en Go quand même, ça va, c'est pas non plus impossible à partager… ça fait juste moins classe que Tiens, clique ici et joue avec les paramètres :p).

    R dans son ensemble est d'une puissance et flexibilité monstrueuse, si bien utilisé. Encore merci pour ton partage !

    • [^] # Re: Reproductibilité

      Posté par  . Évalué à 5 (+3/-0). Dernière modification le 19/09/21 à 08:45.

      En fait ggplot2 semble déjà avoir son système d'annotation customisé à partir d'un svg ;)

      Mais peut-être qu'il y a une bonne raison de ne pas l'utiliser ?

      • [^] # Re: Reproductibilité

        Posté par  . Évalué à 3 (+2/-0).

        Merci pour le lien, il est très pertinent par rapport au sujet du journal et je regrette de ne pas l'avoir inséré dans le journal moi-même :)

        Sur la page en question, Paul Murrell explique dans le détail comment ajouter un fichier svg extérieur à une figure faite avec ggplot(), et il présente aussi les paquets grConvert et gridSVG pour la manipulation de svg dans R. Je ne connaissais pas la fonction ggplot2::annotation_custom(), c'est une bonne surprise de voir que ggplot a déjà un mécanisme pour ce genre de choses !

        Mon cas d'usage était un peu différent, dans la mesure où je voulais pouvoir ajouter un ficher svg extérieur non pas à un objet ggplot mais à une figure faite avec les fonctions R de base (et celles de grid éventuellement). Mais je te remercie pour le lien car cela me sera bien utile si je dois faire la même chose sur un graphe ggplot dans le futur !

    • [^] # Re: Reproductibilité

      Posté par  (site Web personnel) . Évalué à 4 (+2/-0).

      Perso, je n'inclue pas le rapport dans la notion de reproductibilité. Il s'agit simplement d'une présentation de résultats

      si c'est un rapport régulièrement publié, cela permettrait d'indiquer les évolutions depuis la précédente publication (que ce soit mensuel, trimestriel ou semestriel).
      Tu pars du même type de données mais actualisées, cela te permet de consacrer plus de temps à l'analyse :-) (avec quelques KPI calculées automatiquement)

      • [^] # Re: Reproductibilité

        Posté par  . Évalué à 2 (+0/-0). Dernière modification le 19/09/21 à 13:00.

        si c'est un rapport régulièrement publié, cela permettrait d'indiquer les évolutions depuis la précédente publication

        Ce n'est pas ce que j'appelle de la reproductibilité, puisque justement les données changeant, le résultat est sensé changer (ou pas)… mais c'est probablement simplement de la terminologie :)

        Cependant, ce job (exécution potentiellement plannifiée, versionné) est clairement parfait pour un usage via jenkins, d'ailleurs et peut avoir un intérêt en soi, bien sûr !

        • [^] # Re: Reproductibilité

          Posté par  . Évalué à 3 (+1/-0).

          Reproductible dans le sens qu'il n'y a plus la partie manuelle qu'il faut décrire à côté et qui doit être réalisé en face pour obtenir les mêmes images. Oui, question de terminologie : c'était reproductible au sens d'automatisable pour suivre les évolutions et non juste clonable ad infinitum.

          • [^] # Re: Reproductibilité

            Posté par  . Évalué à 7 (+5/-0). Dernière modification le 19/09/21 à 17:29.

            Il y a pas mal de discussions dans les milieux scientifiques pour savoir ce que "reproductible" veut dire. Tout le monde est d'accord pour dire que c'est super d'avoir des analyses reproductibles, mais comme les gens n'entendent pas la même chose…

            Les gens avec une formation forte en informatique cherchent plutôt une reproductibilité informatique (au sens d'une compilation reproductible, par exemple : même binaire généré). Les solutions s'orientent alors vers la puliblication de l'environnement de travail complet (container Docker, machine virtuelle, etc).

            Mais j'ai l'impression que la plupart des scientifiques entendent plutôt la capacité à reproduire l'analyse (dans le sens, être capable de la faire tourner nativement sur leur système), avec leurs propres versions de leurs logiciels. Y compris, avec une version récente (avec des corrections de bugs ou des nouvelles fonctionnalités) des paquets statistiques, par exemple. C'est bien l'analyse qui doit être reproductible (pour pouvoir en refaire une un peu différente), pas les résultats (ou du moins, pas à la dixième décimale près…).

            Le plus gros problème auquel j'ai été confronté, c'est la gestion des caches. En réalité, c'est assez rare d'avoir des analyses de gros jeux de données instantanées; et c'est très désagréable de devoir attendre 20 minutes (ou 20 heures) pour refaire une figure. Il faut donc stocker les calculs intermédiaires (c'est assez facile avec R, puisque les objets sont facilement séralisés), mais il faut gérer quand il faut refaire l'analyse ou non, avec le risque d'avoir un cache désynchronisé (changement dans les données ou dans le script d'analyse).

    • [^] # Re: Reproductibilité

      Posté par  . Évalué à 4 (+3/-0).

      Merci pour ces retours très intéressants ! Je vais essayer de répondre en vrac aux remarques ci-dessus :)

      1. Terminologie du mot "reproductibilité"

      Effectivement, comme déjà mentionné dans les commentaires ci-dessus, on peut avoir des points de vue légèrement différents sur ce qu'on entend par "reproductibilité" selon la terminologie qu'on utilise. Dans le cadre de ce journal, j'aurais peut-être dû utiliser "automatisation" plutôt que "reproductibilité".

      D'un côté, on peut considérer la reproductibilité d'une expérience ou d'une analyse d'un jeu de données. Dans ce cas, ce qui est nécessaire et suffisant pour "reproduire" les choses c'est une description précise des méthodes utilisées (à la manière d'une bonne section "Matériels et Méthodes" dans un rapport scientifique qui doit permettre de reproduire un modèle statistique ou une analyse, même sans avoir accès aux détails de l'implémentation dans le code). Dans ce cas, la présentation des résultats de l'analyse ne rentre pas dans ce critère de reproductibilité : un tableau de résultats ou une figure sont juste un format de présentation de l'information produite par l'analyse, et c'est l'information elle-même qui doit être reproductible, pas sa présentation en tableau ou figure.

      D'un autre côté, on peut considérer la reproductibilité de tout un pipeline qui produit un document final (un rapport pour des décideurs ou un manuscrit à soumettre à un journal). Dans ce cas, le besoin à satisfaire est de pouvoir "reproduire" toutes les étapes de l'analyse et de la production du document final, afin de pouvoir produire un document en suivant exactement les mêmes recettes très facilement. Bien sûr, si les données en entrée changent, le document final va aussi changer, mais la recette appliquée aux données pour produire le document reste la même. Dans ce cas, le mot "reproductibilité" recouvre en fait un mélange de "reproductibilité" comme définie au paragraphe précédent et d'"automatisation".

      2. Reproductibilité et exécution planifiée/avec Jenkins

      Je n'utilise pas Jenkins (cela a l'air assez avancé et au-delà de mes compétences actuelles :) ) mais c'est vrai que l'approche proposée dans le journal se prête bien à l'utilisation des options d'intégration continue sur GitLab et GitHub.

      Pour préciser un peu le contexte, dans mon précédent groupe de recherche en biologie nous utilisions R pour les analyses de données et la préparation de figures, R Markdown pour la préparation de rapports, LaTeX ou Google Docs pour la préparation de manuscrits et Git pour la gestion de versions. Pour travailler de manière collaborative sur un projet, on utilisait GitLab.

      Après un certain temps, notre méthode de travail collaboratif a plus ou moins convergée vers les éléments suivants :

      • Pour chaque projet de recherche, on structure notre code et on stocke nos données à la manière d'un paquet R1. Bien sûr, le paquet en question n'est pas destiné à une publication sur CRAN, mais cela nous permet de suivre une structure claire pour organiser les fichiers et de profiter de tous les outils de documentation (roxygen2) et de test (testthat) disponibles pour les paquets R.

      • Toujours en suivant l'approche "un projet = un paquet", les analyses sont stockées en tant que vignettes R markdown dans le dossier vignettes/ du projet. Là encore, on profite de l'écosystème R : écrire une vignette par analyse nous permet ensuite d'utiliser pkgdown pour générer automatiquement une documentation complète du projet à partir du code R.

      • Finalement, tout cela est partagé entre collaborateurs en utilisant GitLab et son intégration continue : à chaque fois que quelqu'un met à jour le code du projet sur GitLab, le paquet est assemblé, documenté, testé, et les vignettes sont exécutées par pkgdown pour préparer le site web contenant l'ensemble de la documentation et des résultats du projet.

      C'est une approche très agréable, parce qu'elle permet d'avoir un site propre et toujours à jour sur un projet, et de détecter tout de suite quand une analyse marche sur la machine personnelle d'un collaborateur mais échoue sur l'instance GitLab. Cela permet aussi de faciliter le partage de la recherche de manière publique : soit en basculant le dépôt GitLab de "privé" à "public" lorsque l'article final est accepté, soit en ayant tout en "public" dès le début pour une recherche vraiment ouverte !

      Je pense que cela rejoint sans doute un peu ce que tu avais à l'esprit en mentionnant une exécution planifiée avec Jenkins ?

      3. Reproductibilité et paquets

      C'est vrai que l'utilisation de paquets peut rendre les choses plus compliquées. Il n'est pas toujours possible de se passer de paquets tierces pour des raisons pratiques (par exemple, si on a besoin de faire tourner un modèle Bayésien en utilisant une approche HMC, il vaut mieux utiliser rstan plutôt que d'essayer d'écrire sa propre implémentation). Il y a plusieurs outils qui existent dans l'écosystème R pour essayer de pallier à ce problème, comme par exemple les paquets packrat ou renv (voir aussi les autres entrées dans la section "Package Reproducibility" de la CRAN Task View: Reproducible Research). Dans tous les cas, une bonne pratique est d'ajouter à la fin des sorties de scripts R toutes les informations retournées par sessionInfo() afin de garder la trace de l'environnement utilisé (y compris les versions de R et des paquets).

      4. Utilisation de ggplot2

      J'aime beaucoup ggplot2 pour une utilisation interactive, notamment pour explorer les données. Les figures produites sont en général claires et jolies, et le code est court et simple, ce qui permet une manipulation très rapide pour essayer différentes visualisations des données. Cependant, pour les figures finales d'un papier, j'ai presque toujours besoin d'une disposition différente de celle par défaut de ggplot2, et j'ai souvent l'impression de devoir nager à contre-courant lorsque je personnalise trop une figure faite avec ggplot (mais c'est sans doute aussi lié au fait que je connais mieux les commandes R de base que celles de ggplot pour faire des graphiques). Donc en général, pour les figures, j'utilise ggplot2 pour l'exploration et j'utilise les fonctions de base (avec beaucoup de grid aussi) pour les figures à publier. Et c'est pour ces dernières que j'ai plusieurs fois eu à faire quelques ajouts manuels :)

      5. Shiny

      J'aimerais bien apprendre à me servir de Shiny un jour ! Pour ceux et celles qui ne connaissent pas, Shiny permet de créer des applications web à partir de code R2. C'est un outil très puissant pour explorer les données de manière interactive, et c'est vrai que c'est sans doute une excellente façon de partager des résultats compliqués avec des collaborateurs !


      1. Voir le livre de Hadley Wickham accessible en ligne "R Packages" pour apprendre comment écrire un paquet R. 

      2. Voir le livre de Hadley Wickham accessible en ligne "Mastering Shiny"

  • # reproductible en collaboratif

    Posté par  (site Web personnel) . Évalué à 3 (+1/-0).

    Amusez-vous bien avec vos figures maintenant 100% reproductibles :)

    j'imagine que tu as publié tous les éléments de ce journal sur un git (gitlab de préférence :p) afin que cela soit reproductible ?

    cela pourrait être intéressant de fournir l'url :-) vu que cela ferait un jeu de données d'essai voire retravailler la mise en forme.

    • [^] # Re: reproductible en collaboratif

      Posté par  . Évalué à 2 (+1/-0).

      C'est une bonne remarque !

      Je n'ai pas publié les fichiers sources du journal sur une instance Git publique, mais j'ai fait en sorte que le code R fourni dans le journal soit complet (les données sont définies dans l'appel à tibble::tribble()). En faisant un copier-coller du code dans une session R cela produira la figure de base présentée dans le journal.

      La seule partie non-reproductible est, justement, le fichier svg contenant les annotations manuelles faites avec Inkscape, ce que je laisse en tant qu'exercice au lecteur :) Mais si quelqu'un préfère télécharger le fichier d'annotations manuelles que j'ai utilisé dans le journal, il est aussi accessible ici.

      • [^] # Re: reproductible en collaboratif

        Posté par  . Évalué à 3 (+1/-0). Dernière modification le 19/09/21 à 18:56.

        en faisant un copier-coller du code

        Selon moi, pour les données un dput aurait été préférable

        • [^] # Re: reproductible en collaboratif

          Posté par  . Évalué à 3 (+2/-0). Dernière modification le 20/09/21 à 22:56.

          C'est vrai que base::dput() peut convertir au format "code à copier-coller" une gamme d'objets R beaucoup plus large que tibble::tribble(). Mais j'aime bien utiliser tribble() quand je dois utiliser une petite data.frame dans un exemple simple, comme ici, plutôt que la sortie de dput() car je trouve le format de tribble() beaucoup plus facile à lire dans un contexte pédagogique :)

          Pour comparaison, voici la sortie de dput() pour générer le même objet z que le code du journal qui utilise tribble() :

          structure(list(ville = c("Paris", "Marseille", "Lyon", "Toulouse", 
            "Nice", "Nantes", "Montpellier", "Strasbourg", "Bordeaux", "Lille", 
            "Rennes", "Reims", "Toulon", "Saint-Étienne", "Le Havre", "Brest", 
            "Biarritz"), lat = c(48.86, 43.3, 45.76, 43.6, 43.7, 47.22, 43.61, 
            48.57, 44.84, 50.64, 48.11, 49.26, 43.12, 45.43, 49.49, 48.39, 
            43.48), lon = c(2.35, 5.37, 4.83, 1.44, 7.27, -1.55, 3.88, 7.75, 
            -0.58, 3.06, -1.68, 4.03, 5.93, 4.39, 0.1, -4.49, -1.56), superficie_km2 = c(105.4, 
            240.62, 47.87, 118.3, 71.92, 65.19, 56.88, 78.26, 49.36, 34.51, 
            50.39, 47.02, 42.84, 79.97, 46.95, 49.51, 11.66), habitants = c(2175601, 
            868277, 518635, 486828, 341032, 314138, 290053, 284677, 257068, 
            233098, 217728, 182211, 176198, 173089, 169733, 139602, 25532
            )), row.names = c(NA, -17L), class = c("tbl_df", "tbl", "data.frame"
            ))

          À noter aussi que vous pouvez utiliser le paquet datapasta pour générer facilement le code tribble() correspondant à la data.frame que vous voulez reproduire ! datapasta::dpasta() est un peu l'équivalent de base::dput() pour les tableaux de données. Par exemple, pour préparer le code du journal, je suis en fait parti des données stockées dans un fichier tsv puis j'ai utilisé :

          library(readr)
          z <- read_tsv("villes-france.tsv")
          datapasta::dpasta(z)

          Ce qui m'a affiché dans ma console:

          tibble::tribble(
                     ~ville,  ~lat,  ~lon, ~superficie_km2, ~habitants,
                    "Paris", 48.86,  2.35,           105.4,    2175601,
                "Marseille",  43.3,  5.37,          240.62,     868277,
                     "Lyon", 45.76,  4.83,           47.87,     518635,
                 "Toulouse",  43.6,  1.44,           118.3,     486828,
                     "Nice",  43.7,  7.27,           71.92,     341032,
                   "Nantes", 47.22, -1.55,           65.19,     314138,
              "Montpellier", 43.61,  3.88,           56.88,     290053,
               "Strasbourg", 48.57,  7.75,           78.26,     284677,
                 "Bordeaux", 44.84, -0.58,           49.36,     257068,
                    "Lille", 50.64,  3.06,           34.51,     233098,
                   "Rennes", 48.11, -1.68,           50.39,     217728,
                    "Reims", 49.26,  4.03,           47.02,     182211,
                   "Toulon", 43.12,  5.93,           42.84,     176198,
            "Saint-Étienne", 45.43,  4.39,           79.97,     173089,
                 "Le Havre", 49.49,   0.1,           46.95,     169733,
                    "Brest", 48.39, -4.49,           49.51,     139602,
                 "Biarritz", 43.48, -1.56,           11.66,      25532
            )
  • # Raffinement suprême

    Posté par  . Évalué à 7 (+5/-0).

    Dans la série des trucs reproductibles avec R, mon préféré, ça reste les tables en Latex avec le package xtable. On peut les inclure directement dans le document Latex; il y a plein d'options qui font que les tables peuvent souvent être directement publiables. Non seulement c'est classe, mais en plus même les options arbitraires (nombre de décimales des arrondis…) sont clairement documentés.

Envoyer un commentaire

Suivre le flux des commentaires

Note : les commentaires appartiennent à ceux qui les ont postés. Nous n’en sommes pas responsables.