4.5 Différents moteurs graphiques

Prolifération des standards d’après xkcd.

Prolifération des standards d’après xkcd.

Depuis le début, l’ensemble des graphiques que nous vous avons proposés utilise la fonction chart() du package chart. Cependant, il ne s’agit pas de la seule fonction permettant de réaliser des graphiques dans R, loin de là. En fait, chart est tout récent et a été développé pour homogénéiser autant que possible les graphiques issus de trois moteurs graphiques différents : ggplot2, lattice et les graphiques base. La fonction chart() a d’autres avantages également :

  • Un thème par défaut qui est le plus proche possible d’un rendu typique d’une publication scientifique.
  • La possibilité d’utiliser l’interface formule avec ggplot2.
  • La cohérence des objets graphiques obtenus qui peuvent tous êtres combinés en une figure composée, même si ils sont produits avec des moteurs graphiques différents.
  • Un libellé automatique des axes et autres éléments du graphique en fonction des attributs label et units des variables (pour l’instant, seulement les graphiques de type ggplot2).
# Importation des données
(urchin <- read("urchin_bio", package = "data.io", lang = "FR"))
# # A tibble: 421 x 19
#    origin   diameter1 diameter2 height buoyant_weight weight solid_parts
#    <fct>        <dbl>     <dbl>  <dbl>          <dbl>  <dbl>       <dbl>
#  1 Pêcherie      9.90     10.2    5.00             NA  0.522       0.478
#  2 Pêcherie     10.5      10.6    5.70             NA  0.642       0.589
#  3 Pêcherie     10.8      10.8    5.20             NA  0.734       0.677
#  4 Pêcherie      9.60      9.30   4.60             NA  0.370       0.344
#  5 Pêcherie     10.4      10.7    4.80             NA  0.610       0.559
#  6 Pêcherie     10.5      11.1    5.00             NA  0.610       0.551
#  7 Pêcherie     11.0      11.0    5.20             NA  0.672       0.605
#  8 Pêcherie     11.1      11.2    5.70             NA  0.703       0.628
#  9 Pêcherie      9.40      9.20   4.60             NA  0.413       0.375
# 10 Pêcherie     10.1       9.50   4.70             NA  0.449       0.398
# # ... with 411 more rows, and 12 more variables: integuments <dbl>,
# #   dry_integuments <dbl>, digestive_tract <dbl>,
# #   dry_digestive_tract <dbl>, gonads <dbl>, dry_gonads <dbl>,
# #   skeleton <dbl>, lantern <dbl>, test <dbl>, spines <dbl>,
# #   maturity <int>, sex <fct>
# Réalisation du graphique
chart(data = urchin, height ~ weight %col=% origin) + 
  geom_point() 
Graphique typique obtenu avec `chart()` : rendu par défaut publiable tel quel, et libellé automatique des axes avec les unités.

Figure 4.13: Graphique typique obtenu avec chart() : rendu par défaut publiable tel quel, et libellé automatique des axes avec les unités.

4.5.1 ggplot2

Le moteur graphique ggplot2 est écrit pas Hadley Wickham, un personnage emblématique de la “révolution tidyverse” qui propose une surcouche moderne au dessus de R. ggplot2 implémente une “grammaire graphique” particulièrement puissante et flexible, proposée et popularisée par le statisticien Leland Wilkinson. Par défaut, chart() crée en réalité un graphique ggplot2 adapté. Voici la version ggplot2 standard du même graphique représenté à la Fig. 4.13 :

ggplot(data = urchin, mapping = aes(x = weight, y = height, col = origin)) + 
  geom_point() 
Graphique typique obtenu avec `ggplot()` (moteur graphique **ggplot2**).

Figure 4.14: Graphique typique obtenu avec ggplot() (moteur graphique ggplot2).

