Graphique de densité 2D en R : geom_hex, geom_bin2d & contours

Corrigez un nuage de points surchargé sur des données volumineuses avec le binning et la densité 2D

Quand un nuage de points se transforme en bloc noir sur un grand jeu de données, passez à une vue de densité 2D ou en bins. Construisez des bins rectangulaires avec geom_bin2d(), des bins hexagonaux avec geom_hex(), des lignes de contour avec geom_density_2d() et une surface de densité remplie avec stat_density_2d() — le tout dans ggplot2.

Date de publication

27 juin 2026

Modifié

11 juillet 2026

AstucePoints clés
  • Sur un grand jeu de données, un nuage de points surcharge — des milliers de points fusionnent en une masse compacte qui masque la densité réelle.
  • geom_bin2d() divise le plan en rectangles et colore chacun selon son effectif (une heatmap 2D des effectifs de bins).
  • geom_hex() fait de même avec des hexagones, évitant les artefacts d’alignement des bins carrés (nécessite le package hexbin).
  • geom_density_2d() trace des lignes de contour à partir d’une estimation de densité par noyau en 2D ; stat_density_2d(geom = "polygon") la remplit.
  • Utilisez une échelle de remplissage viridis pour que le gradient d’effectifs soit perceptuellement uniforme et adaptée au daltonisme.
Obtenez le livre — GGPlot2 Essentials (PDF)

Introduction

Un nuage de points fonctionne à merveille pour quelques centaines de points. Poussez-le à des dizaines de milliers et il s’effondre : les points s’empilent les uns sur les autres jusqu’à ce que la région la plus dense ne soit plus qu’un bloc noir, et vous ne pouvez plus dire où vit réellement la majeure partie de vos données. C’est la surcharge (overplotting).

La solution consiste à cesser de dessiner des points individuels et à montrer plutôt la densité. Cette leçon couvre quatre outils ggplot2 pour cela, tous sur l’exemple classique de données volumineuses — le jeu de données diamonds (53 940 lignes de carat versus prix) :

  • le binning rectangulaire avec geom_bin2d(),
  • le binning hexagonal avec geom_hex(),
  • les lignes de contour avec geom_density_2d(),
  • une surface de densité remplie avec stat_density_2d().

Commencez par observer le problème. Tracez le carat de chaque diamant en fonction de son price :

library(ggplot2)
ggplot(diamonds, aes(x = carat, y = price)) +
  geom_point() +
  theme_minimal()

ggplot2 scatter plot of 53,940 diamonds (carat versus price); points overplot into a dense dark mass that hides where most diamonds lie.

Le coin inférieur gauche est un bloc d’encre compact. Y a-t-il 100 diamants là ou 10 000 ? Le graphique ne peut pas le dire. Chaque technique ci-dessous répond à cette question.

Binning rectangulaire avec geom_bin2d()

geom_bin2d() découpe la zone de tracé en une grille de rectangles, compte combien de points tombent dans chacun, et remplit chaque rectangle selon cet effectif — une heatmap 2D. Contrôlez la grille avec bins (le nombre de bins le long de chaque axe ; la valeur par défaut est 30). Associez le remplissage à une échelle viridis pour que le gradient d’effectifs se lise correctement.

library(ggplot2)
ggplot(diamonds, aes(x = carat, y = price)) +
  geom_bin2d(bins = 30) +
  scale_fill_viridis_c() +
  theme_minimal()

ggplot2 geom_bin2d heatmap of diamond carat versus price; rectangular tiles are coloured by the number of diamonds in each bin, brightest in the lower-left.

La structure est maintenant évidente : la plupart des diamants sont petits et bon marché (coin inférieur gauche lumineux), s’amincissant vers l’extrémité grande et coûteuse. geom_bin2d() est stat_bin2d() avec une géométrie par défaut — vous pouvez appeler l’un ou l’autre ; la forme geom est celle vers laquelle vous vous tournez.

Binning hexagonal avec geom_hex()

Les bins carrés peuvent créer des bandes verticales et horizontales visibles parce que leurs bords s’alignent parfaitement. Les hexagones pavent le plan sans cet alignement régulier, si bien que geom_hex() donne souvent une lecture plus lisse et plus honnête de la densité. Il nécessite l’installation du package hexbin.

library(ggplot2)
ggplot(diamonds, aes(x = carat, y = price)) +
  geom_hex(bins = 30) +
  scale_fill_viridis_c() +
  theme_minimal()

ggplot2 geom_hex plot of diamond carat versus price; hexagonal tiles coloured by a viridis scale show bin counts, densest in the lower-left.

