Chapter 7. Three-Dimensional Graphics and Plots

Maybe I’ll win Saved by zero Holding onto Winds that teach me I will conquer Space around me

Modern mathematics demands advanced visualization tools. Although Mathematica’s 2D graphics are impressive, 3D graphics is where Mathematica really distinguishes itself. As with 2D, 3D graphics are represented symbolically but with the head Graphics3D instead of Graphics. There are 3D counterparts to most 2D plotting functions. For example, Plot3D and ListPlot3D are the counterparts to the 2D functions Plot and ListPlot. There are also many functions unique to 3D space, such as SphericalPlot3D and RevolutionPlot3D.

Mathematica’s 3D graphics are interactive, although it is difficult to illustrate this in book form! Any 3D plot or drawing can be rotated, flipped, and stretched, allowing you to see different perspectives. Furthermore, Mathematica 6 added a host of options for controlling lighting, camera placement, and even how light reflects off of surfaces (see 7.12 Controlling Viewing Geometry and 7.13 Controlling Lighting and Surface Properties).

I think most users are quite impressed with the breadth and depth of what Mathematica 7 can achieve with plotting functions (see 7.1 Plotting Functions of Two Variables in Cartesian Coordinates through 7.9 Plotting 3D Regions Where a Predicate Is Satisfied). However, as a programmer, I am even more taken with what can be achieved in Mathematica that would be next to impossible in most plotting packages outside of Mathematica. When you ask the Mathematica kernel to perform a plot, it does not produce a raster image that the frontend simply renders using the graphics hardware. Instead, it produces a symbolic representation of the plot that the frontend translates into a raster image. Why is this relevant? Imagine you were working in another domain (e.g., Microsoft Excel) and there were two plotting functions that each did half of what you wanted to render on the screen. How could you morph those two plots to achieve the desired result? You couldn’t. (I’m ignoring whatever skills you might possess as a Photoshop hacker!) In Mathematica, all hope is not lost. In 7.6 Combining 2D Contours with 3D Plots, a 3D plot and a 2D contour plot are combined to achieve a 3D plot with a 2D contour "shadow" underneath. Another example is 7.10 Displaying 3D Geometrical Shapes: RevolutionPlot3D is used to generate a cone to compensate for the lack of a Cone primitive in Mathematica 6 (Cone is built into Mathematica 7). Achieving these results involves sticking your head under the hood and, sometimes, doing quite a bit of trial and error, but the results are within reach once you have the general principles.

In 18.5 Compiling Functions to Improve Performance, I discuss how the attributes of 3D graphics can be controlled through stylesheets. If you intend to create publication-quality documents in Mathematica, you should familiarize yourself with stylesheets.

As you might suspect, Plot3D has a variety of options for customizing presentation. Here I use Complement to list only those options that differ from the 2D Plot function in 6.1 Plotting Functions in Cartesian Coordinates.

In[3]:=  Complement[First /@ Options[Plot3D], First /@ Options[Plot]]
Out[3]=  {AxesEdge, BoundaryStyle, Boxed, BoxRatios, BoxStyle, ControllerLinking,
          ControllerMethod, ControllerPath, FaceGrids, FaceGridsStyle,
          Lighting, NormalsFunction, RotationAction, SphericalRegion, ViewAngle,
          ViewCenter, ViewMatrix, ViewPoint, ViewRange, ViewVector, ViewVertical}

AxesEdge determines where the axes are drawn, and the default value of Automatic (Figure 7-2) usually gives good results. You can override the default by proving a specification of the form {{dir y, dir z},{dir x, dir z},{dir x, dir y}} where each dir i must be either +1 or -1, indicating whether axes are drawn on the edge of the box with a larger or smaller value of coordinate i, respectively (Figure 7-2).

BoundaryStyle allows you to stylize the edge of a plot surface.

Examples of AxesEdge option

Boxed, BoxRatios, and BoxStyle control the presence, proportions, and style of the edges surrounding 3D plots. Each of the plots in Figure 7-3 is of the same function. The differences are that Figure 7-3 is not boxed, Figure 7-3 is boxed with Automatic ratios, and Figure 7-3 and Figure 7-3 have specified ratios.

FaceGrids specifies grid lines to draw on the faces of the bounding box. You can specify All or specific faces using {x,y,z}, where two values are 0 and the third is either +1 (largest value) or -1 (smallest value). FaceGridsStyle allows you to stylize the grid to your liking.

Examples of BoxRatios option

See 7.4 Plotting 3D Surfaces Parametrically for the relationship between SphericalPlot3D and ParametricPlot3D.

The following solution was developed by Ulises Cervantes-Pimentel and Chris Carlson of Wolfram Research. As with 7.6 Combining 2D Contours with 3D Plots, the trick is to leverage Mathematica’s symbolic representation of 3D graphics and to perform transformations on that representation to yield the desired result.

You begin with the shape of interest. Here Chris Carlson was interested in an architectural model of a bubblelike structure. Note the use of the Mesh option, which is central to extracting the wireframe.

Solution

You can go directly to a wireframe by simply extracting the lines.

Solution

7.13 Controlling Lighting and Surface Properties covers Lighting and Specularity.

Chris Carlson gave a superb presentation at the 2009 International Mathematica User Conference (IMUC). This post on the Wolfram Blog covers a good portion of the talk: http://bit.ly/291CDE.

