Visualisation 3D en R avec rgl : le guide complet
Construisez une scène 3D interactive et pivotable en R — nuage de points, sphères, axes, ellipses, une surface de régression et l’export
Un guide complet et pratique des graphiques 3D en R avec le package rgl : ouvrez un périphérique, dessinez un nuage de points 3D avec points3d et spheres3d, ajoutez des axes et une boîte englobante, colorez les points par groupe, tracez une ellipse de concentration à 95 %, ajustez une surface de régression et exportez une capture d’écran, un GIF qui tourne ou un widget HTML interactif autonome. rgl effectue son rendu via OpenGL, ce guide est donc du code statique accompagné de vraies captures d’écran — exécutez-le localement pour faire tourner la scène vous-même.
- Une scène 3D interactive et pivotable en R avec le package
rgl— dessinez des points et des sphères, ajoutez des axes et une boîte englobante, réglez le rapport d’aspect et colorez les points par groupe. - Les extras analytiques qui font parler un nuage de points 3D : une ellipse de concentration à 95 % (globale et par groupe) et une surface de régression ajustée.
- Trois façons de partager le résultat : une capture d’écran PNG statique, un GIF animé qui tourne (
movie3d) et un widget HTML interactif autonome (rglwidget). - Chaque figure ci-dessous est une vraie capture d’écran du code qui l’a produite. Comme
rgldessine via OpenGL, vous exécutez le code localement pour obtenir la scène vivante que l’on peut faire pivoter.
rgl est le package de R dédié aux graphiques 3D interactifs en temps réel. Il ouvre une fenêtre à accélération matérielle que vous pouvez faire pivoter à la souris, zoomer à la molette et y sélectionner des régions — le lieu naturel d’un nuage de points 3D où un angle de vue fixe cache toujours certains points derrière d’autres. Il effectue le rendu via OpenGL (la bibliothèque graphique multiplateforme que parle votre GPU), ce qui explique précisément sa fluidité sur votre propre machine et pourquoi ce guide est livré sous forme de captures d’écran statiques : la scène vivante réside dans une fenêtre OpenGL, pas sur une page web. Copiez n’importe quel bloc, exécutez-le dans votre session R et faites glisser pour explorer. Consultez le package rgl sur le CRAN et le site de référence de rgl pour l’API complète.
Les figures présentées ici sont des captures d’écran prises depuis une session rgl locale. Il n’y a pas de bac à sable dans le navigateur sur cette page — copiez n’importe quel bloc et exécutez-le dans votre propre session R (après la brève configuration ci-dessous) pour reproduire chaque scène et la faire pivoter vous-même.
Les anciens tutoriels rgl (dont l’ancêtre de celui-ci) utilisent les fonctions de périphérique bas niveau rgl.* — rgl.open(), rgl.points(), rgl.spheres(), rgl.bg(). Les versions récentes de rgl les déprécient au profit de l’interface R3D de plus haut niveau — open3d(), points3d(), spheres3d(), bg3d() — qui gère les matériaux et les scènes de façon plus cohérente. Les deux produisent les mêmes images, et nous montrons les appels de périphérique classiques parce qu’ils correspondent un à un aux captures d’écran, mais pour du code neuf, préférez les fonctions *3d. La correspondance est directe : rgl.open → open3d, rgl.points → points3d, rgl.spheres → spheres3d, rgl.bg → bg3d, rgl.lines → segments3d, rgl.texts → text3d, rgl.bbox → bbox3d. La section interface R3D ci-dessous emploie le style moderne d’un bout à l’autre.
Installer et charger rgl
Installez-le une fois depuis le CRAN, puis chargez-le à chaque session :
install.packages("rgl")
library("rgl")Sous Linux, vous aurez peut-être besoin des en-têtes système OpenGL au préalable (par exemple sudo apt-get install r-cran-rgl sous Debian/Ubuntu, qui installe les bibliothèques requises).
Les données
Chaque exemple utilise les données intégrées iris — 150 fleurs de trois espèces (setosa, versicolor, virginica), mesurées sur quatre variables. Nous en représentons trois, en stockant les coordonnées dans x, y, z pour que les appels restent courts :
data(iris)
x <- iris$Sepal.Length
y <- iris$Petal.Length
z <- iris$Sepal.WidthOuvrir et fermer le périphérique
Une scène rgl vit dans un périphérique — sa fenêtre interactive. Quelques fonctions le gèrent : open3d() (ou le classique rgl.open()) en ouvre un nouveau, rgl.close() ferme le périphérique courant, rgl.clear() vide la scène courante pour la redessiner, et rgl.cur() renvoie l’identifiant du périphérique actif. Dans les premières sections, nous ouvrons un périphérique neuf par graphique ; plus bas, une petite fonction utilitaire le fait pour nous.
Un nuage de points 3D de base
rgl.points() (moderne : points3d()) dessine le nuage brut. Ouvrez un périphérique et passez-lui les trois vecteurs de coordonnées :
rgl.open() # Open a new RGL device
rgl.points(x, y, z, color = "lightgray") # 3D scatter plot
Les points sont minuscules et le fond est sombre par défaut. rgl.bg() (moderne : bg3d()) définit la couleur de fond, et size agrandit les marqueurs :
rgl.open() # Open a new RGL device
rgl.bg(color = "white") # White background
rgl.points(x, y, z, color = "blue", size = 5) # Bigger blue points
rgl.viewpoint(zoom = 0.7) # Zoom in a little
Des sphères plutôt que des points
Pour un rendu plus tridimensionnel, dessinez des sphères avec rgl.spheres() (moderne : spheres3d()). Le radius (ici r) contrôle leur taille :
rgl.open()
rgl.bg(color = "white")
rgl.spheres(x, y, z, r = 0.2, color = "grey")
rgl.viewpoint(zoom = 0.7)
Rappelez-vous ce que rgl apporte : maintenez la souris enfoncée pour faire pivoter le nuage et faites défiler pour zoomer. Une seule capture d’écran ne peut pas montrer qu’un groupe se cache derrière un autre — une rotation, si.
Une fonction utilitaire pour initialiser le périphérique
Retaper la même configuration devient lassant. Ce petit rgl_init() n’ouvre un périphérique que lorsque c’est nécessaire, fixe une taille de fenêtre, un fond et un point de vue raisonnables, et efface les formes précédentes — ainsi chaque bloc ultérieur part d’une scène propre et orientée de façon cohérente :
rgl_init <- function(new.device = FALSE, bg = "white", width = 640) {
if (new.device | rgl.cur() == 0) {
rgl.open()
par3d(windowRect = 50 + c(0, 0, width, width)) # Set the window size
rgl.bg(color = bg) # Background colour
}
rgl.clear(type = c("shapes", "bboxdeco")) # Clear the scene
rgl.viewpoint(theta = 15, phi = 20, zoom = 0.7) # Set the viewpoint
}par3d(windowRect = ...) dimensionne la fenêtre, et rgl.viewpoint(theta, phi, zoom) fixe la caméra — theta et phi sont les angles polaires, zoom le facteur de zoom. Définir le point de vue dans le code donne simplement le même angle à chaque capture d’écran ; la scène reste entièrement interactive.
Ajouter une boîte englobante
Une boîte englobante encadre le nuage et porte l’échelle. rgl.bbox() (moderne : bbox3d()) la dessine, et ses arguments de matériau la stylisent :
rgl_init()
rgl.spheres(x, y, z, r = 0.2, color = "yellow")
# Styled bounding box with tick labels
rgl.bbox(color = c("#333377", "black"), emission = "#333377",
specular = "#3333FF", shininess = 5, alpha = 0.8)
La première couleur est le fond de la boîte, la seconde la couleur des étiquettes de graduation ; alpha règle sa transparence (0 entièrement transparent, 1 opaque). Les arguments xlen, ylen, zlen contrôlent le nombre de graduations de chaque axe.
Ajouter des lignes d’axes et des étiquettes
Pour dessiner les axes à la main, rgl.lines() (moderne : segments3d()) trace un segment entre deux points et rgl.texts() (moderne : text3d()) l’étiquette. Passer à chaque axe l’étendue de ses données paraît naturel, jusqu’à ce que vous remarquiez que les axes ne se rejoignent pas à l’origine :
rgl_init()
rgl.spheres(x, y, z, r = 0.2, color = "yellow")
# One coloured line per axis, spanning that variable's range
rgl.lines(c(min(x), max(x)), c(0, 0), c(0, 0), color = "black")
rgl.lines(c(0, 0), c(min(y), max(y)), c(0, 0), color = "red")
rgl.lines(c(0, 0), c(0, 0), c(min(z), max(z)), color = "green")
La solution est de construire les axes autour de zéro. Cette fonction utilitaire rgl_add_axes() étend chaque axe symétriquement avec c(-max, max), marque la direction, l’étiquette et ajoute éventuellement un plan de sol et une boîte englobante :
rgl_add_axes <- function(x, y, z, axis.col = "grey",
xlab = "", ylab = "", zlab = "", show.plane = TRUE,
show.bbox = FALSE, bbox.col = c("#333377", "black")) {
lim <- function(x) c(-max(abs(x)), max(abs(x))) * 1.1
# Axis lines through the origin
xlim <- lim(x); ylim <- lim(y); zlim <- lim(z)
rgl.lines(xlim, c(0, 0), c(0, 0), color = axis.col)
rgl.lines(c(0, 0), ylim, c(0, 0), color = axis.col)
rgl.lines(c(0, 0), c(0, 0), zlim, color = axis.col)
# A point + label at the far end of each axis
axes <- rbind(c(xlim[2], 0, 0), c(0, ylim[2], 0), c(0, 0, zlim[2]))
rgl.points(axes, color = axis.col, size = 3)
rgl.texts(axes, text = c(xlab, ylab, zlab), color = axis.col,
adj = c(0.5, -0.8), size = 2)
# Optional floor plane
if (show.plane)
rgl.quads(x = rep(xlim / 1.1, each = 2), y = c(0, 0, 0, 0),
z = c(zlim[1], zlim[2], zlim[2], zlim[1]) / 1.1)
# Optional bounding box
if (show.bbox)
rgl.bbox(color = c(bbox.col[1], bbox.col[2]), alpha = 0.5,
emission = bbox.col[1], specular = bbox.col[1], shininess = 5,
xlen = 3, ylen = 3, zlen = 3)
}rgl.quads() (moderne : quads3d()) dessine le plan de sol à partir des coordonnées de ses quatre coins. Maintenant les axes se croisent proprement à l’origine :
rgl_init()
rgl.spheres(x, y, z, r = 0.2, color = "yellow")
rgl_add_axes(x, y, z)
Pour des échelles lisibles, le plus simple est de laisser la boîte englobante porter les graduations — passez show.bbox = TRUE :
rgl_init()
rgl.spheres(x, y, z, r = 0.2, color = "yellow")
rgl_add_axes(x, y, z, show.bbox = TRUE)
Régler le rapport d’aspect
aspect3d() définit le rapport apparent des trois axes. Avec aspect3d(1, 1, 1), la boîte englobante est un cube, si bien que les trois variables sont montrées à la même échelle visuelle (isométrique — la valeur par défaut est aspect3d("iso")) :
rgl_init()
rgl.spheres(x, y, z, r = 0.2, color = "yellow")
rgl_add_axes(x, y, z, show.bbox = TRUE)
aspect3d(1, 1, 1)
Modifiez les rapports pour étirer un axe — pratique pour étaler une dimension à l’étroit. aspect3d(2, 1, 1) double l’axe des x :
rgl_init()
rgl.spheres(x, y, z, r = 0.2, color = "yellow")
rgl_add_axes(x, y, z, show.bbox = TRUE)
aspect3d(2, 1, 1) # Stretch the x axis
Colorer les points par groupe
L’intérêt d’un nuage de points 3D est le plus souvent de voir si les groupes se séparent. Une petite fonction utilitaire transforme un facteur en un vecteur de couleurs par point — on indexe une palette par le numéro de groupe pour que chaque observation reçoive la couleur de son groupe :
get_colors <- function(groups, group.col = palette()) {
groups <- as.factor(groups)
ngrps <- length(levels(groups))
if (ngrps > length(group.col)) group.col <- rep(group.col, ngrps)
color <- group.col[as.numeric(groups)]
names(color) <- as.vector(groups)
color
}Passez son résultat directement à rgl.spheres() :
rgl_init()
rgl.spheres(x, y, z, r = 0.2, color = get_colors(iris$Species))
rgl_add_axes(x, y, z, show.bbox = TRUE)
aspect3d(1, 1, 1)
setosa se distingue nettement des deux autres. Fournissez votre propre palette — ici une palette adaptée au daltonisme — comme second argument :
cols <- get_colors(iris$Species, c("#999999", "#E69F00", "#56B4E9"))
rgl_init()
rgl.spheres(x, y, z, r = 0.2, color = cols)
rgl_add_axes(x, y, z, show.bbox = TRUE)
aspect3d(1, 1, 1)
Ou puisez une palette dans RColorBrewer — Dark2 est un solide choix qualitatif :
library("RColorBrewer")
cols <- get_colors(iris$Species, brewer.pal(n = 3, name = "Dark2"))
rgl_init()
rgl.spheres(x, y, z, r = 0.2, color = cols)
rgl_add_axes(x, y, z, show.bbox = TRUE)
aspect3d(1, 1, 1)
Bien choisir ses couleurs est un sujet à part entière — consultez la référence des palettes de couleurs R pour le catalogue complet et savoir quand recourir à chaque type.
Changer la forme des points
rgl fournit six objets maillés (mesh) — des solides 3D utilisables comme marqueurs : cube3d(), tetrahedron3d(), octahedron3d(), icosahedron3d(), dodecahedron3d() et cuboctahedron3d().

