3D Plots, in Python

(Easy version, without the "np" and "plt" namespaces.)

We first load in the toolboxes for numerical python and plotting.

Note the "import * " command will bring in the functions without any namespace labels.


In [1]:
%matplotlib inline
from numpy import *
from matplotlib.pyplot import *
from mpl_toolkits.mplot3d import Axes3D

Plotting a simple surface.

Let's plot the hyperbola $z = x^2 - y^2$.

The 3D plotting commands expect arrays as entries, so we create a mesh grid from linear variables $x$ and $y$, resulting in arrays $X$ and $Y$. We then compute $Z$ as a grid (array).


In [2]:
# Make data
x = linspace(-2, 2, 100)
y = linspace(-2, 2, 100)
X, Y = meshgrid(x, y)
Z = X**2 - Y**2

I don't know how to simply plot in matplotlib.

Instead, we have three steps

  • create a figure
  • indicated that the figure will be in 3D
  • then send the plot_surface command to the figure asix.

In [3]:
fig = figure()
ax = axes(projection='3d')
ax.plot_surface(X, Y, Z, color='b')


Out[3]:
<mpl_toolkits.mplot3d.art3d.Poly3DCollection at 0x112471f98>

Wireframe plots

Use the wireframe command. Note we can adjust the separation between lines, using the stride paameters.


In [4]:
fig = figure()
ax = axes(projection='3d')
ax.plot_wireframe(X, Y, Z, rstride=10, cstride=10)


Out[4]:
<mpl_toolkits.mplot3d.art3d.Line3DCollection at 0x112601b38>

Subplots

To make two plots, side-by-side, you make one figure and add two subplots. (I'm reusing the object label "ax" in the code here.)


In [5]:
fig = figure(figsize=figaspect(0.3))
ax = fig.add_subplot(121, projection='3d')
ax.plot_surface(X, Y, Z, color='b')
ax = fig.add_subplot(122, projection='3d')
ax.plot_wireframe(X, Y, Z, rstride=10, cstride=10)


Out[5]:
<mpl_toolkits.mplot3d.art3d.Line3DCollection at 0x112ffacc0>

Parameterized surfaces

A parameterized surfaces expresses the spatial variable $x,y,z$ as a function of two independent parameters, say $u$ and $v$.

Here we plot a sphere. Use the usual spherical coordinates.

$$x = \cos(u)\sin(v) $$$$y = \sin(u)\sin(v) $$$$z = \cos(v) $$

with appropriate ranges for $u$ and $v$. We set up the array variables as follows:


In [6]:
u = linspace(0, 2*pi, 100)
v = linspace(0, pi, 100)
u,v = meshgrid(u,v)
x = cos(u) * sin(v)
y = sin(u) * sin(v)
z = cos(v)

In [7]:
fig = figure()
ax = axes(projection='3d')
# Plot the surface
ax.plot_surface(x, y, z, color='b')


Out[7]:
<mpl_toolkits.mplot3d.art3d.Poly3DCollection at 0x113b794e0>

Outer product for speed

Python provides an outer product, which makes it easy to multiply the $u$ vector by the $v$ vectors, to create the 2D array of grid values. This is sometime useful for speed, so you may see it in other's people's code when they really need the speed. Here is an example.


In [8]:
u = linspace(0, 2*pi, 100)
v = linspace(0, pi, 100)
x = outer(cos(u), sin(v))
y = outer(sin(u), sin(v))
z = outer(ones(size(u)), cos(v))

In [9]:
fig = figure()
ax = axes(projection='3d')
# Plot the surface
ax.plot_surface(x, y, z, color='b')


Out[9]:
<mpl_toolkits.mplot3d.art3d.Poly3DCollection at 0x113c4e198>

A donut

Let's plot a torus. The idea is to start with a circle $$ x_0 = \cos(u) $$ $$ y_0 = \sin(u) $$ $$ z_0 = 0$$ then add a little circle perpendicular to it $$ (x_0,y_0,0)\cos(v) + (0,0,1)\sin(v) = (\cos(u)\cos(v), \sin(u)\cos(v), \sin(v)).$$ Add them, with a scaling.


In [10]:
# Make data
u = linspace(0, 2*pi, 100)
v = linspace(0, 2*pi, 100)
u,v = meshgrid(u,v)
R = 10
r = 4
x = R * cos(u) + r*cos(u)*cos(v)
y = R * sin(u) + r*sin(u)*cos(v)
z = r * sin(v)

In [11]:
fig = figure()
ax = axes(projection='3d')
ax.set_xlim([-(R+r), (R+r)])
ax.set_ylim([-(R+r), (R+r)])
ax.set_zlim([-(R+r), (R+r)])
ax.plot_surface(x, y, z, color='c')


Out[11]:
<mpl_toolkits.mplot3d.art3d.Poly3DCollection at 0x1146eb390>

In [ ]: