delladata

Améliorez la lisibilité des étiquettes de vos graphiques avec le package ggrepel

Utilisation du package ggrepel pour améliorer le positionnement des étiquettes sur un graphque

Pourquoi utiliser le package ggrepel ?

Lorsque je réalise des graphiques avec ggplot2, en particulier des scatterplots, il m’arrive régulièrement d’avoir besoin d’ajouter des étiquettes sur les points afin de rendre visible une information (un nom, un numéro d’identification, etc.).

Ces étiquettes peuvent être ajoutées facilement grâce aux fonctions geom_text() ou geom_label(). Mais dans la pratique, elles se retrouvent souvent superposées ou trop proches les unes des autres, ce qui rend le graphique difficile à lire et peu exploitable.

Il existe une solution pour résoudre ce problème de lisibilité : le package ggrepel. Celui-ci permet de repositionner automatiquement les étiquettes afin d’éviter les chevauchements, tout en conservant une présentation claire et esthétique.

Dans cet article, je vous montre comment utiliser ggrepel pour améliorer la lisibilité de vos graphiques.

Pour illustrer les exemples, nous allons travailler sur le jeu de données mtcars. L’axe horizontal représentera le poids des voitures (wt) et l’axe vertical leur consommation en miles par gallon (mpg), c’est-à-dire la distance parcourue avec un gallon d’essence. Chaque point correspond donc à un modèle de voiture, dont le nom est stocké dans les rownames du data frame. Nous allons afficher ces noms directement sur les points à l’aide d’étiquettes.

 

Comparaison des fonctions geom_text et geom_text_repel (du package ggrepel)

Pour illustrer l’intérêt de ggrepel, commençons par comparer deux approches pour afficher des étiquettes sur un scatterplot.

Avec geom_text (ggplot2 de base)

Dans ce premier exemple on utilise la fonction geom_text() du package ggplot2 pour générer les étiquettes des différents points :

library(ggplot2)

ggplot(mtcars, aes(x = wt, y = mpg, label = rownames(mtcars))) +
  geom_point() +
  geom_text() +
  ggtitle("Avec geom_text : les étiquettes (labels) se chevauchent") 
Étiquettes obtenues avec la fonction geom_text

On peut voir que les étiquettes chevauchent les points, et que certaines se superposent et le graphique devient difficile à lire.

Avec geom_text_repel (ggrepel)

Voyons maintenant ce que donne la même commande, mais avec la fonction geom_text_repel() du package ggrepel :

library(ggrepel)

ggplot(mtcars, aes(x = wt, y = mpg, label = rownames(mtcars))) +
  geom_point() +
  geom_text_repel() +
  ggtitle("Avec geom_text_repel : les étiquettes (labels) sont lisibles")
  
Warning: ggrepel: 1 unlabeled data points (too many overlaps). Consider
increasing max.overlaps 
Étiquettes obtenues avec la fonction geom_text_repel

Cette fois, les étiquettes sont automatiquement décalées par rapport aux points et espacées entre elles. Chaque point reste identifiable et l’ensemble du graphique est beaucoup plus clair.

On remarque cependant un warning : ggrepel informe que 5 points n’ont pas pu être étiquetés afin d’éviter les chevauchements. C’est un choix volontaire de l’algorithme, qui privilégie la lisibilité globale plutôt que de forcer l’affichage de toutes les étiquettes.

A noter: Le placement des étiquettes par ggrepel n’est pas figé une fois pour toutes : il dépend aussi de la taille de la fenêtre graphique ou du format d’export (PNG, PDF, affichage dans RStudio…).

Comparaison de geom_label et geom_label_repel (du package ggrepel)

Le même principe s’applique avec les fonctions geom_label() de ggplot2 et geom_label_repel() de ggrepel. Contrairement à geom_text(), ces fonctions affichent les étiquettes dans une boîte rectangulaire.

Avec geom_label() (ggplot2 de base)

ggplot(mtcars, aes(x = wt, y = mpg, label = rownames(mtcars))) +
  geom_point() +
  geom_label() +
  ggtitle("Avec geom_label : les étiquettes (labels) se chevauchent") 
Étiquettes obtenues avec la fonction geom_label

Comme avec geom_text(), les étiquettes se chevauchent entre elles et avec les points. Certaines deviennent illisibles malgré la boîte autour du texte.

Avec geom_label_repel() (ggrepel)

ggplot(mtcars, aes(x = wt, y = mpg, label = rownames(mtcars))) +
  geom_point() +
  geom_label_repel() +
  ggtitle("Avec geom_label_repel : les étiquettes (labels) sont lisibles")
  
  
