Lors de cette formation nous allons apprendre à visualiser des jeux de données tabulaires avec ggplot2
.
Téléchargez le matériel de la formation en cliquant sur Download.zip
ou Download.tar.gz
, dezippez le répertoire et ensuite placer vous dedans. Ouvrez avec Rstudio
le fichier Script_ggplot_lesson.R
qui est dans le répertoire materiel
. Nous allons coder ensemble dans ce script, qui est quasiment vide pour le moment.
Lors de cette formation nous allons utiliser plusieurs packages qui contiennent les fonctions dont nous avons besoin:
- tidyverse
qui contient plusiers packages dont ggplot2
- visdat
qui permet une représentation rapide des données
- plotly
pour faire des graphiques interactifs
Vous avez normalement déjà installé ces packages. Pour vérifier qu’ils sont bien installé, et pour les importer dans votre session, utilisez la fonction library()
:
library(tidyverse)
library(visdat)
library(plotly)
Vous devez aussi vous assurer que le répertoire de travail de R est bien le dossier qui contient le matériel de la formation. Le chemin vers ce dossier va être différent en fonction de votre système opérateur.
Pour spécifier le répertoire de travail de R utilisez la fonction setwd()
:
setwd("~/Desktop/ggplot_course/materiel")
Pour cette formation, nous allons utiliser une version légèrement modifée du jeu de donnée publié par Burghard et al 2015.
La version simplifiée des données est dans le dossier data
(burghardt_et_al_2015_expt1.txt
). Il s’agit de données pour des phénotypes associés au temps nécessaire à des plantes de différents génotypes pour fleurir dans différentes conditions.
Comme notre répertoire de travail est le dossier materiel
, nous devons importer les données ainsi:
# Import des données et chargement dans l'objet expt1
expt1 <- read_tsv("../data/burghardt_et_al_2015_expt1.txt")
## Parsed with column specification:
## cols(
## genotype = col_character(),
## background = col_character(),
## temperature = col_double(),
## fluctuation = col_character(),
## day.length = col_double(),
## vernalization = col_character(),
## survival.bolt = col_character(),
## bolt = col_character(),
## days.to.bolt = col_double(),
## days.to.flower = col_double(),
## rosette.leaf.num = col_double(),
## cauline.leaf.num = col_double(),
## blade.length.mm = col_double(),
## total.leaf.length.mm = col_double(),
## blade.ratio = col_double()
## )
La fonction read_tsv()
imprime un message indiquant quel type de données sont contenues dans les différentes colonnes du fichier.
Dans notre cas, certaines colonnes contiennent des données de type “character” (du texte) et d’autres des données numériques (“double” en présence de décimale, “integer” en absence de décimale).
Pour regarder rapidement les données, tapez le nom de l’objet où sont les données (expt1
).
expt1
## # A tibble: 957 x 15
## genotype background temperature fluctuation day.length vernalization
## <chr> <chr> <dbl> <chr> <dbl> <chr>
## 1 Col Ama Col 12 Con 16 NV
## 2 Col Ama Col 12 Con 16 NV
## 3 Col Ama Col 12 Con 16 NV
## 4 Col Ama Col 12 Con 16 NV
## 5 Col Ama Col 12 Con 16 NV
## 6 Col Ama Col 12 Con 16 NV
## 7 Col Ama Col 12 Con 16 NV
## 8 Col Ama Col 12 Con 16 NV
## 9 Col Ama Col 12 Con 8 NV
## 10 Col Ama Col 12 Con 8 NV
## # … with 947 more rows, and 9 more variables: survival.bolt <chr>, bolt <chr>,
## # days.to.bolt <dbl>, days.to.flower <dbl>, rosette.leaf.num <dbl>,
## # cauline.leaf.num <dbl>, blade.length.mm <dbl>, total.leaf.length.mm <dbl>,
## # blade.ratio <dbl>
Cela va montrer les 10 premières lignes du tableau ainsi que les colonnes qui rentrent dans l’écran.
Challenge: Combien y a t’il de lignes et colonnes dans les données?
Une autre option est d’utiliser la fonction View()
pour accéder à une table interactive où il est possible de trier et filtrer les données sans modifier l’objet:
View(expt1)
glimpse()
permet d’avoir une idée de la structure des données:glimpse(expt1)
## Observations: 957
## Variables: 15
## $ genotype <chr> "Col Ama", "Col Ama", "Col Ama", "Col Ama", "Col…
## $ background <chr> "Col", "Col", "Col", "Col", "Col", "Col", "Col",…
## $ temperature <dbl> 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, …
## $ fluctuation <chr> "Con", "Con", "Con", "Con", "Con", "Con", "Con",…
## $ day.length <dbl> 16, 16, 16, 16, 16, 16, 16, 16, 8, 8, 8, 8, 8, 8…
## $ vernalization <chr> "NV", "NV", "NV", "NV", "NV", "NV", "NV", "NV", …
## $ survival.bolt <chr> "Y", "Y", "Y", "Y", "Y", "Y", "Y", "Y", "Y", "Y"…
## $ bolt <chr> "Y", "Y", "Y", "Y", "Y", "Y", "Y", "Y", "Y", "Y"…
## $ days.to.bolt <dbl> 28, 29, 31, 31, 32, 33, 34, 35, 69, 72, 76, 79, …
## $ days.to.flower <dbl> 43, 44, 43, 42, 44, 47, 47, 49, 90, 91, 97, 99, …
## $ rosette.leaf.num <dbl> 18, 15, 13, 17, 19, 14, 15, 18, 53, 49, 51, 55, …
## $ cauline.leaf.num <dbl> 6, 5, 4, 5, 4, 4, 3, 5, 6, 5, 6, 9, 6, 9, 8, 10,…
## $ blade.length.mm <dbl> 12.9, 10.5, 13.2, 14.6, 13.3, 14.7, 13.0, 17.8, …
## $ total.leaf.length.mm <dbl> 21.1, 19.1, 23.4, 27.2, 20.4, 25.3, 23.2, 31.3, …
## $ blade.ratio <dbl> 0.6113744, 0.5497382, 0.5641026, 0.5367647, 0.65…
Challenge Quel est le type des variables dans les données ?
dim()
indique les dimensions du jeu de données (nombre de lignes et colonnes).dim(expt1)
## [1] 957 15
summary()
permet d’obtenir des stats de base pour chaque colonne.summary(expt1)
## genotype background temperature fluctuation
## Length:957 Length:957 Min. :12.00 Length:957
## Class :character Class :character 1st Qu.:12.00 Class :character
## Mode :character Mode :character Median :12.00 Mode :character
## Mean :16.98
## 3rd Qu.:22.00
## Max. :22.00
##
## day.length vernalization survival.bolt bolt
## Min. : 8.00 Length:957 Length:957 Length:957
## 1st Qu.: 8.00 Class :character Class :character Class :character
## Median :16.00 Mode :character Mode :character Mode :character
## Mean :12.01
## 3rd Qu.:16.00
## Max. :16.00
##
## days.to.bolt days.to.flower rosette.leaf.num cauline.leaf.num
## Min. : 15.00 Min. : 21.00 Min. : 5.00 Min. : 1.000
## 1st Qu.: 38.00 1st Qu.: 46.00 1st Qu.: 24.00 1st Qu.: 5.000
## Median : 57.00 Median : 66.00 Median : 40.00 Median : 8.000
## Mean : 66.04 Mean : 71.59 Mean : 39.71 Mean : 7.208
## 3rd Qu.: 85.00 3rd Qu.: 92.00 3rd Qu.: 53.00 3rd Qu.: 9.000
## Max. :162.00 Max. :182.00 Max. :112.00 Max. :17.000
## NA's :83 NA's :95 NA's :96
## blade.length.mm total.leaf.length.mm blade.ratio
## Min. : 7.10 Min. : 9.00 Min. :0.0000
## 1st Qu.:18.00 1st Qu.:29.10 1st Qu.:0.5564
## Median :20.95 Median :34.60 Median :0.5948
## Mean :21.11 Mean :34.69 Mean :0.5874
## 3rd Qu.:24.30 3rd Qu.:40.27 3rd Qu.:0.6342
## Max. :59.00 Max. :66.30 Max. :6.5556
## NA's :327 NA's :303 NA's :304
Nous avons déjà utilisé de noubreuses fonctions:
install.packages()
library()
read_tsv()
View()
glimpse()
summary()
dim()
Il est bien sûr difficile de ce souvenir du nom de toutes ces fonctions, ce qu’elles font et comment les utiliser. Heuresement, pour nous aider, une aide est disponible dans R en tapant le nom d’une fonction précédé de ?
?summary
Bien sur, une recherche sur internet est aussi une solution très efficace pour trouver de l’aide!
Challenge que fait la fonction
head()
?
Challenge Comment regarder les dernières lignes de le notre jeu de données? (indice:
?tail
)
Pour avoir une vue d’ensemble du jeu de données et détecter des problèmes, nous allons ustiliser la fonction vis_dat()
.
vis_dat(expt1)
Challenge Quel est le type de données le plus courrant dans le jeu de données ? Y a t’il des problème?
Le gris dans la figure générée par vis_dat()
sont des données manquantes. Plusieurs stratégies peuvent être utilisées:
Pour la formation, nous allons enlever les lignes contenant des données manquantes.
expt1 <- drop_na(expt1)
Challenge Combien de lignes nous reste-il?
Maintenant que nous avons vérifié la qualité de notre jeu de donnée, nous pouvons générer des graphiques afin d’en apprendre plus sur les données générées par l’expérience.
Nous allons utiliser le package R ggplot2
, qui utilise le principe de “grammar or graphics”. Il s’agit des briques du graphique. Cette méthode permettant de combiner et superposer différentes couches de briques:
Les trois premières briques sont essentielles: data, aesthetics et objet geometrique.
aes()
.geom_object
, et peut en avoir plusieurs. Par exemple:
geom_point
pour des scatter plots, dot plots)geom_line
pour des tendance, time series)Pour plus d’information sur la création de graphique avec ggplot2
, voir cette antisèche très utile.
Commençons avec un boxplot: Dessinons le days.to.flower
pour les différents génotypes.
La fonction ggplot()
permet de commencer le graphique. Il faut aussi indiquer les données à utiliser:
ggplot(expt1)
Mais cela ne produit qu’un canevas gris!
Il nous manque des briques. En l’occurence nous devons indiquer quelle aesthetics (c’est la terminologie de ggplot2
) nous voulons sur ce canevas gris. Nous devons indiquer quelles sont les variables x et y du boxplot.
ggplot(expt1, aes(x = genotype, y = days.to.flower))
ggplot
indique maintenant les variables genotype
et days.to.flower
de nos données sur les axes x and y du graphique.
Mais toujours pas de graphique. C’est parce que nous pas indiqué à ggplot
quelle geometrie nous voulons dessiner sur le canevas. Pour faire un boxplot, nous ajoutons au canevas (littéralement avec un +
) geom_boxplot()
:
ggplot(expt1, aes(genotype, days.to.flower)) +
geom_boxplot()
Exercice: Pouvez vous dessiner un violin plot? (indice:
?geom_violin
)
Nous allons maintenant ajouter d’autres geom_objects
au même graphique. Par exemple, des points pour les valeurs des individus en plus du boxplot:
ggplot(expt1, aes(genotype, rosette.leaf.num)) +
geom_jitter() +
geom_boxplot()
Exercice: Modifiez le graphique pour que les points soient devant plutôt que derrière les boxplots.
Changeons la couleur des boxplots:
ggplot(expt1, aes(genotype, days.to.flower)) +
geom_boxplot(colour = "red")
Ou la couleur à l’interieur ( fill) des boxplots:
ggplot(expt1, aes(genotype, days.to.flower)) +
geom_boxplot(colour = "red", fill = "royalblue")
Ou même leur transparence:
ggplot(expt1, aes(genotype, days.to.flower)) +
geom_boxplot(colour = "red", fill = "royalblue", alpha = 0.5)
C’est sympa, mais cela ne nous apporte pas d’information en plus sur les données.
Par exemple, ajoutons une couleur qui change en fonction d’un des traitements auquel les plantes ont été exposées (par exemple fluctuation
). En langage ggplot2
, nous voulons lier la valeur de la variable fluctuation
à la couleur dans l’ aesthetic du graphique.
Nous devons donc inclure cette information dans aes()
:
ggplot(expt1, aes(genotype, days.to.flower, colour = fluctuation)) +
geom_boxplot()
Wow! ggplot a automatiquement séparé les données de chaque génotype en deux groupes en fonction de fluctuation
et leur a attribué une couleur.
Imaginons que nous voulons ajouter les points pour les valeurs des individus, sans couleur, derrière les boxplots colorés:
ggplot(expt1, aes(genotype, days.to.flower, colour = fluctuation)) +
geom_jitter() +
geom_boxplot(alpha = 0.5)
Ce n’est pas ce que nous voulons. L’aesthetique colour
a été liée à toutes les géométries du graphique. C’est parce qu’elle a été définie dans la fonction ggplot()
, qui affecte tous les geom_object
qui viennent après.
Mais nous pouvons aussi définir l’aesthetique dans chaque géometrie:
ggplot(expt1, aes(genotype, days.to.flower)) +
geom_jitter() +
geom_boxplot(aes(fill = fluctuation), alpha = 0.5)
Exercice: Nous voulons étudier la relation entre le nombre de feuille de rosette et la longueur la limbe des feuilles (en mm) pour les genotypes.
Pour cela, dessinez un scatter plot (
geom_point()
) entreblade.length.mm
etrosette.leaf.num
en colorant les points en fonction degenotype
.Que se passe t-il si les points sont colorés en fonction de
days.to.bolt
?
Souvent trop de variables, ou de groupes, sont dans nos données pour pouvoir uniquement utiliser les couleurs pour les discriminer.
C’est le cas par example du scatterplot produit dans l’exercice précédent, où les points sont colorés en fonction du génotype. Il est difficile de bien discerner les données pour chaque génotype car ils sont très rapprochés. L’idéal serait d’avoir un scatterplot par génotype.
Ceci est assez facile à faire avecggplot2
, il suffit d’ajouter une couche au graphique appelée “facet”:
facet_grid()
- qui permet d’organiser les panneaux du graphique en lignes et/ou colonnesfacet_wrap()
- qui permet d’organiser les panneaux du graphique à la suite les uns des autres qui reviennent à la ligne après un certain nombre de panneaux.Voyons comment facet_grid()
fonctionne:
ggplot(expt1, aes(blade.length.mm, rosette.leaf.num, colour = genotype)) +
geom_point() +
facet_grid(genotype ~ temperature)
Dans facet_grid()
, nous utilisons la notation (ligne ~ colonne)
pour definir les variables qui sont utilisées pour séparer les panneaux en ligne et colonnes.
Exercice: Les couleurs n’apportent plus d’information supplementaire. Pensez à une utilisation plus interessante des couleurs dans ce graphque.
Il est possible de ne préciser qu’une variable dans facet_grid()
:
# Faceter en ligne
ggplot(expt1, aes(blade.length.mm, rosette.leaf.num, colour = fluctuation)) +
geom_point() +
facet_grid(genotype ~ .)
# Faceter en colonne
ggplot(expt1, aes(blade.length.mm, rosette.leaf.num, colour = fluctuation)) +
geom_point() +
facet_grid(. ~ genotype)
Il est aussi possible d’utiliser facet_wrap()
si l’on n’utilise qu’une variable pour séparer les données :
ggplot(expt1, aes(blade.length.mm, rosette.leaf.num, colour = fluctuation)) +
geom_point() +
facet_wrap( ~ genotype)
Exercice: Modifiez le graphiqe précédent afin de séparer les données (facet) en fonction de
fluctuation
en ligne, etday.length
en colonne et de colorer les points en fonction du génotype.
En conclusion, il est possible de représenter de nombreuses informations en combinant efficacement facets, couleurs et autres aesthetiques!
Exercice: Reproduisez le graphique suivant (ou quelque chose d’approchant):
.
Indice: facet le graphique avec
day.length
ettemperature
et colorer l’intérieur des boxplot en fonction defluctuation
.
Pour aller plus loin, il est même possible de créer des graphiques intéractifs en utilsant le package plotly
.
Il faut d’abord mettre le graphique dans un objet, puis d’utiliser cet objet dans la fonction ggplotly()
.
# Mettre le graphique dans l'objet p1
p1 <- ggplot(expt1, aes(blade.length.mm, rosette.leaf.num, colour = fluctuation)) +
geom_point() +
facet_wrap(~genotype)
# Utiliser la fonction ggplotly pour faire un graphique intéractif
ggplotly(p1)
Tous les élépments d’un ggplot sont modifiables. Les themes permettent de modifier l’apparence du graphique. Ce n’est pas le sujet de cette formation, mais voici quelques exemples.
# Example de thèmes existants dans ggplot2
ggplot(expt1, aes(genotype, days.to.flower)) +
geom_boxplot() +
theme_bw() +
labs(title = "Black and white theme")
ggplot(expt1, aes(genotype, days.to.flower)) +
geom_boxplot() +
theme_classic() +
labs(title = "Classic theme")
ggplot(expt1, aes(genotype, days.to.flower)) +
geom_boxplot() +
theme_minimal() +
labs(title = "Minimal theme")
La fonction theme()
peut être utilisée pour modifier des éléments en particulier du graphique. Il y a tellement de possibilités que le mieux est de rechercher sur internet la modification que vous voulez faire.
Par exemple, en recherchant “vertical labels x axis ggplot2” nous obtenons cette solution:
ggplot(expt1, aes(genotype, days.to.flower)) +
geom_boxplot() +
theme(axis.text.x = element_text(angle = 90, hjust = 1))
Rechercher “altering plot colours ggplot2” donne ceci, qui apporte cette solution:
ggplot(expt1, aes(genotype, days.to.flower, fill = fluctuation)) +
geom_boxplot() +
scale_fill_brewer(palette="Dark2")
D’autres packages qui peuvent apporter un plus à ggplot2
: