The question is pretty much in the title; I'm about to teach my multivariable calculus students about orientations on surfaces, and I would like to be able to show them pictures. Any ideas?
-
4You might find a lot already done here. – b.gates.you.know.what Nov 06 '12 at 20:04
4 Answers
The easiest thing to do is differentiate the field and use VectorPlot3D and ContourPlot3D to show orthogonality of these. This is from Documentation Center. I will change this a bit from original to polish graphics for your lecture. These are not unit vectors though - do u really need unit ones? It can be done too if you need.
Use a contour plot to visualize the region of a vector plot:
scalarField = x^2 - y^2 - z;
vectorField = D[scalarField, {{x, y, z}}]
Plot a vector field over a particular region:
v = VectorPlot3D[vectorField, {x, -2, 2}, {y, -2, 2}, {z, -2, 2},
VectorPoints -> 20, VectorScale -> {0.1, Scaled[0.5]},
RegionFunction -> Function[{x, y, z}, -0.1 <= scalarField <= 0.1],
VectorStyle -> "Arrow3D", VectorColorFunction -> "Rainbow"]
Create a contour plot of the vector plot's region:
c = ContourPlot3D[
scalarField == 0, {x, -2, 2}, {y, -2, 2}, {z, -2, 2}, Mesh -> 20,
MeshStyle -> Opacity[.1],
ContourStyle -> Directive[Green, Opacity[0.3], Specularity[White, 30]]]
Combine the vector and contour plots:
Show[v, c]

- 271,378
- 34
- 587
- 1,371
- 73,078
- 9
- 204
- 355
-
This is very helpful, thanks! Is there any way to modify your idea so that it works for surfaces described by parametric equations, rather than as level surfaces of functions of $x$, $y$, and $z$? – Paul Siegel Nov 06 '12 at 21:39
-
@PaulSiegel I modified my answer to show a way to get vector field for surfaces on parametric form. – ssch Nov 07 '12 at 00:25
-
1Nice start--but this is not a unit normal field. The lengths of the arrows come from extraneous, irrelevant information related to the function of which this surface is a zero. (The fix is fairly easy to make--but watch out for places where the gradient is zero!) – whuber Nov 07 '12 at 17:00
-
-
2Sorry; I focused on the image and only skimmed the text! (+1). However, as I pointed out, the lengths of your vectors are extraneous to the problem, so in the intended application it likely is best to normalize them. You are also going to run into trouble where the gradient is zero (at the origin in your example) because you won't be able to calculate a nontrivial normal vector, even though it exists. – whuber Nov 08 '12 at 16:33
Let's start with a parametrized surface. Any one will do, but I guess being orientable helps in this case.
Then calculate the unit normal, and then create a Manipulate object that lets you see how the normal behaves:
σ[u_, v_] := {(2 + Cos[v]) Cos[u], (2 + Cos[v]) Sin[u], Sin[v]}
n[u_, v_] := Evaluate[Normalize[
Cross[D[σ[u, v], u], D[σ[u, v], v]]
]]
surfacePlot =
ParametricPlot3D[σ[u, v], {u, -Pi, Pi}, {v, -Pi, Pi},
PlotRangePadding -> 1];
normalPlot =
ParametricPlot3D[n[u, v], {u, -Pi, Pi}, {v, -Pi, Pi},
PlotStyle -> Opacity[0.5]];
Manipulate[
{Show[{
surfacePlot,
Graphics3D[{Thick, Red,
Arrow[{σ @@ pt, σ @@ pt + n @@ pt}]}]
}],
Show[{
normalPlot,
Graphics3D[{Thick, Red, Arrow[{{0, 0, 0}, n @@ pt}]}]
}]
}
,
{pt, {-Pi, -Pi}, {Pi, Pi}}]

To show the entire vector field for a surface on parametric form you can use a bunch of Arrow's:
Show[{
surfacePlot,
Graphics3D[
Table[
Arrow[{σ[u, v], σ[u, v] + n[u, v]}],
{u, -Pi, Pi, 0.4}, {v, -Pi, Pi, 0.4}]
]
}]

As you can see, the arrows are equally spaced in the parameter space, which leads to uneven distribution of arrows on the surface; it might be worth transforming the parametrization into $f(x,y,z)=0$ form to get a nicer result.
It isn't too hard to roll your own routine, of course:
UnitNormalVector[f_, {u_, u0_}, {v_, v0_}] := Block[{f0, g0},
f0 = f /. {u -> u0, v -> v0};
g0 = Transpose[D[f, {{u, v}}] /. {u -> u0, v -> v0}];
Arrow[{f0, f0 + Normalize[Cross @@ g0]}]]
(* Möbius strip *)
mobius[u_, v_] :=
{(3 + (1/2 - v) Cos[u/2]) Cos[u], (3 + (1/2 - v) Cos[u/2]) Sin[u], (1/2 - v) Sin[u/2]}
Show[ParametricPlot3D[mobius[u, v], {u, 0, 2 π}, {v, 0, 1},
Mesh -> False, PlotPoints -> 55],
Graphics3D[Table[UnitNormalVector[mobius[u, v], {u, u0}, {v, v0}],
{u0, 0, 2 π, 2 π/20}, {v0, 0, 1, 1/5}]], PlotRange -> All]

It's not too hard to give the arrows depicting the normals some style:
% /. Arrow[stuff__] :> {Blue, Arrow[Tube[stuff, 0.05]]}

- 124,525
- 11
- 401
- 574
-
3
-
1@bel, you weren't aware that I've always had a heretical streak? >:) – J. M.'s missing motivation Nov 07 '12 at 02:44
-
-
1+1. Seeing this normal field might help some people understand what's going on in the discussions about Möbius bands here. – whuber Nov 07 '12 at 16:58
Just adding this answer for completion seeing as there is an out-of-the-box solution for this hidden in the documentation.
Essentially the following function:
normalsShow[g_Graphics3D] :=
Module[{pl, vl, n},
{pl, vl} = First @ Cases[g,
GraphicsComplex[pl_, prims_, VertexNormals -> vl_,
opts___?OptionQ] :> {pl, vl}, ∞];
n = Length[pl];
Show[g,
Graphics3D[
GraphicsComplex @@ {Join[pl, pl + vl/3], {Black,
Line[Table[{i, i + n}, {i, n}]]}}]]
];
(that can easily be tweaked to subsample or use arrows instead of lines) works in the previously mentioned examples:
The c of Vitaly:
c // normalsShow

the donut:
surfacePlot // normalsShow

and the Möbius band:
ParametricPlot3D[mobius[u, v], {u, 0, 2 π}, {v, 0, 1},
Mesh -> False, PlotPoints -> 55] // normalsShow

- 124,525
- 11
- 401
- 574
- 9,707
- 3
- 24
- 66