Contrôler les effets spaghetti avec ggplot

Graphique
Auteur·rice·s
Affiliation

Arno Muller

Ined

Marc Thévenin

Ined

Date de publication

12 juillet 2023

Résumé

Un graphique devient très facilement illisible lorsque trop d’objets graphiques y sont introduits, par exemple pour des courbes, au-delà de 5-6. Ce problème est appelé effet spaghetti (effet paella pour un nuage de points). Pour contrôler cette difficulté il est préconiser de réaliser un graphique de type small-multiples (graphique combiné). On peut améliorer cette visualisation avec une technique de highlighting: chaque sous graphique est mis en avant en termes de couleur et d’épaisseur de la courbe tout en gardant en arrière plan la visualisation des autres courbes avec une épaisseur plus petite et une couleur unique (par exemple du gris).

# pour récupérer la palette de couleur qualitatitive Tableau: 
# install.packages(ggthemes

library(dplyr)
library(ggplot2)
library(ggthemes) 

L’effet spaghetti en images

  • Les données utilisées ici sont extraites des bases contextextuelles GGP coordonnées par le datalab de l’Ined.
Important

Pour les graphiques seront présentés dans cette fiches, les données doivent être en format long, ici une observation du taux de fécondité par pays-année

  • On va regarder l’évolution du taux de fécondité de 12 pays de 1950 à 2022.
df <- read.csv("D:/D/Marc/SMS/assistoolsms_marc/R/assist/posts/spaghetti/fecondite_ggp.csv")
df = df %>% mutate_if(is.character,as.factor)
head(df)
  code year   pays    y
1   20 1950 France 2.99
2   20 1951 France 2.87
3   20 1952 France 2.81
4   20 1953 France 2.71
5   20 1954 France 2.71
6   20 1955 France 2.71
  • Les taux de fécondité sont renseignés par la variable y, les années par la variable year et les pays par la variable pays.

En empilant avec ggplot les 12 courbes d’évolution de la fécondité….

ggplot(df) +
 aes(x = year, y = y, colour = pays) +
 geom_line(lwd=1) +
 scale_color_tableau( palette = "Tableau 20") +
 labs(x = "Années", y = "ICF", title = "Indices conjoncturels de fécondité par pays de 1950 à 2022", 
 caption = "Source: GGP - Datalab Ined", color = "Pays") +
 scale_x_continuous(breaks=seq(1950,2020, 10))  +
 theme_light() 

… C’est illisible.

  • On peut améliorer la lecture et naviguer dans le graphique avec un outil de visualisation dynamique, par exemple avec plotly. Mais c’est outils sont strictement réservé à une diffusion de type html.
#install.packages(plotly)

library(plotly)

p = ggplot(df) +
 aes(x = year, y = y, colour = pays) +
 geom_line( lwd=1) +
 scale_color_tableau( palette = "Tableau 20") +
 labs(x = "Années", y = "ICF", title = "Indices conjoncturels de fécondité par pays de 1950 à 2022", 
 caption = "Source: GGP - Datalab Ined", color = "Pays") +
  scale_x_continuous(guide = guide_axis(n.dodge = 2), breaks=seq(1950,2020, 10)) + 
  scale_y_continuous(breaks=seq(0,6,1)) +
 theme_light() 

ggplotly(p)
  • Pour une visualisation statique, il est fortement recommandé de visualiser ce type d’informations à l’aide d’un graphique combiné, appelé small multiples (ou facettes).

Contrôle de l’effet spaghetti avec un graphique combiné

Graphique combiné simple

Par rapport au graphique précédent on va simplement générer des sous graphiques par pays, qui seront combinés avec l’option facet_wrap.

ggplot(df) +
  aes(x = year, y = y) +
  geom_line(colour = "#C24168", lwd=1.2) +
  labs(title = "Taux de fécondité") +
  theme_minimal() +
  labs(x = "Années", 
       y = "ICF", 
       title = "Indices conjoncturels de fécondité par pays de 1950 à 2022", 
       caption = "Source: GGP - Datalab Ined",) +
  scale_x_continuous(guide = guide_axis(n.dodge = 2), breaks=seq(1950,2020, 10)) + 
  scale_y_continuous(breaks=seq(0,6,1)) +
  facet_wrap(vars(pays), ncol = 4L)

Graphique combiné avec highlighting

On peut combiné les deux approches, en gardant en arrière plan de chaque sous graphique les informations des autres graphiques. On peut donc ici, pour chaque pays, positionné l’information de chaque pays par rapport aux autres.

Le principe du code a été récupéré dans le support de Yann Holtz consacré à ce problème Data to viz. On vous recommande très fortement d’utiliser ce support très riche, non seulement en éléments de programmation, mais également en conseils. En particulier la section mise en garde (caveats).

