3-Dimensional (3-D) Visualization using R

In this Blog I would be showing few simple methods to visualize data in 3-D form. A part of it has been borrowed from an excellent book “R Graphics Cookbook - Winston Chang”. This is an excellent book to learn the basics of Data Visualization using R. I would highly recommend chapter - 15 of the Book Getting Your Data into Shape as the author has covered most frequently needed/used , simple yet effective, techniques to prepare the data as it acts like crash-course for an amateur Data-Science enthusiast like me.

We’ll use the rgl package, which provides an interface to the OpenGL graphics library for 3D graphics.

Let us first install the package rgl using a smart and effective style of coding which can be generalized and used when we need to install multiple packages in our program.

#
#The list of packages to be loaded. I already have ggplot2 package in my R environment and I need to install rgl package. This code should work fine for both cases.
#
list.of.packages <- c("rgl","ggplot2","knitr","rglwidget")
#
#You should be able to simply reuse the following lines of code as is
#
new.packages <- list.of.packages[!(list.of.packages %in% installed.packages()[,"Package"])]
#
if(length(new.packages)) install.packages(new.packages)
#
# By now we have installed the requisite packages. Time to load them .
#
lapply(list.of.packages,function(x){library(x,character.only=TRUE)})
## Warning: package 'rgl' was built under R version 3.2.5
## Warning: package 'ggplot2' was built under R version 3.2.4
## Warning: package 'knitr' was built under R version 3.2.5
## Warning: package 'rglwidget' was built under R version 3.2.5
## [[1]]
## [1] "rgl"       "stats"     "graphics"  "grDevices" "utils"     "datasets" 
## [7] "methods"   "base"     
## 
## [[2]]
## [1] "ggplot2"   "rgl"       "stats"     "graphics"  "grDevices" "utils"    
## [7] "datasets"  "methods"   "base"     
## 
## [[3]]
##  [1] "knitr"     "ggplot2"   "rgl"       "stats"     "graphics" 
##  [6] "grDevices" "utils"     "datasets"  "methods"   "base"     
## 
## [[4]]
##  [1] "rglwidget" "knitr"     "ggplot2"   "rgl"       "stats"    
##  [6] "graphics"  "grDevices" "utils"     "datasets"  "methods"  
## [11] "base"
#
knit_hooks$set(webgl = hook_webgl)

We will be using mtcars data that comes with R installation . Let us have a quick look at mtcars data.

#
head(mtcars)
##                    mpg cyl disp  hp drat    wt  qsec vs am gear carb
## Mazda RX4         21.0   6  160 110 3.90 2.620 16.46  0  1    4    4
## Mazda RX4 Wag     21.0   6  160 110 3.90 2.875 17.02  0  1    4    4
## Datsun 710        22.8   4  108  93 3.85 2.320 18.61  1  1    4    1
## Hornet 4 Drive    21.4   6  258 110 3.08 3.215 19.44  1  0    3    1
## Hornet Sportabout 18.7   8  360 175 3.15 3.440 17.02  0  0    3    2
## Valiant           18.1   6  225 105 2.76 3.460 20.22  1  0    3    1
#
str(mtcars)
## 'data.frame':    32 obs. of  11 variables:
##  $ mpg : num  21 21 22.8 21.4 18.7 18.1 14.3 24.4 22.8 19.2 ...
##  $ cyl : num  6 6 4 6 8 6 8 4 4 6 ...
##  $ disp: num  160 160 108 258 360 ...
##  $ hp  : num  110 110 93 110 175 105 245 62 95 123 ...
##  $ drat: num  3.9 3.9 3.85 3.08 3.15 2.76 3.21 3.69 3.92 3.92 ...
##  $ wt  : num  2.62 2.88 2.32 3.21 3.44 ...
##  $ qsec: num  16.5 17 18.6 19.4 17 ...
##  $ vs  : num  0 0 1 1 0 1 0 1 1 1 ...
##  $ am  : num  1 1 1 0 0 0 0 0 0 0 ...
##  $ gear: num  4 4 4 3 3 3 3 4 4 4 ...
##  $ carb: num  4 4 1 1 2 1 4 2 2 4 ...

