3.1 Philosophie du ggplot2
Le package ggplot2
fait partie du tidyverse
et dispose d’une logique de fonctionnement particulière. Cette dernière se nomme The Grammar of Graphics (les deux G sont d’ailleurs à l’origine du nom ggplot2
), proposée par Hadley Wickham (le créateur du tidyverse
!) dans un article intitulé A layered grammar of graphics (Wickham 2010). Nous proposons de synthétiser ici les concepts et principes centraux qui sous-tendent la production de graphiques avec ggplot2
.
3.1.1 Grammaire
Hadley Wickham propose une grammaire pour unifier la création de graphiques. L’idée est donc de dépasser les simples dénominations comme un nuage de points, un diagramme en boîte, un graphique en ligne, etc., pour comprendre ce qui relie tous ces graphiques. Ces éléments communs et centraux sont les géométries, les échelles et systèmes de coordonnées, et les annotations (figure 3.1) :
- Les géométries sont les formes utilisées pour représenter les données. Il peut s’agir de points, de lignes, de cercles, de rectangles, d’arcs de cercle, etc.
- Les échelles et systèmes de coordonnées permettent de contrôler la localisation des éléments dans un graphique en convertissant les données depuis leur échelle originale (dollars, kilomètres, pourcentages, etc.) vers l’échelle du graphique (pixels).
- Les annotations recoupent l’ensemble des informations complémentaires ajoutées au graphique comme son titre et sous-titre, la source des données, la mention sur les droits d’auteurs, etc.
En plus de ces trois éléments, il est bien sûr nécessaire de disposer de données. Ces dernières sont assignées à des dimensions du graphique pour être représentées (notamment les axes X et Y et la couleur). Cette étape est appelée aesthetics mapping dans ggplot2
.
Lorsque nous combinons des données, leur assignation a des dimensions, un type de géométries, des échelles et un système de coordonnées, nous obtenons un calque (layer en anglais). Un graphique peut comprendre plusieurs calques comme nous le verrons dans les prochaines sections.
Prenons un premier exemple très simple et construisons un nuage de points à partir du jeu de données iris fourni de base dans R. Nous représentons la relation qui existe entre la longueur et la largeur des sépales de ces fleurs. Pour commencer, nous devons charger le package ggplot2
et instancier un graphique avec la fonction ggplot
.
library(ggplot2)
data(iris)
names(iris)
## [1] "Sepal.Length" "Sepal.Width" "Petal.Length" "Petal.Width" "Species"
ggplot()
Pour le moment, le graphique est vide (figure 3.2). La seconde étape consiste à lui ajouter des données (au travers du paramètre data
) et à définir les dimensions à associer aux données (avec le paramètre mapping
et la fonction aes()
). Dans notre cas, nous voulons utiliser les coordonnées X pour représenter la largeur des sépales, et les coordonnées Y pour représenter la longueur des sépales. Enfin, nous souhaitons représenter les observations par des points, nous utiliserons donc la géométrie geom_point
.
ggplot(mapping = aes(x = Sepal.Length, y = Sepal.Width), data = iris) +
geom_point()
Ce graphique ne comprend qu’un seul calque avec une géométrie de type point (figure 3.3). Chaque calque est ajouté avec l’opérateur +
qui permet de superposer des calques, le dernier apparaissant au-dessus des autres. Les arguments mapping
et data
sont définis ici dans la fonction ggplot
et sont donc appliqués à tous les calques qui composent le graphique. Il est aussi possible de définir mapping
et data
au sein des fonctions des géométries :
ggplot() +
geom_point(mapping = aes(x = Sepal.Length, y = Sepal.Width), data = iris)
La troisième étape consiste à ajouter au graphique des annotations. Pour notre cas, il faudrait ajouter un titre, un sous-titre et des intitulés plus clairs pour les axes X et Y, ce qu’il est possible de faire avec la fonction labs
(figure 3.5).
ggplot() +
geom_point(mapping = aes(x = Sepal.Length, y = Sepal.Width), data = iris) +
labs(title = "Morphologie des sépales des iris", subtitle = "n = 150",
x = "Longueur des sépales",
y = "Largeur des sépales")
3.1.2 Types de géométries
Le package ggplot2
permet d’utiliser un très grand nombre de géométries différentes. Dans le tableau 3.1, nous avons reporté les principales géométries disponibles afin que vous puissiez vous faire une idée du « bestiaire » existant. Il ne s’agit que d’un extrait des principales fonctions. Sachez qu’il existe aussi des packages proposant des géométries supplémentaires pour compléter ggplot2
.
Géométrie | Fonction |
---|---|
point |
geom_point
|
ligne |
geom_line
|
chemin |
geom_path
|
boîte à moustaches |
geom_boxplot
|
diagramme violon |
geom_violin
|
histogramme |
geom_histogram
|
barre |
geom_bar
|
densité |
geom_density
|
texte |
geom_label
|
barre d’erreur |
geom_errorbar
|
surface |
geom_ribbon
|
3.1.3 Habillage
Dans le premier exemple, nous avons montré comment ajouter le titre, le sous-titre et les titres des axes sur un graphique. Il est aussi possible d’ajouter du texte sous le graphique (généralement la source des données avec l’argument caption
) et des annotations textuelles (annotate
). Pour ces dernières, il convient de spécifier leur localisation (coordonnées x
et y
) et le texte à intégrer (label
); elles sont ensuite ajoutées au graphique avec l’opérateur +
. Ajoutons deux annotations pour identifier deux fleurs spécifiques.
ggplot() +
geom_point(mapping = aes(x = Sepal.Length, y = Sepal.Width), data = iris) +
labs(title = "Morphologie des sépales des iris", subtitle = "n = 150",
x = "Longueur des sépales",
y = "Largeur des sépales",
caption = "Source : jeu de données iris") +
annotate("text", x = 6.7, y = 2.5, # position de la note
label = "une virginica", # texte de la note
hjust = "left", vjust = "top", # ajustement
size = 3, fontface = "italic") +
annotate("text", x = 5.7, y = 4.4, # position de la note
label = "une setosa", # texte de la note
hjust = "left", vjust = "top", # ajustement
size = 3, fontface = "italic")
Comme vous pouvez le constater, de nombreux paramètres permettent de contrôler le style des annotations. Pour avoir la liste des arguments disponibles, n’hésitez pas à afficher l’aide de la fonction : help(annotate)
.
En plus des annotations de type texte, il est possible d’ajouter des annotations de type géométrique. Nous pourrions ainsi délimiter une boîte encadrant les fleurs de l’espère setosa.
<- subset(iris, iris$Species == "setosa")
setosas <- c(min(setosas$Sepal.Length),max(setosas$Sepal.Length))
sepal.length_extent <- c(min(setosas$Sepal.Width),max(setosas$Sepal.Width))
sepal.width_extent
ggplot() +
geom_point(mapping = aes(x = Sepal.Length, y = Sepal.Width), data = iris) +
labs(title = "Morphologie des sépales des iris", subtitle = "n = 150",
x = "Longueur des sépales",
y = "Largeur des sépales",
caption = "Source : jeu de données iris") +
annotate("text", x = 6.7, y = 2.5, # position de la note
label = "une virginica", # texte de la note
hjust = "left", vjust = "top", # ajustement
size = 3, fontface = "italic") +
annotate("text", x = 5.7, y = 4.4, # position de la note
label = "une setosa", # texte de la note
hjust = "left", vjust = "top", # ajustement
size = 3, fontface = "italic") +
annotate("rect",
ymin = sepal.width_extent[[1]],
ymax = sepal.width_extent[[2]],
xmin = sepal.length_extent[[1]],
xmax = sepal.length_extent[[2]],
fill = rgb(0.7,0.7,0.7,.5), # remplissage transparent à 50%
color = "black") # contour de couleur verte
Comme le dernier calque ajouté au graphique est le rectangle, vous noterez qu’il recouvre tous les calques existant, y compris les précédentes annotations. Pour corriger cela, il suffit de changer l’ordre des calques.
ggplot() +
annotate("rect",
ymin = sepal.width_extent[[1]],
ymax = sepal.width_extent[[2]],
xmin = sepal.length_extent[[1]],
xmax = sepal.length_extent[[2]],
fill = rgb(0.7,0.7,0.7,.5), # remplissage transparent à 50%
color = "green") + # contour de couleur verte
geom_point(mapping = aes(x = Sepal.Length, y = Sepal.Width), data = iris) +
labs(title = "Morphologie des sépales des iris", subtitle = "n = 150",
x = "Longueur des sépales",
y = "Largeur des sépales",
caption = "Source : jeu de données iris") +
annotate("text", x = 6.7, y = 2.5, # position de la note
label = "une virginica", # texte de la note
hjust = "left", vjust = "top", # ajustement
size = 3, fontface = "italic") +
annotate("text", x = 5.7, y = 4.4, # position de la note
label = "une setosa", # texte de la note
hjust = "left", vjust = "top", # ajustement
size = 3, fontface = "italic")
3.1.4 Utilisation des thèmes
De nombreux autres éléments peuvent être modifiés dans un graphique comme les paramètres des polices, l’arrière-plan, la grille de repères, etc. Il peut être fastidieux de paramétrer tous ces éléments. Une option intéressante est d’utiliser des thèmes déjà préconstruits. Le package ggplot2
propose une dizaine de thèmes : constatons leur impact sur le graphique précédent.
- Le thème classique (
theme_classic
) (figure 3.9)
ggplot() +
geom_point(mapping = aes(x = Sepal.Length, y = Sepal.Width), data = iris) +
labs(title = "Morphologie des sépales des iris", subtitle = "n = 150",
x = "Longueur des sépales",
y = "Largeur des sépales",
caption = "Source : jeu de données iris") +
theme_classic()
- Le thème gris (
theme_gray
) (figure 3.10)
ggplot() +
geom_point(mapping = aes(x = Sepal.Length, y = Sepal.Width), data = iris) +
labs(title = "Morphologie des sépales des iris", subtitle = "n = 150",
x = "Longueur des sépales",
y = "Largeur des sépales",
caption = "Source : jeu de données iris") +
theme_gray()
- Le thème noir et blanc (
theme_bw
) (figure 3.11)
ggplot() +
geom_point(mapping = aes(x = Sepal.Length, y = Sepal.Width), data = iris) +
labs(title = "Morphologie des sépales des iris", subtitle = "n = 150",
x = "Longueur des sépales",
y = "Largeur des sépales",
caption = "Source : jeu de données iris") +
theme_bw()
- Le thème minimal (
theme_minimal
) (figure 3.12)
ggplot() +
geom_point(mapping = aes(x = Sepal.Length, y = Sepal.Width), data = iris) +
labs(title = "Morphologie des sépales des iris", subtitle = "n = 150",
x = "Longueur des sépales",
y = "Largeur des sépales",
caption = "Source : jeu de données iris") +
theme_minimal()
Il est aussi possible d’utiliser le package ggthemes
qui apporte des thèmes complémentaires intéressants dont :
- Le thème tufte (
theme_tufte
, à l’ancienne…) (figure 3.13)
library(ggthemes)
ggplot() +
geom_point(mapping = aes(x = Sepal.Length, y = Sepal.Width), data = iris) +
labs(title = "Morphologie des sépales des iris", subtitle = "n = 150",
x = "Longueur des sépales",
y = "Largeur des sépales",
caption = "Source : jeu de données iris") +
theme_tufte()
- Le thème economist (
theme_economist
, inspiré de la revue du même nom) (figure 3.14)
ggplot() +
geom_point(mapping = aes(x = Sepal.Length, y = Sepal.Width), data = iris) +
labs(title = "Morphologie des sépales des iris", subtitle = "n = 150",
x = "Longueur des sépales",
y = "Largeur des sépales",
caption = "Source : jeu de données iris") +
theme_economist()
- Le thème solarized (
theme_solarized
, plus original) (figure 3.15)
ggplot() +
geom_point(mapping = aes(x = Sepal.Length, y = Sepal.Width), data = iris) +
labs(title = "Morphologie des sépales des iris", subtitle = "n = 150",
x = "Longueur des sépales",
y = "Largeur des sépales",
caption = "Source : jeu de données iris") +
theme_solarized()
Il en existe bien d’autres et vous pouvez composer vos propres thèmes. N’hésitez pas à explorer la documentation de ggplot2
et de ggthemes
pour en apprendre plus!
3.1.5 Composition d’une figure avec plusieurs graphiques
Il est très fréquent de vouloir combiner plusieurs graphiques dans une même figure. Deux cas se distinguent :
Les données pour les différents graphiques proviennent du même DataFrame et peuvent être distinguées selon une variable catégorielle. L’objectif est alors de dupliquer le même graphique, mais pour des sous-groupes de données. Dans ce cas, nous recommandons d’utiliser la fonction
facet_wrap
deggplot2
.Les graphiques sont complètement indépendants. Dans ce cas, nous recommandons d’utiliser la fonction
ggarrange
du packageggpubr
.
3.1.5.1 ggplot2
et ses facettes
Nous pourrions souhaiter réaliser une figure composite avec le jeu de données iris et séparer notre nuage de points en trois graphiques distincts selon l’espèce des iris (figure 3.16). Pour cela, il faut au préalable convertir la variable espèce en facteur.
$Species_fac <- as.factor(iris$Species)
iris
ggplot() +
geom_point(mapping = aes(x = Sepal.Length, y = Sepal.Width), data = iris) +
labs(title = "Morphologie des sépales des iris", subtitle = "n = 150",
x = "Longueur des sépales",
y = "Largeur des sépales",
caption = "Source : jeu de données iris") +
facet_wrap(vars(Species_fac), ncol=2)
Notez que le nom de la variable (ici Species_fac
) doit être spécifié au sein d’une sous-fonction vars
: vars(Species_fac)
. Nous aurions aussi pu réaliser le graphique sur une seule ligne en spécifiant ncol = 3
(figure 3.17).
ggplot() +
geom_point(mapping = aes(x = Sepal.Length, y = Sepal.Width), data = iris) +
labs(title = "Morphologie des sépales des iris", subtitle = "n = 150",
x = "Longueur des sépales",
y = "Largeur des sépales",
caption = "Source : jeu de données iris") +
facet_wrap(vars(Species_fac), ncol=3)
3.1.5.2 Arrangement des graphiques
La solution avec les facettes est très pratique, mais également très limitée puisqu’elle ne permet pas de créer une figure avec des graphiques combinant plusieurs types de géométries. ggarrange
du package ggpubr
permet tout simplement de combiner des graphiques déjà existant. Créons deux nuages de points comparant plusieurs variables en fonction de l’espèce des iris, puis combinons-les (figure 3.18). Attribuons également aux points une couleur en fonction de l’espèce des fleurs, afin de mieux les distinguer en associant la variable Species
au paramètre color
.
library(ggpubr)
<- ggplot(data = iris) +
plot1 geom_point(aes(x = Sepal.Length, y = Sepal.Width, color = Species)) +
labs(subtitle = "Caractéristiques des sépales",
x = "Longueur",
y = "Largeur",
color = "Espèce")
<- ggplot(data = iris) +
plot2 geom_point(aes(x = Petal.Length, y = Petal.Width, color = Species)) +
labs(subtitle = "Caractéristiques des pétales",
x = "Longueur",
y = "Largeur",
color = "Espèce")
<- list(plot1, plot2)
liste_plots <- ggarrange(plotlist = liste_plots, ncol = 2, nrow = 1,
comp_plot common.legend = TRUE, legend = "bottom") #gérer la légende
annotate_figure(comp_plot,
top = text_grob("Morphologie des sépales et pétales des iris",
face = "bold", size = 12, just = "center"),
bottom = text_grob("Source : jeu de données iris",
face = "italic", size = 8, just = "left")
)
Quatre étapes sont nécessaires :
- Créer les graphiques et les enregistrer dans des objets (ici plot1 et plot2).
- Encapsuler ces objets dans une liste (ici liste_plots).
- Composer la figure finale avec la fonction
ggarrange
. - Ajouter les annotations à la figure composite.
L’argument common.legend
permet d’indiquer à la fonction ggarrange
de regrouper les légendes des deux graphiques. Dans notre cas, les deux graphiques ont les mêmes légendes, il est donc judicieux de les regrouper. L’argument legend
contrôle la position de la légende et peut prendre les valeurs : top, bottom, left, right ou none (absence de légende). La fonction annotate_figure
permet d’ajouter des éléments de texte au-dessus, au-dessous et sur les cotés de la figure composite.
3.1.6 Couleur
Dans un graphique, la couleur peut être utilisée à la fois pour représenter une variable quantitative (dégradé de couleur ou mise en classes), ou une variable qualitative (couleur par catégorie). Dans ggplot2
, il est possible d’attribuer une couleur au contour des géométries avec l’argument color
et au remplissage avec l’argument fill
. Il est possible de spécifier une couleur de trois façons dans R :
- En utilisant le nom de la couleur dans une chaîne de caractère :
"chartreuse4"
. R dispose de 657 noms de couleurs prédéfinis. Pour tous les afficher, utilisez la fonctioncolors()
, qui permet de les visualiser (figure 3.19).
En indiquant le code hexadécimal de la couleur. Il s’agit d’une suite de six lettres et de chiffres précédée par un dièse :
"#99ff33"
.En utilisant une notation RGB (rouge, vert, bleu, transparence). Cette notation doit contenir quatre nombres entre 0 et 1 (0 % et 100 %), indiquant respectivement la quantité de rouge, de vert, de bleu et la transparence. Ces quatre nombres sont donnés comme argument à la fonction
rgb
:rgb(0.6, 1, 0.2, 0)
.
Le choix des couleurs est un problème plus complexe que la manière de les spécifier. Il existe d’ailleurs tout un pan de la sémiologie graphique dédié à la question du choix et de l’association des couleurs. Une première ressource intéressante est ColorBrewer. Il s’agit d’une sélection de palettes de couleurs particulièrement efficaces et dont certaines sont même adaptées pour les personnes daltoniennes (figure 3.20). Il est possible d’accéder directement aux palettes dans R grâce au package RColorBrewer
et la fonction brewer.pal
:
library(RColorBrewer)
display.brewer.all()
Une autre ressource pertinente est le site web coolors.co qui propose de nombreuses palettes à portée de clic.