Warning: ggrepel: 9 unlabeled data points (too many overlaps). Consider
increasing max.overlaps 
Etiquettes obtenues avec la fonction geom_label_repel

Cette fois, les étiquettes sont automatiquement déplacées et espacées, ce qui améliore considérablement la lisibilité.

On observe néanmoins un warning : ggrepel signale que 9 étiquettes n’ont pas pu être affichées afin d’éviter des chevauchements trop importants. Là encore, l’algorithme choisit de préserver la clarté du graphique plutôt que de tout afficher coûte que coûte.

Les arguments utiles de geom_text_repel() et geom_label_repel()

Certaines options disponibles dans ggrepel permettent de mieux contrôler le comportement des étiquettes. Elles s’appliquent aussi bien à geom_text_repel() qu’à geom_label_repel().

max.overlaps : gérer le nombre d’étiquettes affichées

Par défaut, ggrepel calcule pour chaque étiquette combien d’éléments elle chevauche (autres étiquettes ou points). Si ce nombre dépasse la limite fixée par max.overlaps (valeur par défaut = 10), l’étiquette est supprimée du graphique.

Exemple 1 : valeur par défaut (max.overlaps = 10)

ggplot(mtcars, aes(x = wt, y = mpg, label = rownames(mtcars))) +
  geom_point() +
  geom_label_repel(max.overlaps = 10)+
  ggtitle("Avec max.overlaps=10 (valeur par défaut)")

Warning: ggrepel: 9 unlabeled data points (too many overlaps). Consider
increasing max.overlaps 
Limiter le nombre d'étiquettes affichées avec l'argument max.overlaps

Dans cet exemple, 9 étiquettes n’ont pas pu être affichées car elles auraient entraîné des chevauchements trop importants.

Exemple 2 : augmenter la tolérance (max.overlaps = 12)

ggplot(mtcars, aes(x = wt, y = mpg, label = rownames(mtcars))) +
  geom_point() +
  geom_label_repel(max.overlaps = 12)+
  ggtitle("Avec max.overlaps=12")

Warning: ggrepel: 1 unlabeled data points (too many overlaps). Consider
increasing max.overlaps
 
Augmentation du nombre d'étiquettes affichées

En augmentant la tolérance à 12, seule une étiquette n’a pas pu être affichée. On accepte donc davantage de chevauchements pour conserver plus de labels visibles.

box.padding : espace autour des labels

L’argument box.padding contrôle la marge autour de la boîte englobante du texte. Autrement dit, il définit de combien chaque étiquette doit s’éloigner des autres pour éviter les chevauchements.Par défaut, sa valeur est 0.25 et l’unité est la ligne de texte (lines), mais vous pouvez utiliser d’autres unités en passant un objet unit(x, “units”) du package grid (par exemple “mm”, “pt”, etc.)

Exemple 1 : valeur par défaut (box.padding = 0.25)

ggplot(mtcars, aes(x = wt, y = mpg, label = rownames(mtcars))) +
  geom_point() +
  geom_label_repel(box.padding = 0.25)+
  ggtitle("Avec box.padding = 0.25 (valeur par défaut")

Warning: ggrepel: 9 unlabeled data points (too many overlaps). Consider
increasing max.overlaps
 
utilisation de l'argument box.padding pour gérer l'espace autour des étiquettes

Avec la velaur par défaut, 9 étiquettes n’ont pas pu être affichées.

Exemple 2 : marge réduite (box.padding = 0.1)

ggplot(mtcars, aes(x = wt, y = mpg, label = rownames(mtcars))) +
  geom_point() +
  geom_label_repel(box.padding = 0.1)+
  ggtitle("Avec box.padding = 0.1")

Warning: ggrepel: 3 unlabeled data points (too many overlaps). Consider
increasing max.overlaps 
Utilisation de l'argument box.padding du package ggrepel pour contrôller l'espace autour des labels

À présent, seules 3 étiquettes n’ont pas pu être affichées.

point.padding : espacer l’étiquette de son point

L’argument point.padding définit la marge autour du point annoté. Il permet d’éviter que le texte touche directement le point associé, en ajoutant un petit espace. Sa valeur par défaut est 0 (pas d’espace). Comme pour box.padding, l’unité est par défaut la ligne de texte (lines), mais on peut aussi utiliser d’autres unités (millimètres, points typographiques, etc.) via la fonction unit(x, “units”) du package grid.

Exemple 1 : valeur par défaut (point.padding = 0)

ggplot(mtcars, aes(x = wt, y = mpg, label = rownames(mtcars))) +
  geom_point() +
  geom_text_repel(point.padding = 0)+
  ggtitle("Avec point.padding = 0 (valeur par défaut)")

