A Three Dimensional Plotting Tutorial

Part II

Additional Plotting Techniques For Curves

Plotting Projections of Space Curves in Coordinate Planes

It is sometimes useful to visualize the projection of a curve in a coordinate plane. It is possible to do this by adding the plot option orientation=[theta,phi] to the argument list of spacecurve . Here the angles theta and phi are the usual spherical coordinates (but an approach that can be used prior to the introduction of spherical coordinates is given below).

Example: Plot the helix

x = t*cos(2*t)
y = t*sin(2*t)
z = t^2


for
t ranging from 0 to 12 . Visualize the projections in the xy -plane and the yz -plane. Then plot those projections.

Solution:

When viewed from Maple's default vantage point (namely orientation=[45,45] ), the helix looks like

> spacecurve([t*cos(2*t), t*sin(2*t), t^2, t = 0..12], numpoints=100);

[Maple Plot]

The projection to the xy -plane is obtained as follows:

> spacecurve([t*cos(2*t), t*sin(2*t), t^2, t = 0..12],
numpoints=100, orientation = [0,0]);

[Maple Plot]

The projection to the yz -plane is obtained as follows:

> spacecurve([t*cos(2*t), t*sin(2*t), t^2, t = 0..12],
numpoints=100, orientation = [0,90]);

[Maple Plot]

The notion of "orientation of vantage point" itself requires some practice in visualization and is not ideal for the beginner who is seeing space curves for the first time. I therefore wrote a routine, projection_plot , to plot projections. Once again, after the following function, projection_plot , has been compiled, it may be added to the Maple kernel and used in the same way as a built-in function. The code (which I have provided) does not ever have to be seen by the user.

Code for projection_plot

> projection_plot := proc()
local tt, aa, bb, n1, n2;
if nargs <> 3
then
error "projection_plot expects 3 arguments.";
elif not type(args[3],set)
then
error "projection_plot expects a set as its third argument.";
elif nops(args[3])<> 2
then
error "projection_plot expects a set with two elements as its third argument.";
elif not verify(args[3],{1,2,3},'subset')
then
error "projection_plot expects a set with two elements from {1,2,3} as its third argument.";
elif not type(args[1],list) then
error "projection_plot expects a list as its first argument.";
elif nops(args[1]) <> 3 then
error "projection_plot expects a list with three entries as its first argument.";
elif not type(args[2],equation) then
error "projection_plot expects an equation as its second argument.";
elif not type(lhs(args[2]),name) or not type(rhs(args[2]),range) then error "projection_plot expects an equation of the form var = a..b as its second argument.";
elif not type(op(1,rhs(args[2])),realcons) or not type(op(2,rhs(args[2])),realcons) then
error "projection_plot expects an equation of the form var = a..b as its second argument with a and b specified real numbers.";
else
n1 := op(1,sort(convert(args[3],list)));
n2 := op(2,sort(convert(args[3],list)));
plot([op(n1,args[1]),op(n2,args[1]),args[2]]);
fi:
end:

Description of projection_plot

projection_plot - create a two-dimensional plot of the projection of a space curve

Calling Sequence:

projection_plot(F, t = a .. b, S)

Parameters:

F - An ordered triple of expressions in t

t - a name

a - a real constant

b - a real constant

S - a two element subset of {1,2,3}

Description:

Example: Redo the previous example using projection_plot . That is, plot the projections of the helix

x = t*cos(2*t)
y = t*sin(2*t)
z = t^2


for
t ranging from 0 to 12 in the xy -plane and the yz -plane.

Solution:


Here is the projection in the
xy -plane.

> projection_plot( [t*cos(2*t), t*sin(2*t), t^2], t = 0 .. 12, {1,2} );

[Maple Plot]

Here is the projection in the yz -plane.

> projection_plot( [t*cos(2*t), t*sin(2*t), t^2], t = 0 .. 12, {2,3} );

[Maple Plot]

Lagrange Multiplier Problems

Maple can be highly effective in illustrating the underlying idea of the Method of Lagrange Multipliers.

First, let us work numerically through a classic Lagrange Multiplier problem. It is traditionally referred to as
the
Milkmaid Problem .

Example:

Suppose that a farmhand lives in a house that is represented by the point P = [0,0] . Suppose that the farmhand has to go from P to a barn located at Q = [10,0] . However, the farmhand must first stop at the river, represented by the equation x/16-y/5 = 1 , in order to fill a bucket of water to bring to the barn animals. At what point R on the river should the farmhand go in order to minimize the distance PR+RQ ?

Solution:

The function to be extremized is

> f := (x,y) -> sqrt(x^2+y^2) + sqrt((x-10)^2 + y^2);

