Contour Plots of Linear Functions

by
K. D.  Stroyan
University of Iowa

copyright 1997 by Academic Press, Inc. - All rights reserved.

Special Mathematica Functions used in this NoteBook

We told you not to look.  This horrible stuff sets various defaults and defines some functions needed to draw the geometric side of the lexicon.  Ignore the details here and go on to the lesson.

Off[General::spell];
Off[General::spell1];
Off[ParametricPlot3D::ppcom]
Needs["Graphics`Colors`"]

SetOptions[Graphics,Axes->False,AxesOrigin->{0,0},AspectRatio->Automatic];
SetOptions[Graphics3D,ViewPoint->{5,2,1},Boxed->False,AspectRatio->Automatic];
SetOptions[ParametricPlot3D,ViewPoint->{5,2,1},AspectRatio->Automatic];
SetOptions[Plot3D,ViewPoint->{5,2,1},AspectRatio->Automatic];
SetOptions[ParametricPlot,AspectRatio->Automatic];
SetOptions[Plot,AspectRatio->Automatic];

colorQ[a_]:=(Head[a]===RGBColor);
grayQ[a_]:=(Head[a]===GrayLevel);
thickQ[a_]:=(Head[a]===Thickness);
absthickQ[a_]:=(Head[a]===AbsoluteThickness);
notruleQ[u_] := !(Head[u]===Rule);
ruleQ[u_] := (Head[u]===Rule);

Norm::usage = "Norm[expr] returns the Euclidean length of the
		vector, 'expr'.";

Norm[a_?VectorQ] := Sqrt[a.a];

Angle[a_?VectorQ,b_?VectorQ] := ArcCos[(a.b)/(Norm[a] Norm[b])]

Proj[a_?VectorQ,b_?VectorQ] := ((a.b)/(b.b))b

tol = .5*10^-6;

OrthUp[a_?VectorQ] :=
	Module[{b,c,d,f},
		d = N[a/Norm[a]];
		If[Chop[d[[3]]^2 - 1,tol] == 0, b={1,0,0} ,
		b = {0,0,1} - d[[3]] d; b = b/Norm[b];];
	Return[b]];
	
OrthSet[a_?VectorQ] :=
	Module[{b,c,d},
		d = N[a/Norm[a]];
		If[Chop[d[[1]],tol]==0,b={1,0,0},
			 If[Chop[d[[2]],tol]==0,b={0,1,0},
			  b={-d[[2]],d[[1]],0}]];
			b=b/Norm[b];c = Cross[d,b];
	Return[{b,c/Norm[c],d}]];

				
Rotate[a_?VectorQ,theta_] :=
	Module[{u,v,r},
		u = OrthSet[a];
		v = Transpose[u];
		r = N[{{Cos[theta],-Sin[theta],0},{Sin[theta],Cos[theta],0},{0,0,1}}];
	Return[v.r.u]];

Vector2D[tail_,tip_,opts___]:=
	Module[{ntail,ntip,sopts,Punit,up,arrow},
	ntail = N[tail];
	ntip = N[tip];
	
	sopts = Join[Select[{opts},colorQ],Select[{opts},
				thickQ],Select[{opts},absthickQ],Select[{opts},grayQ]];

If[Chop[ntail.ntail+ntip.ntip,tol] == 0,
			(*too small to plot or not number*)
			Return[Graphics[Point[{0,0}]]];
	,						
If[Chop[(ntip-ntail).(ntip-ntail),tol] == 0,
		Return[Graphics[{Join[sopts,{Line[{ntail,ntip}]}]}]];
	,
	Punit = (.075 Norm[ntip-ntail]/Norm[ntip-ntail]) (ntip-ntail) ;
	up = 0.15 {-Punit[[2]],Punit[[1]]};
	arrow = Line[{ntail,ntip,ntip-Punit+up,ntip,ntip-Punit-up}];
	]];
Return[Graphics[{Join[{AbsoluteThickness[2]},Join[sopts,{arrow}]]}]];
];