Warning: ggrepel: 1 unlabeled data points (too many overlaps). Consider
increasing max.overlaps 
Espacement de l'étiquette par rapport à son point avec l'argument point.padding

Avec la valeur par défaut, une seule étiquette n’a pas pu être affichée.

 

Exemple 2 : marge importante (point.padding = 10)

ggplot(mtcars, aes(x = wt, y = mpg, label = rownames(mtcars))) +
  geom_point() +
  geom_text_repel(point.padding = 10)+
  ggtitle("Avec point.padding = 10")

Warning: ggrepel: 4 unlabeled data points (too many overlaps). Consider
increasing max.overlaps 
Augmentation de la distance entre l'étiquette et son point avec l'argument point.padding

Cette fois, l’espace entre les textes et les points est beaucoup plus grand. La différence est moins visible que pour box.padding, mais en observant attentivement (par exemple dans le coin inférieur droit), on constate que les étiquettes sont repoussées plus loin.

En contrepartie, 4 étiquettes n’ont pas pu être affichées : plus l’espace est large, plus ggrepel doit arbitrer et en supprimer.

min.segment.length : contrôler les traits reliant labels et points

Quand une étiquette est éloignée de son point, ggrepel trace automatiquement un trait de liaison. L’argument min.segment.length permet de ne pas dessiner les segments trop courts : si la distance entre le label et le point est inférieure à cette valeur, la ligne est omise. La valeur par défaut est 0.5.L’unité est par défaut la ligne de texte (lines), mais on peut utiliser d’autres unités (millimètres, points, etc.) avec unit(x, “units”). Pour forcer l’affichage des segments même très courts, il suffit de fixer la valeur à 0 avec min.segment.length = 0.

Exemple 1 : valeur par défaut (min.segment.length = 0.5)

ggplot(mtcars, aes(x = wt, y = mpg, label = rownames(mtcars))) +
  geom_point() +
  geom_text_repel()+
  ggtitle("Avec min.segment.length  = 0.5 (valeur par défaut)")

Warning: ggrepel: 1 unlabeled data points (too many overlaps). Consider
increasing max.overlaps 
Utilisation de l'argument min.segment.length

Ici, les segments reliant le point et son label ne s’affichent que si le label est suffisamment éloigné. Les étiquettes très proches du point n’ont donc pas de trait.

Exemple 2 : forcer l’affichage de tous les segments (min.segment.length = 0)

ggplot(mtcars, aes(x = wt, y = mpg, label = rownames(mtcars))) +
  geom_point() +
  geom_text_repel(min.segment.length = 0)+
  ggtitle("Avec min.segment.length  = 0" )

Warning: ggrepel: 1 unlabeled data points (too many overlaps). Consider
increasing max.overlaps 
Gestion de la valeur de l'argument min.segment.length

Ici, tous les segments sont tracés, y compris pour les étiquettes situées juste à côté du point.

Pour aller plus loin

La vignette du package ggrepel

Vous trouverez une multitude d’informations,  et de nombreux exemples d’utilisation du package ggrepel, en consultant sa vignette ici : 

vignette du package ggrepel

Le package plotly

Si vous souhaitez partager vos graphiques dans une présentation, sur un site web ou dans un tableau de bord, une autre approche intéressante consiste à utiliser le package plotly. Contrairement à ggrepel, qui résout le problème en déplaçant les étiquettes, plotly laisse le graphique épuré et affiche les informations supplémentaires uniquement au survol de la souris.

Le principe de plotly est de transformer un graphique statique en graphique interactif. Pour cela, vous commencez par créer un graphique classique avec ggplot2, comme vous en avez l’habitude, puis vous passez ensuite ce graphique dans la fonction ggplotly(), qui le convertit en version interactive.

Voici un exemple :

library(plotly)
# Graphique de base avec ggplot2
p <- ggplot(mtcars, aes(x = wt, y = mpg, text = rownames(mtcars))) +
  geom_point() +
  labs(title = "Consommation vs poids (mtcars)",
       x = "Poids (1000 lbs)",
       y = "Miles par gallon")

# Conversion en graphique interactif avec plotly
ggplotly(p) 
Création de graphiques interactifs avec plotly

En passant votre souris sur les points (du grahique sous RStudio) vous pourrez afficher les informations relatives à ce point.

 

Pour limiter ces informations à ce qui est défini dans l’argument text de la fonction aes() du ggplot , il est nécessaire d’ajouter l’argument tooltip = "text" dans la fonction ggplotly comme ceci :

#Conversion en graphique interactif avec plotly
ggplotly(p, tooltip = "text") 
Affichage d'une étiquette interactive avec plotly

Le package ggiraph