3-D Scatterplot

To create a 3-D Scatterplot, use plot3d() function (from rgl package) and pass in a data frame where the first three columns represent x, y, and z coordinates, or pass in three vectors representing the x, y, and z coordinates.

#
#
# Viewers can rotate the image by clicking and dragging with the mouse, and zoom in and out with the scroll wheel.
#
plot3d(mtcars$wt, mtcars$disp, mtcars$mpg, type="s", size=1, lit=TRUE, main = "Car Weight Vs Engine Displacement Vs Mileage",sub="3-D Plot")

You must enable Javascript to view this page properly.

You can click on the plot and drag it to rotate it. Try it out.

You can click on this graph and rotate it to have a 3-D look at the graph from different angles.

To improve its appearance, let us make a few changes -

#
#
# Viewers can rotate the image by clicking and dragging with the mouse, and zoom in and out with the scroll wheel.
#
plot3d(mtcars$wt, mtcars$disp, mtcars$mpg, type="p", size=5, lit=FALSE,box=FALSE, col = c("red","blue","green"),expand = 1, main = "Car Weight Vs Engine Displacement Vs Mileage",sub="3-D Plot", xlab = "Weight", ylab="Engine Disp",zlab = "Mileage")
#
#
# Add bounding box decoration
rgl.bbox(color=c("#333377","black"), emission="#112233",
         specular="#1A2B3C", shininess=5, alpha=0.8, nticks = 3 ) 
#
#
# Change the axis aspect ratios
#
aspect3d(1,1,1)
#
# In order to Animate this 3D plot, you may use the following commands which would automatically roate the plot
#
# play3d(spin3d())   # This has been commented as it would otherwise not allow to move ahead with script execution
#
# Spin on x-axis, at 4 rpm, for 20 seconds
#
# play3d(spin3d(axis=c(1,0,0), rpm=4), duration=20)
#

You must enable Javascript to view this page properly.

You can click on the plot and drag it to rotate it. Try it out.

Adding vertical segments to 3-D Plot

Three-dimensional scatter plots can be difficult to interpret, we’ll add vertical segments to help give a sense of the spatial positions of the points

#
# Function to interleave the elements of two vectors
#
interleave <- function(v1, v2) as.vector(rbind(v1,v2))
#
# Plot the points
#
plot3d(mtcars$wt, mtcars$disp, mtcars$mpg, xlab="Weight", ylab="Displacement", zlab="MPG", size=.75, type="s", lit=FALSE)
#
# Add the segments
#
segments3d(interleave(mtcars$wt, mtcars$wt),interleave(mtcars$disp, mtcars$disp),interleave(mtcars$mpg, min(mtcars$mpg)), alpha=0.4, col="blue")

You must enable Javascript to view this page properly.

You can click on the plot and drag it to rotate it. Try it out.

Making further customizations to the 3-D Plot

Let us further tweak the appearance of the background and the axes. Here we would also change the number of tick marks and add tick marks and axis labels to the specified sides.

#
# Make plot without axis ticks or labels
#
plot3d(mtcars$wt, mtcars$disp, mtcars$mpg,xlab = "", ylab = "", zlab = "",axes = FALSE,
size=.75, type="s", lit=FALSE)
#
#
segments3d(interleave(mtcars$wt, mtcars$wt),interleave(mtcars$disp, mtcars$disp),interleave(mtcars$mpg, min(mtcars$mpg)),alpha = 0.4, col = "blue")
#
# Draw the box.
#
rgl.bbox(color="grey50", # grey60 surface and black text
emission="grey50", # emission color is grey50
xlen=0, ylen=0, zlen=0) # Don't add tick marks
#
# Set default color of future objects to black
#
rgl.material(color="black")
#
#
# Add axes to specific sides. Possible values are "x--", "x-+", "x+-", and "x++".
#
axes3d(edges=c("x--", "y+-", "z--"),
ntick=6, # Attempt 6 tick marks on each side
cex=.75) # Smaller font
#
#
# Add axis labels. 'line' specifies how far to set the label from the axis.
#
mtext3d("Weight", edge="x--", line=2)
mtext3d("Displacement", edge="y+-", line=3)
mtext3d("MPG", edge="z--", line=3)