Même histoire, des tuiles plus nettes. Baissez bins pour des hexagones plus grossiers et plus marqués ; augmentez-le pour plus de détail. Comme geom_hex() dépend d’un package compilé, il s’exécute au moment du build ici — le bac à sable en direct à la fin de la leçon s’en tient à des alternatives purement ggplot2 pour démarrer rapidement dans votre navigateur.

Lignes de contour avec geom_density_2d()

Au lieu de compter les points dans des cellules, vous pouvez estimer une densité 2D lisse et tracer ses lignes de contour — comme les courbes de niveau sur une carte topographique. geom_density_2d() fait cela. Il se lit bien superposé à un nuage de points discret, vous conservez donc les points bruts et la densité.

library(ggplot2)
ggplot(diamonds, aes(x = carat, y = price)) +
  geom_point(color = "lightgray", alpha = 0.4) +
  geom_density_2d(color = "#3a86d4") +
  theme_minimal()

ggplot2 scatter of diamond carat versus price in light grey with blue 2D kernel density contour lines overlaid, concentric around the dense lower-left region.

Les anneaux serrés et imbriqués marquent le cœur de haute densité ; les anneaux largement espacés marquent les régions clairsemées.

Densité 2D remplie avec stat_density_2d()

Pour remplir les contours plutôt que les tracer en silhouette, utilisez stat_density_2d() avec geom = "polygon" et associez le remplissage au niveau (level) de densité calculé. Dans le ggplot2 actuel, vous référencez une variable calculée par un stat avec after_stat() :

library(ggplot2)
ggplot(diamonds, aes(x = carat, y = price)) +
  stat_density_2d(aes(fill = after_stat(level)), geom = "polygon") +
  scale_fill_viridis_c() +
  theme_minimal()

ggplot2 filled 2D density of diamond carat versus price; nested polygons shaded by a viridis scale show density level, brightest at the dense core.

Cela donne un « îlot de chaleur » rempli là où les données se concentrent. Cela fonctionne aussi sur des données plus petites — remplacez par faithful (les éruptions de l’Old Faithful) pour voir clairement la forme à deux groupes :

library(ggplot2)
ggplot(faithful, aes(x = eruptions, y = waiting)) +
  geom_point(color = "lightgray") +
  stat_density_2d(aes(fill = after_stat(level)), geom = "polygon", alpha = 0.6) +
  scale_fill_viridis_c() +
  theme_minimal()

ggplot2 filled 2D density of Old Faithful eruption duration versus waiting time, showing two distinct viridis-shaded density peaks.

Les deux pics remplis sont les deux modes d’éruption — une structure que le nuage de points brut ne fait qu’esquisser.

Essayez en direct

Modifiez le code et appuyez sur Run — il s’exécute dans votre navigateur via webR (sans serveur, sans installation). Ce bac à sable utilise le binning et les contours purement ggplot2 (geom_bin2d + geom_density_2d) pour démarrer rapidement ; geom_hex nécessite le package compilé hexbin et est rendu pour vous ci-dessus.

Vous travaillez en Python ? Un guide de densité 2D matplotlib/seaborn arrive bientôt dans la série Python.

🟢 Avec un agent IA

Demandez à Prova « quand devrais-je utiliser geom_hex plutôt que geom_bin2d ? » — elle répond avec du code que vous pouvez exécuter, donc l’explication est reproductible. The runtime is the judge. Demander à Prova →

Problèmes courants

geom_hex() génère l’erreur « Computation failed … could not find function ». geom_hex() dépend du package hexbin. Installez-le une fois avec install.packages("hexbin"), puis rechargez ggplot2. (C’est aussi pourquoi le bac à sable en direct ci-dessus évite geom_hex.)

..level.. déclenche un avertissement de dépréciation. Les tutoriels plus anciens écrivent aes(fill = ..level..). Le ggplot2 actuel veut aes(fill = after_stat(level)) — même résultat, sans avertissement.

Les bins semblent trop grossiers ou trop fins. Il n’existe pas de nombre de bins universellement « correct ». Ajustez bins (un seul nombre, ou un vecteur de longueur 2 pour des résolutions x/y différentes) jusqu’à ce que la structure soit visible mais pas bruitée — commencez à 30 et ajustez.

Foire aux questions

Cessez de dessiner des points individuels et montrez plutôt la densité. Découpez le plan en bins et colorez par effectif avec geom_bin2d() (rectangles) ou geom_hex() (hexagones), ou estimez une densité lisse avec geom_density_2d() (contours) / stat_density_2d() (remplie). Des correctifs plus légers comme alpha et une size de point plus petite aident un peu, mais le binning est la vraie réponse pour des dizaines de milliers de points.