Mathematica provides quite sophisticated control of light via the options Lighting, Specularity, and Glow. The simplest settings for Lighting are Automatic, "Neutral", and None (Figure 7-13).

For more sophisticated control, you can specify combinations of ambient, directional, spot, and point light sources (Figure 7-14). Try the code on your own for the full effect.

Glow is the opposite of Lighting. It specifies the color of the surface itself. Glow is also different from an object’s color, as you can see in Figure 7-15. (However, Glow is not easily demonstrated in monochrome print. Please try the code on your own to see the effect.) Both the cylinder and the sphere have a green color, but the cylinder also has a green glow. There is no lighting, so only the cylinder appears bright because of Glow. Another way Glow differs from Lighting is that it does not affect surrounding objects, only the objects with Glow. In other words, a glowing object is not a light source in the Graphics3D domain.

Use Scale to stretch or shrink graphics.

Solution

Use Translate to move graphics in 3D space. Figure 7-16 presents four translations of a sphere that is originally constructed at the origin.

Use Rotate to change the orientation of graphics. Figure 7-17 rotates a cube through Pi/4 radians (45 degrees) but uses different vectors to define the rotation axis.

PolyhedraData contains a treasure trove of polyhedra information. In the solution we demonstrate how to extract graphics by name. Here we show the input form of a cube.

   In[66]:=  PolyhedronData["Cube"] // InputForm
Out[66]//InputForm=
             Graphics3D[GraphicsComplex[{{-1/2, -1/2, -1/2}, {-1/2, -1/2, 1/2}, {-1/2,
             1/2, -1/2}, {-1/2, 1/2, 1/2}, {1/2, -1/2, -1/2},
                {1/2, -1/2, 1/2}, {1/2, 1/2, -1/2}, {1/2, 1/2, 1/2}}, Polygon[{{8, 4, 2,
             6}, {8, 6, 5, 7}, {8, 7, 3, 4}, {4, 3, 1, 2},
                 {1, 3, 7, 5}, {2, 1, 5, 6}}]]]

The solution also exploits the ability to list all the polyhedra by providing no arguments. The solution used the first 20, but there are many more, as you can see.

In[67]:=  Length[PolyhedronData[]]
Out[67]=  187

You can explore all of them with this little dynamic widget.

Discussion

The polyhedra are grouped into classes. You can get a list of these classes or a list of the members of a particular class.

In[69]:=  PolyhedronData["Classes"]
Out[69]=  {Amphichiral, Antiprism, Archimedean, ArchimedeanDual, Chiral, Compound,
           Concave, Convex, Cuboid, Deltahedron, Dipyramid, Equilateral, Hypercube,
           Johnson, KeplerPoinsot, Orthotope, Platonic, Prism, Pyramid, Quasiregular,
           RectangularParallelepiped, Rhombohedron, Rigid, SelfDual, Shaky,
           Simplex, SpaceFilling, Stellation, Uniform, UniformDual, Zonohedron}

In[70]:=  PolyhedronData["Chiral"]
Out[70]=  {GyroelongatedPentagonalBicupola, GyroelongatedPentagonalBirotunda,
           GyroelongatedPentagonalCupolarotunda, GyroelongatedSquareBicupola,
           GyroelongatedTriangularBicupola, PentagonalHexecontahedron,
           PentagonalIcositetrahedron, SnubCube, SnubDodecahedron}

Polyhedra also have various properties, which you can list or use with a polyhedron to retrieve the value.

In[71]:=  PolyhedronData["Properties"]
Out[71]=  {AdjacentFaceIndices, AlternateNames, AlternateStandardNames, Amphichiral,
           Antiprism, Archimedean, ArchimedeanDual, Centroid, Chiral, Circumcenter,
           Circumradius, Circumsphere, Classes, Compound, Concave, Convex, Cuboid,
           DefaultOrientation, Deltahedron, DihedralAngleRules, DihedralAngles,
           Dipyramid, DualCompound, DualName, DualScale, EdgeCount, EdgeIndices,
           EdgeLengths, Edges, Equilateral, FaceCount, FaceCountRules, FaceIndices,
           Faces, GeneralizedDiameter, Hypercube, Image, Incenter, InertiaTensor,
           Information, Inradius, Insphere, Johnson, KeplerPoinsot, Midcenter,
           Midradius, Midsphere, Name, NetCoordinates, NetCount, NetEdgeIndices,
           NetEdges, NetFaceIndices, NetFaces, NetImage, NotationRules,
           Orientations, Orthotope, Platonic, PolyhedronIndices, Prism, Pyramid,
           Quasiregular, RectangularParallelepiped, RegionFunction, Rhombohedron,
           Rigid, SchlaefliSymbol, SelfDual, Shaky, Simplex, SkeletonCoordinates,
           SkeletonGraphName, SkeletonImage, SkeletonRules, SpaceFilling,
           StandardName, StandardNames, Stellation, StellationCount, SurfaceArea,
           SymmetryGroupString, Uniform, UniformDual, VertexCoordinates,
           VertexCount, VertexIndices, Volume, WythoffSymbol, Zonohedron}

In[72]:=  PolyhedronData["GyroelongatedPentagonalBicupola", "VertexCount"]
Out[72]=  30
Discussion

Skeletal images show the polygons in terms of connected graphs.

Discussion

NetImage is my favorite aspect of PolyhedronData because it shows how to make a cutout that can be folded into an actual 3D model of the named polyhedron. My kids like this one, too, although I have to do all the tedious parts!

Discussion