shapelist3d() place un solide choisi à chaque point de données. Ici, des tétraèdres remplacent les sphères, colorés par espèce :
rgl_init()
shapelist3d(tetrahedron3d(), x, y, z, size = 0.15,
color = get_colors(iris$Species))
rgl_add_axes(x, y, z, show.bbox = TRUE)
aspect3d(1, 1, 1)
Ajouter une ellipse de concentration
Une ellipse de concentration (un ellipsoïde, en 3D) est la région censée contenir une fraction donnée des points sous un modèle normal — la cousine 3D de l’ellipse de confiance. ellipse3d() l’estime à partir de la matrice de covariance ; elle renvoie un objet mesh3d (la géométrie de maillage triangulaire de rgl) que vous dessinez avec shade3d() (une surface pleine), wire3d() (un fil de fer), ou les deux :
rgl_init()
rgl.spheres(x, y, z, r = 0.2, color = "#D95F02")
rgl_add_axes(x, y, z, show.bbox = TRUE)
# 95% ellipse of concentration
ellips <- ellipse3d(cov(cbind(x, y, z)),
centre = c(mean(x), mean(y), mean(z)), level = 0.95)
shade3d(ellips, col = "#D95F02", alpha = 0.1, lit = FALSE) # translucent solid
wire3d(ellips, col = "#D95F02", lit = FALSE) # wireframe
aspect3d(1, 1, 1)
Plus utile encore : une ellipse par groupe — elle montre la dispersion de chaque espèce et où elles se chevauchent. Parcourez les niveaux en boucle, calculez un ellipsoïde à partir de la covariance de chaque groupe, et étiquetez-le en son centre :
groups <- iris$Species
levs <- levels(groups)
group.col <- c("red", "green", "blue")
rgl_init()
rgl.spheres(x, y, z, r = 0.2, color = group.col[as.numeric(groups)])
rgl_add_axes(x, y, z, show.bbox = FALSE)
for (i in seq_along(levs)) {
selected <- groups == levs[i]
xx <- x[selected]; yy <- y[selected]; zz <- z[selected]
ellips <- ellipse3d(cov(cbind(xx, yy, zz)),
centre = c(mean(xx), mean(yy), mean(zz)), level = 0.95)
shade3d(ellips, col = group.col[i], alpha = 0.1, lit = FALSE)
texts3d(mean(xx), mean(yy), mean(zz), text = levs[i],
col = group.col[i], cex = 2) # label at the group centre
}
aspect3d(1, 1, 1)
Ajuster une surface de régression
Pour montrer comment une variable dépend de deux autres, ajustez un modèle linéaire et dessinez sa surface. Prédisez les valeurs ajustées sur une grille régulière, puis dessinez la grille avec rgl.surface() (moderne : surface3d()) — une fois pleine, une fois en lignes de grille :
rgl_init()
rgl.spheres(x, y, z, r = 0.2, color = "#D95F02")
rgl_add_axes(x, y, z, show.bbox = FALSE)
aspect3d(1, 1, 1)
# Fit y ~ x + z and predict on a regular x-z grid
fit <- lm(y ~ x + z)
grid.lines <- 26
x.pred <- seq(min(x), max(x), length.out = grid.lines)
z.pred <- seq(min(z), max(z), length.out = grid.lines)
xz <- expand.grid(x = x.pred, z = z.pred)
y.pred <- matrix(predict(fit, newdata = xz), nrow = grid.lines, ncol = grid.lines)
# Draw the fitted surface, then its grid lines
rgl.surface(x.pred, z.pred, y.pred, color = "steelblue", alpha = 0.5, lit = FALSE)
rgl.surface(x.pred, z.pred, y.pred, color = "black", alpha = 0.5, lit = FALSE,
front = "lines", back = "lines")
Les points au-dessus de la surface sont sous-estimés par le modèle, ceux en dessous surestimés. (planes3d() dessine un plan plat à partir de l’équation ax + by + cz + d = 0 si vous n’avez besoin que du plan.)
L’interface R3D : plot3d()
Tout ce qui précède utilise les fonctions de périphérique bas niveau. rgl propose aussi une interface R3D de plus haut niveau qui ressemble au plot() de R de base — et c’est le style moderne recommandé. plot3d() dessine tout le nuage en un seul appel ; type = "s" donne des sphères, radius les dimensionne, et xlab/ylab/zlab étiquettent les axes :
open3d()
plot3d(x, y, z, col = "blue", box = FALSE, type = "s", radius = 0.15,
xlab = "Sepal.Length", ylab = "Petal.Length", zlab = "Sepal.Width")
plot3d() ajoute aussi un ellipsoïde directement — dessinez le nuage, calculez l’ellipse et ajoutez-la avec type = "wire" pour une cage nette :
open3d()
plot3d(x, y, z, col = "blue", box = FALSE, type = "s", radius = 0.15)
ellips <- ellipse3d(cov(cbind(x, y, z)),
centre = c(mean(x), mean(y), mean(z)), level = 0.95)
plot3d(ellips, col = "blue", alpha = 0.5, add = TRUE, type = "wire")
L’interface R3D dispose d’un jeu complet de verbes « ajouter une forme à la scène courante » — points3d(), lines3d(), segments3d(), quads3d(), text3d(), plus axes3d(), title3d() et box3d() pour la décoration. C’est le vocabulaire à privilégier dans du code rgl neuf.
Exporter votre scène
Une fois la scène satisfaisante, enregistrez-la de trois façons.
Une image statique. snapshot3d() (classique : rgl.snapshot()) écrit un PNG ; postscript3d() (classique : rgl.postscript()) écrit des formats vectoriels (PDF, SVG, EPS, …) :
snapshot3d(filename = "plot.png") # PNG screenshot
postscript3d("plot.pdf", fmt = "pdf") # Vector PDFUn GIF qui tourne. movie3d() effectue le rendu d’une rotation vers un GIF animé (il a besoin d’ImageMagick installé pour la conversion en GIF). spin3d() fournit la rotation :
movie3d(spin3d(axis = c(0, 0, 1)), duration = 3, dir = getwd())
Un widget HTML interactif. Pour conserver l’interactivité sur une page web, exportez la scène avec rglwidget() et enregistrez-la avec htmlwidgets::saveWidget(). C’est le remplaçant moderne de l’ancien writeWebGL() (retiré des versions récentes de rgl), et il produit une page WebGL autonome que l’on peut faire pivoter — WebGL est la version navigateur d’OpenGL :
open3d()
plot3d(x, y, z, col = get_colors(iris$Species), type = "s", radius = 0.15)
# Save the current scene as a stand-alone interactive HTML page
htmlwidgets::saveWidget(rglwidget(), file = "rgl-scene.html")Sélectionner et identifier des points
Comme la scène est vivante, vous pouvez aussi sélectionner des points à la souris. select3d() renvoie une fonction de test pour une région que vous délimitez ; identify3d() étiquette les points sur lesquels vous cliquez — les deux sont interactifs, ils s’exécutent donc dans votre session locale (il n’y a pas de capture d’écran statique à montrer) :
# Drag a box to select points, then recolour them
f <- select3d()
sel <- f(x, y, z)
rgl.spheres(x[sel], y[sel], z[sel], r = 0.2, color = "green")
# Or click to label up to 5 points
identify3d(x, y, z, labels = rownames(iris), n = 5)Foire aux questions
rgl construit des graphiques 3D interactifs en temps réel en R via OpenGL. Vous pouvez dessiner des nuages de points 3D, des sphères, des surfaces, des maillages et des ellipsoïdes, puis faire pivoter la scène à la souris, zoomer à la molette et sélectionner des points. C’est l’outil de référence pour les nuages de points 3D où un unique angle fixe cacherait des points les uns derrière les autres, et il peut exporter une capture d’écran statique, un GIF qui tourne ou un widget HTML interactif autonome.
Installez et chargez rgl, puis utilisez l’interface R3D : plot3d(x, y, z, type = "s", radius = 0.15, col = "blue"). Elle ouvre une fenêtre à accélération matérielle que vous pouvez faire glisser pour pivoter et faire défiler pour zoomer. Colorez par groupe en passant un vecteur de couleurs par point à col, et ajoutez une décoration comme une boîte englobante (bbox3d()) ou un ellipsoïde de concentration (ellipse3d()).
rgl effectue son rendu via une fenêtre OpenGL, qui ne s’intègre pas d’elle-même comme une image statique. Pour placer une scène rgl dans un document HTML rendu, ajoutez rglwidget() (le remplaçant moderne de writeWebGL(), retiré), qui convertit la scène courante en un widget WebGL intégrable. Pour un PDF statique ou une page non interactive, capturez une image avec snapshot3d() et insérez ce PNG à la place — c’est exactement ainsi que les figures de cette page ont été réalisées.
Elles dessinent la même chose, mais appartiennent à deux API. Les fonctions rgl.* (rgl.points(), rgl.spheres(), rgl.bg()) constituent l’ancienne interface de périphérique bas niveau ; les fonctions *3d (points3d(), spheres3d(), bg3d(), open3d()) forment l’interface R3D de plus haut niveau qui gère les matériaux et les scènes de façon plus cohérente. Les versions récentes de rgl déprécient les appels rgl.*, donc préférez les fonctions *3d dans du code neuf — ce guide ne montre les appels classiques que parce qu’ils correspondent directement aux captures d’écran.
Construisez un vecteur de couleurs par point en indexant une palette avec le facteur de groupe : cols <- c("#999999", "#E69F00", "#56B4E9")[as.numeric(iris$Species)], puis passez color = cols à spheres3d() (ou col = cols à plot3d()). Le piège est de passer une couleur par groupe au lieu d’une par point — cela recycle la palette dans l’ordre des lignes au lieu de la faire correspondre au facteur.
Conclusion
rgl transforme trois colonnes de données en une scène que vous pouvez tenir entre vos mains — faites-la pivoter, colorez-la par groupe, enveloppez chaque regroupement d’un ellipsoïde de concentration et ajustez-y une surface. Construisez avec open3d(), spheres3d() et les verbes R3D *3d, décorez avec une boîte englobante et des axes, et exportez une capture d’écran, un GIF ou une page HTML rglwidget() selon l’endroit où le graphique doit vivre. Pour un nuage de points 3D statique et prêt à imprimer, ou une version interactive native pour le web, voyez les recettes complémentaires ci-dessous.
Pour aller plus loin
- plot3d en R (package plot3D) — nuages de points 3D, barres et surfaces statiques avec le package
plot3D. · Nuages de points 3D en R — statique avecscatterplot3d, interactif avecplotly. · Leçon scatterplot3d · Visualisation de données.
Demandez à Prova « dessine mes données à trois colonnes en un nuage de points 3D rgl coloré par groupe avec un ellipsoïde de concentration » — elle répond avec du code que vous pouvez exécuter sur vos propres données. The runtime is the judge. Demander à Prova →
Citation
@online{kassambara2026,
author = {Kassambara, Alboukadel},
title = {Visualisation 3D en R avec rgl : le guide complet},
date = {2026-07-13},
url = {https://www.datanovia.com/blog/rgl-3d-visualization-in-r},
langid = {fr}
}