Vector3D[tail_,tip_,opts___]:=
	Module[{ntail,ntip,sopts,Punit,up,u2,u3,u4,rotmat,arrow},
	ntail = N[tail];
	ntip = N[tip];
	
	sopts = Join[Select[{opts},colorQ],Select[{opts},
				thickQ],Select[{opts},absthickQ],Select[{opts},grayQ]];

If[Chop[ntail.ntail+ntip.ntip,tol] == 0,
			(*too small to plot or not number*)
			Return[Graphics3D[Point[{0,0,0}]]];					
	,		
If[Chop[(ntip-ntail).(ntip-ntail),tol] == 0,
		Return[Graphics3D[{Join[sopts,{Line[{ntail,ntip}]}]}]];
	,
	Punit = (ntip-ntail);
	rotmat = Rotate[Punit,N[Pi/2]];
	up = OrthUp[Punit];
	Punit = .075 Punit;
	up = .15 Norm[Punit] up;
	u2 = rotmat.up;
	u3 = rotmat.u2;
	u4 = rotmat.u3;
	arrow = Line[{ntail,ntip,
				ntip - Punit + up,ntip,
				ntip - Punit + u2,ntip,
				ntip - Punit + u3,ntip,
				ntip - Punit + u4}];
	]];
Return[Graphics3D[{Join[{AbsoluteThickness[2]},Join[sopts,{arrow}]]}]];
];

aRCtAN[y_,x_] := Module[{v},
	If[ Chop[N[x],tol] == 0 ,If[ N[y] < 0, v = -N[Pi/2], v = N[Pi/2]],
		v = N[ArcTan[y/x]];
		If[ x < 0 && y < 0, v = N[Pi -  v],v]];
	Return[v]];

Arc2D[X_,Y_,opts___] := Graphics[{opts,
		Disk[{0,0},1,{Min[
							aRCtAN[
						N[X[[2]]],N[X[[1]]]
								]
							,
							aRCtAN[
							N[Y[[2]]],N[Y[[1]]]
								]
						]
						,
					Max[
							aRCtAN[
						N[X[[2]]],N[X[[1]]]
								]
							,
							aRCtAN[
							N[Y[[2]]],N[Y[[1]]]
								]
						]}
				]}
				];
Arc3D[X_,Y_] := 
	Module[{t,U,V},
		U[V_]:= N[(1/Sqrt[V.V]) V];
		Return[Graphics3D[
		Polygon[Append[Table[U[t X + (1-t) Y],{t,0,1,0.1}],{0,0,0}]]
				]
		]
	];

(*Zero Arrow causes trouble. Put in Vector?*)

Vector[tail_,tip_,opts___]:=
	If[Length[N[tail]]==2,Return[Vector2D[tail,tip,opts]],
		Return[Vector3D[tail,tip,opts]]];
		
Arrow[vec_,opts___]:= 
	Module[{a,b},
				If[Length[N[vec]]==2,
				a=ToExpression["Tail"]/.Select[{opts},ruleQ]/.
					{ToExpression["Tail"]->{0,0}};
				Return[Vector2D[a,a+vec,opts]],
				a=ToExpression["Tail"]/.Select[{opts},ruleQ]/.
					{ToExpression["Tail"]->{0,0,0}};
				Return[Vector3D[a,a+vec,opts]]]
				];

Frame2D[delta_] := 
      Graphics[{
            {Green,Line[{{-delta/4,0},{delta,0}}]},
                    Text["x",{1.01 delta,0}],
            {Green,Line[{{0,-delta/4},{0,delta}}]},
                    Text["y",{0, 1.01 delta}]}];

Frame3D[delta_] := 
      Graphics3D[{
            {Green,Line[{{-delta/4,0,0},{delta,0,0}}]},
                    Text["x",{1.01 delta,0,0}],
            {Green,Line[{{0,-delta/4,0},{0,delta,0}}]},
                    Text["y",{0, 1.01 delta,0}],
            {Green,Line[{{0,0,-delta/4},{0,0,delta}}]},
                    Text["z",{0,0,1.01 delta}]}];

View2D[stuff_,opns___] := Show[stuff,Frame2D[1],opns];
View3D[stuff_,opns___] := Show[stuff,Frame3D[1],opns];

Notebook Overview

A linear function in two independent variables

z = f[x,y] = m x + n y + b

for constants  m, n, and  b  is studied geometrically by its explicit plot in the NoteBook PlaneLines.  In this NoteBook, we study the geometric meaning of the constants in terms of the contour plot of  f[x,y].  Specifically,

1)  we show how to measure  m  and  n  from a given contour plot