Les courbes en arrière plan ont une épaisseur plus faible (lwd=0.1) et on une couleur unique ( color="grey ). Pour facilité la lecture, le quadrillage a été allégé dans l’option theme().

tmp <- df %>%
  mutate(pays2=pays)   

ggplot(tmp) +
  aes(x = year, y = y) +
  geom_line( data=tmp %>% dplyr::select(-pays), aes(group=pays2), color="grey", lwd=0.1) +    
  geom_line(colour = "#C24168", lwd=1.4) +
  labs(title = "Taux de fécondité") +
  theme_minimal() +
  theme(panel.grid.major.x = element_blank(),
        panel.grid.minor.x = element_blank(),  
        panel.grid.minor.y = element_blank()) + 
  labs(x = "Années", 
       y = "ICF", 
       title = "Indices conjoncturels de fécondité par pays de 1950 à 2022", 
       caption = "Source: GGP - Datalab Ined",) +
  scale_x_continuous(guide = guide_axis(n.dodge = 2), breaks=seq(1950,2020, 10)) + 
  scale_y_continuous(breaks=seq(0,6,1)) +
  facet_wrap(vars(pays), ncol = 4L)

On peut vouloir trier les sous graphiques selon un ordre particulier, ici ils sont simplement affichés par ordre alphabétique.

Si on souhaite par exemple, affiché les sous graphiques par ordre décroissant du taux de fécondité en 2022, donc d’Israel en haut à gauche à la Corée du Sud en bas à droite, on doit réarranger l’ordre de la variable pays avec le code suivant:

pays_order <- df %>%
  filter(year == 2022) %>% 
  arrange(desc(y))
pays_order <- as.character(pays_order[,"pays"])
pays_order
 [1] "Israel"            "Turkey"            "Argentina"        
 [4] "France"            "Iceland"           "USA"              
 [7] "Germany"           "Portugal"          "Japan"            
[10] "Italy"             "Taiwan"            "Republic of Korea"
tmp <- df %>%
  mutate(pays2=pays)
tmp$pays <- factor(tmp$pays, levels = pays_order)
tmp$pays2 <- factor(tmp$pays2, levels = pays_order)
unique(tmp$pays2)
 [1] France            Germany           Iceland           Israel           
 [5] Italy             Japan             Portugal          Turkey           
 [9] USA               Argentina         Taiwan            Republic of Korea
12 Levels: Israel Turkey Argentina France Iceland USA Germany ... Republic of Korea

Et on réexécute le graphique précédent

ggplot(tmp) +
  aes(x = year, y = y) +
  geom_line( data=tmp %>% dplyr::select(-pays), aes(group=pays2), color="grey", lwd=0.1) +    
  geom_line(colour = "#C24168", lwd=1.4) +
  labs(title = "Taux de fécondité") +
  theme_minimal() +
  theme(panel.grid.major.x = element_blank(),
        panel.grid.minor.x = element_blank(),  
        panel.grid.minor.y = element_blank()) + 
  labs(x = "Années", 
       y = "ICF", 
       title = "Indices conjoncturels de fécondité par pays de 1950 à 2022", 
       caption = "Source: GGP - Datalab Ined",) +
  scale_x_continuous(guide = guide_axis(n.dodge = 2), breaks=seq(1950,2020, 10)) + 
  scale_y_continuous(breaks=seq(0,6,1)) +
  facet_wrap(vars(pays), ncol = 4L)

Une fonction pour simplifier et automatiser le code

  • Version 0.1 - Juillet 2023 [Arno Muller]
  • Des options seront ajoutées ultérieurement (couleurs, épaisseurs, options thème(), ….).

Chargement de la fonction:

source("https://raw.githubusercontent.com/arnomuller/Fonction_R/main/spag_plot/spag_plot.R")

Maintenant on va trier les graphiques pas ordre décroissant du taux de fécondité en 1950

df <- read.csv("D:/D/Marc/SMS/assistoolsms_marc/R/assist/posts/spaghetti/fecondite_ggp.csv")
df = df %>% mutate_if(is.character,as.factor)

spag_plot(df,                  # Base de données au format long
          var_x = "year",      # Variable en X (numérique)
          var_y = "y",         # Variable en Y (numérique)
          var_group= "pays",   # Variable de groupe (factor)
          ordre =  1950,      # Ordre des plots ("alpha", valeur num de var_x, un vecteur)
          decroiss = "oui",    # Ordre décroissant de l'ordre choisi au dessus
          titre   = "TITRE",   # Choix du titre
          titre_x = "Années",  # Choix du titre de l'axe X
          titre_y   ="Taux",   # Choix du titre de l'axe Y
          source    = "",      # Source des données
          interval = 20,       # Echelle de X
          n_col = 6)           # Nombre de colonnes pour les graphiques