# Plot3d: How to color a surface according to the slope of the surface?

Here is my approach, for an example surface function:

surface[x_, y_] := Sin[x y];


The normal vector of a point in the surface is computed as:

NormalVector[a_, b_] := {D[surface[xx, yy], xx], D[surface[xx, yy], yy],1} /. {xx -> a, yy -> b};


Then the plot is as follows:

Plot3D[surface[x, y], {x, 0, 3}, {y, 0, 3}, ColorFunction -> Function[{x, y, z},
RGBColor[0, 0, VectorAngle[NormalVector[x, y], {0, 0, 1}]]]]


However it fails, why?

To be honest, I'm not really sure why you need ColorFunctionScaling since there aren't any outlayers that could make the rest of the plot flat, nevertheless:

Plot3D[surface[x, y], {x, 0, 3}, {y, 0, 3}, ColorFunctionScaling -> False,
Lighting -> "Neutral", ColorFunction -> Function[{x, y, z},
Blend[{Blue, White}, 2 #/Pi] &@ VectorAngle[NormalVector[x, y], {0, 0, 1}]]]


Update

Plot3D[surface[x, y], {x, 0, 3}, {y, 0, 3}, ColorFunctionScaling -> False,
ColorFunction -> Function[{x, y, z}, Blend["Rainbow", Rescale[#, {0, Pi/2}]
] & @ VectorAngle[NormalVector[x, y], {0, 0, 1}]],
PlotLegends -> BarLegend[{"Rainbow", {0, 90}},  ColorFunctionScaling -> True,
LegendLabel -> "normal vs zenith [\[Degree]]"]
]


• @Kuba.Aha! But is there a way to assign more color to the different slope values. It looks a bit dull. Dec 16, 2013 at 8:23
• @novice Of course, take a look at Blend or Color Schemes. Try for example Blend["Rainbow", #] &@
– Kuba
Dec 16, 2013 at 8:27
• @KubaThank you, I tried and made it. Dec 16, 2013 at 8:33
• @KubaAnother small problem is that PlotLegends -> Automatic fails. Dec 16, 2013 at 8:50
• @novice ok, see my edit.
– Kuba
Dec 16, 2013 at 9:56

Just for variety: Note also outward normal to surface $z=f(x,y)$: $\nabla(z-f(x,y))=<-f_x,-f_y,1>$ (inward negative)...not same as "NormalVector" function listed (apologies if I have misinterpreted or made error). I have rewritten taking into account:

f[x_, y_] := Sin[x y];
n[x_, y_] := {-D[f[a, b], a], -D[f[a, b], b], 1} /. {a -> x, b -> y};
va[x_, y_] := VectorAngle[n[x, y], {0, 0, 1}];
Manipulate[
Show[Plot3D[f[x, y], {x, 0, 3}, {y, 0, 3},
ColorFunction ->
Function[{x, y, z},
ColorData["Rainbow"][Rescale[va[x, y], {0, 1.4}]]],
ColorFunctionScaling -> False, PlotRange -> {-2, 2},
PerformanceGoal -> "Quality"],
Graphics3D[{Red, Thick,
Arrow[{{s[[1]], s[[2]],
f[s[[1]], s[[2]]]}, {s[[1]], s[[2]], f[s[[1]], s[[2]]]} +
Normalize@n[s[[1]], s[[2]]]}, 0.03]}],
ContourPlot3D[{x - s[[1]], y - s[[2]], z - f[s[[1]], s[[2]]]}.n[
s[[1]], s[[2]]] == 0, {x, s[[1]] - 0.2,
0.2 + s[[1]]}, {y, -0.2 + s[[2]], 0.2 + s[[2]]}, {z, -2, 2},
Mesh -> False]], {s, {0.1, 0.1}, {3, 3}}]


The graphic illustrates color of surface based on angle between normal and $\vec{k}$ (which seems to be intended color function). I show the unit normal and tangent plane.

• @ubpdqn__Yes, it is my fault. The upward normal should be ∇(z−f(x,y)). Thanks for reminding. Nice illustration. Dec 17, 2013 at 23:35
• @novice...just wanted to clarify...thanks Dec 20, 2013 at 0:44