You must enable Javascript to view this page properly.

You can click on the plot and drag it to rotate it. Try it out.

Adding a Prediction Surface to a Three-Dimensional (3-D) Plot

Here we add a surface of predicted value to a three-dimensional scatter plot.

We will make a linear model from the data and plot it as a mesh along with the data, using the surface3d() function. Let us plot the mesh now -

#
# Make a copy of the data set
m <- mtcars
#
# Generate a linear model
#
mod <- lm(mpg ~ wt + disp + wt:disp, data = m) # wt:disp is used to capture interaction between weight and displacement
#

# Get predicted values of mpg from wt and disp
#
m$pred_mpg <- predict(mod)
#

# Get predicted mpg from a grid of wt and disp  
#
# Find the range of the predictor variable. This works for lm and glm
# and some others, but may require customization for others.
#
# define some simple variable 
#
model<-mod
xvar<-"wt"
yvar<- "disp"
zvar<- "mpg"
res <- 16  # This will be the number of values generated when used in seq function


#
(xrange <- range(model$model[[xvar]]) )
## [1] 1.513 5.424
(yrange <- range(model$model[[yvar]]))
## [1]  71.1 472.0
#

newdata <- expand.grid(x = seq(xrange[1], xrange[2], length.out = res),
                       y = seq(yrange[1], yrange[2], length.out = res)) 


str(newdata)
## 'data.frame':    256 obs. of  2 variables:
##  $ x: num  1.51 1.77 2.03 2.3 2.56 ...
##  $ y: num  71.1 71.1 71.1 71.1 71.1 71.1 71.1 71.1 71.1 71.1 ...
##  - attr(*, "out.attrs")=List of 2
##   ..$ dim     : Named num  16 16
##   .. ..- attr(*, "names")= chr  "x" "y"
##   ..$ dimnames:List of 2
##   .. ..$ x: chr  "x=1.513000" "x=1.773733" "x=2.034467" "x=2.295200" ...
##   .. ..$ y: chr  "y= 71.10000" "y= 97.82667" "y=124.55333" "y=151.28000" ...
#
#
head(newdata)
##          x    y
## 1 1.513000 71.1
## 2 1.773733 71.1
## 3 2.034467 71.1
## 4 2.295200 71.1
## 5 2.555933 71.1
## 6 2.816667 71.1
#

(names(newdata) <- c(xvar, yvar))
## [1] "wt"   "disp"
newdata[[zvar]] <- predict(model, newdata = newdata, type = NULL) 

#
# This is our final dataframe with predicted value
#
head(newdata)
##         wt disp      mpg
## 1 1.513000 71.1 31.50617
## 2 1.773733 71.1 30.02953
## 3 2.034467 71.1 28.55288
## 4 2.295200 71.1 27.07624
## 5 2.555933 71.1 25.59960
## 6 2.816667 71.1 24.12295
#
#

