# Encapsulated plot function misbehaves

To insure a collection of plots has identical appearance, the plot command is encapsulated in a function. The results are undesirable. The fiducial plot is

 ggood = ParametricPlot[{r, ZernikeR[100, 0, r]}, {r, -1, 1},
PlotRange -> {Automatic, 1.05 {-1, 1}}]


which creates

The functional version is

Clear[pp];
pp[ψ_, options___] :=
ParametricPlot[{r, ψ}, {r, -1, 1}, options,
PlotRange -> {Automatic, 1.05 {-1, 1}}]

gbad = pp[ZernikeR[100, 0, r]]


which produces

How should the functional form be posed?

• BTW: did you know that ParametricPlot[{r, f[r]}, {r, a, b}] is the same as Plot[f[r], {r, a, b}]? With the HoldFirst attribute you learned from the Wizard, you can now use this much simpler construction. May 23, 2015 at 2:42
• Michael E2 demonstrates the difference between these macros here: mathematica.stackexchange.com/questions/83375/…. What are your thoughts? May 25, 2015 at 20:54

## 3 Answers

As MarcoB posted before me this has to do with evaluation differences. Simply setting HoldFirst on pp produces the original plot:

SetAttributes[pp, HoldFirst]

pp[ψ_, options___] :=
ParametricPlot[{r, ψ}, {r, -1, 1}, options, PlotRange -> {Automatic, 1.05 {-1, 1}}]

pp[ZernikeR[100, 0, r]]


You will want this attribute anyway as without it the global value of r will be used, if it exists, which would result in even worse behavior.

As to why the symbolic expansion of ZernikeR[100, 0, r] needs extra WorkingPrecision to get the desired output please see:

• HoldFirst! That's what I was looking for!! Man, I have spent the last ten minutes thinking "If only there was a way to tell a function not to evaluate its arguments..." Thank you for putting me out of my misery. I'm also out of votes, I've just realized, so I guess we owe each other one :-) May 22, 2015 at 20:37
• @MarcoB There is a whole family of Hold functions, e.g. HoldRest, SequenceHold, etc. Some of the lesser known (I think) are NHoldAll (and rest, first) but these can be very important at times. May 22, 2015 at 20:44
• I definitely need to get some practice with those. I came across HoldAll and its effects early in my tinkering days, through the classical beginner's problem of coloring when plotting things that evaluate to lists, but are not lists yet. I should have followed through then! Anyway, I saw your post today re: Robby Villegas tutorial on Unevaluated, so I have it on my list of things to read. I've scanned it briefly, and I think it mentions Hold* attributes too. May 22, 2015 at 21:01
• @MrW: Great explanation and extremely helpful link! This solves many problems dealing with the Zernike polynomial set. May 22, 2015 at 21:02

This is a comment rather than an answer, but it grew too long for the comment box, and I wanted to show graphics, so I'll leave it here in hopes that someone better versed in the inner workings of MMA might explain this behavior. I am using your definition of the wrapper function pp.

First of all, I get a slightly different version of the "wrong" function:

Having said that, it seems that this behavior has something to do with the order of evaluation. In fact, if I pass the function to plot to the pp wrapper unevaluated, then I obtain the same well-behaved output as your "free standing" ParametricPlot:

pp[Unevaluated@ZernikeR[100, 0, r]]


The opposite is also true: if I pre-evaluate the ZernikeR function, then try to plot the result, I obtain the same result I had from feeding this function straight to your wrapper:

ZernikeR[100, 0, r];
ParametricPlot[{r, %}, {r, -1, 1}, PlotRange -> {Automatic, 1.05 {-1, 1}}]


I am afraid that this is as far as I was able to go to understand the problem. Depending on how you are constructing the lists of functions to plot, you may be able to pass the functions unevaluated programmatically, and get around the road block for now. For instance

pp /@
Unevaluated/@
Unevaluated@
{ZernikeR[20, 0, r], ZernikeR[50, 0, r], ZernikeR[100, 0, r]}


I'd still like to understand why this is the case, however.

• +1 good observation. If you see the polynomial that results from ZernikeR[100, 0, r] you can see why extended precision is needed. Actually you can see the trouble if you just do (z = ZernikeR[100, 0, r]; z /. r -> .9) vs ZernikeR[100, 0, .9] May 22, 2015 at 20:36
• @george2079 That's a very nice example, thank you. In fact, playing around with the precision of that $0.9$ shows that one needs at least 40 digits of precision to obtain a reasonable result... Ouch! May 22, 2015 at 20:48
• @MarcoB: Very nice approach; wonderful example. May 22, 2015 at 21:06

Eliminate the options and impose a reasonable WorkingPrecision:

Clear[pp];
pp[\[Psi]_] :=
ParametricPlot[{r, \[Psi]}, {r, -1, 1},
PlotRange -> {Automatic, 1.05 {-1, 1}},
WorkingPrecision -> 200]


• Why is WorkingPrecision only needed inside of the function wrapper? (Also, WorkingPrecision->100 can be placed in the options slot.) One reason to use ParametricPlot in lieu of Plot is to obviate the need to adjust WorkingPrecision. Thanks for your comment. May 22, 2015 at 19:50