We’ll use the rgl package, which provides an interface to the OpenGL graphics library for 3D graphics. To create a 3D scatter plot, as in Figure 13.14, use
plot3d() 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.
# You may need to install first, with install.packages("rgl") library(rgl) plot3d(mtcars$wt, mtcars$disp, mtcars$mpg, type = "s", size = 0.75, lit = FALSE)
If you are using a Mac, you will need to install XQuartz before you can use rgl. You can download it from https://www.xquartz.org/.
Viewers can rotate the image by clicking and dragging with the mouse, and zoom in and out with the scroll wheel.
plot3d()uses square points, which do not appear properly when saving to a PDF. For improved appearance, the example above uses
type="s"for spherical points, made them smaller with
size=0.75, and turned off the 3D lighting with
lit=FALSE(otherwise they look like shiny spheres).
Three-dimensional scatter plots can be difficult to interpret, so it’s often better to use a two-dimensional representation of the data. That said, there are things that can help make a 3D scatter plot easier to understand.
In Figure 13.15, 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 function(v1, v2) as.vector(rbind(v1,v2)) interleave <- # 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")
It’s possible to tweak the appearance of the background and the axes. In Figure 13.16, we 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)