The matplotlib tutorial provides a nice example of how to draw a spherical suface:
from mpl_toolkits.mplot3d import Axes3D import matplotlib.pyplot as plt import numpy as np fig = plt.figure() ax = fig.add_subplot(111, projection='3d') u = np.linspace(0, 2 * np.pi, 100) v = np.linspace(0, np.pi, 100) x = 10 * np.outer(np.cos(u), np.sin(v)) y = 10 * np.outer(np.sin(u), np.sin(v)) z = 10 * np.outer(np.ones(np.size(u)), np.cos(v)) ax.plot_surface(x, y, z, rstride=4, cstride=4, color='b') plt.show()
From what I understand, this creates a 2D grid for each x
, y
, and z
variable corresonding to the product of the parameters u
and v
. The calculated x
, y
, and z
variables are then the cartesian coordinates created from the spherical coordinates in u
and v
.
My question is the following: Why does the input to plot_surface
have to be in 2D arrays?
I suspect it has something to do with calculating the normals of each of the surface faces, but I can't seem to figure it out. Is there some detailed documentation that describes this?
This question seems to ask something similar, but the single answer isn't particularly enlightening.
The Equation of a surface is:
f(x,y,z)=c
where the constants characterize the surfaces. In the case of a circle it is:
(x^2 + y^2 + z^2)^(1/2) = c
Where c is the radius. each value of gives one surface. In other words, f(x,y,z) can be written as z=g(x,y). Now if you have to span an area with two independent variables x & y, both will have to be 2D arrays. note that both x and y will be 2D arrays and so will z.
A: Because the interface specification orders that.
However strange does that look, the 2D-parametric grid,
describing the surface [ R = const, u = < 0, 2pi >, v = < 0, pi > ]
from Spherical coordinate space is translated into a cartesian-space via a mapping,
stored in a set of [ MAT2Dx[,], MAT2Dy[,], MAT2Dz[,] ]
because that is the requirement the .plot_surface()
method requires the surface-data to be received.
>>> print ax.plot_surface.__doc__ Create a surface plot. By default it will be colored in shades of a solid color, but it also supports color mapping by supplying the *cmap* argument. ============= ================================================ Argument Description ============= ================================================ *X*, *Y*, *Z* Data values as 2D arrays *rstride* Array row stride (step size) *cstride* Array column stride (step size) *color* Color of the surface patches *cmap* A colormap for the surface patches. *facecolors* Face colors for the individual patches *norm* An instance of Normalize to map values to colors *vmin* Minimum value to map *vmax* Maximum value to map *shade* Whether to shade the facecolors ============= ================================================ Other arguments are passed on to :class:`~mpl_toolkits.mplot3d.art3d.Poly3DCollection`
By design, a surface is a 2D-entity, here parametrised either by in [R,u,v] or [X,Y,Z] coordinate system, and due to the ease of [R,u,v] analytic description of a sphere surface, the meshing started in [u,v]
-grid produced by a pair of .linspace()
methods, whereas remained R=const=10
.
Further:
>>> print np.outer.__doc__ Compute the outer product of two vectors. Given two vectors, ``a = [a0, a1, ..., aM]`` and ``b = [b0, b1, ..., bN]``, the outer product [1]_ is:: [[a0*b0 a0*b1 ... a0*bN ] [a1*b0 . [ ... . [aM*b0 aM*bN ]]
has created x
, y
, z
matrices in a shape of [100,100], as a trigonometry-laws-based mapping of [u,v] -> x(u,v), y(u,v), z(u,v)
finally, .plot_surface()
method has consumed these in
x,y,z = np.broadcast_matrices( x, y, z )
before starting to produce a list of 2D-surface-objects ( to be plot ), iterating over the scope of the original [u,v]
-2Dgrid.