Greboca  

Suport technique et veille technologique

Aujourd’hui, les grandes entreprises et administrations publiques hésitent entre continuer à utiliser des logiciels propriétaires ou basculer vers les Logiciels Libres. Pourtant, la plupart des logiciels libres sont capables de bien traiter les données issues des logiciels propriétaire, et parfois avec une meilleur compatibilité.

C’est alors la barrière de la prise en main qui fait peur, et pourtant...

Les logiciels libres

L’aspect « Logiciel Libre » permet une évolution rapide et une plus grande participation des utilisateurs. Les aides et tutoriels foisonnent sur Internet ou sont directement inclus dans le logiciel lui-même.

Enfin, les concepteurs sont plus proches des utilisateurs, ce qui rend les logiciels libres plus agréable à utiliser et conviviaux.

Grâce à la disponibilité des logiciels libres, vous trouverez facilement des services de support techniques et la licence n’est plus un frein à l’utilisation de ces logiciels par votre personnel.

Notre support technique concerne essentiellement les logiciels libres, que ce soit sous forme de services ponctuels ou de tutoriels.

LinuxFr.org : les journaux  -  Préparation de figures avec R : automatiser l'ajout d'annotations manuelles

 -  Septembre 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 :)

Commentaires : voir le flux Atom ouvrir dans le navigateur

par pompoko

LinuxFr.org : les journaux

LinuxFr.org : Journaux

firefox, nouvelle fenêtre dans une session isolée

 -  15 avril - 

Les fenêtres de navigation privées de firefox partagent leurs cookies de session or je souhaitais avoir des fenêtres de navigation isolées, (qui ne (...)


Pretendo tente de déprogrammer l'obsolescence des consoles Nintendo

 -  9 avril - 

Ah Nal,Gros N vient de faire un gros doigt aux utilisateurs de ses consoles 3DS et Wii U en annonçant la fermeture des services en ligne pour (...)


[Trolldi] Vulgarisation sur l'IA pour décideur pressé

 -  5 avril - 

Cher 'Nal,Je fais un article-marque-page sur un post tout frais de Ploum où il est question d'un fantasme vieux comme le Talmud avec le Golem. (...)


Super Marian and Robin: les roms en collant

 -  3 avril - 

Bonjour Nal,Je t'écris pour te proposer de tester mon nouveau jeu: Super Marian and Robin.Il s'agit d'un jeu de plateformes pour un ou deux (...)


Le roi est mort, vive le roi ! Les alternatives de Redis sont là

 -  3 avril - 

Bonjour Nal !Après le changement de licence de Redis, ce qui devait arriver arriva, et des alternatives libres apparaissent.Tout d'abord, on a (...)