Visualisation 3D avec le package rgl

Alexis D-Laflamme et Alexandre Richard

2019-05-29



Introduction

Le package rgl permet de réaliser des graphiques interactifs en 3D et la représentation d’objets géométriques. Il a été réalisé principalement par Ducan Murdoch qui est professeur de statistique à l’University of Western Ontario et Daniel Adler. Ce package exploite l’API graphique OpenGL, permettant la production de graphiques interactifs en 2D et 3D, comme moteur de rendu.

Les avantages qui distinguent particulièrement ce package sont qu’il permet la création de scènes et l’ajout de contrôles permettant des actions dans une figure en trois dimensions. C’est-à-dire qu’il permet de programmer une série d’actions permettant de mettre en valeur certaines caractéristiques des graphiques générés grâce à celui-ci. Ce package permet aussi d’ajouter des contrôles, auxquels nous pouvons attribuer diverse actions permettant des manipulations contrôlées d’une figure.

Le package rgl est conçu pour que son utilisation ressemble à la librairie graphique de base de R. Cela rend son utilisation très intuitive pour les connaisseurs de R. De plus, il permet de nombreuses fonctionnalités dont l’exportation des graphiques qu’il produit dans divers formats interactifs et statiques et, depuis peu de temps, l’intégration de ces graphiques dans une page web.

Puisque la création de graphique en 2D n’est pas la force de ce package et n’offre aucun avantage par rapport à la librairie graphique de base de R ou ggplot par exemple, nous ne l’aborderons pas.

Installation et chargement du package rgl

L’installation du package R rgl s’effectue avec la commande suivante :

install.packages("rgl")

Pour charger le package dans votre environnement de travail, utilisez la fonction library :

library(rgl)

Présentation des données utilisées

Afin d’illustrer l’utilisation des principales fonctions du package, nous utiliserons le jeu de données quakes du package datasets. Il contient des informations sur 1000 séismes, d’une magnétude supérieure à 4 MB, survenus dans les alentours des Îles Fidji depuis 1964. Pour le bien de l’exercice, nous ajoutons deux nouvelles variables au jeu de données. Celles-ci sont générées à partir de variables déjà contenues dans le jeu de données quakes. Voici des informations sur les données contenues dans le jeu quakes :

#Création de la variable "magFactor" 
quakes$magFactor <- factor(floor(quakes$mag)) 

#Création de la variable "region"
quakes$region <- factor(quakes$long >= 175, labels = c("Ouest", "Est"))

#Informations sur le jeu de données quakes
str(quakes)
## 'data.frame':    1000 obs. of  7 variables:
##  $ lat      : num  -20.4 -20.6 -26 -18 -20.4 ...
##  $ long     : num  182 181 184 182 182 ...
##  $ depth    : int  562 650 42 626 649 195 82 194 211 622 ...
##  $ mag      : num  4.8 4.2 5.4 4.1 4 4 4.8 4.4 4.7 4.3 ...
##  $ stations : int  41 15 43 19 11 12 43 15 35 19 ...
##  $ magFactor: Factor w/ 3 levels "4","5","6": 1 1 2 1 1 1 1 1 1 1 ...
##  $ region   : Factor w/ 2 levels "Ouest","Est": 2 2 2 2 2 2 1 2 2 2 ...

Fonction de base plot3d

Graphique de base

La fonction de base du package rgl est plot3d. À la base, chacune des figures produites par cette fonction sont interactives. C’est-à-dire qu’il est possible d’explorer l’environnement 3D de celles-ci, à l’aide d’une souris d’ordinateur. Les arguments minimaux à donner à la fonction plot3d sont les suivants :

  • x : un vecteur des valeurs des points pour l’axe des X.
  • y : un vecteur des valeurs des points pour l’axe des Y.
  • z : un vecteur des valeurs des points pour l’axe des Z.

Voici un exemple de graphique de base produit par la fonction plot3d si l’on ne fait que donner les arguments minimaux nécessaires :

## wgl 
##   2
plot3d(x = quakes$long, y = quakes$lat, z = quakes$depth)

Arguments de base

Pour modifier des éléments graphiques basiques, nous pouvons intégrer les arguments dans la fonction plot3d, comme dans l’exemple qui suit. Nous pouvons aussi les intégrer dans la fonction decorate3d incluse dans le package rgl. Voici un tableau résumant les principaux arguments pouvant être passés aux fonctions plot3d et decorate3d :