(x <- unique(newdata[[xvar]]))
##  [1] 1.513000 1.773733 2.034467 2.295200 2.555933 2.816667 3.077400
##  [8] 3.338133 3.598867 3.859600 4.120333 4.381067 4.641800 4.902533
## [15] 5.163267 5.424000
#
(y <- unique(newdata[[yvar]]))
##  [1]  71.10000  97.82667 124.55333 151.28000 178.00667 204.73333 231.46000
##  [8] 258.18667 284.91333 311.64000 338.36667 365.09333 391.82000 418.54667
## [15] 445.27333 472.00000
#
(z <- matrix(newdata[[zvar]], nrow = length(y), ncol = length(x)))
##            [,1]      [,2]      [,3]      [,4]     [,5]     [,6]     [,7]
##  [1,] 31.506172 30.473243 29.440315 28.407386 27.37446 26.34153 25.30860
##  [2,] 30.029528 29.078169 28.126810 27.175451 26.22409 25.27273 24.32137
##  [3,] 28.552884 27.683095 26.813306 25.943517 25.07373 24.20394 23.33415
##  [4,] 27.076241 26.288021 25.499801 24.711582 23.92336 23.13514 22.34692
##  [5,] 25.599597 24.892947 24.186297 23.479647 22.77300 22.06635 21.35970
##  [6,] 24.122954 23.497873 22.872793 22.247712 21.62263 20.99755 20.37247
##  [7,] 22.646310 22.102799 21.559288 21.015777 20.47227 19.92876 19.38524
##  [8,] 21.169667 20.707725 20.245784 19.783843 19.32190 18.85996 18.39802
##  [9,] 19.693023 19.312651 18.932280 18.551908 18.17154 17.79116 17.41079
## [10,] 18.216380 17.917578 17.618775 17.319973 17.02117 16.72237 16.42357
## [11,] 16.739736 16.522504 16.305271 16.088038 15.87081 15.65357 15.43634
## [12,] 15.263093 15.127430 14.991767 14.856104 14.72044 14.58478 14.44911
## [13,] 13.786449 13.732356 13.678262 13.624169 13.57008 13.51598 13.46189
## [14,] 12.309806 12.337282 12.364758 12.392234 12.41971 12.44719 12.47466
## [15,] 10.833162 10.942208 11.051254 11.160299 11.26935 11.37839 11.48744
## [16,]  9.356519  9.547134  9.737749  9.928365 10.11898 10.30960 10.50021
##           [,8]     [,9]    [,10]    [,11]    [,12]    [,13]    [,14]
##  [1,] 24.27567 23.24274 22.20982 21.17689 20.14396 19.11103 18.07810
##  [2,] 23.37002 22.41866 21.46730 20.51594 19.56458 18.61322 17.66186
##  [3,] 22.46436 21.59457 20.72478 19.85499 18.98520 18.11541 17.24562
##  [4,] 21.55870 20.77048 19.98226 19.19404 18.40582 17.61760 16.82938
##  [5,] 20.65305 19.94640 19.23975 18.53310 17.82645 17.11980 16.41315
##  [6,] 19.74739 19.12231 18.49723 17.87215 17.24707 16.62199 15.99691
##  [7,] 18.84173 18.29822 17.75471 17.21120 16.66769 16.12418 15.58067
##  [8,] 17.93608 17.47414 17.01219 16.55025 16.08831 15.62637 15.16443
##  [9,] 17.03042 16.65005 16.26968 15.88931 15.50893 15.12856 14.74819
## [10,] 16.12476 15.82596 15.52716 15.22836 14.92956 14.63075 14.33195
## [11,] 15.21911 15.00188 14.78464 14.56741 14.35018 14.13295 13.91571
## [12,] 14.31345 14.17779 14.04213 13.90646 13.77080 13.63514 13.49947
## [13,] 13.40780 13.35370 13.29961 13.24552 13.19142 13.13733 13.08323
## [14,] 12.50214 12.52962 12.55709 12.58457 12.61204 12.63952 12.66700
## [15,] 11.59648 11.70553 11.81457 11.92362 12.03267 12.14171 12.25076
## [16,] 10.69083 10.88144 11.07206 11.26267 11.45329 11.64390 11.83452
##          [,15]    [,16]
##  [1,] 17.04517 16.01224
##  [2,] 16.71050 15.75914
##  [3,] 16.37583 15.50604
##  [4,] 16.04116 15.25295
##  [5,] 15.70650 14.99985
##  [6,] 15.37183 14.74675
##  [7,] 15.03716 14.49365
##  [8,] 14.70249 14.24055
##  [9,] 14.36782 13.98745
## [10,] 14.03315 13.73435
## [11,] 13.69848 13.48125
## [12,] 13.36381 13.22815
## [13,] 13.02914 12.97505
## [14,] 12.69447 12.72195
## [15,] 12.35980 12.46885
## [16,] 12.02513 12.21575
#
mtlist <- list(x, y, z)
#
head(mtlist)
## [[1]]
##  [1] 1.513000 1.773733 2.034467 2.295200 2.555933 2.816667 3.077400
##  [8] 3.338133 3.598867 3.859600 4.120333 4.381067 4.641800 4.902533
## [15] 5.163267 5.424000
## 
## [[2]]
##  [1]  71.10000  97.82667 124.55333 151.28000 178.00667 204.73333 231.46000
##  [8] 258.18667 284.91333 311.64000 338.36667 365.09333 391.82000 418.54667
## [15] 445.27333 472.00000
## 
## [[3]]
##            [,1]      [,2]      [,3]      [,4]     [,5]     [,6]     [,7]
##  [1,] 31.506172 30.473243 29.440315 28.407386 27.37446 26.34153 25.30860
##  [2,] 30.029528 29.078169 28.126810 27.175451 26.22409 25.27273 24.32137
##  [3,] 28.552884 27.683095 26.813306 25.943517 25.07373 24.20394 23.33415
##  [4,] 27.076241 26.288021 25.499801 24.711582 23.92336 23.13514 22.34692
##  [5,] 25.599597 24.892947 24.186297 23.479647 22.77300 22.06635 21.35970
##  [6,] 24.122954 23.497873 22.872793 22.247712 21.62263 20.99755 20.37247
##  [7,] 22.646310 22.102799 21.559288 21.015777 20.47227 19.92876 19.38524
##  [8,] 21.169667 20.707725 20.245784 19.783843 19.32190 18.85996 18.39802
##  [9,] 19.693023 19.312651 18.932280 18.551908 18.17154 17.79116 17.41079
## [10,] 18.216380 17.917578 17.618775 17.319973 17.02117 16.72237 16.42357
## [11,] 16.739736 16.522504 16.305271 16.088038 15.87081 15.65357 15.43634
## [12,] 15.263093 15.127430 14.991767 14.856104 14.72044 14.58478 14.44911
## [13,] 13.786449 13.732356 13.678262 13.624169 13.57008 13.51598 13.46189
## [14,] 12.309806 12.337282 12.364758 12.392234 12.41971 12.44719 12.47466
## [15,] 10.833162 10.942208 11.051254 11.160299 11.26935 11.37839 11.48744
## [16,]  9.356519  9.547134  9.737749  9.928365 10.11898 10.30960 10.50021
##           [,8]     [,9]    [,10]    [,11]    [,12]    [,13]    [,14]
##  [1,] 24.27567 23.24274 22.20982 21.17689 20.14396 19.11103 18.07810
##  [2,] 23.37002 22.41866 21.46730 20.51594 19.56458 18.61322 17.66186
##  [3,] 22.46436 21.59457 20.72478 19.85499 18.98520 18.11541 17.24562
##  [4,] 21.55870 20.77048 19.98226 19.19404 18.40582 17.61760 16.82938
##  [5,] 20.65305 19.94640 19.23975 18.53310 17.82645 17.11980 16.41315
##  [6,] 19.74739 19.12231 18.49723 17.87215 17.24707 16.62199 15.99691
##  [7,] 18.84173 18.29822 17.75471 17.21120 16.66769 16.12418 15.58067
##  [8,] 17.93608 17.47414 17.01219 16.55025 16.08831 15.62637 15.16443
##  [9,] 17.03042 16.65005 16.26968 15.88931 15.50893 15.12856 14.74819
## [10,] 16.12476 15.82596 15.52716 15.22836 14.92956 14.63075 14.33195
## [11,] 15.21911 15.00188 14.78464 14.56741 14.35018 14.13295 13.91571
## [12,] 14.31345 14.17779 14.04213 13.90646 13.77080 13.63514 13.49947
## [13,] 13.40780 13.35370 13.29961 13.24552 13.19142 13.13733 13.08323
## [14,] 12.50214 12.52962 12.55709 12.58457 12.61204 12.63952 12.66700
## [15,] 11.59648 11.70553 11.81457 11.92362 12.03267 12.14171 12.25076
## [16,] 10.69083 10.88144 11.07206 11.26267 11.45329 11.64390 11.83452
##          [,15]    [,16]
##  [1,] 17.04517 16.01224
##  [2,] 16.71050 15.75914
##  [3,] 16.37583 15.50604
##  [4,] 16.04116 15.25295
##  [5,] 15.70650 14.99985
##  [6,] 15.37183 14.74675
##  [7,] 15.03716 14.49365
##  [8,] 14.70249 14.24055
##  [9,] 14.36782 13.98745
## [10,] 14.03315 13.73435
## [11,] 13.69848 13.48125
## [12,] 13.36381 13.22815
## [13,] 13.02914 12.97505
## [14,] 12.69447 12.72195
## [15,] 12.35980 12.46885
## [16,] 12.02513 12.21575
#
str(mtlist)
## List of 3
##  $ : num [1:16] 1.51 1.77 2.03 2.3 2.56 ...
##  $ : num [1:16] 71.1 97.8 124.6 151.3 178 ...
##  $ : num [1:16, 1:16] 31.5 30 28.6 27.1 25.6 ...
#
(names(mtlist) <- c(xvar, yvar, zvar))
## [1] "wt"   "disp" "mpg"
#
# Make the plot with the data points
#
plot3d(m$wt, m$disp, m$mpg, type="s", size=0.5, lit=FALSE)
#
# Add the corresponding predicted points (smaller)
#
spheres3d(m$wt, m$disp, m$pred_mpg, alpha=0.4, type="s", size=0.5, lit=FALSE)

