12
$\begingroup$

I wanted to draw some contours. I succeeded with this:

W1 = {p, -2, 2, 0.5};
W2 = {p, -10, 10, 1};
P = W1; ContourPlot[ 
 Evaluate[Union[Table[y^2 == 2 p*x, Evaluate[P]], 
   Table[x^2 == 2 p*y, Evaluate[P]]]], {x, -5, 5}, {y, -5, 5}]
P = W2;
ContourPlot[Evaluate[
  Union[Table[y^2 == 2 p*x, Evaluate[ P]], 
   Table[x^2 == 2 p*y, Evaluate[P]]]], {x, -5, 5}, {y, -5, 5}]

I don't like this solution. I used Evaluate[] a few times and I feel like it is unnecessary although without the function I get errors. Could anyone explain me that. I find the reference unhelpful (maybe that's my lack of language?) "causes expr to be evaluated even if it appears as the argument of a function whose attributes specify that it should be held unevaluated.".

$\endgroup$
4
  • 1
    $\begingroup$ ContourPlot[] and Table[] both have the HoldAll attribute, so the Evaluate[] is needed. $\endgroup$ Commented Jun 16, 2012 at 17:49
  • 2
    $\begingroup$ See also the discussions on MathGroup with follow-ups here. Incidentally, one of the critical voices there, AES, has recently passed away. $\endgroup$
    – Jens
    Commented Jun 16, 2012 at 18:30
  • $\begingroup$ @jens Thanks for the pointer, I love this part: Would you really want to argue that high school students, or freshman students in college, should have to first go through a tutorial in Hold and Evaluate (and maybe also HoldAll, HoldFirst, NHoldAll, HoldAllComplete, HoldRest, SequenceHold, Extract,and Unevaluated) before they could start plotting Lists using Plot? $\endgroup$ Commented Jun 16, 2012 at 23:20
  • $\begingroup$ Related: mathematica.stackexchange.com/q/1375/121 $\endgroup$
    – Mr.Wizard
    Commented Aug 30, 2012 at 18:30

2 Answers 2

14
$\begingroup$

ContourPlot has the attribute HoldAll. That means that it receives its arguments before they are evaluated. So, if you put as a first argument, something that evaluates to a list but it's not a list, it won't fit with the overloaded version of ContourPlot that expects a list. The same happens with the second argument of Table. Whether they end up not evaluating, using another overload, giving a warning, or simply taking more time than they should, that depends on the particular case at hand

Evaluate is something that makes the containing function behave temporarily as non-holding. Try

SetAttributes[f, HoldAll];
f[x_]:=Hold[x];
f[2+2]
f[Evaluate[2+2]]

If you don't find this neat, what's usually done is use With

With[{P = P},
 With[{lists = Union[Table[y^2 == 2 p*x, P], Table[x^2 == 2 p*y, P]]},
   ContourPlot[lists, {x, -5, 5}, {y, -5, 5}]
  ]
 ]
$\endgroup$
7
$\begingroup$

You needed Evaluate because you want evaluation of an argument that is normally held, both in the case of ContourPlot and Table. There are several ways to force this evaluation.

  1. Evaluate causes evaluation of an argument before the function reads it, or even "sees" it for pattern matching. It only works at the first level of the function, meaning it must wrap (be the head of) an argument, and not a sub-expression. Compare: Hold[Evaluate[2 + 2], 3 + 3] and Hold[5 + Evaluate[2 + 2]]. (Hold is used as a representative of an arbitrary function with the HoldAll attribute.)

  2. Some functions such as Plot (and FindRoot) can use the option Evaluated -> True -- for these this is superior to other methods because the range variable is still correctly localized.

  3. You can use a function which does not have a Hold attribute to cause intermediate evaluation. The most direct way is a "pure function" using &:
    Hold[1 + 2 + #] &[2 + 2]
    This works because the & function evaluates its argument before Hold ever sees it, and # (Slot) can appear anywhere in the body of the function, not merely the first level.

  4. As Rojo stated you can use With to do a lexical replacement of specific variables: With[{x = 2 + 2}, Hold[x, 3 + 3]]

  5. More complicated evaluations and insertion may be achieved using the methods I described here.

Example using the pure function method:

W1 = {p, -2, 2, 0.5};
P = W1;

ContourPlot[#, {x, -5, 5}, {y, -5, 5}] &[
  Union[Table[y^2 == 2 p*x, #], Table[x^2 == 2 p*y, #]] & @ P
]

Mathematica graphics

$\endgroup$
1
  • $\begingroup$ @Rojo actually I didn't try Evaluated -> True in this case before posting; I am surprised to find that it doesn't work here. Oops! $\endgroup$
    – Mr.Wizard
    Commented Jun 16, 2012 at 19:57

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.