Arguments Éléments graphiques contrôlés
main titre de la figure
sub sous-titre de la figure
————————— ———————–
xlab, ylab, zlab noms des axes
xlim, ylim, zlim étendue des axes
————————— ———————–
type type de représentation (p = points, s = sphères, l = lignes, etc.)
————————— ———————–
box si FALSE, retire la boite autour de la zone du graphique
axes si FALSE, retire les axes de la zone graphique
————————— ———————–
lwd épaisseur des lignes
size épaisseur des points et des sphères.
————————— ———————–
col couleur des éléments du graphique.

Dans l’exemple qui suit, nous ajoutons des noms aux trois axes et un titre, retirons la boite autour de la figure (effectif dans une fenêtre interactive, pas dans un document HTML) et modifions la représentation et la taille des points de la figure précédente.

#Création d'une couleur associée à chaque niveau de magFactor
quakes$magCol <- ifelse(quakes$magFactor == 4, "red", 
                       ifelse(quakes$magFactor == 5, "blue", "green"))

#Création du graphique
plot3d(x = quakes$long, y = quakes$lat, z = quakes$depth,
       xlab = "longitude", ylab = "latitude", zlab = "profondeur (km)",                                   
       main = "Pronfondeur de 1000 seismes aux alentours de Fidji selon leur latitude et longitude",  
       col = quakes$magCol, type = "s", size = 1, box = FALSE)

Bonification de graphiques

Tout d’abord, dans la première sous-section, nous recréerons le graphique produit à l’exemple précédent, en le bonifiant quelque peu, à l’aide de fonctions permettant l’ajout de divers éléments dans une scène en 3 dimensions dans le but d’illustrer l’utilisation possible de celles-ci.

Par la suite, nous traiterons l’ajout de formes géométriques en 3D plus complexe à la sous-section suivante puisque leur utilisation dans R est légèrement différente des formes traitées dans la première sous-section. Nous ferons un exemple d’ajout de formes géométriques en 3 dimensions dans la figure créée précédemment.

Les manipulations des exemples qui suivent permettront de bonifier une scène vide en 3D générée à partir de la commande open3d du package rgl. Cependant, il est important de noter que ces manipulations auraient pu être effectuées sur n’importe quel graphique en 3 dimensions généré par une fonction du package.

Ajout d’éléments graphiques de base

Tout comme la librairie de production de graphique de base dans R, le package rgl permet l’ajout de divers éléments dans une représentation. Le tableau suivant présente les principales fonctions permettant des ajouts à un graphique initialisé.

Fonction Description
axes3d, axis3d ajout d’axes
box3d, bbox3d ajout d’une boite autour du graphique
title3d ajout d’un titre
text3d ajout d’un texte dans la zone graphique
mtext3d ajout d’un texte dans la marge
decorate3d ajout d’éléments graphiques de base
aspect3d définit les proportions du graphique
bg3d, bgplot3d définit l’arrière plan du graphique
show2d montre une représentation 2D d’une scène 3D
legend3d ajout d’une légende à la scène
grid3d ajout d’une grille de références
————————— ———————–
points3d ajout de points
lines3d ajout de lignes
segments3d ajout de segments
triangles3d ajout de triangles
quads3d ajout de quadrilatères
abclines3d ajout d’une ligne droite
arc3d ajout d’arcs ou de spirales
planes3d ajout de plans
spheres3d ajout de sphères
surface3d, terrain3d ajout de sufaces
arrow3d ajout de flèches

La première section du tableau contient les éléments qui influencent l’apparence du graphique, la seconde contient des fonctions qui permettent l’ajout de données selon diverses représentations en 3D ou de formes géométriques selon une formule donnée.

Dans l’exemple qui suit, nous commençons par simplement recréer le graphique produit par la fonction plot3d à l’exemple précédent.

#Overture d'une scène 3D vide
open3d()

#Dimensionnement de la scène
#Nous revenons sur la fonction par3d plus tard dans le document
par3d(windowRect = c(0, 0, 512, 512))

#Ajout de sphères représentant les différents séismes
spheres3d(x = quakes$long, y = quakes$lat, z = quakes$depth, radius = 10, col = quakes$magCol )

#Redimensionnement du graphique pour qu'il forme un cube parfait
aspect3d(x = 1, y = 1, z = 1)

#Ajout d'axes au graphique
axes3d()

#Ajout d'un titre au graphique et aux axes
title3d(xlab = "longitude", ylab = "latitude", zlab = "profondeur (km)", 
        main = "Pronfondeur de 1000 seismes aux alentours de Fidji selon leur latitude et longitude")

À cette étape, nous utilisons le graphique que nous venons de construire et ajoutons certains éléments comme un plan séparant l’ouest et l’est et différents textes pour donner des exemples supplémentaires sur l’utilisation de fonctions permettant l’ajout d’éléments graphiques.