En complément de plotly une autre approche consiste à utiliser le package ggiraph.Développé par David Gohel (auteur également de packages comme officer ou flextable (voir mon article : Obtenir des tableaux personnalisés dans les trois formats de sortie de quarto grâce à flextable), ggiraph permet de rendre des graphiques ggplot2 interactifs directement en HTML, avec la possibilité d’afficher des infobulles (tooltips) au survol de la souris, ou même de rendre certains éléments cliquables.

Avec ggiraph, le principe est très simple : on commence par créer un graphique ggplot2 classique, comme on le ferait habituellement. Ensuite, au lieu d’utiliser les geom standards, on choisit une fonction interactive comme geom_point_interactive() ou geom_col_interactive(). Dans la fonction aes(), on ajoute l’argument tooltip, qui définit le texte à afficher au survol de chaque élément du graphique. Enfin, il suffit de passer ce graphique dans la fonction girafe(), qui le convertit en une version interactive, directement utilisable dans un document HTML, Shiny, Quarto ou R Markdown.

library(ggiraph)

# Graphique de base avec un tooltip
p <- ggplot(mtcars, aes(x = wt, y = mpg,
                        tooltip = rownames(mtcars))) +
  geom_point_interactive(size = 3, color = "steelblue") +
  labs(title = "Consommation vs poids (mtcars)",
       x = "Poids (1000 lbs)",
       y = "Miles par gallon")

# Rendu interactif avec ggiraph
girafe(ggobj = p) 
Réalisation de graphiques interactif avec le package ggiraph

Conclusion

La lisibilité des étiquettes dans un graphique est un élément important. Avec ggrepel, vous disposez d’une solution simple et efficace pour repositionner automatiquement vos étiquettes et éviter les chevauchements, que ce soit avec geom_text_repel() ou geom_label_repel(). Les différents arguments tels que max.overlapsbox.paddingpoint.padding ou encore min.segment.length vous permettent d’affiner le rendu et d’adapter vos graphiques à vos besoins.

Et si vous cherchez une alternative, des packages comme plotly et ggiraph offrent une approche complémentaire : plutôt que de déplacer les étiquettes, ils misent sur l’interactivité en affichant les informations au survol de la souris. Cela permet de garder des visuels épurés tout en rendant accessibles les détails. Ces outils sont particulièrement adaptés lorsque vos graphiques sont destinés à être partagés dans des documents HTML, intégrés dans des rapports Quarto, ou utilisés au sein d’applications Shiny et de tableaux de bord interactifs

Et vous, comment faites-vous pour améliorer la lisibilité de vos graphiques ? Que ce soit une astuce avec ggrepel, une expérience avec plotly ou ggiraph, ou même une autre méthode, n’hésitez pas à la partager en commentaire. Vos idées et vos questions sont toujours les bienvenues, et elles pourront inspirer d’autres lectrices et lecteurs du blog !

Et si vous préférez le format vidéo, j’ai également préparé une présentation de {ggrepel} sur YouTube. Vous y retrouverez les points essentiels de cet article, illustrés directement dans R.

👉 Voir la vidéo sur YouTube

Remerciements

🙏 Un grand merci à Gilles Besombes,lecteur fidèle du blog, qui m’a écrit pour me parler du package ggrepel. Bien que je le connaissais déjà et que je l’utilisais régulièrement, son message m’a donné l’idée d’écrire cet article. Si le sujet l’intéressait, il pouvait sûrement être utile à d’autres lecteurs et lectrices également. C’est toujours un plaisir de transformer vos échanges en contenus qui profitent à toute la communauté !

Poursuivez votre lecture

📩 Envie de recevoir plus d’astuces et de tutoriels sur R ?

Abonnez-vous gratuitement à la lettre de diffusion du blog pour ne rien manquer !

Vous serez directement informés de la publication de mes nouveaux articles, de la mise à disposition de ressources exclusives, et des actualités sur mes formations.

Vous recevrez également un cadeau 🎁 de bienvenu : des fiches « aide mémoire » (ou cheat sheets) qui vous permettront de réaliser facilement les principales analyses biostatistiques avec le logiciel R 

🎓 Vous souhaitez vous former à la réalisation de graphiques sous R avec ggplot 2 ?

Vous souhaitez soutenir mon travail ?

Vous pouvez soutenir mon travail en faisant un don libre sur le Tipeee du blog

4 réponses

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *

Fonctions statistiques R

Aide mémoire off'R ;)

Enregistrez vous pour recevoir gratuitement mes fiches « aide mémoire » (ou cheat sheets) qui vous permettront de réaliser facilement les principales analyses biostatistiques avec le logiciel R et pour être informés des mises à jour du site.