Tous deux divisent le plan en cellules et colorent chaque cellule selon le nombre de points qu’elle contient. geom_bin2d() utilise des rectangles ; geom_hex() utilise des hexagones. Les hexagones évitent les artefacts d’alignement horizontal/vertical réguliers que les bins carrés peuvent créer, si bien que geom_hex() se lit souvent plus lisse — mais il nécessite le package hexbin.

Pour les lignes de contour, utilisez geom_density_2d() ; pour une surface remplie, utilisez stat_density_2d(aes(fill = after_stat(level)), geom = "polygon") plus une échelle de remplissage telle que scale_fill_viridis_c(). Les deux effectuent une estimation de densité par noyau en 2D et sont de bonnes alternatives à un nuage de points lorsque les points se chevauchent.

La cause habituelle est l’absence du package hexbingeom_hex() ne peut pas calculer ses bins sans lui. Exécutez install.packages("hexbin") et redémarrez votre session. Dans un runtime navigateur/WASM (comme un bac à sable intégré à la page), le package compilé peut être indisponible ; utilisez donc geom_bin2d() à la place.

Définissez l’argument bins : geom_bin2d(bins = 50) ou geom_hex(bins = 15). Passez un seul nombre pour la même résolution sur les deux axes, ou un vecteur de longueur 2 comme bins = c(40, 20) pour binner x et y différemment.

Testez votre compréhension

Le graphique ci-dessous surcharge. Remplacez geom_point() par une couche de binning rectangulaire qui colore chaque bin selon son effectif, et ajoutez un remplissage viridis.

# Use geom_bin2d() for the bins and scale_fill_viridis_c() for the fill.
library(ggplot2) ggplot(diamonds, aes(x = carat, y = price)) + geom_bin2d(bins = 30) + scale_fill_viridis_c() + theme_minimal()
library(ggplot2)
ggplot(diamonds, aes(x = carat, y = price)) +
  geom_bin2d(bins = 30) +
  scale_fill_viridis_c() +
  theme_minimal()

Quel appel dessine une densité 2D remplie (et pas seulement des lignes de contour) ?

  1. geom_density_2d()
  2. geom_bin2d()
  3. stat_density_2d(aes(fill = after_stat(level)), geom = "polygon")

c. stat_density_2d() avec geom = "polygon" et le remplissage associé à after_stat(level) remplit la densité. geom_density_2d() ne dessine que les lignes de contour, et geom_bin2d() produit une heatmap d’effectifs rectangulaire.

Conclusion

Quand un nuage de points surcharge sur un grand jeu de données, passez à la densité. geom_bin2d() et geom_hex() vous donnent une heatmap d’effectifs en rectangles ou en hexagones ; geom_density_2d() et stat_density_2d() vous donnent des lignes de contour ou une surface remplie à partir d’une estimation de densité par noyau. Une échelle viridis garde le gradient honnête et adaptée au daltonisme.

Leçons associées

Vous préférez un livre ? GGPlot2 Essentials est disponible en PDF téléchargeable — toutes les leçons de cette série, hors ligne et à vous.

Obtenir le livre (PDF) →Les leçons restent gratuites en ligne.
Cette page vous a-t-elle été utile ?

Prouvez que vous savez le faire. Maîtrisez toute la série ggplot2 — suivez votre parcours, construisez des projets et obtenez un certificat.

Commencer gratuitement →

Passez à Pro — Prova illimité sur vos propres données et un certificat vérifiable qui atteste la compétence.

dès 15 $/mois facturé annuellement

Passer à Pro →

✓ Vous êtes Pro — continuez. The runtime is the judge.

Recevez les nouvelles leçons R & Python par e-mail

Pratique, reproductible, sans spam. Désinscription à tout moment.

Double opt-in. Nous ne partageons jamais votre e-mail.

Partager cette pageXLinkedInRedditHN
Note

Cette leçon est reproductible : chaque figure a été produite par le code affiché (si elle s’affiche, le code fonctionne), et le bac à sable se ré-exécute en direct dans votre navigateur. The runtime is the judge.

Réutilisation

Citation

BibTeX
@online{2026,
  author = {},
  title = {Graphique de densité 2D en R : geom\_hex, geom\_bin2d \&
    contours},
  date = {2026-06-27},
  url = {https://www.datanovia.com/learn/data-visualization/ggplot2/2d-density-hexbin},
  langid = {fr}
}
Veuillez citer ce travail comme suit :
“Graphique de densité 2D en R : geom_hex, geom_bin2d & contours.” 2026. June 27. https://www.datanovia.com/learn/data-visualization/ggplot2/2d-density-hexbin.