#Création d'un plan séparant le graphique selon l'est et l'ouest
planes3d(a = -1, b = 0, c = 0, d = 175, col = "blue", alpha = 0.3)

#Ajout de text identifiant les différentes sections du graphique
text3d(x = 187, y = -30, z =  600, text = "Est")
text3d(x = 168, y = -30, z =  600, text = "Ouest")

#Retrouve les informations du seisme le plus puissant du jeux de données
rowPlusGrosSeisme <- quakes[which.max(quakes$mag), ]

#Ajout d'une flèche qui pointe la sphère correspondant au seisme le plus puissant
arrow3d(p0 = c(170, -30, 490), p1 = c(rowPlusGrosSeisme$long, rowPlusGrosSeisme$lat, rowPlusGrosSeisme$depth),
        type = "rotation", s =  1/30, n = 4)

#Ajout d'un texte donnant des informations sur la donnée pointée
text3d(x = 170, y = -30, z = 500, text = "Seisme le plus fort", cex = 0.8)

Ajout de formes géométriques complexes

Cette sous-section présente les principales fonctions utiles à la construction de formes en 3D complexes et propose un exemple permettant d’illustrer la création de ces formes. Le tableau qui suit présente les fonctions de base permettant la création de formes complexes.

Fonction Description
shape3d permet d’ajouter des forme géométrique
polygon3d génère un polygone
ellipse3d génère un élipse
shapelist3d permet de générer un liste de formes

Voici un exemple sur la création de deux ellipses représentant la variance et la covariance des données de l’est et de l’ouest.

#Création de jeux de données contenant les données selon leur position géographique
quakes_est <- quakes[quakes$region == "Est",]
quakes_ouest <- quakes[quakes$region == "Ouest",]

#Création d'une élipse à partir des informations sur la longitude, la latitude et 
#de la profondeur des différents séismes contenus dans le jeux de données quakes
ellipse_est <- ellipse3d(
  x = cov(cbind(quakes_est$long, quakes_est$lat, quakes_est$depth)), 
  centre = c(mean(quakes_est$long), mean(quakes_est$lat), mean(quakes_est$depth))
)

ellipse_ouest <- ellipse3d(
  x = cov(cbind(quakes_ouest$long, quakes_ouest$lat, quakes_ouest$depth)), 
  centre = c(mean(quakes_ouest$long), mean(quakes_ouest$lat), mean(quakes_ouest$depth))
)

#Ajout de l'élipse dans le graphique en 3D
plot3d(ellipse_est, col = "orange", alpha = 0.2, add = TRUE, box = FALSE)
plot3d(ellipse_ouest, col = "yellow", alpha = 0.2, add = TRUE, box = FALSE)

aspect3d(x = 1, y = 1, z = 1)

Ajout de contrôles

L’ajout de contôles personnalisés est une particularité du package rgl. Ceux-ci permettent des options plaisantes pouvant améliorer l’interactivité et les manipulations possibles de l’utilisateur vis-à-vis les graphiques produits. Le tableau suivant énumère quelques fonctions permettant l’ajout de contôles ainsi qu’une légère description de leur utilité propre.

Fonction Description
subsetControl Contrôle quels objets sont affichés
playWidget Affiche des contôles automatisés
toggleWidget Affichage de boutons contrôlant les données affichées
Polar Rotation du graphique selon les coordonnées polaires
%>% Opérateur pipe importé du package magrittr
figHeight, figWidth Dimensions des figures dans un document R Markdown
rglMouse Change les mode de la souris dans une scène rgl
asRow Fait l’arrangement de plusieurs objets dans un affichage HTML

Les sous-sections qui suivent présentent des exemples d’utilisation de certaines de ces fonctions dans diverses situations.

Annimation automatisée

Certains boutons peuvent être ajoutés pour aider les interactions avec le graphique. Comme vous le verrez dans l’exemple ci-dessous, la fonction playwidget nous donne accès aux boutons “Reverse”,“Play”,“Slower”,“Faster” et “Reset” servant à lancer une vidéo. Le code suivant sert à créer une matrice de rotation afin que celle-ci soit utilisée pour faire tourner le graphique en trois dimensions durant la vidéo. L’option userMatrix permet de créer une matrice 4 par 4 spécifiant le point de vue de l’utilisateur. Pour sa part, la fonction par3dinterp permet d’ajuster au fil du temps des options par3d et ainsi être utilisée dans une animation. Nous pouvons aussi voir de quelle façon nous ferons apparaître ce widget tout en lui assignant la matrice de rotation. Ici, la fonction par3dinterpControl, sert à gérer toutes les options conçernant la vidéo comme la durée, la vitesse et bien plus.