2)  we show how the gradient vector  G = {m,n}  is connected to the spacing of contour lines.

The gradient  G  has an interpretation as a "vector slope" for the explicit plane and we know from the explicit graph (and the NoteBook PlaneLines) that

a)  G points in the (x,y)-direction of fastest increase in  z

b)  |G| is the slope of a line in the fastest direction, specifically, |G|  is the amount of increase in  z  if we move a unit distance in the direction of  G.

Geometric Summary of  a x + b y = k

Here is a review of the geometric interpretation of the implicit equation of a line.  (See the text and the NoteBook "PlaneLines" for more details.)

The implicit equation

a x + b y = k

is the line perpendicular to the direction of  V = {a,b}  translated in the direction of  V  a distance

((| k | )/(| V | ))

from the origin.  In particular, if  V = {a,b}  is a unit length vector (a^2 + b^2 = 1), then

a x + b y = k

is the line perpendicular to  {a,b}  a distance  k  from the origin along {a,b}.

References to the Text

This NoteBook goes with Section 17.4 on linear contours and gradients.

The Gradient and Contour Maps of z = m x + n y + b

Contours of  z = m x + n y + b  & implicit lines  m x + n y = k

A contour plot of a function  f[x,y]  is a family of curves,  f[x,y] = k1, f[x,y] = k2, f[x,y] = k3, for a sequence of constants  k1, k2, k3,...  When  f[x,y] = m x + n y + b, these curves are implicit lines:

m x + n y = h1

m x + n y = h2

m x + n y = h3, ...

where the constants  hj = kj - b.

For example, if  f[x,y] = 3 x + 4 y, a contour plot could consist of the implicit lines

3 x + 4 y = 0,  3 x + 4 y = 1, 3 x + 4 y = 2, 3 x + 4 y = 3, 3 x + 4 y = 4, 3 x + 4 y = 5

Clear[G, X, P, x, y, k]; G = {3, 4}; X = {x, y}; Print["G.X =", G . X, " = k"]; Print["Gradient G = ", G]; graph = 
      ContourPlot[G . X, {x, -5, 5}, {y, -5, 5}, 
        Contours -> {0, 1, 2, 3, 4, 5}, AspectRatio -> Automatic, 
        ContourShading -> False, DisplayFunction -> Identity]; 
    View2D[{graph, Arrow[G, Red]}, 
      DisplayFunction -> $DisplayFunction];

Now let's look at another example with a parallel but smaller gradient.  Notice that the gradient is shorter and the spacing is wider.

Clear[G, X, P, x, y, k]; G = {(3/5), (4/5)}; X = {x, y}; Print["G.X =", G . X, " = k"]; Print["Gradient G = ", G]; graph = 
      ContourPlot[G . X, {x, -5, 5}, {y, -5, 5}, 
        Contours -> {0, 1, 2, 3, 4, 5}, AspectRatio -> Automatic, 
        ContourShading -> False, DisplayFunction -> Identity]; 
    View2D[{graph, Arrow[G, Red]}, 
      DisplayFunction -> $DisplayFunction];

Finding m and n from the contour map

The following program makes a contour map of a function

f[x,y] = m x + n y

with  z-levels at integers from  -10  to  10.  The levels are shaded dark for low and light for high.  Since  f[0,0] = 0, the line through the origin is the zero level.  <Enter> the computation and then answer the questions below it.

