Exploiting the Tangent Plane
by Keith Brandt and Tom Linton
The Maple worksheet, tanplane.mws You can copy commands directly from this HTML file and paste them into a local session of Maple, or save the Maple worksheet via the previous link, and then load that into Maple. Sorry about all of the images in this document, it may take a while to load.
Using the tangent plane to help motivate the chain rule and directional derivatives. This file gives sample, or template Maple V release 5 commands for creating visuals, for a calculus 3 class, to motivate the chain rule and directional derivatives. It assumes that the user more or less knows Maple.
Load some plotting packages:
> map(with,{plots,plottools}):
Many commands in this file have the form:
actual Maple definition:
another "readable" version;
Maple uses a command ending colon to designate "do the command, but show no output", and a command ending semicolon to do the command and show the output. If the output is misleading, or "not what we want to see", I end the original command with a colon, they immediately ask Maple to produce a more meaningful display of what the command accomplished. In particular, since several images need to be "re-displayed", they are first named (Maple echos assignments in its internal format, so assigning a name to a plot structure yields an unreadable mess), then displayed as plots (not assignments), by simply entering the name just assigned as a secondary command.
The Chain Rule
For appropriately well behaved functions f:
R^2 -> R, and g:
,
with g(t) = [x(t), y(t)], the chain rule states that the derivative, with
respect to t, of the composite function, f(g(t)) is
f(x(t),
y(t)) =
*x'(t)
+
*y'(t),
which can also be calculated using the tangent plane to f(x,y) (at the appropriate time t). The purpose of this section is to illustrate graphically, the reasonableness of this fact.
Define a function f:
> f := (x,y) -> 9-((x-3)^2 + (y - 2)^2);
![]()
A "multiplied out" version of f (the equals sign is just a label in Maple, no assigning is done here):
> f=expand(f(x,y));
![]()
A point:
> pt:= 3.3, 2.2;
![]()
The partials of f:
> fx := D[1](f);
fy := D[2](f);
![]()
The tangent plane equation to f at the point:
> T := (x,y) -> f(pt)+fx(pt)*(x-3.3)
+ fy(pt)*(y-2.2):
T(x,y);
![]()
A curve g, and its plot in the xy-plane. Note: it is required that the graph of g includes the point pt = (3.3, 2.2)!
> g := t -> [t + 1.8, 2*t+sin(2*t)-.941120008]:
> plot([g(t)[1], g(t)[2], t=0.5 ..
2.5],
color= black,title=`g(t)`, labels = [`x`,
`y`],
thickness=2);
![[Maple Plot]](images/keith311.gif)
The time when g goes through the point was setup to be t = 1.5, here is a check:
> g(1.5);
![]()
Here is a 3d plot of g in the xy-plane
> gbase:= spacecurve([g(t)[1], g(t)[2],0],
t= 0 .. 3.5,
color=black, thickness=2, labels=[`x`,`y`,`z`],
axes=FRAMED):
gbase;
![[Maple Plot]](images/keith313.gif)
Add a "floor" for perspective:
> flr:=polygon([[-1,8,0],[8,8,0],
[8,-2,0],[-1,-2,0]],color=grey):
> display3d([gbase,flr]);
![[Maple Plot]](images/keith314.gif)
Find reasonable x and y bounds for the surface plot:
> solve(f(x,y)=0,{y});
![]()
> implicitplot(f(x,y)=0,x=0..6,y=-1..5);
![[Maple Plot]](images/keith316.gif)
The surface:
> surf:= plot3d(f(x,y), x=0..6,
y= 2-sqrt(-x^2+6*x).. 2+sqrt(-x^2+6*x),
color=cyan,axes=FRAMED,
style=wireframe, view=[0..8,-1..8,0..9]):
surf;
![[Maple Plot]](images/keith317.gif)
All the pieces together:
> display3d([gbase,flr,surf],
view=[-1..7,-2..9,-1..9]);
![[Maple Plot]](images/keith318.gif)
The tangent plane at (3.3, 2.2):
> tanplane:=plot3d(T(x,y), x=1.3 ..
5.3, y=0.2 .. 4.2,
axes=frame,grid=[15,15],
style=wireframe):
tanplane;
![[Maple Plot]](images/keith319.gif)
> display3d([gbase,flr,surf,tanplane],
view=[-1..7,-2..9,-1..12]);
![[Maple Plot]](images/keith320.gif)
The Maple function transform (in the plottools package) can be used to render the spacecurve gbase, at other locations.
> toPlane:=transform((x,y,z)->[x,y,T(x,y)]):
toSurf:=transform((x,y,z)->[x,y,f(x,y)]):
We need to trim down the range on the plot of g however.
> gshort:= spacecurve([g(t)[1], g(t)[2],0],
t= .25 .. 2.7,
color=black, thickness=2, labels=[`x`,`y`,`z`],
axes=FRAMED):
Technically, the things listed first in a display3d command, end up on top (front?), and those listed later are behind, but 3d images seem to obsure other images, regardless of order.
> display3d([gshort,toPlane(gshort),
toSurf(gshort),
flr,surf,tanplane],
view=[-1..7,-2..9,-1..12],
orientation=[120,65]);
![[Maple Plot]](images/keith321.gif)
The image above (in Maple, not HTML) can be clicked (to select it and enclose it in an anchored frame) and then clicked and dragged around to see the pieces from different perspectives. I ask students to try and drag it so that all 3 copies of the curve g align themselves (i.e. look straight down on the image from the top).
Now, an attempt with a solid surface (raised up off the floor).
> solve(f(x,y)=5,{y});
implicitplot(f(x,y)=5,x=0..6,y=-1..8);
![[Maple Plot]](images/keith323.gif)
> cap:=plot3d(f(x,y),x=1..5,
y=2-sqrt(-5-x^2+6*x) .. 2+sqrt(-5-x^2+6*x),
axes=frame):
display3d([toSurf(gshort),cap],view=2..10,
style=patchnogrid);
![[Maple Plot]](images/keith324.gif)
A second tangent plane is created here, using only 2 gridpoints, which just draws its outline when rendered in a wireframe style. I'll try to make the plane's edges lie near the ends of the curve g (the short version that is):
> g(.25),g(2.7);
![]()
> tanplane2:=plot3d(T(x,y), x=g(-.2)[1]
.. g(3)[1],
y=g(.1)[2] .. g(2.85)[2],
axes=frame,grid=[2,2],color=blue,thickness=2,
style=wireframe):
flr2:= polygon([[1,5,0],[6,5,0],
[6,-1,0],[1,-1,0]],color=grey):
> display3d([gshort,toPlane(gshort),
toSurf(gshort),
tanplane2,flr2,cap],
style=patchnogrid,
orientation=[-36,53],lightmodel=light1,shading=ZHUE,
view=[1..6,-1..5,0..12]);
![[Maple Plot]](images/keith326.gif)
That looks decent. Many features can be changed however (click on the plot to enclose it in an anchored frame and select various options from the Style and Color menus which appear after the plot is clicked). Again, dragging the image above around in real time can be very informative for students.
Here's a sequence of red lines to show that the versions of g(t) "line up". The command op removes the braces from around a list, giving just the operands, as in
> op([x,y]);
![]()
Try 5 lines as t runs from .25 to 2.7 (the times in gshort).
> tvals:=[.3, .45, .6, .8,1.1,1.5, 2.1, 2.3, 2.45, 2.6]:
> redlines:=seq(line([op(g(t)),0],
[op(g(t)), T(op(g(t)))],
color=red,thickness=2), t=tvals):
Here's our image above with these lines:
> display3d([gshort,toPlane(gshort),
toSurf(gshort),
tanplane2,flr2,cap,redlines ],
style=patchnogrid,
orientation=[-36,53],lightmodel=light1,shading=ZHUE,
view=[1..6,-1..5,0..12]);
![[Maple Plot]](images/keith328.gif)
Back to wireframe?:
> display3d([gshort,toPlane(gshort),
toSurf(gshort),
tanplane2,flr2,surf,redlines ],
orientation=[-36,53],lightmodel=light1,shading=ZHUE,
view=[1..6,-1..5,0..12]);
![[Maple Plot]](images/keith329.gif)
The solid cap seems best (for a static image). However, if students have a live copy of these 3d images, the red lines, running from the surface to the tangent plane (i.e. from f(g(t)) to T(g(t)) ), in a live version which they can drag around, rotate and look at from various perspectives might be a good thing. Here it is:
> redlines2:=seq(line([op(g(t)),f(op(g(t)))],
[op(g(t)), T(op(g(t)))],
color=red,thickness=2), t=tvals):
> display3d([toPlane(gshort), toSurf(gshort),
redlines2 ], orientation=[-41,53],
view=[1..6,-1..5,4..12],labels=[`x`,`y`,`z`]);
![[Maple Plot]](images/keith330.gif)
Maybe even a plot of T( g(t) ) - f( g(t) )? This plot shows not only that the error = 0 at t = 1.5, but that error' = 0 (i.e., Tg' = fg')!
> plot(T(op(g(t)))-f(op(g(t))),t=1.4
.. 1.6,y=-.1..0.1,
title=`The error in T(g(t)) vs f(g(t))`,
thickness=2,color=red,labels=[`t`,`error`]);
![[Maple Plot]](images/keith331.gif)
I can't help but pitch the numerical approach here too. The claim is that f( g(t) ) is "close to" T( g(t) ) near the point of tangency (t = 1.5). Having students click on and drag the above 3dplots is quite convincing, but why not show them a table of values, or, since we're looking at derivatives, just compute difference quotients!
Unfortunately we can't just use f( g(t) ) in Maple, as g(t) is a list [x,y], not just plain old x, y. Likewise for T( g(t) ), the op command comes in handy here too. The definitions:
> fg := t -> f( op(g(t)) ):
Tg := t -> T( op(g(t)) ):
What students should see, and be able to find on their own:
> fg(t);
Tg(t);
![]()
Now, difference quotients are easy:
> (fg(1.501) - fg(1.499)) / (1.501
- 1.499);
(Tg(1.501) - Tg(1.499)) / (1.501 - 1.499);
![]()
As are comparing values one at a time:
> fg(1.51), Tg(1.51);
fg(1.493), Tg(1.493);
![]()
Tables in Maple can be constructed using matricies. The evalm command evaluates its argument as a matrix.
A list of times:
> tvals2:=[seq(1.5 -.003 +k*.001,k=0..6)];
![]()
Now, we can make a row of our table by constructing a triple [t, f(g(t)), T(g(t))]. Start with a row of labels, then a sequence of actual data rows:
> evalm([[`t`,`f(g(t))`,`T(g(t))`],
seq([t,fg(t),Tg(t)],t=tvals2)]);
![[Maple Math]](images/keith339.gif)
>
That makes the point quite well too!
Directional derivatives
Directional derivatives of f(x,y), can also be motivated using the tangent plane:
Directional derivatives correspond to taking g(t) = a line, in the above section. We can re-use much of our work, by taking our line, or direction to be the one that starts at g(1.5) = pt, and moves in a direction towards the front right corner of our view (x = 6, y = 5).
> dir:=[6.,5.]-g(1.5);
![]()
Here is a "length" function for ordered pairs (lists in Maple):
> len:= xypair -> (xypair[1]^2+xypair[2]^2)^.5:
And a unit vector in our direction.
> dir:=dir/len(dir);
![]()
A new g(t) (no brackets this time, so f( g2(t) ) and T( g2(t) ) make sense):
> g2:= t -> ([pt][1] + t*dir[1], [pt][2]
+ t*dir[2]):
g2(t);
![]()
Now, we can use arrows for the vectors, but Maple's 3d arrows (in the plottools package) are weak and highly technical to designate. Here are the pieces we need:
> bw:=.1: #width of body of arrow
hw:=.2: #head width of arrow
hh:=.15: #head height, as portion of total
length
nrm1:=[0,0,1]; #normal to plane of 1st arrow
nrm2:=[fx(pt),fy(pt),-1]; #normal for arrow
2
dir1:= [4., 2.92, 0]-[3.3,2.2,0]; #direction
of arrow1
dir2:= [4., 2.92, T(4.,2.92)]-[3.3,2.2,T(3.3,2.2)];
![]()
> g2(1);
![]()
> basearrow:=arrow([3.3,2.2,0.1],dir1,
nrm1, bw,hw,hh,color=red):
planearrow:=arrow([pt,T(pt)],
dir2,nrm2,bw,hw,hh,
color=blue):
liness:=line([pt,0],[pt,T(pt)],color=red,
linestyle=2), line([g2(1.),0],[g2(1),T(g2(1))],
color=red,linestyle=2):
> display3d([liness, basearrow, planearrow,
tanplane2,cap,flr2],
style=patchnogrid,
orientation=[-15,60],lightmodel=light1,shading=ZHUE,
view=[1..6,-1..6,0..12]);
![[Maple Plot]](images/keith348.gif)
The image above is a good one for students to click on and drag around.
A smaller tangent plane, and a shadow of the arrow on the surface:
> tanplane3:=plot3d(T(x,y), x=[g2(-.5)][1]
.. [g2(1.3)][1],
y=[g2(-.5)][2] .. [g2(1.3)][2],
axes=frame,grid=[2,2],color=blue,thickness=2,
style=wireframe):
shadow:=spacecurve([g2(t),f(g2(t))],t=0..1,
color=black,thickness=2):
> display3d([liness, basearrow, planearrow,
shadow, tanplane3,cap,flr],
style=patchnogrid,
orientation=[-15,60],lightmodel=light4,shading=ZHUE,
view=[1..6,0 ..4,0..12]);
![[Maple Plot]](images/keith349.gif)
I'll try lines instead of arrows:
> arrowlines:= line([pt,.1],[g2(1),.1],color=red,thickness=2),
line([g2(1),.1],[4, 2.74,.1],color=red,thickness=2),
line([g2(1),.1],[3.82, 2.88,.1],color=red,thickness=2),
line([pt,T(pt)],[g2(1),T(g2(1))],color=blue,thickness=2),
line([g2(1),T(g2(1))],[3.83, 2.88, T(3.83,
2.88)],
color=blue,thickness=2),
line([g2(1),T(g2(1))],[3.96, 2.74, T(3.96,
2.74)],
color=blue,thickness=2):
> display3d([liness, arrowlines,
shadow, tanplane3,cap,flr],
style=patchnogrid,
orientation=[-15,60],lightmodel=light4,shading=ZHUE,
view=[1..6,0 ..4,0..12]);
![[Maple Plot]](images/keith350.gif)
Just lines, no heads:
> display3d([liness, [arrowlines][1],[arrowlines][4],
shadow, tanplane3,cap,flr],
style=patchnogrid,
orientation=[-15,60],lightmodel=light4,shading=ZHUE,
view=[1..6,0 ..4,0..12]);
![[Maple Plot]](images/keith351.gif)
![[Maple Plot]](images/keith352.gif)
Again, the numerical perspective is quite convincing:
> startpt:=[pt];
stoppt:=[g2(.001)];
dist:=len(stoppt-startpt);
![]()
Change in f over change in distance:
> (f(3.300694136, 2.200719844)-f(3.3,2.2))/dist;
![]()
The unit "vector" U was called dir above, we define the gradient vector here also:
> dir;
gradf:=[fx(pt), fy(pt)];
![]()
The true directional derivative:
> linalg[dotprod](gradf,dir);
![]()
The tangent line approximation:
> (T(3.300694136, 2.200719844)-T(3.3,2.2))/dist;
![]()
The output values are nearly the same!