#
# Add line segments showing the error
#
segments3d(interleave(m$wt,   m$wt), interleave(m$disp, m$disp), interleave(m$mpg,  m$pred_mpg), alpha=0.4, col="red")
#
# Add the mesh of predicted values
#
surface3d(mtlist$wt, mtlist$disp, mtlist$mpg,alpha=0.4, front="lines", back="lines")

You must enable Javascript to view this page properly.

You can click on the plot and drag it to rotate it. Try it out.

We can further tweak the appearance of the graph for better visualization.

#
plot3d(mtcars$wt, mtcars$disp, mtcars$mpg,xlab = "", ylab = "", zlab = "",axes = FALSE,
size=.5, type="s", lit=FALSE)
#

#
# Add the corresponding predicted points (smaller)
#
spheres3d(m$wt, m$disp, m$pred_mpg, alpha=0.4, type="s", size=0.5, lit=FALSE)
#

# Add line segments showing the error
#
segments3d(interleave(m$wt, m$wt),interleave(m$disp, m$disp),interleave(m$mpg, m$pred_mpg),
alpha=0.4, col="red")
#
# Add the mesh of predicted values
#
surface3d(mtlist$wt, mtlist$disp, mtlist$mpg, alpha=0.4, front="lines", back="lines")
#
# Draw the box
#
rgl.bbox(color="grey50", # grey60 surface and black text

emission="grey50", # emission color is grey50

xlen=0, ylen=0, zlen=0) # Don't add tick marks

