Modified Plot Functions
By Ted Ersek
      ersektr@navair.navy.mil

Sometimes we need to use Evaluate on the arguments given to the Mathematica Plot functions

The examples that follow use the Plot function, but the same principles apply to ContourPlot, DensityPlot, ParametricPlot, ParametricPlot3D, Plot3D and Play.
 
As explained in section 1.9.1 and 2.5.5 of The Mathematica Book it sometimes helps to wrap the first argument given to Plot in Evaluate.  One such example is given in the next cell.  If Evaluate isn't used inside Plot the expression Sum[Sin[n π t]/(n π), {n, 1, 40}] is evaluated for every sample and it takes about 18 times longer to evaluate.  When Evaluate is used inside Plot the sum is evaluated only once.

ClearAll[f1]
f1[t_] := Sum[Sin[n π t]/(n π), {n, 1, 40}]
Plot[Evaluate[f1[t]], {t, 0, 6}];

In the three examples that follow Evaluate must be used inside Plot or the algorithm doesn't know a list of functions is being plotted.

ClearAll[f2, x];
f2 = {(x^2), (x^3)};
Plot[Evaluate[f2], {x, 0, 2}];

Plot[
        Evaluate[{x^2 - c1, x^2 + c1} /. c1 -> 2], {x, -2, 
          2}];

Plot[
        Evaluate[Table[BesselJ[n, x], {n, 4}]], {x, 0, 10}];

Evaluate must be used in the next cell to ensure the derivative is taken before (x) is assigned a number.

Plot[ 
        Evaluate[D[Sin[((π x)/20)] 400/π, x]], {x, 0, 
          50}];

A lot of novices who want to make graphs like those made by the previous cells will use trial and error until they find a way to make the desired graph.  Eventually users learn when to use Evaluate inside Plot.  Novices would have much less trouble with the Plot function if this wasn't necessary.  Even advanced users could benefit from not typing "Evaluate[]" when required by the built in Plot function.

The modified Plot functions are easier to use

The package (PlotFunctions.m) includes definitions that change the evaluation procedure used by Plot, ContourPlot, DensityPlot, ParametricPlot, ParametricPlot3D, Plot3D and Play.  When using the modified plot functions one never needs to use Evaluate on the arguments given to the Plot functions and the intended graphic is usually produced.

Before trying the examples below the (PlotFunctions.m) package should be in the (3.0\AddOns\ExtraPackages) folder and the next cell should be evaluated to load the package.

<< PlotFunctions.m

Once the package is loaded each of the cells below produce the expected graphic.

ClearAll[f1]
f1[t_] := Sum[Sin[n π t]/(n π), {n, 1, 40}]
Plot[f1[t], {t, 0, 6}];

ClearAll[f2, x];
f2 = {(x^2), (x^3)};
Plot[f2, {x, 0, 2}];

Plot[{x^2 - c1, x^2 + c1} /. c1 -> 2, {x, -2, 
          2}];

Plot[Table[BesselJ[n, x], {n, 4}], {x, 0, 10}];

Plot[
        D[Sin[((π x)/20)] 400/π, x], {x, 0, 50}];

The next example is a little difficult to deal with using the built in Plot function, but the modified Plot function can handle it without a problem.

ClearAll[funs];
\(\(\(funs[
        x_]\)\(:=\)\({NIntegrate[\ 
          Exp[\@Abs[u]]\/\(20  u + 1\), {u, 0, x}], 

        D[Sin[\(π\ x\)\/20] 400/π, x]}\)\(
\)\(\ \)\)\)
Plot[funs[t], {t, 0, 50}];

The modified version of Plot uses a local environment for the dummy variable so it ignores any value assigned to this variable just like the built in Plot function.  This is demonstrated in next cell.

x = 2;
Plot[Sin[π x], {x, 0, 4}];

In the cells below graphics or sounds are made using modified versions of ContourPlot, DensityPlot, ParametricPlot, ParametricPlot3D, Plot3D, and Play.  In each case the intended graphic or sound is produced even though Evaluate wasn't used.

\(\(ContourPlot[
        D[x\ Sin[4\ x + 3\ y], x], \ {x, \(-2\), 2}, {y, \(-2\), 2}, 

        PlotPoints -> 40];\)\)

\(\(DensityPlot[
        D[x\ Sin[4\ x + 3\ y], x], \ {x, \(-2\), 2}, {y, \(-2\), 2}, 

        PlotPoints -> 40, Mesh -> False];\)\)

\(\(Plot3D[D[x\ Sin[4\ x + 3\ y], x], \ {x, \(-2\), 2}, {y, \(-2\), 2}, 

        PlotPoints -> 40];\)\)

ParametricPlot[{D[t Sin[t], t],  t Cos[t + π/6]},  {t, 0, 
          10}];

\(\(ParametricPlot3D[
	{D[t\ Sin[t], t], t\ Cos[t + π/6], \ 
          t\ Cos[t + π/6]}, 
	\ {t, 0, 10}];\)\)

\(\(ParametricPlot3D[{D[Sin[u\ t], t], \ Cos[t], \ u}, 
\ \ \ \ \ {t, \ 
          0, \ Pi}, \ {u, \ 0, 1}];\)\)

Play[D[Cos[t^2], t], {t, 0, π}];

Sometimes we need to use the built in plot functions

In the cells below two examples are given that demonstrate when the built in Plot function might be needed.  In similar situations one might need to use the built in versions of ContourPlot, DensityPlot, ParametricPlot, ParametricPlot3D, Plot3D, or Play.

Evaluating the next cell with the built in Plot function produces a graph that looks like a parabola plus white noise.  On the other hand the modified Plot function produces the graph of a smooth parabola plus a random constant.