En comparant les Figs. 4.13 et 4.14 (en faisant abstraction des instructions R utilisées pour l’instant), plusieurs points sautent immédiatement aux yeux:

  • Le thème par défaut de ggplot2 est très reconnaissable avec un quadrillage blanc sur fond gris clair. On aime ou on n’aime pas, mais il est clair que (1) ce n’est pas une présentation “standard” d’un graphique scientifique, et (2) le thème tord un peu le cou à une règle importante pour réaliser un graphique de qualité : minimiser la quantité d’“encre” nécessaire pour représenter un graphique, autrement dit, plus le graphique est simple et sobre, mieux c’est. Le thème par défaut de chart() respecte mieux tout ceci15.

  • La taille des caractères est légèrement plus grande dans la Fig. 4.13 réalisée avec chart(). Le manque de lisibilité des parties textuelles dans un graphique est un défaut fréquent, dépendant de la résolution et de la taille de reproduction du graphique dans le document final. Le choix de chart() recule un peu ce risque.

  • chart() est capable d’aller lire les métadonnées (libellés en français et unités des variables) et les utilisent automatiquement pour proposer des libellés corrects et complets des axes par défaut. ggplot() ne peut pas le faire, et il faut utiliser la fonction labs() pour l’indiquer manuellement.

De manière générale, par rapport à ggplot(), chart() a été conçu pour produire le graphique le plus proche d’un rendu final impeccable avec tous les paramètres par défaut.

Quelques règles simples vous permettent de passer des instructions ggplot() à chart() et vice versa16 :

  1. On peut toujours remplacer ggplot() par chart() dans les instructions R (à condition que le package chart soit chargé bien sûr, par exemple via SciViews::R). Dans ce cas, le thème par défaut diffère, et le libellé automatique des axes (non disponible avec ggplot()) est activé.

  2. Avec chart() on peut utiliser aes() pour spécifier les “esthétiques” (éléments à visualiser sur le graphique) comme pour ggplot(), mais on peut aussi utiliser une interface formule plus compacte. Cette interface formule rapproche la version chart() des graphiques ggplot2 d’un autre moteur de graphique dans R : lattice.

  3. Outre les esthétiques classiques x et y, l’interface formule de chart() permet d’en inclure d’autres directement dans la formule à l’aide d’opérateurs spécifiques %<esth>%=. Par exemple, aes(x = weight, y = height, col = origin) dans la Fig. 4.14 se traduit en la formule plus concise height ~ weight %col=% origin avec chart() (notez la position inversée de x et y dans la formule puisqu’on a y ~ x). Tous les esthétiques de ggplot2 sont supportés de cette manière.

  4. Partout où aes() est utilisé pour les instructions ggplot2, on peut utiliser à la place f_aes() et y spécifier plutôt une formule de type chart().

  5. Avec ggplot() les facettes doivent être spécifiées à l’aide de facet_XXX(). A condition d’utiliser chart(), il est possible d’inclure les spécifications des facettes les plus utilisées directement dans la formule en utilisant l’opérateur |. Cette façon de procéder est, encore une fois, identique à ce qui se fait dans lattice (voir plus loin).

Le point (5) mérite une petite démonstration pour comparaison :

a <- chart(data = urchin, height ~ weight | origin) + 
  geom_point() 

b <- ggplot(data = urchin, mapping = aes(x = weight, y = height)) + 
  geom_point() +
  facet_grid( ~ origin)

combine_charts(list(a, b))
Graphique à facettes. A. version `chart()`, B. version `ggplot()`.

Figure 4.15: Graphique à facettes. A. version chart(), B. version ggplot().

4.5.2 lattice

Autant ggplot2 est complètement modulable en ajoutant littéralement à l’aide de l’opérateur + des couches successives sur le graphique, autant lattice vise à réaliser les graphiques en une seule instruction. lattice utilise également abondamment l’interface formule pour spécifier les variables à utiliser dans le graphique. La version lattice du graphique d’exemple est présentée à la Fig. 4.16.