#
# Set default color of future objects to black
#
rgl.material(color="black")
#
# Add axes to specific sides. Possible values are "x--", "x-+", "x+-", and "x++".
#
axes3d(edges=c("x--", "y+-", "z--"),
       
ntick=6, # Attempt 6 tick marks on each side

cex=.75) # Smaller font

#
# Add axis labels. 'line' specifies how far to set the label from the axis.
#
mtext3d("Weight", edge="x--", line=2)
mtext3d("Displacement", edge="y+-", line=3)
mtext3d("MPG", edge="z--", line=3)

You must enable Javascript to view this page properly.

You can click on the plot and drag it to rotate it. Try it out.

Saving a Three-Dimensional Plot

If you want to save a three-dimensional plot created with the rgl package, use rgl.snapshot() to save a bitmap image of plot.This will capture the exact image that is on the screen.

plot3d(mtcars$wt, mtcars$disp, mtcars$mpg, type="s", size=0.75, lit=FALSE)
#
#
rgl.snapshot('3dplot.png', fmt='png') # Check your default directory using command getwd() for the location of the image.

You must enable Javascript to view this page properly.

You can also use rgl.postscript() to save a Postscript or PDF file using the following commands -

#
#rgl.postscript('C://PB Backup//R//3dplot.pdf', fmt='pdf')
#
#rgl.postscript('C://PB Backup//R//3dplot.ps', fmt='ps')