Plot[x^2 + Random[], {x, -2, 2}];

Now consider the next cell where the built in Plot function and the modified Plot function both produce the graph of a function parametrically defined as (Tan[y]==y*x+1/2).  The result is a graph monotonically increasing from {0, 0.463648} to {15, 1.52813}.

ClearAll[f3];
f3[x_] :=  
      y /. FindRoot[Tan[y] == y*x + 1/2,  {y, -1.57, 1.57}]
Plot[f3[x], {x, 0, 15}];

However the two versions of Plot produce different results when the next cell is evaluated using the definition of (f3) above.  Here the built in Plot function produces the same graphic that the previous cell produced, but the modified Plot function plots a constant value that solves the equation (Tan[y]==y*y+1/2).

Plot[f3[y], {y, 0, 15}];

A different definition of (f3) can be used to avoid the problem in the last example

If the definition of (f3) in the next cell is used the built in Plot function and the modified Plot function will produce the same graphic.

ClearAll[f3];
\(\(f3[x_] := 
        Module[{y}, 
	\ y /. 
            FindRoot[
              Tan[y] == y*x + 1/2, \ {y, \(-1.57\), 1.57}]
];\)\)

How to switch between the built in plot functions and the modified plot functions

We can switch back to the built in Plot function by evaluating a cell that causes (HiddenSymbols`ModifyPlot) to evaluate to anything but True.  The following cell will suffice for this purpose.

HiddenSymbols`ModifyPlot =.

After evaluating the previous cell the next two cells will produce the same graphic we would get if we never modified the Plot function.

Plot[x^2 + Random[], {x, -2, 2}];

ClearAll[f3];
f3[x_] :=  
      y /. FindRoot[Tan[y] == y*x + 1/2,  {y, -1.57, 1.57}]
Plot[f3[y], {y, 0, 15}];

We could then evaluate the following cell and the modified version of Plot will be used.

HiddenSymbols`ModifyPlot = True;

In a similar manner we can ensure the built in versions of ContourPlot, DensityPlot, ParametricPlot, ParametricPlot3D, Plot3D or Play are used by evaluating one of the following cells as appropriate.  We can then return to the modified version by making the symbol True again.

HiddenSymbols`ModifyContourPlot =.

HiddenSymbols`ModifyDensityPlot =.

HiddenSymbols`ModifyParametricPlot =.

HiddenSymbols`ModifyParametricPlot3D =.

HiddenSymbols`ModifyPlot3D =.

HiddenSymbols`ModifyPlay =.

How the modified Plot function works

The implementation of the modified Plot function is explained below.  The modified versions of ContourPlot, DensityPlot, ParametricPlot, ParametricPlot3D, Plot3D and Play are similar

Plot has the HoldAll attribute which ensures functions that can only be used on numeric arguments don't evaluate too early.  An example of such a function is f[x_] := NIntegrate[Exp[(Sqrt[Abs])[u]]/(20 u + 1), {u, 0, x}].  However, the kernel will return any expression that it can't evaluate as demonstrated for some examples in the cells below.

Clear[x];
NIntegrate[ Exp[(Sqrt[Abs])[u]]/(20  u + 1), {u, 0, x}]

expr = D[3 Exp[3],  3];
InputForm[expr]

Sin[t, 3]

One exception to the convention demonstrated above is when we attempt to evaluate an incomplete expression.  In this case the evaluation process is cut short and no output is returned.  This is demonstrated by attempting to evaluate the next two input cells.

Exp[x+]

Max[{2, 3, 7]

The definition of (funs) defined above is shown below.  This function will be used to explain how the modified Plot algorithm works.

?funs

The evaluation of the next cell (using the modified Plot function) is now explained.

t = 2;
Plot[funs[t], {t, 0, 50}];

When the cell above is evaluated the expression in the next cell is evaluated provided (HiddenSymbols`ModifyPlot) is True.  If (HiddenSymbols`ModifyPlot) isn't True the built in definition of Plot is used.

Block[{HiddenSymbols`ModifyPlot}, 
Plot @@ 
        Block[{t, 
            Message}, 
Hold @@ {funs[t], {t, 0, 
                50}}]
]

In the cell above the outer Block temporarily clears the value of (HiddenSymbols`ModifyPlot) before the rest of the expression begins evaluation.  Then the expression in the next cell evaluates.

Block[{t, Message}, Hold @@ {funs[t], {t, 0, 50}}]

When the previous cell evaluates the use of the Block temporarily clears the value assigned to (t).  This is necessary since the symbol (t) must not have a numeric value to ensure proper evaluation of  D[Sin[π t/20] 400/Pi,  t].  On the other hand evaluation of Nintegrate[Exp[(Sqrt[Abs])[u]/(20 u + 1)], {u, 0, t}] without a numeric value assigned to (t) would normally produce an error message since the upper limit of integration is non-numeric.  However, the use of the Block prevented the kernel from producing the message.  Before evaluation inside the Block is complete the head of the result is changed to Hold.  If the head wasn't changed to Hold the expression would evaluate after the Block finishes and NIntegrate would produce the message that was prevented.  

After evaluating the cell above the head of the result is changed to Plot.  Then the built in Plot function is used since the value of (HiddenSymbols`ModifyPlot) was cleared earlier.  The built in version of Plot now has a function it can sample without a problem.  The expression Block[{t, Message},   ... ] has completed evaluation so the Plot function will produce messages when appropriate.  An example where the modified Plot function will produce a message is given in the next cell.

Clear[t];
Plot[Sin[x], {x, 0, t}]