Clear[G, X, x, y]; G = {(2/5), (4/5)}; X = {x, y}; graph = 
      ContourPlot[G . X, {x, -10, 10}, {y, -10, 10}, 
        Contours 
          -> {-10, -9, -8, -7, -6, -5, -4, 
            -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, 
        AspectRatio -> Automatic];

Look at the point labeled  0  on the x-axis.  Notice that there is a contour line touching at this point.  Move along the x-axis. How many contour levels do you cross as you move from  x = 0 to  x = 10?  This is the change in z, since each level in this plot is an integer.  How many x-units did you move?  What is the ratio

z-change/x-change = ?

Look at the point labeled  0  on the y-axis.  Notice that there is a contour line touching at this point.  Move along the y-axis. How many contour levels do you cross as you move from  y = 0 to  y = 10?  This is the change in z, since each level in this plot is an integer.  How many y-units did you move?  What is the ratio

z-change/y-change = ?

Your answers should be:

z-change/x-change = m = 2/5

z-change/y-change = n = 4/5

Why are these the correct answers?

Practice Exercise

Plot the contour plot of

f[x,y] = m x + n y

with  m = 3/4  and  n =1/2.  And use the contour plot to measure the ratios of z-change to x-change and  z-change to  y-change.  Verify that you get the correct answer analytically.

Varying z

The next figure shows the contours at integer levels from -10 to 10 for  f[x,y] = m x + n y.  Look at the figure and ask, "What is the shortest (x,y)-distance I can move in order to increase z by one level?"

Clear[G, X, x, y]; G = {(5/7), (4/3)}; X = {x, y}; graph = 
      ContourPlot[G . X, {x, -10, 10}, {y, -10, 10}, 
        Contours 
          -> {-10, -9, -8, -7, -6, -5, -4, 
            -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, 
        AspectRatio -> Automatic, DisplayFunction -> Identity]; 
    View2D[{graph, Arrow[G, Red]}, 
      DisplayFunction -> $DisplayFunction];

An increase in  z  of one unit on a contour map with integer levels is movement from one level to the next.  The gradient vector is perpendicular to the level lines, so the distance between the level lines is measured along the direction of  G.  The "steepness" of the function is the ratio of the z-change to this distance.

How can we compute the distance between the lines

m x + n y = 0   and   m x + n y = 1 ?

graph = 
      ContourPlot[G . X, {x, -1, 2}, {y, -1, 2}, 
        Contours -> {0, 1}, AspectRatio -> Automatic, 
        DisplayFunction -> Identity]; View2D[{graph, Arrow[G, Red]}, 
      DisplayFunction -> $DisplayFunction];

The function f[0,0] =0, so if we take a multiple of  G  that satisfies  f[ t G ] = 1, the length  |t G|  is the distance from   m x + n y = 0   to   m x + n y = 1.  Let

X1 = {x1,y1} = t G = t {m,n} = {t m, t n} and substitute in  m x + n y = 1,

m x + n y = 1

m (t m) + n (t n) = 1

t (m^2) + t (n^2) = 1

solve

t = (1/((m^2) + (n^2)))  or  t = \(1\/\(| G  |\^2\)\)

The distance between the lines is

|X1| = | t G | = |G|\(1\/\(| G  |\^2\)\) = (1/(| G | ))

t = (1/Norm)[G]^2; Print["The (x,y)-distance moved to climb 1 z-uint ="]; Print[(1/Norm)[G], " ~ ", N[(1/Norm)[G]]]; graph = 
      ContourPlot[G . X, {x, -1, 2}, {y, -1, 2}, 
        Contours -> {0, 1}, AspectRatio -> Automatic, 
        DisplayFunction -> Identity]; View2D[{graph, Arrow[G, Red], Arrow[t G, Blue]}, 
      DisplayFunction -> $DisplayFunction];

Exercises

Problem 17.4: Density of Contours

a

Plot the contour plot of  g[x,y] = m x + n y = G.X for integer contours from  -10  to  10  when  G = {m,n} = {(Sqrt[3]), 1}.

b

Plot the contour plot of  h[x,y] = p x + q y = H.X for integer contours from  -10  to  10  when  H = {p,q} = {((Sqrt[3])/2), (1/2)}.

Draw the vectors  G  and  H  on each of the respective contour plots.

c

Show that the equation of the line through the origin perpendicular to G is  m x + n y = 0 and the line through the origin perpendicular to  H  is p x + q y = 0.

d

Show that  G and  H  are perpendicular to all of the level lines.

e

Show that the only vectors perpendicular to the level lines are multiples of  G  and  H.

f

Compute the lengths  |G|  and   |H|.

g

Which multiple  s G  lies on  G.X = 1?  Which multiple  t H  lies on  H.X = 1?

h

Show that the distance between integer contours of  g[x,y]  is  1/|G|  and the distance between integer contours of  h[x,y]  is  1/|H|, so the bigger the gradient, the denser the contour lines.

extra credit

Show that motion of one (x,y)-unit in the direction of  G  increases the z-value of  z = g[x,y]  by  |G|.  Show that motion of one (x,y)-unit in the direction of  H  increases the z-value of  z = h[x,y]  by  |H|.  Explain the connection between this result and the density of the contour lines.