Note: Postscript and PDF output does not support many features of the OpenGL library on which rgl is based. For example, it does not support transparency, and the sizes of objects such as points and lines may not be the same as what appears on the screen.

To make the output more repeatable, you can save your current viewpoint and restore it later-

# Save the current viewpoint
#
(view <- par3d("userMatrix"))
##      [,1]       [,2]      [,3] [,4]
## [1,]    1  0.0000000 0.0000000    0
## [2,]    0  0.3420201 0.9396926    0
## [3,]    0 -0.9396926 0.3420201    0
## [4,]    0  0.0000000 0.0000000    1
#
# Restore the saved viewpoint
#
par3d(userMatrix = view)
#
# To save view in a script, you can use dput(), then copy and paste the output into your script
#
dput(view)
## structure(c(1, 0, 0, 0, 0, 0.342020143325668, -0.939692620785909, 
## 0, 0, 0.939692620785909, 0.342020143325668, 0, 0, 0, 0, 1), .Dim = c(4L, 
## 4L))
#
# Once you have the text representation of the userMatrix, add the following to your script
#
view<-structure(c(1, 0, 0, 0, 0, 0.342020143325668, -0.939692620785909, 
0, 0, 0.939692620785909, 0.342020143325668, 0, 0, 0, 0, 1), .Dim = c(4L, 
4L))
#
# And use the restored userMatrix
#
par3d(userMatrix = view)

You must enable Javascript to view this page properly.

Saving the Animated Three-Dimensional (3-D) Plot

To animate a 3D plot, use play3d() with spin3d()

# plot3d(mtcars$wt, mtcars$disp, mtcars$mpg, type="s", size=0.75, lit=FALSE)
#
# Owing to Blog rendering limitations, you might not see the spinning of the plot on the web-page here
#
# Use this command -  " play3d(spin3d()) "
#
# By default, the graph will be rotated on the z (vertical) axis, until you send a break command to R.
#
# You can change the rotation axis, rotation speed, and duration
# 
# Spin on x-axis, at 4 rpm, for 20 seconds
#
# play3d(spin3d(axis=c(1,0,0), rpm=4), duration=20)

You must enable Javascript to view this page properly.

To save the movie, use the movie3d() function in the same way as play3d(). It will generate a series of .png files, one for each frame, and then attempt to combine them into a single animated .gif file using the convert program from the ImageMagick image utility.

Hope you have enjoyed the journey to the realm of 3-D world with some good example using mtcars data.

To get a detailed understanding of rgl package use the following command in R ?rgl.material

Keep your ideas flowing !!!