2

There is an example in the Mathematica 7 help for Plot > Options > ColorFunctionScaling.

Table[Plot[Sin[4 Pi x], {x, 0, 1/2}, PlotStyle -> Thick, 
  ColorFunction -> Function[{x, y}, Hue[x]], 
  ColorFunctionScaling -> cf], {cf, {False, True}}]

enter image description here

When I evaluate it myself on Mathematica 7, both output plots look like the one on the left.

However, if I evaluate this, I get the plot on the right, as shown above:

Plot[Sin[4 Pi x], {x, 0, 1/2}, PlotStyle -> Thick, 
 ColorFunction -> Function[{x, y}, Hue[x]], 
 ColorFunctionScaling -> True]

Why might the example as given fail?


Alexey and Simon demonstrated that this is not the result of HoldAll, as I presumed before.

The existence of the example leads me to suspect it once worked, and the information that it works on version 8 tells me that the behavior has changed. What precisely has changed?

Mr.Wizard
  • 24,179
  • 5
  • 44
  • 125
  • Since this behaviour does not occur in the current v8, I changed the link to point to the legacy v7 documentation. (I hope that's ok!) – Simon Mar 23 '11 at 07:33

3 Answers3

2

Your question is really interesting. The mentioned method of supplying option values to built-in functions is widely used in the Documentation. The fact that it fails only for ColorFunctionScaling looks like a bug. And information that in v.8 this problem does not exist confirms that this is a bug in v.7.

In any way consider the following:

In[1]:= SetAttributes[f, HoldAll]
f[__, OptionsPattern[ColorFunctionScaling -> False]] := 
 OptionValue[ColorFunctionScaling]
Table[f[Sin[4 Pi x], {x, 0, 1/2}, 
  ColorFunctionScaling -> cf], {cf, {False, True}}]


Out[3]= {False, True}

You can see that HoldAll attribute in really does not prevent substituting of cf.

In this way, it is really interesting what was the cause of described buggy behavior of Plot with Table in v.7?

Alexey Popkov
  • 9,355
  • 4
  • 42
  • 93
  • Alexey, I missed this reply. Let me think about that! +1 – Mr.Wizard Apr 12 '11 at 09:01
  • 2
    @Mr.Wizard `HoldAll` does prevent the substitution all right. What you observed is due to the `Block`-like (dynamic) scoping mechanism used by `Table`, plus the magic used in `OptionValue`, which uses the run-time value for `cf`. You can use `Trace` to see that `OptionValue` expands into `OptionValue[ColorFunctionScaling->False,{ColorFunctionScaling->cf},ColorFunctionScaling]`, and then it is this evaluation where the value for the `cf` is being substituted. Older `OptionQ` - based way of option checks was much more direct and easier to understand, and did not involve any magic. – Leonid Shifrin Apr 12 '11 at 13:05
  • @Leonid I did not see this until now (I believe only the first @person gets notified). Would you please post this as an answer, with more detail? – Mr.Wizard May 01 '11 at 13:11
  • 1
    @Mr.Wizard I would prefer to not post this as an answer since my comment is tangential to the question being asked, but is a comment to @Alexey's observation. Also, I don't know how to explain it better. @Alexey noted that `HoldAll` for `f` did not prevent the substitution of `cf` by its value, and I noted that that substitution was happening not when `f[args]` was evaluated (l.h.s), but when `OptionValue` on the r.h.s of the definition for `f` was evaluated. So, my point was that it was a consequence of `OptionValue`'s evaluation and had nothing to do with the `HoldAll` attribute of `f`. – Leonid Shifrin May 01 '11 at 16:41
1

The evaluation order seems slightly out. It works if you force cf to be substituted in before the Plot command is looked at. To do this we use the With[{x=x},...] construct:

Table[With[{cf = cf}, 
  Plot[Sin[4 Pi x], {x, 0, 1/2}, PlotStyle -> Thick, 
   ColorFunction -> Function[{x, y}, Hue[x]], 
   ColorFunctionScaling -> cf]], {cf, {False, True}}]

plot

It's strange that you don't need such a kludge in Mathematica version 8.

It's even stranger that the Mathematica 7 documentation has an example where the pre-evaluated graphics does not match what is produced by that version. (Nice find, btw)

Simon
  • 14,631
  • 4
  • 41
  • 101
  • 1
    Beat me to it! I suspect this was a bug with the variable localization of `cf` inside `Plot`/`Table`, and apparently fixed in 8.0, as you noted. – Michael Pilat Mar 23 '11 at 07:21
  • What else does this effect? I thought `Table` was a valid scoping construct, and that this would/should not happen. – Mr.Wizard Mar 23 '11 at 07:27
  • 4
    @Mr.Wizard: `Table` uses `Block`-like scoping and `Plot` is `HoldAll`, so if `Plot` doesn't evaluate the value it won't resolve to its value. – Brett Champion Mar 23 '11 at 13:31
  • @Brett Now I see. I should have realized this, and I am surprised I didn't have problems with this before. I didn't even check for that as I was confident the option value was evaluated. I blame myself for being ignorant of this, but I console myself I am not the first (re: help file). – Mr.Wizard Mar 23 '11 at 14:07
  • 2
    @Brett @Mr.Wizard: I'm not sure if it's quite that simple. Other Plot options are happy to be placed into a table, e.g. `Table[Plot[Sin[4 Pi x], {x, 0, 1/2}, PlotStyle -> {tt}], {tt, {nonesense, Thin, Thick}}]`. Or do the same with the `ColorFunction` ranging over `{Hue, GrayLevel}`.... – Simon Mar 23 '11 at 21:14
  • @Simon, somehow I missed this comment and Alexey's entire answer. Thanks for pointing this out. Perhaps it is "just" a bug after all. – Mr.Wizard Apr 12 '11 at 09:16
1

This bug in fact is related to the HoldAll attribute, but I was fooled by this auto-load issue into thinking it was not. This can be seen by executing this:

Plot[Sin[x], {x, 0, Pi}];

Unprotect[Plot]
ClearAttributes[Plot, HoldAll]

Table[Plot[Sin[4 Pi x], {x, 0, 1/2}, PlotStyle -> Thick, 
  ColorFunction -> Function[{x, y}, Hue[x]], 
  ColorFunctionScaling -> cf], {cf, {False, True}}]

The first Plot is needed to activate the package load.

One can therefore get the correct behavior by wrapping ColorFunctionScaling -> ... in Evaluate:

Table[Plot[Sin[4 Pi x], {x, 0, 1/2}, PlotStyle -> Thick, 
  ColorFunction -> Function[{x, y}, Hue[x]], 
  Evaluate[ColorFunctionScaling -> cf]], {cf, {False, True}}]

enter image description here

Community
  • 1
  • 1
Mr.Wizard
  • 24,179
  • 5
  • 44
  • 125
  • Interestingly, which package is loaded and what is the mechanism for loading the package? `Definition[Plot]` does not give the answer. – Alexey Popkov May 02 '11 at 16:45
  • @Alexey, did you see [the question here](http://stackoverflow.com/questions/5649379/)? Using Plot the first time loads some .mx file that resets its attributes, so if you try the code above in a fresh kernel, **without** the first `Plot` line, `Plot` has attribute `HoldAll` again when the plots are created. – Mr.Wizard May 03 '11 at 00:30
  • I did and in that case the mechanism can be found by looking at the definition for `LogLinearPlot`: `Unprotect[LogLinearPlot]; ClearAttributes[LogLinearPlot,ReadProtected]; Definition[LogLinearPlot]` explains what happens. In the case of `Plot` it does not work. – Alexey Popkov May 03 '11 at 03:58