owned this note
owned this note
Published
Linked with GitHub
# Visualisation de données dans R avec ggplot2 et autres packages
Au même titre que la préparation de données avec le tidyverse présentée dans cette [page Web](https://hackmd.io/zoXTvwg8SqiFZ-pw9-98AA?view), la visualisation de données avec R nécessite l’apprentissage d’un nouveau langage, mais permet la construction rapide de **graphiques complexes et personnalisables**.
![](https://i.imgur.com/9GzFShN.png)
Cette page Web centralise une série d'exemples de datavisualisations produites dans l'environnement R avec `ggplot2` et d'autres packages dédiés.
**ggplot2** est une librairie R de **visualisation de données**. La librairie est développée selon les principes développés par Leland Wilkinson dans son ouvrage The Grammar of Graphics2.
Les commandes pour la **préparation** des jeux de données et la **création** des dataviz sont fournies.
![](https://i.imgur.com/fnC4QfH.png)
cheatsheets ggplot2 en français : https://raw.githubusercontent.com/rstudio/cheatsheets/master/translations/french/ggplot2-french-cheatsheet.pdf
---
## Les données
Dans cet exemple nous nous basons sur le jeu de données des signalements de [l'application Dans Ma Rue de la ville de Paris](https://teleservices.paris.fr/dansmarue/).
Ce jeu de données mis à jour quotidiennement est [disponible sur le portail open data de la ville de Paris](https://opendata.paris.fr/explore/dataset/dans-ma-rue/table/?disjunctive.type&disjunctive.soustype&disjunctive.code_postal&disjunctive.ville&disjunctive.arrondissement&disjunctive.prefixe&disjunctive.conseilquartier)
Ce jeu de données est particuliérement intéressant à plusieurs titres :
* il contient plus de 900 000 lignes (anomalies)
* il est bien structuré et complet
* les anomalies sont caractérisées par de nombreux champs
* comme des champs temporels
* comme des champs qualitatifs
* comme des champs géographiques
* et même des coordonnées géographiques
---
## BAR CHART
Un **diagramme à barres** (*bar chart*) est un graphique qui présente des variables catégorielles avec des barres rectangulaires avec des hauteurs ou des longueurs proportionnelles aux valeurs qu'elles représentent.
```
geom_col
geom_bar
```
### Bar chart pour représenter la répartition des signalements par type
Etape1 : créer le dataframe adéquat
```
Type <- DMR %>% group_by(TYPE) %>% summarise( nb = n())
```
Etape 2 : Faire le graphique
```
ggplot(Type) + geom_col(aes(x = TYPE, y = nb), fill="blue", width = .9)
```
![](https://i.imgur.com/3yxQj8W.png)
On peux **passer le graphique à l'horizontal** en ajoutant la fonction `+ coord_flip()`
```
ggplot(Type) + geom_col(aes(x = TYPE, y = nb), fill="blue", width = .9) + coord_flip()
```
![](https://i.imgur.com/Wz3VbiY.png)
Pour finaliser le graphique on peux ajouter divers élements comme:
```
reorder() > pour ordonner par valeur les modalités dans le graphique
fill() > pour modifier la couleur des barres
ggtitle > pour ajouter un titre
xlab > pour peronnaliser le nom de l'axe x
ylab > pour peronnaliser le nom de l'axe y
labs > pour ajouter une source
theme_bw() > pour personnaliser le thème
```
Plus d'informations sur les thèmes ggplot2
https://ggplot2.tidyverse.org/reference/ggtheme.html
```
ggplot(Type, aes(reorder(TYPE, nb), nb, width = .9)) +
geom_col(fill="#0074D9") +
coord_flip() +
ggtitle("Nombre de signalements par type") +
xlab("Type") + ylab("Nb de signalements") +
labs(caption="Source : Ville de Paris") + theme_bw()
```
![](https://i.imgur.com/I8yxF01.png)
Pour finaliser on peut afficher les valeurs numériques en entier
```
install.packages("scales")
library(scales)
```
Ajouter dans le script ` scale_y_continuous(labels = comma)`
```
ggplot(Type, aes(reorder(TYPE, nb), nb, width = .9)) +
geom_col(fill="#0074D9") +
coord_flip() +
scale_y_continuous(labels = comma) +
ggtitle("Nombre de signalements par type") +
xlab("Type") + ylab("Nb de signalements") +
labs(caption="Source : Ville de Paris") + theme_bw()
```
![](https://i.imgur.com/TtqeXhR.png)
---
### Bar chart pour représenter la répartition des signalements par arrondissement
Etape1 : créer le dataframe adéquat
```
ARDT <- DMR %>% group_by(CODE_POSTAL) %>% summarise( nb = n()) %>% mutate(CODE_POSTAL = as.character(CODE_POSTAL))
```
Etape 2 : Faire le graphique
```
ggplot(ARDT) + geom_col(aes(x = CODE_POSTAL, y = nb), fill="#001f3f", width = .9)
+ theme_bw()
```
![](https://i.imgur.com/wbu8dLw.png)
---
### Bar chart pour représenter l'évolution du nombre de signalement par année
Etape1 : créer le dataframe adéquat
```
ANNEE <- DMR %>% group_by(ANNEE = ANNEE.DECLARATION) %>% summarise(nb= n()) %>% mutate(ANNEE= as.charact er(ANNEE))
```
Etape 2 : Faire le graphique
```
ggplot(ANNEE) + geom_col(aes(x=ANNEE, y=nb, fill = "orange")) + theme_bw()
```
![](https://i.imgur.com/vHdLM5o.png)
Pour forcer l'affichage de toutes les années en abcisse
```
+ scale_x_continuous(breaks=seq(2012, 2019, 1)) +
```
---
### Bar chart (empilé) pour représenter le nombre de signalement par arrondississement et la proportion de chaque type
Il est possible de faire des graphiques empilés (*stacked*) pour représenter des proportions dans des regroupements.
Etape1 : créer le dataframe adéquat
```
ARDTYPE <- DMR %>% group_by(CODE_POSTAL, TYPE) %>%
summarise( nb = n()) %>% mutate(CODE = as.character(CODE_POSTAL))
```
Etape 2 : Faire le graphique
```
ggplot(ARDTYPE) + geom_col(aes(x=CODE, y=nb, fill=TYPE)) + scale_fill_brewer(palette="Paired")
```
![](https://i.imgur.com/mbk1cQ6.png)
**Produire ce graphique
**
![](https://i.imgur.com/XOay9uq.png)
---
### Bar chart pour représenter l'évolution du nombre de signalement par année et par arrondissement
Il est aussi possible de **représenter au sein d'un même Bar chart des groupes** *dodge*
Etape1 : créer le dataframe adéquat
```
ARDTANNEE <- DMR %>% group_by(CODE_POSTAL, ANNEE = ANNEE.DECLARATION) %>% summarise(nb= n()) %>% mutate(CODE = as.character(CODE_POSTAL), ANNEE= as.character(ANNEE))
```
Etape 2 : Faire le graphique
```
ggplot(ARDTANNEE) + geom_col(aes(x = CODE, y = nb, fill = ANNEE), position = "dodge") + scale_fill_viridis_d(direction=-1) + theme_bw()
```
![](https://i.imgur.com/IsCzQE3.png)
### Graphiques empilés dans les règles de l'art...
```
ANNEETYPE <- DMR %>% group_by(ANNEE.DECLARATION, TYPE) %>% summarise( nb = n())
```
```
ggplot(ANNEETYPE, aes(x=ANNEE, y=nb, fill = TYPE)) +
geom_bar( stat = "identity", position = "stack") +
scale_fill_brewer(palette="Paired") +
theme_bw()
```
![](https://i.imgur.com/22hZJoU.png)
```
ggplot(ANNEETYPE, aes(x=ANNEE, y=nb, fill = TYPE)) +
geom_bar( stat = "identity", position = "fill") +
scale_y_continuous(labels = comma) +
scale_fill_brewer(palette="Paired") +
theme_bw()
```
![](https://i.imgur.com/6pfe0ze.png)
```
ggplot(ANNEETYPE, aes(x=ANNEE, y=nb, fill = TYPE)) +
geom_bar( stat = "identity", position = "dodge") +
scale_y_continuous(labels = comma) +
scale_fill_brewer(palette="Paired") +
theme_bw()
```
![](https://i.imgur.com/TSFTOG8.png)
---
## JOUER AVEC LES *SMALL MULTIPLE*
Un ***small multiple*** est une série de graphiques similaires utilisant la même échelle et les mêmes axes, ce qui permet de les comparer facilement.
On peut "décomposer" un graphique (en small multiples) avec les fonctions :
```
facet_wrap(~variable)
```
>Décompose le graphique en autant de modalité que contenues dans la variable mobilisée.
Le paramétrage de l'agencement se fait avec les arguments `nrow` (nombre de lignes) et/ou `ncol` (nombre de colonnes).
```
facet_grid(variable1~variable2)
```
>Décompose le graphique en un croisement des modalités contenues dans variable1 et variable2
---
### Représenter le nombre de signalements par mois pour chaque année
Etape1 : créer le dataframe adéquat
```
SignalementAnneeEtMois <- DMR %>% group_by(Annee = ANNEE.DECLARATION, Mois=mois) %>% summarise(nb=n())
```
Etape 2 : Faire le graphique
```
ggplot(signalementAnneeEtMois) + geom_col(aes(x=Mois, y=nb, fill = "orange")) + theme_bw() + facet_wrap(~Annee, nrow = 4)
```
![](https://i.imgur.com/m6iSXPq.png)
---
### Représenter le nombre de signalements par journée pour chaque arrondissement
Etape1 : créer le dataframe adéquat
```
SignalJourArdt <- DMR %>% group_by(Journee = journee, Ardt=CODE_POSTAL) %>% summarise(nb=n()) %>% mutate(Ardt= as.character(Ardt))
```
Etape 2 : Faire le graphique
```
ggplot(SignalJourArdt, aes(x=Journee, y=nb, fill = Ardt)) + geom_col() + theme_bw() + facet_wrap(~Ardt, ncol = 4)
```
![](https://i.imgur.com/qQ0OW57.png)
---
### Représenter le nombre de signalements par mois selon le type
Etape1 : créer le dataframe adéquat
```
Moisettype <- DMR %>% filter( ! TYPE %in% c('Activités commerciales et professionnelles', 'Du vert près de chez moi', 'Problème sur un chantier', 'Eau')) %>% group_by(Type=TYPE, Mois = mois) %>% summarise(nb = n())
```
Etape 2 : Faire le graphique
```
ggplot(Moisettype, aes(x=Mois, y=nb, fill = Type)) + geom_col() + theme_bw() + facet_wrap(~Type, ncol = 4)
```
![](https://i.imgur.com/9gfgNVT.png)
---
### Représenter le nombre de signalements par mois pour chaque année et chaque arrondissement
Etape1 : créer le dataframe adéquat
```
signalementAnneeEtMoisArdt <- DMR %>% group_by(Annee = ANNEE.DECLARATION, Mois=mois, Ardt=CODE_POSTAL) %>% summarise(nb=n()) %>% mutate(Ardt= as.character(Ardt))
```
Etape 2 : Faire le graphique
```
ggplot(signalementAnneeEtMoisArdt, aes(x=Mois, y=nb, fill = Ardt)) + geom_col() +
theme_bw() + facet_grid(Ardt~Annee)
```
![](https://i.imgur.com/hn3fy6N.png)
---
### Représenter "spatialement" les signalements par type pour une année
Etape1 : créer le dataframe adéquat
```
DMRGEO <- DMR %>% separate(col= geo_point_2d, into = c("Latitude", "Longitude"), sep= ",") %>%
filter(ANNEE.DECLARATION==2015) %>%
mutate(Latitude = as.numeric(Latitude), Longitude = as.numeric(Longitude))
```
Etape 2 : Faire le graphique
```
ggplot(DMRGEO) + geom_point(aes(x= Longitude, y= Latitude, color=TYPE)) + facet_wrap(~TYPE, ncol = 2)
```
![](https://i.imgur.com/oPsWSok.png)
---
## DOUGHNUT CHART
Un **Doughnut chart** est simplement un diagramme circulaire avec un trou au milieu ;) Très utile pour représenter les proportions des modalités d'une variable.
https://www.r-graph-gallery.com/128-ring-or-donut-plot.html
---
### Doughnut chart des types de signalement
**Etape1 : créer le dataframe adéquat**
```
type <- DMR %>% group_by(TYPE) %>% summarise(nb = n())
```
Il faut ici procéder ici à plusieurs sous-étapes supplémentaires :
* Calculer les pourcentages des types de signalement
```
type$fraction = type$nb /sum(type$nb)
```
* Calculer les pourcentages cumulatifs des types de signalement
```
type$ymax = cumsum(type$fraction)
```
* Calculer le minimum de chaque types de signalement
```
type$ymin = c(0, head(type$ymax, n=-1))
```
Une fois ces trois sous-étapes réalisées la detaframe ressemble à ça
![](https://i.imgur.com/MF7klC6.png)
**Etape 2 : Faire le graphique**
```
ggplot(type, aes(ymax=ymax, ymin=ymin, xmax=4, xmin=3, fill=TYPE)) +
geom_rect() + coord_polar(theta="y") + xlim(c(2, 4))
```
![](https://i.imgur.com/SroYG0G.png)
Changer les couleurs en utilisant le package `Rcolobrewer`
https://rdrr.io/cran/RColorBrewer/man/ColorBrewer.html
![](https://i.imgur.com/JK0S2E6.png)
```
ggplot(type, aes(ymax=ymax, ymin=ymin, xmax=4, xmin=3, fill=TYPE)) +
geom_rect() + scale_fill_brewer(palette = "Paired") +
coord_polar(theta="y") +
xlim(c(2, 4))
```
![](https://i.imgur.com/7jirMkv.png)
---
## TREEMAP
Une carte proportionnelle (***treemap***) est une représentation de données hiérarchiques dans un espace limité. Elle permet de représenter la proportion de modalités d'une ou de plusieurs variables qualitatives.
https://www.rdocumentation.org/packages/treemap/versions/2.4-2/topics/treemap
https://www.r-graph-gallery.com/treemap.html
```
install.packages("treemap")
library(treemap)
```
---
### Treemap pour représenter la proportion de chacun des types de signalement
Etape1 : créer le dataframe adéquat
```
Agregtype <- DMR %>% group_by(TYPE) %>% summarise(nb=n())
```
Etape 2 : Faire le graphique
```
treemap(Agregtype, index=c("TYPE"),vSize="nb", type="index",
fontsize.labels=c(15,12),
fontcolor.labels=c("white","orange"),
fontface.labels=c(2,1),
bg.labels=c("transparent"),
align.labels=list(
c("center", "center"),
c("right", "bottom")),
overlap.labels=0.5,
inflate.labels=F,)
```
![](https://i.imgur.com/YFl6Y1r.png)
---
### Treemap pour représenter la proportion de chacun des sous-types de signalement
Etape1 : créer le dataframe adéquat
```
AgregStype <- DMR %>% group_by(TYPE, SOUSTYPE) %>% summarise(nb=n())
```
Etape 2 : Faire le graphique
```
treemap(Agregtype, index=c("TYPE"),vSize="nb", type="index",
fontsize.labels=c(15,12),
fontcolor.labels=c("white","orange"),
fontface.labels=c(2,1),
bg.labels=c("transparent"),
align.labels=list(
c("center", "center"),
c("right", "bottom")),
overlap.labels=0.5,
inflate.labels=F,)
```
![](https://i.imgur.com/la4oM5D.png)
---
### Treemap pour représenter la proportion de chacun des sous-types de signalement en les regroupant par type
Etape1 : créer le dataframe adéquat
```
AgregStype <- DMR %>% group_by(TYPE, SOUSTYPE) %>% summarise(nb=n())
```
Etape 2 : Faire le graphique
```
treemap(AgregStype, index=c("TYPE", "SOUSTYPE"),vSize="nb", type="index",
fontsize.labels=c(13,10),
fontcolor.labels=c("white","white"),
fontface.labels=c(2,1),
bg.labels=c("transparent"),
align.labels=list(
c("center", "center"),
c("right", "bottom")),
overlap.labels=0.5,
inflate.labels=F,)
```
![](https://i.imgur.com/0lY8Gzq.png)
---
### Treemap pour représenter la proportion de chacun des types de signalement par arrondissement
Etape1 : créer le dataframe adéquat
```
AgregArdtType <- DMR %>% group_by(ARRONDISSEMENT, TYPE) %>% summarise(nb=n())
```
Etape 2 : Faire le graphique
```
treemap(AgregArdtType , index=c("ARRONDISSEMENT", "TYPE"),vSize="nb", type="index",
fontsize.labels=c(21,8),
fontcolor.labels=c("black","white"),
fontface.labels=c(2,3),
bg.labels=c("transparent"),
align.labels=list(
c("left", "top"),
c("center", "center")),
overlap.labels=0.1,
inflate.labels=F,)
```
![](https://i.imgur.com/09U0M3q.png)
---
## HEATMAP
Une **heatmap** est une représentation graphique de données statistiques qui fait correspondre à l'intensité d'une grandeur variable une gamme de tons ou un nuancier de couleurs sur une matrice à deux dimensions. Très pertinentes pour représenter des variables quantitatives dans une approche temporelle.
http://www.columbia.edu/~sg3637/blog/Time_Series_Heatmaps.html
---
### Heatmap du nombre de signalements par jour depuis 2016
**Etape1 : créer le dataframe adéquat**
Il faut pour cela correctement préparer le jeu de données en travaillant sur les données temporelles. Pour cela il faut mobiliser le package `lubridate`
```
install.packages("lubridate")
library(lubridate)
```
1. Ajouter le nom de la journée de la semaine, le nom du mois, le numéro de la semaine du mois pour chaque signalement
```
DMR <- DMR %>% mutate(jour = (day(DMR$DATEDECL)),journee = (wday(DMR$DATEDECL,label = TRUE, abbr = FALSE)), mois = month(DMR$DATEDECL, label = TRUE, abbr = FALSE ), wotm= ceiling(day(DMR$DATEDECL) / 7))
```
![](https://i.imgur.com/G9JvHwf.png)
2. Faire l'agrégation adéquate
```
heatmap <- DMR %>% group_by(date = DATEDECL, journee, jour, mois, annee = ANNEE.DECLARATION, wotm) %>% summarise(nb= n())
```
![](https://i.imgur.com/0oCf4J2.png)
**Etape2 : Faire le graphique**
Au préalable charger le package de couleur `wesanderson`
```
install.packages("wesanderson")
library(wesanderson)
```
Puis charger la palette Zissou1
```
pal <- wes_palette("Zissou1", 100, type = "continuous")
```
Commande pour réaliser la heatmap
```
ggplot(heatmap2, aes(wotm, journee, fill = nb)) + geom_tile(colour = "white") +
facet_grid(annee~mois) + labs(fill = "Nombre de signalement") +
scale_fill_gradientn(colours = pal) + xlab("Semaine du mois") +
ylab("Journée") + ggtitle("Nombre de signalements par jour du service Dans Ma Rue") +
labs(caption="Source : Ville de Paris") + theme_bw()
```
![](https://i.imgur.com/HDVlnTM.png)
---
## DIAGRAMME SANKEY
Un **diagramme de Sankey** ou diagramme Sankey est un type de diagramme de flux dans lequel la largeur des liens est proportionnelle aux flux représentés. Très utile pour représenter et quantifier des liens entre des variables qualitatives.
```
library(networkD3)
```
https://www.rdocumentation.org/packages/networkD3/versions/0.4/topics/sankeyNetwork
### Diagramme Sankey pour représenter le lien entre type de signalement et arrondissements
Au préalable il faut créer le dataframe adéquat, ici je résume le nombre de signalements en fonction du type et de l'arrondissement.
Pour faciliter la lecture du graphique je ne conserve que :
* les Types de signalementles les plus présents
* uniquement les arrondisssement du 10eme au 20eme
```
sankey <- DMR %>% filter(! TYPE %in% c('Activités commerciales et professionnelles', 'Du vert près de chez moi', 'Problème sur un chantier', 'Eau', 'Éclairage / Électricité', 'Mobiliers urbains', 'Arbres, végétaux et animaux' ), ! VILLE %in% c("Paris 1","Paris 2", "Paris 3", "Paris 4","Paris 5", "Paris 6", "Paris 7","Paris 8", "Paris 9")) %>% group_by(Type = TYPE, Ardt = VILLE) %>% summarise( nb= n())
```
Il faut ensuite créer un dataframe des **noeuds** (*nodes*) qui regroupe toutes les modalités de source et de cible
```
nodes <- data.frame(
name=c(as.character(sankey$Type),
as.character(sankey$Ardt)) %>% unique())
```
![](https://i.imgur.com/U8URIRr.png)
Il faut ensuite créer les **liens** (*links*) entre tous les noeuds
```
sankey$IDsource <- match(sankey$Type, nodes$name)-1
sankey$IDtarget <- match(sankey$Ardt, nodes$name)-1
```
![](https://i.imgur.com/jznpyPO.png)
Enfin on peux produire le diagramme de Sankey
```
sankeyNetwork(Links = sankey, Nodes = nodes,
Source = "IDsource", Target = "IDtarget",
Value = "nb", NodeID = "name",
fontSize = 19, nodeWidth = 55)
```
![](https://i.imgur.com/TDXHl6B.png)
On peux maintenant personnaliser les couleurs en ajoutant une petite fonction ;)
```
nodes$group <- gsub(" ", "-", nodes$name)
```
```
sankeyNetwork(Links = sankey, Nodes = nodes,
Source = "IDsource", Target = "IDtarget",
Value = "nb", NodeID = "name",
fontSize = 19, nodeWidth = 55, NodeGroup = "group")
```
![](https://i.imgur.com/KdjMPE0.png)
---
## STREAMGRAPH
Un **streamgraph** est un type de graphique en aires empilées qui est déplacé structurée autour d'un axe central, ce qui donne une forme organique fluide. Très pertinent pour représenter l'évolution dans le temps d'une variable quantitive realtives à plusieurs modalités qualitatiaes.
https://hrbrmstr.github.io/streamgraph/
```
install.packages("devtools")
library(devtools)
```
Il faut ici installer le package `streamgraph`
```
devtools::install_github("hrbrmstr/streamgraph")
```
---
### Streamgraph pour représenter l'évolution dans le temps du nombre de types de signalement
Etape1. Créer le dataframe adéquat
```
streamgraph <- DMR %>% group_by(Anne = ANNEE.DECLARATION ,Type = TYPE) %>% summarise(nb = n())
```
Etape2. Produire le streamgraph
```
streamgraph(streamgraph, key="Type", value="nb", date="Anne", height="700px", width="1300px") %>% sg_axis_x("Date") %>% sg_legend(show=TRUE, label="I- Type: ")
```
![](https://i.imgur.com/wI5HxO9.png)
---
### Streamgraph pour représenter l'évolution dans le temps du nombre de sous-types de signalement
Etape1. Créer le dataframe adéquat
```
streamgraph <- DMR %>% filter(! ANNEE.DECLARATION %in% c(2012,2013,2014))
%>% group_by(Anne = ANNEE.DECLARATION ,SousType = SOUSTYPE)
%>% summarise(nb = n())
```
Etape2. Produire le streamgraph
```
streamgraph(streamgraph, key="SousType", value="nb", date="Anne", height="700px", width="1300px") %>% sg_axis_x("Date") %>% sg_legend(show=TRUE, label="I- Type: ")
```
![](https://i.imgur.com/pE3pUBP.png)