xyplot(height ~ weight, data = urchin, groups = origin, auto.key = TRUE)
Graphique exemple réalisé avec **lattice**.

Figure 4.16: Graphique exemple réalisé avec lattice.

Et voici la version chart() utilisant le moteur lattice. Notez la façon d’appeler la fonction xyplot() de lattice via chart$xyplot() :

theme_sciviews_lattice(n = 2)
a <- chart$xyplot(height ~ weight, data = urchin, groups = origin,
  auto.key = list(space = "right", title = "Origine", cex.title = 1, columns = 1),
  ylab = "Hauteur du test [mm]", xlab = "Masse totale [g]",
  par.settings = list(superpose.symbol = list(col = scales::hue_pal()(2))))

b <- chart(data = urchin, height ~ weight %col=% origin) + 
  geom_point() 

combine_charts(list(a, b))
Graphique exemple réalisé avec `chart()` A. avec le moteur **lattice**, B. avec le moteur **ggplot2**.

Figure 4.17: Graphique exemple réalisé avec chart() A. avec le moteur lattice, B. avec le moteur ggplot2.

La quantité d’instructions nécessaires pour rendre la version lattice proche de la version ggplot2 devrait disparaître dans les prochaines versions de chart(). Un autre objectif est aussi de gommer le plus possible les différences entre les rendus des différents moteurs de graphiques R, et en particuliers entre ggplot2 et lattice. Comparez la Fig. 4.17A avec la Fig. 4.16 pour apprécier le gain déjà obtenu en matière d’homogénéisation.

Par rapport à ggplot2, les graphiques lattice sont moins flexibles du fait qu’ils doivent être spécifiés en une seule instruction. Cependant, ils sont beaucoup plus rapides à générer (appréciable quand il y a beaucoup de points à tracer) ! lattice offre également quelques types de graphiques non supportés par ggplot2 comme les graphiques en 3D à facettes, par exemple.

Voici un graphique à facettes réalisé avec chart() et le moteur lattice. Notez que la formule utilisée est identique à cette employée pour la version ggplot2 avec chart().

chart$xyplot(data = urchin, height ~ weight | origin,
  scales = list(alternating = 1),
  xlab = "Masse totale [g]", ylab = "Hauteur du test [mm]")
Graphique à facettes, avec `chart()` version **lattice**.

Figure 4.18: Graphique à facettes, avec chart() version lattice.

Mise à part les instructions additionnelles encore nécessaires dans cette version de chart(), l’appel et le rendu sont très similaires par rapport à la version ggplot2 du même graphique avec chart() :

chart(data = urchin, height ~ weight | origin) + 
  geom_point()
Graphique à facettes, avec `chart()` version **ggplot2**.

Figure 4.19: Graphique à facettes, avec chart() version ggplot2.

4.5.3 Graphiques de base

Comme son nom le suggère, le moteur graphique de base est celui qui est implémenté de manière natif dans R. Il est donc utilisé un peu partout. Il est vieillissant et est plus difficile à manipuler que ggplot2 certainement, et même que lattice. Néanmoins, il est très flexible et rapide, … mais son rendu par défaut n’est plus vraiment au goût du jour. Voici notre graphique d’exemple rendu avec le moteur graphique R de base :

plot(urchin$weight, urchin$height,
  col = c("red", "darkgreen")[urchin$origin], pch = 1)
legend(x = 80, y = 10, legend = c("Culture", "Pêcherie"),
  col = c("red", "darkgreen"), pch = 1)
Graphique exemple réalisé avec le moteur graphique R de base.

Figure 4.20: Graphique exemple réalisé avec le moteur graphique R de base.

Vous rencontrerez très fréquemment la fonction plot(). C’est une fonction dite générique dont le comportement change en fonction de l’objet fourni en premier argument. Ainsi, elle réalise le graphique le plus pertinent à chaque fois en fonction du contexte. Notez tout de suite les instructions un peu confuses nécessaires pour spécifier la couleur souhaitée en fonction de l’origine des oursins. Le moteur graphique de base ne gère pas automatiquement des aspects plus complexes du graphique, telle que le positionnement d’une légende. Donc, à moins d’avoir prévu la place suffisante avant de tracer le graphique, nous ne pouvons que l’inclure à l’intérieur du cadre du graphique dans un second temps à l’aide de la fonction legend(). Comme cette dernière ne comprend rien à ce qui a été réalisé jusqu’ici, il faut lui respécifier les couleurs, formes et tailles de points utilisés ! C’est un des aspects pénibles du moteur graphique R de base.

Voici maintenant une version chart() de ce graphique de base :

chart$base({
  par(mar = c(5.1, 4.1, 4.1, 6.1))
  plot(urchin$weight, urchin$height,
    col = scales::hue_pal()(2)[urchin$origin], pch = 19, cex = 0.8,
    xlab = "Masse totale [g]", ylab = "Hauteur du test [mm]")
  legend(x = 105, y = 20, legend = c("Culture", "Pêcherie"), title = "Origine",
    col = scales::hue_pal()(2), pch = 19, bty = "n", cex = 0.8, y.intersp = 2)
})
Graphique exemple réalisé avec le moteur graphique de base et la fonction `chart()`.

Figure 4.21: Graphique exemple réalisé avec le moteur graphique de base et la fonction chart().

Notez que le graphique est généré deux fois : une première fois dans un format propre aux graphiques R de base, et ensuite, il est traduit en une forme compatible avec les autres graphiques ggplot2 et lattice (et au passage, il gagne la grille en traits grisés). Dans le chunck, nous devons spécifier fig.keep = 2 pour éviter d’imprimer la première version dans le rapport lorsqu’on utilise chart$base().

Pour l’instant, le seul avantage de chart() avec les graphiques de base est qu’il les convertit en une forme combinable avec les autres graphiques dans une figure composite (sinon, ce n’est pas possible). A part cela, il faut fournir à chart$base() tout le code nécessaire pour tracer et personnaliser le graphique. Comme on peut le voir sur cet exemple, cela demande une quantité considérable de code. C’est aussi un autre aspect pénible de ce moteur graphique : il est très flexible, mais l’interface n’est pas optimale. Pour finir, les graphiques de base ont plus de mal avec les facettes, mais il peuvent quand même générer les versions les plus simples, par exemple à l’aide de la fonction coplot() qui accepte une formule très similaire à ce qui s’utilise avec lattice :

coplot(data = urchin, height ~ weight | origin)
Graphique à facettes avec le moteur graphique de base.

Figure 4.22: Graphique à facettes avec le moteur graphique de base.

A l’issue de cette comparaison, vous pourrez décider du moteur graphique que vous préférerez utiliser. Dans le cadre de ce cours, nous n’utiliserons en tous cas que quasi-exclusivement des graphiques ggplot2 créés à l’aide la fonction chart().

A vous de jouer

Proposez cinq graphiques inédits (qui n’ont pas été vu jusqu’ici) dans vos différents projets. Employez par exemple les liens suivants pour vous inspirer :

Terminez ce module en vérifiant que vous avez acquis l’ensemble des notions abordées.

Ouvrez RStudio dans votre SciViews Box, puis exécutez l’instruction suivante dans la fenêtre console :

BioDataScience::run("04a_test")
Pour en savoir plus

  1. Notez que plusieurs thèmes existent dans ggplot2. Il est facile d’en changer et des les personnaliser… mais c’est toujours appréciable d’avoir un rendu impeccable dès le premier essai.

  2. Etant donné l’abondante littérature écrite sur ggplot2, il est utile de pouvoir convertir des exemples ggplot2 en graphiques chart(), si vous êtes convaincu par cette nouvelle interface.