f := proc (x, y) options operator, arrow; sqrt(x^2+...


The constraint is

> phi := (x,y) -> x/16-y/5;

phi := proc (x, y) options operator, arrow; 1/16*x-...


Maple does not have a built-in function to solve Lagrange Multiplier problems. But it has all the necessary tools to create such a function. In the next subsection I define a function
lagrange_mult_2d that solves Lagrange Multiplier problems.

Code for lagrange_mult_2d

> lagrange_mult_2d := proc()
local xx, yy, constraint, constraintfn, constraintconst, expr, eqn_set, lambda, var_list, soln_set;
if nargs <> 3 then
error "lagrange_mult_2d expects 3 arguments.";
elif not type(args[3],set) then
error "lagrange_mult_2d expects a set as its third argument.";
elif nops(args[3])<> 2 then
error "lagrange_mult_2d expects a set with two elements as its third argument.";
elif not type(op(1,args[3]),{name,equation})
or not type(op(2,args[3]),{name,equation}) then
error "lagrange_mult_2d expects its third argument to be of the form {var1,var2} or {var1 = a,var2=b}.";
else
var_list := convert(args[3],list):
end if:

if type(op(1,var_list),name) then
xx := op(1,var_list):
else
if not type(lhs(op(1,var_list)),name) or not type(rhs(op(1,var_list)),realcons) then
error "lagrange_mult_2d expects each equation in its third argument to be of the form name = realconstant.";
else
xx := lhs(op(1,var_list)):
end if:
end if:

if type(op(2,var_list),name) then
yy := op(2,var_list):
else
if not type(lhs(op(2,var_list)),name) or not type(rhs(op(2,var_list)),realcons) then
error "lagrange_mult_2d expects each equation in its third argument to be of the form name = realconstant.";
else
yy := lhs(op(2,var_list)):
end if:
end if:

if not type(args[2],equation)
then
error "lagrange_mult_2d expects an equation as its second argument.";
elif nops(lhs(args[2]))<> 2
then
error "lagrange_mult_2d expects the left side of its second argument to be of the form g(x,y).";
elif not type(rhs(args[2]),realcons)
then
error "lagrange_mult_2d expects the right side of its second argument to a real constant.";
else
constraintfn := lhs(args[2]):
constraintconst := rhs(args[2]):
end if:

if not has(constraintfn,xx) or
not has(constraintfn,yy)
then
WARNING("The constraint does not involve one of the stated variables.");
end if:

if not type(args[1],algebraic)
then
error "lagrange_mult_2d expects an expression as its first argument.";
else
expr := args[1]:
end if:

if not has(expr,xx) or
not has(expr,yy)
then
WARNING( "The expression to be extremized does not involve one of the stated variables.");
end if:

if nops(lhs(args[2]))<> 2
then
error "lagrange_mult_2d expects the left side of its second argument to be of the form g(x,y).";
elif not type(rhs(args[2]),realcons)
then
error "lagrange_mult_2d expects the right side of its second argument to a real constant.";
else
constraint := args[2]:
constraintfn := lhs(args[2]):
constraintconst := rhs(args[2]):
end if:

eqn_set := {diff(expr,xx)=lambda*diff(constraintfn,xx),
diff(expr,yy)=lambda*diff(constraintfn,yy),
constraint}:
soln_set := fsolve(eqn_set, {op(args[3]),lambda});
if not type(soln_set, set) then
printf("\n\nNo solution was found.\n\n");
return;
end if:

return soln_set;
end proc:

Description of lagrange_mult_2d

lagrange_mult_2d - extremizes an expression in two variables subject to a constraint
Calling Sequence:
lagrange_mult_2d(expr, constraint, set_of_vars)

Parameters:
expr - an expression to be extremized
constraint - an equation whose right side is a real constant
set_of_vars - a set consisting of two independent variables. Optionally, either variable may be specified as the left side of an equation, with the right side of the equation equal to a real constant.

Description:

Examples:

> lagrange_mult_2d( x, x^2+y^2=1, {x,y});

Warning, The expression to be extremized does not involve one of the stated variables.

{y = 0., lambda = -.5000000000, x = -1.000000000}

> lagrange_mult_2d( x, x^2+y^2=1, {x=0.2,y});

Warning, The expression to be extremized does not involve one of the stated variables.

{y = 0., lambda = .5000000000, x = 1.000000000}


We can now apply
lagrange_mult_2d :

> lagrange_mult_2d( f(x,y), phi(x,y)=1, {x,y} );

{y = -2.484632805, lambda = 5.407404184, x = 8.0491...


For physical reasons we know that this extremum is a minimum.
The minimum distance is therefore

> min_val := f(8.049175024,-2.484632805);

min_val := 11.58290555

The tangential nature of the constraint and the level curve of f corresponding to this extremal value can be seen by using the function implicitplot in the plots package.

> with(plots):

Warning, the name changecoords has been redefined

> implicitplot({f(x,y) = min_val, phi(x,y) = 1}, x=-2..14,y=-5..3);

[Maple Plot]

I have also written an automated function, plotlm2d that first solves the Lagrange Multiplier problem and then illustrates the solution with a plot.

Code for plotlm2d

> plotlm2d := proc()
local xx, yy, constraint, constraintfn, constraintconst, expr, eqn_set, lambda, var_list, plot1, plot2, plot3, jj, ii, soln_set, extreme_val, xx_, yy_;
if nargs <> 3 and nargs <> 5
then
error "plotlm2d expects 3 or 5 arguments.";
elif not type(args[3],set)
then
error "plotlm2d expects a set as its third argument.";
elif nops(args[3])<> 2
then
error "plotlm2d expects a set with two elements as its third argument.";
elif not type(op(1,args[3]),{name,equation}) or not type(op(2,args[3]),{name,equation}) then
error "plotlm2d expects its third argument to be of the form {var1,var2} or {var1 = a,var2=b}.";
else
var_list := convert(args[3],list):
end if:


if type(op(1,var_list),name) then
xx := op(1,var_list):
else
if not type(lhs(op(1,var_list)),name) or not type(rhs(op(1,var_list)),realcons) then
error "plotlm2d expects each equation in its third argument to be of the form name = realconstant.";
else
xx := lhs(op(1,var_list)):
end if:
end if:

if type(op(2,var_list),name) then
yy := op(2,var_list):
else
if not type(lhs(op(2,var_list)),name) or not type(rhs(op(2,var_list)),realcons) then
error "v expects each equation in its third argument to be of the form name = realconstant.";
else
yy := lhs(op(2,var_list)):
end if:
end if:

if not type(args[2],equation)
then
error "plotlm2d expects an equation as its second argument.";
elif nops(lhs(args[2]))<> 2
then
error "plotlm2d expects the left side of its second argument to be of the form g(x,y).";
elif not type(rhs(args[2]),realcons)
then
error "plotlm2d expects the right side of its second argument to a real constant.";
else
constraintfn := lhs(args[2]):
constraintconst := rhs(args[2]):
end if:

if not has(constraintfn,xx) or
not has(constraintfn,yy)
then
WARNING("The constraint does not involve one of the stated variables.");
end if:


if not type(args[1],algebraic)
then
error "plotlm2d expects an expression as its first argument.";
else
expr := args[1]:
end if:

if not has(expr,xx) or
not has(expr,yy)
then
WARNING( "The expression to be extremized does not involve one of the stated variables.");
end if:

if nops(lhs(args[2]))<> 2
then
error "plotlm2d expects the left side of its second argument to be of the form g(x,y).";
elif not type(rhs(args[2]),realcons)
then
error "plotlm2d expects the right side of its second argument to a real constant.";
else
constraint := args[2]:
constraintfn := lhs(args[2]):
constraintconst := rhs(args[2]):
end if:

eqn_set := {diff(expr,xx)=lambda*diff(constraintfn,xx),
diff(expr,yy)=lambda*diff(constraintfn,yy),
constraint}:
soln_set := fsolve(eqn_set, {op(args[3]),lambda});
if not type(soln_set, set) then
printf("\n\nNo solution was found.\n\n");
return;
end if:
for jj from 1 to 3 do
if has(op(jj,soln_set),xx) then xx_ := rhs(op(jj,soln_set)) end if:
if has(op(jj,soln_set),yy) then yy_ := rhs(op(jj,soln_set)) end if: end do:

extreme_val := subs( {xx=xx_,yy=yy_}, expr):

printf("\nThe extreme value is %f. It occurs at %s = %f, %s = %f.\n\n", extreme_val, xx,xx_,yy,yy_);

if nargs = 3 then

plot1 := plots[implicitplot](constraint,xx=xx_-2..xx_+2,yy=yy_-2..yy_+2,thickness=3,color=navy):
plot2 := plots[implicitplot](expr=extreme_val,xx=xx_-2..xx_+2,yy=yy_-2..yy_+2,color=blue,thickness=2):
plot3 := plots[contourplot](expr,xx=xx_-2..xx_+2,yy=yy_-2..yy_+2,color=wheat):
return plots[display]({plot1,plot2,plot3});
end if:

if not type(args[4],equation) or not type(args[5],equation)
then
error "The fourth and fifth arguments of plotlm2d must be equations.";
elif not type(rhs(args[4]),range) or not type(rhs(args[5]),range)
then
error "The fourth and fifth arguments of plotlm2d must be equations of the form var = a..b.";
elif {lhs(args[4]),lhs(args[5])}<>{xx,yy} then
error "The variables in the fourth and fifth arguments of plotlm2d must match those of the thrid argument."
else
plot1 := plots[implicitplot](constraint,args[4],args[5],thickness=3,color=navy):
plot2 := plots[implicitplot](expr=extreme_val,args[4],args[5],color=blue, thickness=2):
plot3 := plots[contourplot](expr,args[4],args[5],color=wheat):
return plots[display]({plot1,plot2,plot3});
end if
end proc;

plotlm2d := proc () local xx, yy, constraint, const...
plotlm2d := proc () local xx, yy, constraint, const...
plotlm2d := proc () local xx, yy, constraint, const...
plotlm2d := proc () local xx, yy, constraint, const...
plotlm2d := proc () local xx, yy, constraint, const...
plotlm2d := proc () local xx, yy, constraint, const...
plotlm2d := proc () local xx, yy, constraint, const...
plotlm2d := proc () local xx, yy, constraint, const...
plotlm2d := proc () local xx, yy, constraint, const...
plotlm2d := proc () local xx, yy, constraint, const...
plotlm2d := proc () local xx, yy, constraint, const...
plotlm2d := proc () local xx, yy, constraint, const...
plotlm2d := proc () local xx, yy, constraint, const...
plotlm2d := proc () local xx, yy, constraint, const...
plotlm2d := proc () local xx, yy, constraint, const...
plotlm2d := proc () local xx, yy, constraint, const...
plotlm2d := proc () local xx, yy, constraint, const...
plotlm2d := proc () local xx, yy, constraint, const...
plotlm2d := proc () local xx, yy, constraint, const...
plotlm2d := proc () local xx, yy, constraint, const...
plotlm2d := proc () local xx, yy, constraint, const...
plotlm2d := proc () local xx, yy, constraint, const...
plotlm2d := proc () local xx, yy, constraint, const...
plotlm2d := proc () local xx, yy, constraint, const...
plotlm2d := proc () local xx, yy, constraint, const...
plotlm2d := proc () local xx, yy, constraint, const...
plotlm2d := proc () local xx, yy, constraint, const...
plotlm2d := proc () local xx, yy, constraint, const...
plotlm2d := proc () local xx, yy, constraint, const...
plotlm2d := proc () local xx, yy, constraint, const...
plotlm2d := proc () local xx, yy, constraint, const...
plotlm2d := proc () local xx, yy, constraint, const...
plotlm2d := proc () local xx, yy, constraint, const...
plotlm2d := proc () local xx, yy, constraint, const...
plotlm2d := proc () local xx, yy, constraint, const...
plotlm2d := proc () local xx, yy, constraint, const...
plotlm2d := proc () local xx, yy, constraint, const...
plotlm2d := proc () local xx, yy, constraint, const...
plotlm2d := proc () local xx, yy, constraint, const...
plotlm2d := proc () local xx, yy, constraint, const...
plotlm2d := proc () local xx, yy, constraint, const...
plotlm2d := proc () local xx, yy, constraint, const...
plotlm2d := proc () local xx, yy, constraint, const...
plotlm2d := proc () local xx, yy, constraint, const...
plotlm2d := proc () local xx, yy, constraint, const...
plotlm2d := proc () local xx, yy, constraint, const...
plotlm2d := proc () local xx, yy, constraint, const...
plotlm2d := proc () local xx, yy, constraint, const...
plotlm2d := proc () local xx, yy, constraint, const...
plotlm2d := proc () local xx, yy, constraint, const...
plotlm2d := proc () local xx, yy, constraint, const...
plotlm2d := proc () local xx, yy, constraint, const...
plotlm2d := proc () local xx, yy, constraint, const...
plotlm2d := proc () local xx, yy, constraint, const...
plotlm2d := proc () local xx, yy, constraint, const...
plotlm2d := proc () local xx, yy, constraint, const...
plotlm2d := proc () local xx, yy, constraint, const...
plotlm2d := proc () local xx, yy, constraint, const...
plotlm2d := proc () local xx, yy, constraint, const...
plotlm2d := proc () local xx, yy, constraint, const...
plotlm2d := proc () local xx, yy, constraint, const...
plotlm2d := proc () local xx, yy, constraint, const...
plotlm2d := proc () local xx, yy, constraint, const...
plotlm2d := proc () local xx, yy, constraint, const...
plotlm2d := proc () local xx, yy, constraint, const...
plotlm2d := proc () local xx, yy, constraint, const...
plotlm2d := proc () local xx, yy, constraint, const...
plotlm2d := proc () local xx, yy, constraint, const...
plotlm2d := proc () local xx, yy, constraint, const...
plotlm2d := proc () local xx, yy, constraint, const...
plotlm2d := proc () local xx, yy, constraint, const...
plotlm2d := proc () local xx, yy, constraint, const...
plotlm2d := proc () local xx, yy, constraint, const...
plotlm2d := proc () local xx, yy, constraint, const...
plotlm2d := proc () local xx, yy, constraint, const...
plotlm2d := proc () local xx, yy, constraint, const...
plotlm2d := proc () local xx, yy, constraint, const...

Description of plotlm2d

plotlm2d - plots
Calling Sequence:
plotlm2d(expr, constraint, set_of_vars)
plotlm2d(expr, constraint, set_of_vars, range1, range2)

Parameters:
expr - an expression to be extremized
constraint - an equation whose right side is a real constant
set_of_vars - a set consisting of two independent variables, say x and y. Optionally, either variable may
be specified as the left side of an equation, with the right side of the equation equal to a
real constant.
range1 - (optional) an equation that specifies a plotting range such as x = a..b
range2 - (optional) an equation that specifies a plotting range such as y = a..b
Description:

Examples:

> plotlm2d( x, x^2+y^2=1, {x,y});

Warning, The expression to be extremized does not involve one of the stated variables.

The extreme value is -1.000000. It occurs at x = -1.000000, y = 0.000000.

[Maple Plot]

> plotlm2d( x+y, x^2+y^2=1, {x=0.2,y});

The extreme value is -1.414214. It occurs at y = -.707107, x = -.707107.

[Maple Plot]

> plotlm2d( x^2+y, x+y=1, {x,y} , x = -1.5..2.5, y = -2..3.5);

The extreme value is .750000. It occurs at x = .500000, y = .500000.

[Maple Plot]


We can now apply
plotlm2d :

> plotlm2d( f(x,y), phi(x,y)=1, {x,y} );

The extreme value is 11.582906. It occurs at x = 8.049175, y = -2.484633.

[Maple Plot]


The default window is not the best. The constraint curve (in navy) is not seen to traverse level curves.

Often, once the location of the extreme value is found, a better plot can be obtained by changing the viewing window. This involves the five argument form of plotlm2d :

> plotlm2d( f(x,y), phi(x,y)=1, {x,y} , x= -2..15,y=-6..6);

The extreme value is 11.582906. It occurs at x = 8.049175, y = -2.484633.

[Maple Plot]



We conclude with a three dimensional picture of what is happening.

First we plot, but defer displaying the plot, the surface defined by
z = f(x,y) . We give the plot structure a name in order to display it later. Before displaying this surface, we will plot to relevant curves on it. In order to better see these curves, we plot the surface with a light color by specifying the red, blue, and green components to be just slightly less than 1 - when these three components are 1, then white results and when these three components are 0, black results.

> surface_plot := plot3d( f(x,y), x= -2..15, y=-6..6, color=COLOR(RGB,.93,.93,.93)):



Next we add the curve on the surface that lies over the constraint. We will plot this curve in navy. Again we will defer viewing it.

> curve_over_constraint := spacecurve([x, 5*(x/16-1), f(x,5*(x/16-1)), x=-2..15], thickness=3, color=navy ):


Finally, we plot the contour of the extremized function that corresponds to its minimum value relative to the constraint. We specify blue for the color of this contour.

> contour_at_min := plot3d( f(x,y), x= -2..15, y=-6..6, style=CONTOUR, contours = [min_val], thickness=3, color=blue):


Finally we display the superposition of our three plot structures:

> display( {surface_plot, curve_over_constraint, contour_at_min} );

[Maple Plot]

Visualizing The Tangent Plane Piece by Piece

We can use the sequential displaying of plot components to illustrate the development of the tangent plane.

Example:

Illustrate the curve formed by the intersection of the graph of f(x,y) = 80-2*x^2-y^2 with the plane that is perpendicular to the xy -plane and that is defined by the equation x = 1 . Repeat with the plane that is perpendicular to the xy -plane and that is defined by the equation y = 2 . Plot the tangent lines of these two curves of intersection at the point [1, 2] . Plot the plane that is determined by these two tangent lines.

Solution:

> a := 1: b := 2:

> f := (x,y) -> 80-2*x^2-y^2:


For the graph of the surface we use:

> figure[1] := plot3d(f(x,y),x=-4..4,y=-5..5,shading = ZGRAYSCALE):

Next we add the lines x = 1 and y = 2 in the xy -plane.

> figure[2] := spacecurve([a,y,0,y=-5..5],color=sienna,thickness=3):

> figure[3] := spacecurve([x,b,0,x=-4..4],color=sienna,thickness=3):


Now we add a dotted vertical line from the point
[1,2,0] up to the surface:

> figure[4] := spacecurve([a,b,z,z=0..f(a,b)],color=sienna,linestyle=2,thickness=3):

Now we add the plane through x = 1 :

> figure[5] := plot3d([a,y,z],y=-5..5,z=0..f(a,b),color=COLOR(RGB,.99,.85,.80), style=PATCHNOGRID):

and its intersection with the surface:

> figure[6] := spacecurve([a,y,f(a,y),y=-5..5],color=red,thickness=3):


We add the tangent line:

> figure[7] := spacecurve([a,y,f(a,b)+D[2](f)(a,b)*(y-b), y=-5..5],color=maroon,thickness=3):


We repeat with the plane through
y = 2 .

> figure[8] := plot3d([x,b,z],x=-4..4,z=0..f(a,b),color=COLOR(RGB,.99,.85,.80), style=PATCHNOGRID):


and its intersection with the surface:

> figure[9] := spacecurve([x,b,f(x,b),x=-4..4],color=red, thickness=3):


and its tangent line:

> figure[10] := spacecurve([x,b,f(a,b)+D[1](f)(a,b)*(x-a),x=-4..4],color=maroon, thickness=3):


Finally, the tangent plane:

> figure[11] := plot3d(f(a,b)+D[1](f)(a,b)*(x-a)+D[2](f)(a,b)*(y-b),x=-4..4,y=-5..5,color=pink):


Now we are ready to piece everything together:

> plot_list[1] := [figure[1]]:
for j from 2 to 11 do
plot_list[j] := [op(plot_list[j-1]),figure[j]]:
end do:


Now for the display:

> for j from 1 to 11 do
display(plot_list[j]);
end do;

[Maple Plot]

[Maple Plot]

[Maple Plot]

[Maple Plot]

[Maple Plot]

[Maple Plot]

[Maple Plot]

[Maple Plot]

[Maple Plot]

[Maple Plot]

[Maple Plot]

Naturally it is possible to automate this procedure. Here is a function, construct_tangent_plane , that does just that. (However, the (beige-colored) planes have intentionally been omitted.)

An example is provided in the subsection that describes
construct_tangent_plane .

Code for construct_tangent_plane

> construct_tangent_plane := proc()
local figure, a, b, xx, yy, z, H, j, plot_list, expr:
global tangent_plane_plot_sequence:

if nargs <> 4 then
error "construct_tangent_plane expects 4 arguments.";
elif not type(args[2],list) then
error "construct_tangent_plane expects an ordered pair as its second argument.";
elif nops(args[2])<> 2 then
error "construct_tangent_plane expects a list with two elements as its second argument.";
elif not type(op(1,args[2]),realcons)
or not type(op(2,args[2]),realcons) then
error "construct_tangent_plane expects its second argument to be of the form [a,b] where a and b are real constants.";
elif not type(args[1],algebraic) then
error "construct_tangent_plane expects its first argument to be an algebraic expression.";
elif not type(args[3],equation) or not type(args[4],equation) or not type(lhs(args[3]),name) or not type(lhs(args[4]),name) or not type(rhs(args[3]),range) or not type(rhs(args[4]),range) then
error "construct_tangent_plane expects each its third and fourth arguments to be of the form name_of_variable = realconstant..realconstant";
elif not type( op(1,rhs(args[3])), realcons) or not type( op(2,rhs(args[3])), realcons) or not type( op(1,rhs(args[4])), realcons) or not type( op(2,rhs(args[4])), realcons) then
error "construct_tangent_plane expects each its third and fourth arguments to be of the form name_of_variable = realconstant..realconstant";
elif op(1,args[2]) < op(1,rhs(args[3])) or op(1,args[2]) > op(2,rhs(args[3])) or
op(2,args[2]) < op(1,rhs(args[4])) or op(2,args[2]) > op(2,rhs(args[4]))then
error "construct_tangent_plane expects the view ranges entered as the third and fourth arguments to define a rectangle that contains the point entered as the second argument.";


else
a := op(1,args[2]):
b := op(2,args[2]):
xx := lhs(args[3]):
yy := lhs(args[4]):
expr := args[1]:
H := subs({xx = a, yy = b} , expr):
figure[1] := plot3d(expr,args[3],args[4],shading=ZGRAYSCALE):
figure[2] := plots[spacecurve]([a,yy,0,args[4]],color=sienna,thickness=3):
figure[3] := plots[spacecurve]([xx,b,0,args[3]],color=sienna,thickness=3):
figure[4] := plots[spacecurve]([a,b,z,z=0..H],color=sienna,linestyle=2,thickness=3):
figure[5] := plots[spacecurve]([a,yy,subs({xx= a} ,expr),args[4]],color=red,thickness=3):
figure[6] := plots[spacecurve]([a,yy,H+subs({xx = a, yy = b}, diff(args[1],yy))*(yy-b), args[4]],color=maroon,thickness=3):
figure[7] := plots[spacecurve]([xx,b,subs({yy= b} ,args[1]),args[3]],color=red, thickness=3):
figure[8] := plots[spacecurve]([xx,b,H+subs({xx= a, yy= b}, diff(expr,xx))*(xx-a),args[3]],color=maroon, thickness=3):
figure[9] := plot3d(H+subs({xx = a, yy = b}, diff(expr,xx))*(xx-a)+subs({xx = a, yy= b}, diff(expr,yy))*(yy-b),args[3],args[4],color=pink):
plot_list[1] := [seq(figure[j],j=1..4)]:
tangent_plane_plot_sequence := [plot_list[1]]:
for j from 2 to 6 do
plot_list[j] := [op(plot_list[j-1]),figure[j+3]]:
tangent_plane_plot_sequence := [op(tangent_plane_plot_sequence),plot_list[j]]:
end do:
printf("\nThe global variable
tangent_plane_plot_sequence has been created.\n\nCopy, paste, and execute the following code at the next Maple prompt: \n\nwith(plots): for j from 1 to 6 do display(tangent_plane_plot_sequence[j]) end do;\n\n"):
end if:
end proc:

Description of construct_tangent_plane

construct_tangent_plane - creates a list of plot structures to illustrate the tangent plane
Calling Sequence:
construct_tangent_plane(expr, point, range1, x_view, y_view)

Parameters:
expr - an expression to be plotted
point - a list [a,b] with a and b specified real constants
x_view - an equation of the form x = c..d where c and d are real constants containing a
and x is the name of the first independent variable of expr.
y_view - an equation of the form y = e..f where e and f are real constants containing b
and y is the name of the first independent variable of expr.
Description:

Examples:

> construct_tangent_plane(1000-x^2-5*x*y^3, [3,1], x = 1..5, y = 0..3);

The global variable

tangent_plane_plot_sequence has been created.

Copy, paste, and execute the following code at the next Maple prompt: 

with(plots): for j from 1 to 6 do display(tangent_plane_plot_sequence[j]) end do;

> with(plots): for j from 1 to 6 do display(tangent_plane_plot_sequence[j]) end do;

[Maple Plot]

[Maple Plot]

[Maple Plot]

[Maple Plot]

[Maple Plot]

[Maple Plot]

Plotting Vectors On a Surface

The need for plotting a vector field on a surface arises from time to time. Rather than reinvent the wheel, I will use Robert Israel's code for doing this. It was posted to the Maple User's Group on 9 May 1997. It was written for Releases 3 and 4 of Maple V. Apart from an extremely trivial update to Maple 6 syntax, I have not changed the code. The code may be freely used but Professor Israel retains copyright.


In practice, the next three execution groups would be executed and the resulting functions would be incorporated into an installed package. The user would see none of the code and could use the functions as he would any built-in function.

> evl := t -> convert(evalm(t), list);
enull:= proc(s) if type(s,string) then NULL else s fi end;

evl := proc (t) options operator, arrow; convert(ev...

enull := proc (s) if type(s,string) then NULL else ...

> myarrow := proc(base::{list,vector},vect::{list,vector})

## Plots an arrow as a line with a pyramidal head.
## usage: myarrow(base, vect, options)
## "base" is point for base of arrow, "vect" is tip - base
## These can be lists or vectors.
## "options" are the usual plot3d options.
## Colour is red by default.
## More options could be added to control the proportions of the arrow.

local b1,v1,stem,r,hbase,hpoint,v2,v3,head,opts;
b1 := evalf(evl(base));
v1 := evalf(evl(vect));
if nops(b1) <> 3 or nops(v1) <> 3 then
ERROR(`points need three dimensions`)
fi;
if not (type(b1,[realcons,realcons,realcons]) and
type(v1,[realcons,realcons,realcons])) then
ERROR(`points must evaluate to real constants`)
fi;
hbase := evl(b1+.8*v1);
hpoint := evl(b1+v1);
opts := args[3 .. nargs];
if indets({opts}) intersect {color,colour} = {} then
opts := opts,colour = red
fi;
stem := plots[spacecurve]([b1,hbase],thickness = 3,opts);
if v1 = [0,0,0] then RETURN(stem) fi;
r := sqrt(linalg[norm](v1,2));
v2 := evl(linalg[crossprod]([1,0,0],v1));
if linalg[dotprod](v2,v2) < .01*linalg[dotprod](v1,v1) then
v2 := evl(linalg[crossprod]([0,1,0],v1))
fi;
v2 := evl(.05*r*v2/linalg[norm](v2,2));
v3 := linalg[crossprod](v1,v2);
v3 := evl(.05*r*v3/linalg[norm](v3,2));
head := plots[polygonplot3d]([hpoint,evl(hbase+v2),
evl(hbase+v3), evl(hbase-v2),
evl(hbase-v3), evl(hbase+v2)]
,style = patch,opts);
plots[display]({stem,head})
end;

myarrow := proc (base::{vector, list}, vect::{vecto...
myarrow := proc (base::{vector, list}, vect::{vecto...
myarrow := proc (base::{vector, list}, vect::{vecto...
myarrow := proc (base::{vector, list}, vect::{vecto...
myarrow := proc (base::{vector, list}, vect::{vecto...
myarrow := proc (base::{vector, list}, vect::{vecto...
myarrow := proc (base::{vector, list}, vect::{vecto...
myarrow := proc (base::{vector, list}, vect::{vecto...
myarrow := proc (base::{vector, list}, vect::{vecto...
myarrow := proc (base::{vector, list}, vect::{vecto...
myarrow := proc (base::{vector, list}, vect::{vecto...
myarrow := proc (base::{vector, list}, vect::{vecto...
myarrow := proc (base::{vector, list}, vect::{vecto...
myarrow := proc (base::{vector, list}, vect::{vecto...
myarrow := proc (base::{vector, list}, vect::{vecto...
myarrow := proc (base::{vector, list}, vect::{vecto...
myarrow := proc (base::{vector, list}, vect::{vecto...
myarrow := proc (base::{vector, list}, vect::{vecto...
myarrow := proc (base::{vector, list}, vect::{vecto...
myarrow := proc (base::{vector, list}, vect::{vecto...
myarrow := proc (base::{vector, list}, vect::{vecto...
myarrow := proc (base::{vector, list}, vect::{vecto...
myarrow := proc (base::{vector, list}, vect::{vecto...
myarrow := proc (base::{vector, list}, vect::{vecto...
myarrow := proc (base::{vector, list}, vect::{vecto...
myarrow := proc (base::{vector, list}, vect::{vecto...

> surfarrows := proc(fld,surf,r1,r2)
## Plots a 3d surface (parametric or cartesian) with arrows from
## a vector field at points on the surface
## Usage:
## surfarrows(F(s,t), [x(s,t),y(s,t),z(s,t)], s=a1 .. b1, t=a2 .. b2, options)
## for vectors F(s,t) at points [x(s,t), y(s,t), z(s,t)]
## where F(s,t) is a list expression
## surfarrows(F(x,y), z(x,y), x=a1 .. b1, y=a2 .. b2, options)
## for vectors F(x,y) at points [x, y, z(x,y)]
## where F(x,y) is a list expression
## surfarrows(F, [x(s,t),y(s,t),z(s,t)], s=a1 .. b1, t=a2 .. b2, options)
## for vectors F(x(s,t),y(s,t),z(s,t)) at [x(s,t),y(s,t),z(s,t)]
## where F is a list-valued function of three variables
## surfarrows(F, z(s,t), x=a1 .. b1, y=a2 .. b2, options)
## for vectors F(x,y,z(s,t)] at [x,y,z(x,y)]
## where F is a list-valued function of three variables
## "options" are the usual 3d plot options, plus
## arrowgrid= [n1, n2]
## for arrows in an n1 by n2 grid, equally spaced in terms of the parameters
## of the surface (default is arrowgrid=[8,8])
## Caution: inputs are not checked for validity

local opts,gspec,p1,p2,s2,f2,v1,v2,a1,a2,b1,b2,n1,n2,h1,h2,i,j;
opts := args[5 .. nargs];
v1 := op(1,r1);
v2 := op(1,r2);
a1 := op(1,op(2,r1));
b1 := op(2,op(2,r1));
a2 := op(1,op(2,r2));
b2 := op(2,op(2,r2));
gspec := indets({opts},identical('arrowgrid') = list);
if gspec = {} then gspec := arrowgrid = [8,8]
else opts := op({opts} minus gspec); gspec := gspec[1]
fi;
p1 := plot3d(surf,r1,r2,opts);
opts :=
op({opts} minus indets({opts},identical('grid') = list))
;
n1 := op(2,gspec)[1]-1;
n2 := op(2,gspec)[2]-1;
h1 := (b1-a1)/n1;
h2 := (b2-a2)/n2;
if type(surf,list) then s2 := surf
elif type(surf,vector) then s2 := evl(surf)
else s2 := [v1,v2,surf]
fi;
if type(fld,procedure) then f2:= evl(fld(op(s2)))
else f2:= evl(fld)
fi;
p2 := seq(seq(enull(traperror(
myarrow(op(subs(v1 = a1+h1*i,v2 = a2+j*h2,[s2,f2])),opts))),
i = 0 .. n1),j = 0 .. n2);
plots[display]({p2,p1},opts)
end;

surfarrows := proc (fld, surf, r1, r2) local opts, ...
surfarrows := proc (fld, surf, r1, r2) local opts, ...
surfarrows := proc (fld, surf, r1, r2) local opts, ...
surfarrows := proc (fld, surf, r1, r2) local opts, ...
surfarrows := proc (fld, surf, r1, r2) local opts, ...
surfarrows := proc (fld, surf, r1, r2) local opts, ...
surfarrows := proc (fld, surf, r1, r2) local opts, ...
surfarrows := proc (fld, surf, r1, r2) local opts, ...
surfarrows := proc (fld, surf, r1, r2) local opts, ...
surfarrows := proc (fld, surf, r1, r2) local opts, ...
surfarrows := proc (fld, surf, r1, r2) local opts, ...
surfarrows := proc (fld, surf, r1, r2) local opts, ...
surfarrows := proc (fld, surf, r1, r2) local opts, ...
surfarrows := proc (fld, surf, r1, r2) local opts, ...
surfarrows := proc (fld, surf, r1, r2) local opts, ...
surfarrows := proc (fld, surf, r1, r2) local opts, ...
surfarrows := proc (fld, surf, r1, r2) local opts, ...
surfarrows := proc (fld, surf, r1, r2) local opts, ...
surfarrows := proc (fld, surf, r1, r2) local opts, ...
surfarrows := proc (fld, surf, r1, r2) local opts, ...
surfarrows := proc (fld, surf, r1, r2) local opts, ...
surfarrows := proc (fld, surf, r1, r2) local opts, ...
surfarrows := proc (fld, surf, r1, r2) local opts, ...
surfarrows := proc (fld, surf, r1, r2) local opts, ...
surfarrows := proc (fld, surf, r1, r2) local opts, ...
surfarrows := proc (fld, surf, r1, r2) local opts, ...


Here are some examples:

> surfarrows((x,y,z) -> [x, y, 2*x^2-2*y^2]/3, x^2 - y^2, x=-1 .. 1, y=-1 .. 1,scaling=constrained,style=patch);

[Maple Plot]


And one with the field of normal vectors:

> sphere:= [cos(u)*cos(v), sin(u)*cos(v), sin(v)]:
with(linalg):
unit:= V -> evl(V/norm(V,2)):
tnormal:= unit(crossprod(diff(sphere,u),diff(sphere,v))):
surfarrows( tnormal/2, sphere, u=0 .. 2*Pi, v=-Pi/2 .. Pi/2,
scaling=constrained);

Warning, the protected names norm and trace have been redefined and unprotected

[Maple Plot]

There are two large resources that contain a wealth of freely available Maple materials. One is the Maple Share Library. The other is the Archive of the Maple User Group.

Plotting Vectors On a Curve (Planar or Space)

Robert Israel also contributed code for doing this. It was posted to the Maple User's Group on 21 May 1997. Apart from an extremely trivial update to Maple 6 syntax, I have not changed his code. The code may be freely used but Professor Israel retains copyright.

> evl:= t -> convert(evalm(t), list);
enull:= proc(s) if type(s,string) then NULL else s fi end;

evl := proc (t) options operator, arrow; convert(ev...

enull := proc (s) if type(s,string) then NULL else ...

> myarrow2d := proc(base, vect)
## Plots an arrow as a line with a triangular head.
## usage: myarrow2d(base, vect, options)
## "base" is point for base of arrow, "vect" is tip - base
## These can be lists or vectors.
## "options" are the usual plot options.
## Colour is red by default.

local b1,v1,stem,r,hbase,hpoint,v2,v3,head,opts;
b1 := evalf(evl(base));
v1 := evalf(evl(vect));
if nops(b1) <> 2 or nops(v1) <> 2 then
ERROR(`points need two dimensions`)
fi;
if not (type(b1,[realcons,realcons]) and
type(v1,[realcons,realcons])) then
ERROR(`points must evaluate to real constants`)
fi;
hbase := evl(b1+.8*v1);
hpoint := evl(b1+v1);
opts := args[3 .. nargs];
if indets({opts}) intersect {color,colour} = {} then
opts := opts,colour = red
fi;
stem := plot([b1,hbase],thickness = 3,opts);
if v1 = [0,0] then RETURN(stem) fi;
v2:= [.1*v1[2],-.1*v1[1]];
head := plots[polygonplot]([hpoint,evl(hbase+v2),evl(hbase-v2)],
style = patch,opts);
plots[display]({stem,head})
end;

myarrow2d := proc (base, vect) local b1, v1, stem, ...
myarrow2d := proc (base, vect) local b1, v1, stem, ...
myarrow2d := proc (base, vect) local b1, v1, stem, ...
myarrow2d := proc (base, vect) local b1, v1, stem, ...
myarrow2d := proc (base, vect) local b1, v1, stem, ...
myarrow2d := proc (base, vect) local b1, v1, stem, ...
myarrow2d := proc (base, vect) local b1, v1, stem, ...
myarrow2d := proc (base, vect) local b1, v1, stem, ...
myarrow2d := proc (base, vect) local b1, v1, stem, ...
myarrow2d := proc (base, vect) local b1, v1, stem, ...
myarrow2d := proc (base, vect) local b1, v1, stem, ...
myarrow2d := proc (base, vect) local b1, v1, stem, ...
myarrow2d := proc (base, vect) local b1, v1, stem, ...
myarrow2d := proc (base, vect) local b1, v1, stem, ...
myarrow2d := proc (base, vect) local b1, v1, stem, ...
myarrow2d := proc (base, vect) local b1, v1, stem, ...
myarrow2d := proc (base, vect) local b1, v1, stem, ...
myarrow2d := proc (base, vect) local b1, v1, stem, ...

> curvarrows := proc(fld,curv,t::name=range)
## Plots a 2d or 3d curve (parametric or cartesian) with arrows from
## a vector field at points on the curve
## Usage:
## curvarrows(F(t), [x(t),y(t) {,z(t)}], t=a .. b, options)
## for vectors F(t) at points [x(t), y(t) {, z(t)}]
## where F(t) is a list expression
## curvarrows(F(x), y(x), x=a .. b, options)
## for vectors F(x) at points [x, y(x)]
## where F(x) is a list expression
## curvarrows(F, [x(t),y(t) {, z(t)}], t=a .. b, options)
## for vectors F(x(t),y(t) {, z(t)}) at [x(t),y(t) {,z(t)} ]
## where F is a list-valued function of two {or three} variables
## curvarrows(F, y(x), x=a .. b, options)
## for vectors F(x,y(x)) at [x,y(x)]
## where F is a list-valued function of two variables
## "options" are the usual plot or plot3d options, plus
## arrownum= n
## for n arrows along the curve, equally spaced in terms of the
## parameter defining the curve (default is 10)
## Caution: inputs are not checked for validity

local opts,gspec,p1,p2,s2,f2,v1,a1,b1,n1,n2,h1,h2,i,j,dim,aproc;
opts := args[4 .. nargs];
v1 := op(1,t);
a1 := op(1,op(2,t));
b1 := op(2,op(2,t));
gspec := indets({opts},identical('arrownum') = posint);
if gspec = {} then gspec := arrownum = 10
else opts := op({opts} minus gspec); gspec := gspec[1]
fi;
if type(curv, list) and nops(curv)=3 then dim:= 3; aproc:= eval(myarrow)
else dim:= 2; aproc:=eval(myarrow2d)
fi;
if dim=2 then
if type(curv, list) then p1:= plot([op(curv), t], opts) # parametric 2d
else p1 := plot(curv,t,opts) # cartesian 2d
fi
else p1:= plots[spacecurve](curv,t,opts) # parametric 3d
fi;
opts :=
op({opts} minus indets({opts},identical('numpoints') = list))
;
n1 := op(2,gspec)-1;
h1 := (b1-a1)/n1;
if type(curv,list) then s2 := curv
else s2 := [v1,curv]
fi;
if type(fld,procedure) then f2:= evl(fld(op(s2)))
else f2:= evl(fld)
fi;
p2 := seq(enull(traperror(
aproc(op(subs(v1 = a1+h1*i,[s2,f2])),opts))),
i = 0 .. n1);
plots[display]({p2,p1},opts)
end;

curvarrows := proc (fld, curv, t::(name = range)) l...
curvarrows := proc (fld, curv, t::(name = range)) l...
curvarrows := proc (fld, curv, t::(name = range)) l...
curvarrows := proc (fld, curv, t::(name = range)) l...
curvarrows := proc (fld, curv, t::(name = range)) l...
curvarrows := proc (fld, curv, t::(name = range)) l...
curvarrows := proc (fld, curv, t::(name = range)) l...
curvarrows := proc (fld, curv, t::(name = range)) l...
curvarrows := proc (fld, curv, t::(name = range)) l...
curvarrows := proc (fld, curv, t::(name = range)) l...
curvarrows := proc (fld, curv, t::(name = range)) l...
curvarrows := proc (fld, curv, t::(name = range)) l...
curvarrows := proc (fld, curv, t::(name = range)) l...
curvarrows := proc (fld, curv, t::(name = range)) l...
curvarrows := proc (fld, curv, t::(name = range)) l...
curvarrows := proc (fld, curv, t::(name = range)) l...
curvarrows := proc (fld, curv, t::(name = range)) l...
curvarrows := proc (fld, curv, t::(name = range)) l...
curvarrows := proc (fld, curv, t::(name = range)) l...
curvarrows := proc (fld, curv, t::(name = range)) l...
curvarrows := proc (fld, curv, t::(name = range)) l...
curvarrows := proc (fld, curv, t::(name = range)) l...
curvarrows := proc (fld, curv, t::(name = range)) l...
curvarrows := proc (fld, curv, t::(name = range)) l...

Here is an example of the tangent field for a planar curve:

> curvarrows((x,y) -> [-y, x]/2, [cos(x),sin(x)], x=-Pi .. Pi,scaling=constrained);

[Maple Plot]

Here is an example of the tangent vector field for a space curve.

> curvarrows((x,y,z) -> [-y, x, 1], [cos(z),sin(z),z], z=0..4*Pi);

[Maple Plot]

Plotting Level Surfaces

Plotting One Level Surface

If F is a function of three variables and if c is a constant, then the equation F(x,y,z) = c defines a surface in xyz -space. It is called a level surface . Maple has a function, implicitplot3d , in the plots package. Its syntax is pretty obvious: implicitplot( F(x, y, z) = c, x = a..b, y = c..d, z = e..f );

Example: Plot the one-sheeted hyperboloid defined by x^2+y^2-z^2 = 1 .

Solution:

> with(plots):

> F := (x,y,z) -> x^2+y^2-z^2:

> implicitplot3d( F(x,y,z) = 1, x=-2..2, y=-2..2, z=-2..2);

[Maple Plot]

Example: Plot the two-sheeted hyperboloid defined by x^2-y^2-z^2 = 1 .

Solution:

> with(plots):

> G := (x,y,z) -> x^2-y^2-z^2:

> implicitplot3d( G(x,y,z) = 1, x=-5..5, y=-5..5, z=-5..5);

[Maple Plot]

Plotting Several Level Surfaces

A set of level surfaces can be plotted by using a set as the first argument of implicitplot3d .


Example:

Plot the three cylinders x^2+y^2 = 1, x^2+z^2 = 1, y^2+z^2 = 1 .

Solution:

> F1 := (x,y,z) -> x^2+y^2:
F2 := (x,y,z) -> x^2+z^2:
F3 := (x,y,z) -> y^2+z^2:

> w := x,y,z:

> implicitplot3d({F1(w)=1,F2(w)=1,F3(w)=1} , x=-2..2,y=-2..2,z=-2..2);

[Maple Plot]

Copyright and Author Information

MultivariablePlottingII.mws A Maple Release 6 worksheet.

Author: Brian E. Blank (17 March 2000)

Except where otherwise noted, all parts of this document, including the code for the

Maple functions that have been included, are copyrighted to the author.

This html document may not be distributed by any medium,
including print, disk, and electronic transfer, without
prior written permission of the author.

The worksheet MultivariablePlottingII.mws on which this html'ed format
is based may be downloaded for
personal, noncommercial use.
Please check the author's Maple page (http://ascc.artsci.wustl.edu/~bblank/Maple/)
for a link.


For more information, please contact the author:

Department of Mathematics,
Washington University in St. Louis
St. Louis, MO 63130

Telephone: (314) 935-6763
e-mail: brian@math.wustl.edu

Copyright: © 2000 Brian E. Blank, All Rights Reserved.

Copyright and Author Information:
MultivariablePlottingI.mws A Maple Release 6 worksheet.

Author: Brian E. Blank (17 March 2000)

This html document may not be distributed by any medium,
including print, disk, and electronic transfer, without
prior written permission of the author.

The worksheet MultivariablePlottingII.mws on which this html'ed format
is based may be downloaded for
personal, noncommercial use.
Please check the author's Maple page (http://ascc.artsci.wustl.edu/~bblank/Maple/)
for a link.


For more information, please contact the author:

Department of Mathematics,
Washington University in St. Louis
St. Louis, MO 63130

Telephone: (314) 935-6763
e-mail: brian@math.wustl.edu

Copyright: © 2000 Brian E. Blank, All Rights Reserved.