#Création du graphique
plot3d(x = quakes$long, y = quakes$lat, z = quakes$depth, type = 's', col = quakes$magCol,
       size = quakes$mag/4, main = "Longitude, latitude et profondeur des seismes selon la region")

#Créer la matrice du point de vue de l'utilisateur 
MatriceVue <- r3dDefaults$userMatrix

#Créer les transformations, ici rotations de la matrice du point de vue
ModifParametre <- par3dinterp(time = (0:2), userMatrix = list(MatriceVue,
                                      rotate3d(MatriceVue, pi/3, 5, 0, 4),
                                      rotate3d(MatriceVue, pi/3, 0, 1, 2)) )
#Permet à la sortie d'être affichée en HTML
rglwidget() %>%
  
#Permet de rajouter les boutons pour démarer et contrôler l'animation  
playwidget(par3dinterpControl(ModifParametre, 0, 4, steps=10),
           step = 0.05, loop = TRUE, rate = 0.5)

Contrôles pour manipuler les données

Une autre fonction plus avancée est de séparer le jeu de données en plusieurs classes afin de pouvoir faire apparaitre et disparaitre certaines classes précises. Cela est démontré dans l’exemple ci-dessous, où trois classes ont été créées en fonction de la magnitude des séismes. Encore une fois, c’est grâce à des boutons que nous serons capable de contrôler les données voulues. C’est la fonction toggleWidget qui nous sera utile pour cet exemple afin de faire apparaître différents boutons et de leur assigner une classe.

#Supprime les paramètres du graphique précédent
clear3d()

#Création de la variable Mag_4 contenant les données en 3D des séismes de magnitude 4
Mag_4 <- with(subset(quakes, magFactor == "4"), 
              spheres3d(x = long, y = lat, z =  depth, col = magCol, radius = 6))

#Création de la variable Mag_5 contenant les données en 3D des séismes de magnitude 5
Mag_5 <- with(subset(quakes, magFactor == "5"), 
              spheres3d(x = long, y = lat, z =  depth, col = magCol, radius = 6))

#Création de la variable Mag_6 contenant les données en 3D des séismes de magnitude 6
Mag_6 <- with(subset(quakes, magFactor == "6"), 
              spheres3d(x = long, y = lat, z =  depth, col = magCol, radius = 6))

#Mise en forme des proportions du graphique
aspect3d(1,1,1)

#Rajout des options supplémentaires du graphique comme les titres et la forme des points 
decorate3d(xlab = "longitude", ylab = "latitude", zlab = "profondeur (km)",
           main = "Longitude, latitude et profondeur des seismes selon la region",
           col = quakes$magCol, type = "s", size = quakes$mag/4 , box = FALSE)

#Permet à la sortie d'être affichée en HTML
rglwidget() %>%
  
#Rajout de 3 boutons côte à côte étant associés aux variables créées plus haut
toggleWidget(ids = Mag_4) %>%
toggleWidget(ids = Mag_5) %>%
toggleWidget(ids = Mag_6) %>%
asRow(last = 3)

Contrôle sur les fonctionnalités de la souris

La fonction rglMouse nous permet de sélectionner l’interaction que nous voulons avoir avec le graphique. Par défaut, on y retrouve les options Selecting, Trackball,xAxis,yAxis,zAxis,Polar,Zoom,Fov et None. Lorsqu’une option est sélectionnée, celle-ci peut être utilisée avec le clic gauche de la souris. L’option mouseMode nous permet de choisir par défaut l’option que l’on veut au départ. Voici un petit tableau expliquant brièvement chaque option :

Options Fonction réalisée par le clic gauche de la souris
Selecting Selection d’une portion des données du graphique
Trackball Rotation du graphique selon n’importe quelles axes
xAxis, yAxis, zAxis Rotation du graphique selon l’axe choisi
Polar Rotation du graphique selon les coordonnées polaires
Zoom, Fov Deux options de zoom, Fov étant plus rapide
None Le clic gauche ne fait rien
#Création du graphique
plot <- plot3d(x = quakes$long, y = quakes$lat, z = quakes$depth,
               xlab = "longitude", ylab = "latitude", zlab = "profondeur (km)", 
               main = "Longitude, latitude et profondeur des seismes selon la region", 
               col = quakes$magCol, type = "s", size = 1, box = FALSE)

#Sélection de l'option par défault
par3d(mouseMode = "trackball")

#Nous permettons a l'option rglMouse d'intéragir avec les données du graphiques
rglwidget(shared = rglShared(plot["data"])) %>%
  
#Sélection des options contenus dans le boutons
rglMouse(choice = c("trackball", "xAxis", "yAxis", "zAxis", "polar", "zoom", "fov"))