Visualisation des données

Last updated on 2026-11-07 | Edit this page

Overview

Questions

  • Visualisation dans R

Objectives

  • Créer des nuages de points, des boîtes à moustaches, des graphiques en courbes, etc., à l’aide de ggplot.
  • Définir les paramètres globaux des graphiques.
  • Décrire le facettage et l’appliquer dans ggplot.
  • Modifier l’aspect visuel d’un graphique ggplot existant (y compris les libellés d’axes et la couleur).
  • Créer des graphiques complexes et personnalisés à partir de données contenues dans un tableau de données.

Cet épisode est basé sur la leçon Data Analysis and Visualisation in R for Ecologists de Data Carpentries.

Visualisation des données


Nous commençons par charger les packages nécessaires. ggplot2 est inclus dans le package tidyverse.

R

library("tidyverse")

Si les données enregistrées lors de la leçon précédente ne sont plus présentes dans l’espace de travail, chargez-les.

R

rna <- read.csv("data/rnaseq.csv")

La fiche pratique de visualisation de données couvrira les bases et les fonctionnalités plus avancées de ggplot2, et permettra, en plus de servir de rappel, d’obtenir un aperçu des nombreuses représentations de données disponibles dans le package. Les tutoriels vidéo suivants (partie 1 et partie 2) de Thomas Lin Pedersen sont également très instructifs.

Graphiques avec ggplot2


ggplot2 est une bibliothèque de graphisme qui permet de créer facilement des graphiques complexes à partir de données contenues dans un tableau de données. Elle offre une interface plus programmatique pour spécifier les variables à tracer, la manière dont elles sont affichées ainsi que les propriétés visuelles générales. Le fondement théorique qui sous-tend ggplot2 est la Grammar of Graphics ( Wilkinson (2005) ). En utilisant cette approche, nous n’avons besoin que de modifications minimales si les données sous-jacentes changent ou si nous décidons de passer d’un graphique en barres à un graphique à dispersion. Cela permet de créer des graphiques de qualité publication avec un minimum d’ajustements et de peaufinage.

Il existe un ouvrage sur ggplot2 ( Wickham (2016) ) qui offre un bon aperçu, mais il est obsolète. La 3e édition est en préparation et sera disponible gratuitement en ligne. La page web ggplot2 (https://ggplot2.tidyverse.org) propose une documentation complète.

ggplot2 fonctionne avec des données au format « long », c’est-à-dire une colonne pour chaque dimension et une ligne pour chaque observation. Des données bien structurées vous feront gagner beaucoup de temps lors de la création de figures avec ggplot2.

Les graphiques ggplot sont construits étape par étape en ajoutant de nouveaux éléments. L’ajout de couches de cette manière permet une grande flexibilité et une personnalisation approfondie des graphiques.

Le principe de la Grammaire des graphiques est que l’on peut construire tout graphique à partir des mêmes 3 composants : (1) un jeu de données, (2) un système de coordonnées et (3) des geoms — c’est-à-dire des marques visuelles qui représentent des points de données 1

Pour créer un ggplot, nous utiliserons le modèle de base suivant, applicable à différents types de graphiques :

ggplot(data = <DATA>, mapping = aes(<MAPPINGS>)) +  <GEOM_FUNCTION>()
  • utilisez la fonction ggplot() et liez le graphique à un tableau de données spécifique à l’aide de l’argument data

R

ggplot(data = rna)
  • définissez une correspondance (avec la fonction esthétique (aes)), en sélectionnant les variables à tracer et en précisant comment les représenter dans le graphique, par exemple par les positions x/y ou par des caractéristiques telles que la taille, la forme, la couleur, etc.

R

ggplot(data = rna, mapping = aes(x = expression))
  • ajoutez des « geoms » — géométries, ou représentations graphiques des données dans le graphique (points, lignes, barres). ggplot2 propose de nombreuses geoms différentes ; nous utiliserons aujourd’hui quelques-unes des plus courantes, notamment :

    * `geom_point()` for scatter plots, dot plots, etc.
    * `geom_histogram()` for histograms
    * `geom_boxplot()` for, well, boxplots!
    * `geom_line()` for trend lines, time series, etc.

Pour ajouter un geom(etry) au graphique, utilisez l’opérateur +. Utilisons d’abord geom_histogram() :

R

ggplot(data = rna, mapping = aes(x = expression)) +
  geom_histogram()

OUTPUT

`stat_bin()` using `bins = 30`. Pick better value `binwidth`.
Default histogram produced by ggplot() and geom_histogram() for the expression data.

Le + du package ggplot2 est particulièrement utile car il permet de modifier des objets ggplot existants. Cela signifie que vous pouvez facilement configurer des modèles de graphiques et explorer commodément différents types de graphiques ; ainsi, le graphique ci-dessus peut également être généré avec un code comme celui-ci :

R

# Assign plot to a variable
rna_plot <- ggplot(data = rna,
                   mapping = aes(x = expression))

# Draw the plot
rna_plot + geom_histogram()
Challenge

Défi

Vous avez probablement remarqué un message automatique qui s’affiche lors du tracé de l’histogramme :

OUTPUT

`stat_bin()` using `bins = 30`. Pick better value `binwidth`.

Modifiez les arguments bins ou binwidth de geom_histogram() pour modifier le nombre ou la largeur des intervalles.

R

# change bins
ggplot(rna, aes(x = expression)) +
    geom_histogram(bins = 15)
Histograms produced by ggplot() and geom_histogram() for the expression data with bin set of 15 (top) and binwith set to 2000 (bottom).

R

# change binwidth
ggplot(rna, aes(x = expression)) +
    geom_histogram(binwidth = 2000)
Histograms produced by ggplot() and geom_histogram() for the expression data with bin set of 15 (top) and binwith set to 2000 (bottom).

On constate ici que les données sont asymétriques vers la droite. Nous pouvons appliquer une transformation logarithmique en base 2 pour obtenir une distribution plus symétrique. Notons que nous ajoutons ici une petite valeur constante (+1) afin d’éviter que des valeurs -Inf ne soient renvoyées pour des valeurs d’expression égales à 0.

R

rna <- rna |>
  mutate(expression_log = log2(expression + 1))

Si nous traçons maintenant l’histogramme des expressions transformées en logarithme en base 2, la distribution est effectivement plus proche d’une distribution normale.

R

ggplot(rna, aes(x = expression_log)) + geom_histogram()

OUTPUT

`stat_bin()` using `bins = 30`. Pick better value `binwidth`.
Histogram produced by ggplot() and geom_histogram() for the pre-computed log of expression.

Désormais, nous travaillerons sur les valeurs d’expression transformées par logarithme.

Challenge

Défi

Une autre façon de visualiser cette transformation consiste à examiner l’échelle des observations. Par exemple, il peut être utile de modifier l’échelle de l’axe afin de mieux répartir les observations dans l’espace du graphique. La modification de l’échelle des axes s’effectue de la même manière que l’ajout ou la modification d’autres composants (c’est-à-dire en ajoutant des commandes progressivement). Essayez d’effectuer cette modification :

  • Représentez l’expression non transformée à l’échelle log10 ; voir scale_x_log10(). Comparez-la au graphique précédent. Pourquoi des messages d’avertissement s’affichent-ils désormais ?

R

ggplot(data = rna,mapping = aes(x = expression))+
  geom_histogram() +
  scale_x_log10()

WARNING

Warning in scale_x_log10(): log-10 transformation introduced infinite values.

OUTPUT

`stat_bin()` using `bins = 30`. Pick better value `binwidth`.

WARNING

Warning: Removed 507 rows containing non-finite outside the scale range
(`stat_bin()`).
Histogram produced by ggplot(), geom_histogram() and scale_x_log10() for the log of expression.

Notes

  • Tout ce que vous insérez dans la fonction ggplot() est visible par toutes les couches geom que vous ajoutez (c’est-à-dire qu’il s’agit de paramètres de tracé globaux). Cela inclut la correspondance des axes x et y que vous configurez dans aes().
  • Vous pouvez également spécifier des correspondances pour un geom donné, indépendamment des correspondances définies globalement dans la fonction ggplot().
  • Le signe + utilisé pour ajouter de nouvelles couches doit être placé à la fin de la ligne contenant la couche précédente. Si, en revanche, le signe + est ajouté au début de la ligne contenant la nouvelle couche, ggplot2 n’ajoutera pas la nouvelle couche et renvoiera un message d’erreur.

R

# This is the correct syntax for adding layers
rna_plot +
  geom_histogram()

# This will not add the new layer and will return an error message
rna_plot
  + geom_histogram()

Création itérative de vos graphiques


Nous allons maintenant tracer un nuage de points avec deux variables continues et la fonction geom_point(). Ce graphique représentera les log2 des rapports d’expression (log2 fold changes), en comparant le temps 8 au temps 0 et le temps 4 au temps 0. Pour cela, nous devons d’abord calculer les moyennes des valeurs d’expression transformées en log2, par gène et par temps. Nous calculons ensuite les log2 des rapports d’expression en soustrayant la moyenne au temps 0 de celle au temps 8, puis de celle au temps 4. Notez que nous incluons également le biotype des gènes, que nous utiliserons plus tard pour représenter les gènes. Nous enregistrerons ces log2 des rapports d’expression dans un nouveau tableau de données appelé rna_fc..

R

rna_fc <- rna |> select(gene, time,
                         gene_biotype, expression_log) |>
  group_by(gene, time, gene_biotype) |>
  summarize(mean_exp = mean(expression_log)) |>
  pivot_wider(names_from = time,
              values_from = mean_exp) |>
  mutate(time_8_vs_0 = `8` - `0`, time_4_vs_0 = `4` - `0`)

OUTPUT

`summarise()` has regrouped the output.
ℹ Summaries were computed grouped by gene, time, and gene_biotype.
ℹ Output is grouped by gene and time.
ℹ Use `summarise(.groups = "drop_last")` to silence this message.
ℹ Use `summarise(.by = c(gene, time, gene_biotype))` for per-operation grouping
  (`?dplyr::dplyr_by`) instead.

Nous pouvons ensuite créer un ggplot avec le jeu de données rna_fc nouvellement créé. La création de graphiques avec ggplot2 est généralement un processus itératif. Nous commençons par définir le jeu de données que nous utiliserons, disposer les axes et choisir un geom :

R

ggplot(data = rna_fc, mapping = aes(x = time_4_vs_0, y = time_8_vs_0)) +
  geom_point()
Scatter plot produced by ggplot() and geom_point() comparing the log-foldchanges computed above. All dots are black.

Ensuite, nous commençons à modifier ce graphique pour en extraire davantage d’informations. Par exemple, nous pouvons ajouter de la transparence (alpha) afin d’éviter la superposition des points :

R

ggplot(data = rna_fc, mapping = aes(x = time_4_vs_0, y = time_8_vs_0)) +
  geom_point(alpha = 0.3)
Scatter plot produced by ggplot() and geom_point() comparing the log-foldchanges computed above. All dots are semi-transparent black.

Nous pouvons également ajouter des couleurs pour tous les points :

R

ggplot(data = rna_fc, mapping = aes(x = time_4_vs_0, y = time_8_vs_0)) +
  geom_point(alpha = 0.3, color = "blue")
Scatter plot produced by ggplot() and geom_point() comparing the log-foldchanges computed above. All dots are semi-transparent blue.

Ou encore, pour colorer chaque gène du graphique différemment, vous pourriez utiliser un vecteur comme entrée pour l’argument color. ggplot2 fournira une couleur différente correspondant à différentes valeurs du vecteur. Voici un exemple où nous colorions avec gene_biotype :

R

ggplot(data = rna_fc, mapping = aes(x = time_4_vs_0, y = time_8_vs_0)) +
  geom_point(alpha = 0.3, aes(color = gene_biotype))
Scatter plot produced by ggplot() and geom_point() comparing the log-foldchanges computed above. Dots are colour-coded based on the gene's biotype.

Nous pouvons également spécifier les couleurs directement au sein de la correspondance fournie dans la fonction ggplot(). Celles-ci seront prises en compte par toutes les couches geom, et la correspondance sera déterminée par les axes x et y configurés dans aes().

R

ggplot(data = rna_fc, mapping = aes(x = time_4_vs_0, y = time_8_vs_0,
                                color = gene_biotype)) +
  geom_point(alpha = 0.3)
Scatter plot produced by ggplot() and geom_point() comparing the log-foldchanges computed above. Dots are colour-coded based on the gene's biotype.

Enfin, nous pourrions également ajouter une ligne diagonale avec la fonction geom_abline() :

R

ggplot(data = rna_fc, mapping = aes(x = time_4_vs_0, y = time_8_vs_0,
                                color = gene_biotype)) +
  geom_point(alpha = 0.3) +
  geom_abline(intercept = 0)
Scatter plot produced by ggplot() and geom_point() comparing the log-foldchanges computed above. Dots are colour-coded based on the gene's biotype. A black line of slope 1 crossing the origin was added by geom_abline().

Notons que nous pouvons modifier la couche geom de geom_point à geom_jitter et que les couleurs resteront déterminées par gene_biotype.

R

ggplot(data = rna_fc, mapping = aes(x = time_4_vs_0, y = time_8_vs_0,
                                color = gene_biotype)) +
  geom_jitter(alpha = 0.3) +
  geom_abline(intercept = 0)
Scatter plot produced by ggplot() and geom_point() comparing the log-foldchanges computed above. Dots are colour-coded based on the gene's biotype. A black line of slope 1 crossing the origin was added by geom_abline().
Challenge

Défi

Les nuages de points peuvent être des outils exploratoires utiles pour de petits jeux de données. Pour les jeux de données comportant un grand nombre d’observations, comme le jeu de données rna_fc, la superposition des points peut constituer une limite. Une stratégie pour gérer de tels cas consiste à regrouper les observations dans des cellules hexagonales. L’espace du graphique est pavé d’hexagones. Une couleur est attribuée à chaque hexagone en fonction du nombre d’observations qu’il contient.

  • Pour regrouper les observations dans des cellules hexagonales avec ggplot2, installez d’abord le package R hexbin depuis CRAN et chargez-le.

  • Utilisez ensuite la fonction geom_hex() pour générer la figure hexbin.

  • Quels sont les avantages et les inconvénients d’un graphique à cellules hexagonales par rapport à un nuage de points ? Examinez le nuage de points ci-dessus et comparez-le au graphique à cellules hexagonales que vous avez créé.

R

install.packages("hexbin")

R

library("hexbin")

ggplot(data = rna_fc, mapping = aes(x = time_4_vs_0, y = time_8_vs_0)) +
  geom_hex() +
  geom_abline(intercept = 0)
Scatter plot produced by ggplot() and geom_hexbin() comparing the log-foldchanges computed above shows hexagons coloured based on the underlying dot density. A black line of slope 1 crossing the origin was added by geom_abline().
Challenge

Défi

Utilisez ce que vous venez d’apprendre pour créer un graphique de dispersion de expression_log en fonction de sample à partir du jeu de données rna, en affichant le temps dans différentes couleurs. Est-ce un bon moyen de présenter ce type de données ?

R

ggplot(data = rna, mapping = aes(y = expression_log, x = sample)) +
    geom_point(aes(color = time))
Figures showing a stretch of overlapping points indicating the log of expression + 1 for each sample. The points are coloured with different shades of blue for samples collected at different time points.

Diagramme en boîtes


Nous pouvons utiliser des boîtes à moustaches pour visualiser la distribution des expressions géniques au sein de chaque échantillon :

R

ggplot(data = rna,
         mapping = aes(y = expression_log, x = sample)) +
  geom_boxplot()
Boxplot showing the distribution of log expression + 1 values for each sample, as produced by geom_boxlpot(). Each boxplot is filled with white colour.

En ajoutant des points au graphique en boîtes, nous pouvons mieux appréhender le nombre de mesures et leur répartition :

R

ggplot(data = rna,
         mapping = aes(y = expression_log, x = sample)) +
  geom_jitter(alpha = 0.2, color = "tomato") +
  geom_boxplot(alpha = 0)
Boxplot and dots showing the distribution of log expression + 1 values for each sample, as produced by geom_boxlpot(). Each boxplot is transparent and the jittered dots are semi-transparent tomato-coloured and behind the boxpots.
Challenge

Défi

Remarquez que la couche du boxplot se trouve devant la couche du jitter. Que faut-il modifier dans le code pour placer le boxplot sous les points ?

Nous devrions inverser l’ordre de ces deux geoms :

R

ggplot(data = rna,
         mapping = aes(y = expression_log, x = sample)) +
  geom_boxplot(alpha = 0) +
  geom_jitter(alpha = 0.2, color = "tomato")
Boxplot and dots showing the distribution of log expression + 1 values for each sample, as produced by geom_boxlpot(). Each boxplot is transparent and the jittered dots are semi-transparent tomato-coloured. This time, the boxplots are behind the dots.

Vous remarquerez peut-être que les valeurs sur l’axe des abscisses sont toujours mal lisibles. Modifions l’orientation des étiquettes et ajustons-les verticalement et horizontalement pour qu’elles ne se chevauchent pas. Vous pouvez utiliser un angle de 90 degrés, ou expérimenter pour trouver l’angle approprié pour des étiquettes orientées en diagonale :

R

ggplot(data = rna,
         mapping = aes(y = expression_log, x = sample)) +
  geom_jitter(alpha = 0.2, color = "tomato") +
  geom_boxplot(alpha = 0) +
  theme(axis.text.x = element_text(angle = 90,  hjust = 0.5, vjust = 0.5))
Boxplot and dots showing the distribution of log expression + 1 values for each sample, as produced by geom_boxlpot(). Each boxplot is transparent and the jittered dots are semi-transparent tomato-coloured. The sample labels are displayed vertically and readable.
Challenge

Défi

Ajoutez de la couleur aux points de votre graphique en boîtes en fonction de la durée de l’infection (time).

Indice : Vérifiez la classe de time. Envisagez de modifier la classe de time, passant de nombre entier à facteur, directement dans la correspondance ggplot. Pourquoi ce changement modifie-t-il la façon dont R crée le graphique ?

R

# time as integer
ggplot(data = rna,
         mapping = aes(y = expression_log,
                       x = sample)) +
  geom_jitter(alpha = 0.2, aes(color = time)) +
  geom_boxplot(alpha = 0) +
  theme(axis.text.x = element_text(angle = 90,  hjust = 0.5, vjust = 0.5))
Boxplot and dots showing the distribution of log expression + 1 values for each sample, as produced by geom_boxlpot(). On the first figure, each boxplot is transparent and the jittered dots are semi-transparent and coloured in different shares of blue. On the second figures, each boxplot is transparent and the jittered dots are semi-transparent and coloured red, green and blue.

R

# time as factor
ggplot(data = rna,
         mapping = aes(y = expression_log,
                       x = sample)) +
  geom_jitter(alpha = 0.2, aes(color = as.factor(time))) +
  geom_boxplot(alpha = 0) +
  theme(axis.text.x = element_text(angle = 90,  hjust = 0.5, vjust = 0.5))
Boxplot and dots showing the distribution of log expression + 1 values for each sample, as produced by geom_boxlpot(). On the first figure, each boxplot is transparent and the jittered dots are semi-transparent and coloured in different shares of blue. On the second figures, each boxplot is transparent and the jittered dots are semi-transparent and coloured red, green and blue.
Challenge

Défi

Les boîtes à moustaches sont des résumés utiles, mais masquent la forme de la distribution. Par exemple, si la distribution est bimodale, nous ne la verrions pas dans une boîte à moustaches. Une alternative à la boîte à moustaches est le graphique en violon, où la forme (de la densité des points) est tracée.

  • Remplacez le graphique en boîtes par un graphique en violons ; voir geom_violin(). Remplissez les violons en fonction du temps à l’aide de l’argument fill.

R

ggplot(data = rna,
         mapping = aes(y = expression_log, x = sample)) +
  geom_violin(aes(fill = as.factor(time))) +
  theme(axis.text.x = element_text(angle = 90,  hjust = 0.5, vjust = 0.5))
Violin plot showing the distribution of log expression + 1 values for each sample, as produced by geom_violin(). Each boxplot is transparent and the jittered dots are semi-transparent and coloured red, green and blue.
Challenge

Défi

  • Modifiez le graphique en violons pour remplir les violons par sex.

R

ggplot(data = rna,
         mapping = aes(y = expression_log, x = sample)) +
  geom_violin(aes(fill = sex)) +
  theme(axis.text.x = element_text(angle = 90,  hjust = 0.5, vjust = 0.5))
Violin plot showing the distribution of log expression + 1 values for each sample, as produced by geom_violon(). Each violin plot is coloured in red or blue depending on the sex variable.

Graphiques en courbes


Calculons l’expression moyenne par durée d’infection pour les 10 gènes présentant les log2 des rapports d’expression les plus élevés entre le temps 8 et le temps 0. Tout d’abord, nous devons sélectionner les gènes et créer un sous-ensemble de rna appelé sub_rna contenant les 10 gènes sélectionnés, puis regrouper les données et calculer l’expression génique moyenne au sein de chaque groupe :

R

rna_fc <- rna_fc |> arrange(desc(time_8_vs_0))

genes_selected <- rna_fc$gene[1:10]

sub_rna <- rna |>
    filter(gene %in% genes_selected)

mean_exp_by_time <- sub_rna |>
  group_by(gene,time) |>
    summarize(mean_exp = mean(expression_log))

OUTPUT

`summarise()` has regrouped the output.
ℹ Summaries were computed grouped by gene and time.
ℹ Output is grouped by gene.
ℹ Use `summarise(.groups = "drop_last")` to silence this message.
ℹ Use `summarise(.by = c(gene, time))` for per-operation grouping
  (`?dplyr::dplyr_by`) instead.

R

mean_exp_by_time

OUTPUT

# A tibble: 30 × 3
# Groups:   gene [10]
   gene   time mean_exp
   <chr> <int>    <dbl>
 1 Acr       0     5.07
 2 Acr       4     5.54
 3 Acr       8     7.31
 4 Aipl1     0     3.70
 5 Aipl1     4     3.89
 6 Aipl1     8     6.56
 7 Bst1      0     3.20
 8 Bst1      4     3.77
 9 Bst1      8     5.22
10 Chil3     0     4.00
# ℹ 20 more rows

Nous pouvons créer le graphique en courbes avec la durée de l’infection sur l’axe des abscisses et l’expression moyenne sur l’axe des ordonnées :

R

ggplot(data = mean_exp_by_time, mapping = aes(x = time, y = mean_exp)) +
  geom_line()
Line plot, as produced by geom_line(), but the lines are clearly not show what we expect.

Malheureusement, cela ne fonctionne pas car nous avons tracé les données de tous les gènes ensemble. Nous devons indiquer à ggplot de tracer une ligne pour chaque gène en modifiant la fonction esthétique pour y inclure group = gene :

R

ggplot(data = mean_exp_by_time,
       mapping = aes(x = time, y = mean_exp, group = gene)) +
  geom_line()
Line plot, as produced by geom_line(), with 10 lines showing increasing expression values over time.

Nous pourrons distinguer les gènes dans le graphique si nous ajoutons des couleurs (l’utilisation de color regroupe également automatiquement les données) :

R

ggplot(data = mean_exp_by_time,
       mapping = aes(x = time, y = mean_exp, color = gene)) +
  geom_line()
Line plot, as produced by geom_line(), with 10 colour-coded lines showing increasing expression values over time.

Facettage


ggplot2 dispose d’une technique appelée facettage qui permet de diviser un graphique en plusieurs sous-graphiques selon un facteur du jeu de données. Ces différents sous-graphiques héritent des mêmes propriétés (limites des axes, graduations, etc.) afin de faciliter leur comparaison directe. Nous l’utiliserons pour créer un graphique en courbes au fil du temps pour chaque gène :

R

ggplot(data = mean_exp_by_time,
       mapping = aes(x = time, y = mean_exp)) + geom_line() +
  facet_wrap(~ gene)
Line plot, as produced by geom_line(), with 10 sub-plots/facets, each showing one line with increasing expression values over time. All y-scales are identical.

Ici, les axes x et y ont tous deux la même échelle pour tous les sous-graphiques. Vous pouvez modifier ce comportement par défaut en modifiant scales afin de permettre une échelle libre pour l’axe y :

R

ggplot(data = mean_exp_by_time,
       mapping = aes(x = time, y = mean_exp)) +
  geom_line() +
  facet_wrap(~ gene, scales = "free_y")
Line plot, as produced by geom_line(), with 10 sub-plots/facets, each showing one line with increasing expression values over time. y-scales are now adapted to the expression range for each facet/gene.

Nous souhaitons maintenant séparer la ligne dans chaque graphique selon le sexe des souris. Pour ce faire, nous devons calculer l’expression moyenne dans le tableau de données, regroupé par gene, time et sex :

R

mean_exp_by_time_sex <- sub_rna |>
  group_by(gene, time, sex) |>
    summarize(mean_exp = mean(expression_log))

OUTPUT

`summarise()` has regrouped the output.
ℹ Summaries were computed grouped by gene, time, and sex.
ℹ Output is grouped by gene and time.
ℹ Use `summarise(.groups = "drop_last")` to silence this message.
ℹ Use `summarise(.by = c(gene, time, sex))` for per-operation grouping
  (`?dplyr::dplyr_by`) instead.

R

mean_exp_by_time_sex

OUTPUT

# A tibble: 60 × 4
# Groups:   gene, time [30]
   gene   time sex    mean_exp
   <chr> <int> <chr>     <dbl>
 1 Acr       0 Female     5.13
 2 Acr       0 Male       5.00
 3 Acr       4 Female     5.93
 4 Acr       4 Male       5.15
 5 Acr       8 Female     7.27
 6 Acr       8 Male       7.36
 7 Aipl1     0 Female     3.67
 8 Aipl1     0 Male       3.73
 9 Aipl1     4 Female     4.07
10 Aipl1     4 Male       3.72
# ℹ 50 more rows

Nous pouvons désormais créer le graphique facetté en effectuant un nouveau découpage selon le sexe à l’aide de color (au sein d’un même graphique) :

R

ggplot(data = mean_exp_by_time_sex,
       mapping = aes(x = time, y = mean_exp, color = sex)) +
  geom_line() +
  facet_wrap(~ gene, scales = "free_y")
Line plot, as produced by geom_line(), with 10 sub-plots/facets, each showing two coloured lines (red for Female and blue for Make) with increasing expression values over time.

En général, les graphiques à fond blanc sont plus lisibles une fois imprimés. Nous pouvons régler le fond sur blanc à l’aide de la fonction theme_bw(). De plus, nous pouvons supprimer la grille :

R

ggplot(data = mean_exp_by_time_sex,
       mapping = aes(x = time, y = mean_exp, color = sex)) +
  geom_line() +
  facet_wrap(~ gene, scales = "free_y") +
  theme_bw() +
  theme(panel.grid = element_blank())
Line plot, as produced by geom_line(), with 10 sub-plots/facets, each showing two coloured lines (red for Female and blue for Make) with increasing expression values over time. The figure background is now white.
Challenge

Défi

Utilisez ce que vous venez d’apprendre pour créer un graphique illustrant l’évolution de l’expression moyenne de chaque chromosome au cours de l’infection.

R

mean_exp_by_chromosome <- rna |>
  group_by(chromosome_name, time) |>
  summarize(mean_exp = mean(expression_log))

OUTPUT

`summarise()` has regrouped the output.
ℹ Summaries were computed grouped by chromosome_name and time.
ℹ Output is grouped by chromosome_name.
ℹ Use `summarise(.groups = "drop_last")` to silence this message.
ℹ Use `summarise(.by = c(chromosome_name, time))` for per-operation grouping
  (`?dplyr::dplyr_by`) instead.

R

ggplot(data = mean_exp_by_chromosome, mapping = aes(x = time,
                                y = mean_exp)) +
  geom_line() +
  facet_wrap(~ chromosome_name, scales = "free_y")
Line plot, as produced by geom_line(), with 21 sub-plots/facets, each showing one line with expression values over time for each chromosome.

La fonction facet_wrap répartit les facettes sur plusieurs lignes et colonnes afin qu’elles tiennent clairement sur une seule page. La fonction facet_grid permet, quant à elle, de spécifier explicitement la disposition des facettes à l’aide d’une formule (rows ~ columns ; un . peut servir de marqueur pour indiquer une seule ligne ou une seule colonne).

Modifions le graphique précédent pour comparer l’évolution de la moyenne de l’expression génique chez les mâles et les femelles au fil du temps :

R

# One column, facet by rows
ggplot(data = mean_exp_by_time_sex,
       mapping = aes(x = time, y = mean_exp, color = gene)) +
  geom_line() +
  facet_grid(sex ~ .)
Two line plots above each other, each showing 10 lines coloured by gene. The top facet shows the expression values for Female sample, the bottom one for Male samples.

R

# One row, facet by column
ggplot(data = mean_exp_by_time_sex,
       mapping = aes(x = time, y = mean_exp, color = gene)) +
  geom_line() +
  facet_grid(. ~ sex)
Two line plots next to each other, each showing 10 lines coloured by gene. The left facet shows the expression values for Female sample, the right one for Male samples.

Thèmes de ggplot2


En plus de theme_bw(), qui change l’arrière-plan du graphique en blanc, ggplot2 propose plusieurs autres thèmes qui peuvent s’avérer utiles pour modifier rapidement l’aspect de votre visualisation. La liste complète des thèmes est disponible à https://ggplot2.tidyverse.org/reference/ggtheme.html. theme_minimal() et theme_light() sont populaires, et theme_void() peut être utile comme point de départ pour créer un nouveau thème personnalisé.

Le package ggthemes propose une grande variété d’options (dont un thème Excel 2003). Le site web des extensions ggplot2 propose une liste de packages qui étendent les fonctionnalités de ggplot2, notamment des thèmes supplémentaires.

Personnalisation


Revenons au graphique facetté de l’expression moyenne selon le temps et le gène, coloré par sexe.

Jetez un coup d’œil à la fiche pratique ggplot2, et réfléchissez à des moyens d’améliorer le graphique.

Désormais, nous pouvons remplacer les noms des axes par des appellations plus informatives que « time » et « mean_exp », et ajouter un titre à la figure :

R

ggplot(data = mean_exp_by_time_sex,
       mapping = aes(x = time, y = mean_exp, color = sex)) +
  geom_line() +
  facet_wrap(~ gene, scales = "free_y") +
  theme_bw() +
  theme(panel.grid = element_blank()) +
  labs(title = "Mean gene expression by duration of the infection",
       x = "Duration of the infection (in days)",
       y = "Mean gene expression")
Line plot with white background and custom title and axis legends.

Les axes possèdent des noms plus explicites, mais leur lisibilité peut être améliorée en augmentant la taille de la police :

R

ggplot(data = mean_exp_by_time_sex,
       mapping = aes(x = time, y = mean_exp, color = sex)) +
  geom_line() +
  facet_wrap(~ gene, scales = "free_y") +
  theme_bw() +
  theme(panel.grid = element_blank()) +
  labs(title = "Mean gene expression by duration of the infection",
       x = "Duration of the infection (in days)",
       y = "Mean gene expression")  +
  theme(text = element_text(size = 16))
Line plot with white background and larger custom title and axis legends.

Notez qu’il est également possible de modifier les polices de vos graphiques. Si vous utilisez Windows, vous devrez peut-être installer le package extrafont.

Nous pouvons encore personnaliser la couleur du texte des axes X et Y, la couleur de la grille, etc. Nous pouvons également, par exemple, déplacer la légende en haut en définissant legend.position à "top".

R

ggplot(data = mean_exp_by_time_sex,
       mapping = aes(x = time, y = mean_exp, color = sex)) +
  geom_line() +
  facet_wrap(~ gene, scales = "free_y") +
  theme_bw() +
  theme(panel.grid = element_blank()) +
  labs(title = "Mean gene expression by duration of the infection",
       x = "Duration of the infection (in days)",
       y = "Mean gene expression")  +
  theme(text = element_text(size = 16),
        axis.text.x = element_text(colour = "royalblue4", size = 12),
        axis.text.y = element_text(colour = "royalblue4", size = 12),
        panel.grid = element_line(colour="lightsteelblue1"),
        legend.position = "top")
Line plot with white background and larger custom title and axis legends and blue grid.

Si vous préférez votre personnalisation au thème par défaut, vous pouvez l’enregistrer sous la forme d’un objet afin de l’appliquer facilement à d’autres graphiques. Voici un exemple avec l’histogramme que nous avons créé précédemment.

R

blue_theme <- theme(axis.text.x = element_text(colour = "royalblue4",
                                               size = 12),
                    axis.text.y = element_text(colour = "royalblue4",
                                               size = 12),
                    text = element_text(size = 16),
                    panel.grid = element_line(colour="lightsteelblue1"))

ggplot(rna, aes(x = expression_log)) +
  geom_histogram(bins = 20) +
    blue_theme
Custrom 'blue_theme() showing a blue grid and blue axis legends.
Challenge

Défi

Avec toutes ces informations en main, prenez encore cinq minutes pour soit améliorer l’un des graphiques générés dans cet exercice, soit créer votre propre graphique esthétique. Consultez la fiche de référence ggplot2 de RStudio pour vous inspirer. Voici quelques idées :

  • Voyez si vous pouvez modifier l’épaisseur des lignes.
  • Pouvez-vous trouver un moyen de modifier le nom de la légende ? Et pour ses étiquettes ? (indice : cherchez une fonction ggplot commençant par scale_)
  • Essayez d’utiliser une autre palette de couleurs ou de spécifier manuellement les couleurs des lignes (voir https://www.cookbook-r.com/Graphs/Colors_(ggplot2)/).

Par exemple, en se basant sur ce graphique :

R

ggplot(data = mean_exp_by_time_sex,
       mapping = aes(x = time, y = mean_exp, color = sex)) +
  geom_line() +
  facet_wrap(~ gene, scales = "free_y") +
  theme_bw() +
  theme(panel.grid = element_blank())
Plain facetted line plot, as produced by theme_bw() and a blank grid above.

Nous pouvons le personnaliser de la manière suivante :

R

# change the thickness of the lines
ggplot(data = mean_exp_by_time_sex,
       mapping = aes(x = time, y = mean_exp, color = sex)) +
  geom_line(size=1.5) +
  facet_wrap(~ gene, scales = "free_y") +
  theme_bw() +
  theme(panel.grid = element_blank())

WARNING

Warning: Using `size` aesthetic for lines was deprecated in ggplot2 3.4.0.
ℹ Please use `linewidth` instead.
This warning is displayed once per session.
Call `lifecycle::last_lifecycle_warnings()` to see where this warning was
generated.
Plain facetted line plot, as produced by theme_bw() and a blank grid with wide lines.

R

# change the name of the legend and the labels
ggplot(data = mean_exp_by_time_sex,
       mapping = aes(x = time, y = mean_exp, color = sex)) +
  geom_line() +
  facet_wrap(~ gene, scales = "free_y") +
  theme_bw() +
  theme(panel.grid = element_blank()) +
  scale_color_discrete(name = "Gender", labels = c("F", "M"))
Plain facetted line plot, as produced by theme_bw() and a blank grid with renamed colour labels.

R

# using a different color palette
ggplot(data = mean_exp_by_time_sex,
       mapping = aes(x = time, y = mean_exp, color = sex)) +
  geom_line() +
  facet_wrap(~ gene, scales = "free_y") +
  theme_bw() +
  theme(panel.grid = element_blank()) +
  scale_color_brewer(name = "Gender", labels = c("F", "M"), palette = "Dark2")
Plain facetted line plot, as produced by theme_bw() and a blank grid with a different color palette and renamed colour labels.

R

# manually specifying the colors
ggplot(data = mean_exp_by_time_sex,
       mapping = aes(x = time, y = mean_exp, color = sex)) +
  geom_line() +
  facet_wrap(~ gene, scales = "free_y") +
  theme_bw() +
  theme(panel.grid = element_blank()) +
  scale_color_manual(name = "Gender",  labels = c("F", "M"),
                     values = c("royalblue", "deeppink"))
Plain facetted line plot, as produced by theme_bw() and a blank grid with a manually-set colors and renamed colour labels..

Composer des graphiques


Le facettage est un excellent outil pour diviser un graphique en plusieurs sous-graphiques, mais il arrive que vous souhaitiez créer une seule figure contenant plusieurs graphiques indépendants, c’est-à-dire fondés sur des variables différentes ou même sur des tableaux de données distincts.

Commençons par créer les deux graphiques que nous souhaitons disposer côte à côte :

Le premier graphique compte le nombre de gènes uniques par chromosome. Nous devons d’abord réordonner les niveaux de chromosome_name et filtrer les gènes uniques par chromosome. Nous modifions également l’échelle de l’axe des ordonnées pour passer à une échelle logarithmique en base 10, afin d’améliorer la lisibilité.

R

rna$chromosome_name <- factor(rna$chromosome_name,
                               levels = c(1:19,"X","Y"))

count_gene_chromosome <- rna |>
  select(chromosome_name, gene) |>
  distinct() |> ggplot() +
  geom_bar(aes(x = chromosome_name), fill = "seagreen",
           position = "dodge", stat = "count") +
  labs(y = "log10(n genes)", x = "chromosome") +
  scale_y_log10()

count_gene_chromosome
A simple histogram with greed bars showing the log10 number of genes per chromosome.

Ci-dessous, nous supprimons également entièrement la légende en définissant legend.position à "none".

R

exp_boxplot_sex <- ggplot(rna, aes(y=expression_log, x = as.factor(time),
                 color=sex)) +
   geom_boxplot(alpha = 0) +
  labs(y = "Mean gene exp",
       x = "time") + theme(legend.position = "none")

exp_boxplot_sex
Transparently-filled red and blue boxplots for Female and Male expression values for different time points.

Le package patchwork propose une approche élégante pour combiner des figures en utilisant + pour les disposer (généralement côte à côte). Plus précisément, | les dispose explicitement côte à côte et / les empile les uns sur les autres.

R

install.packages("patchwork")

R

library("patchwork")
count_gene_chromosome + exp_boxplot_sex
A composed figure show the histogram (left) and boxplots (right) next to each other.

R

## or count_gene_chromosome | exp_boxplot_sex

R

count_gene_chromosome / exp_boxplot_sex
A composed figure show the histogram (top) and boxplots (bottom) on top or each other.

Nous pouvons affiner davantage le contrôle de la mise en page de la composition finale à l’aide de plot_layout pour créer des mises en page plus complexes :

R

count_gene_chromosome + exp_boxplot_sex + plot_layout(ncol = 1)
A composed figure show the histogram (top) and boxplots (bottom) on top or each other.

R

count_gene_chromosome +
 (count_gene_chromosome + exp_boxplot_sex) +
 exp_boxplot_sex +
 plot_layout(ncol = 1)
A figure composed of 4 plots with on top the histogram, in the middle the histogram and the boxpot, side-by-side, and at the bottom, the boxplot.

Le dernier graphique peut également être créé à l’aide des composants | et / :

R

count_gene_chromosome /
 (count_gene_chromosome | exp_boxplot_sex) /
 exp_boxplot_sex
As above, a figure composed of 4 plots with on top the histogram, in the middle the histogram and the boxpot, side-by-side, and at the bottom, the boxplot.

Pour en savoir plus sur patchwork, consultez sa page web ou cette vidéo.

Une autre option est le package gridExtra, qui permet de combiner des ggplots distincts en une seule figure à l’aide de grid.arrange() :

R

install.packages("gridExtra")

R

library("gridExtra")
grid.arrange(count_gene_chromosome, exp_boxplot_sex, ncol = 2)
A composed figure with the histogram (left) and boxplot (right) side-by-side.

En plus des arguments ncol et nrow, utilisés pour réaliser des dispositions simples, il existe des outils permettant de construire des mises en page plus complexes.

Exportation de graphiques


Une fois votre graphique créé, vous pouvez l’enregistrer dans un fichier au format de votre choix. L’onglet Exportation du volet Plot dans RStudio enregistre vos graphiques à faible résolution, ce qui ne sera pas accepté par de nombreuses revues et ne sera pas adapté aux posters.

Utilisez plutôt la fonction ggsave(), qui vous permet de modifier facilement la dimension et la résolution de votre graphique en ajustant les arguments correspondants (width, height et dpi).

Assurez-vous d’avoir le dossier fig_output/ dans votre répertoire de travail.

R

my_plot <- ggplot(data = mean_exp_by_time_sex,
       mapping = aes(x = time, y = mean_exp, color = sex)) +
  geom_line() +
  facet_wrap(~ gene, scales = "free_y") +
  labs(title = "Mean gene expression by duration of the infection",
         x = "Duration of the infection (in days)",
         y = "Mean gene expression") +
  guides(color=guide_legend(title="Gender")) +
  theme_bw() +
  theme(axis.text.x = element_text(colour = "royalblue4", size = 12),
        axis.text.y = element_text(colour = "royalblue4", size = 12),
        text = element_text(size = 16),
        panel.grid = element_line(colour="lightsteelblue1"),
        legend.position = "top")
ggsave("fig_output/mean_exp_by_time_sex.png", my_plot, width = 15,
       height = 10)

# This also works for grid.arrange() plots
combo_plot <- grid.arrange(count_gene_chromosome, exp_boxplot_sex,
                           ncol = 2, widths = c(4, 6))
ggsave("fig_output/combo_plot_chromosome_sex.png", combo_plot,
       width = 10, dpi = 300)

Remarque : Les paramètres width et height déterminent également la taille de la police dans le graphique enregistré.

Autres packages de visualisation


ggplot2 est un package très puissant qui s’intègre parfaitement à notre pipeline de données ordonnées et d’outils ordonnés. Il existe d’autres packages de visualisation dans R qu’il ne faut pas négliger.

Graphismes de base

Le système graphique par défaut fourni avec R, souvent appelé graphismes R de base, est simple et rapide. Il repose sur le modèle du peintre ou de la toile, où différentes sorties sont superposées directement les unes aux autres (voir figure ci-dessous ). C’est une différence fondamentale avec ggplot2 (et avec lattice, décrit ci-dessous), qui renvoie des objets dédiés, rendus à l’écran ou dans un fichier, et qui peuvent même être mis à jour.

R

par(mfrow = c(1, 3))
plot(1:20, main = "First layer, produced with plot(1:20)")

plot(1:20, main = "A horizontal red line, added with abline(h = 10)")
abline(h = 10, col = "red")

plot(1:20, main = "A rectangle, added with rect(5, 5, 15, 15)")
abline(h = 10, col = "red")
rect(5, 5, 15, 15, lwd = 3)
The 'base' figures, side-by-side, showing (from left to right) 20 empty dots along the diagonal, same with a vertical red line, and same as the second one with a rectangle overlaid in the middle of the plot.
Successive layers added on top of each other.

Une autre différence majeure est que la fonction de tracé des graphiques de base tente de faire la bonne chose en fonction du type d’entrée, c’est-à-dire qu’elle adapte son comportement en fonction de la classe de son entrée. Cela diffère encore grandement de ce que l’on trouve dans ggplot2, qui n’accepte que les tableaux de données en entrée et nécessite que les graphiques soient construits petit à petit.

R

par(mfrow = c(2, 2))
boxplot(rnorm(100),
        main = "Boxplot of rnorm(100)")
boxplot(matrix(rnorm(100), ncol = 10),
        main = "Boxplot of matrix(rnorm(100), ncol = 10)")
hist(rnorm(100))
hist(matrix(rnorm(100), ncol = 10))
A two-by-two composition of 2 boxplots at the top, and 2 histograms at the bottom.
Plotting boxplots (top) and histograms (bottom) vectors (left) or a matrices (right).

L’approche par défaut des graphiques de base peut s’avérer très efficace pour des figures simples et standard, qui peuvent être produites très rapidement avec une seule ligne de code et une seule fonction telle que plot, ou hist, ou boxplot, … Les paramètres par défaut ne sont cependant pas toujours les plus attrayants, et le réglage des figures, surtout lorsqu’elles deviennent plus complexes (par exemple pour produire des facettes), peut s’avérer long et fastidieux.

Le package lattice

Le package lattice ressemble à ggplot2 en ce qu’il utilise des tableaux de données en entrée, restitue des objets graphiques et prend en charge le facettage. lattice, en revanche, ne repose pas sur la grammaire graphique et possède une interface plus complexe.

Une bonne référence pour le package lattice est Deepayan (2008).

Key Points
  • Visualisation dans R
Deepayan, Sarkar. 2008. Lattice: Multivariate Data Visualization with r. Springer. http://lmdvr.r-forge.r-project.org.
Wickham, Hadley. 2016. ggplot2: Elegant Graphics for Data Analysis. Springer-Verlag New York. http://ggplot2.org.
Wilkinson, Leland. 2005. The Grammar of Graphics (Statistics and Computing). Springer-Verlag.