Take the 2-minute tour ×
Mathematica Stack Exchange is a question and answer site for users of Mathematica. It's 100% free, no registration required.

Consider the example

plotOptions = {PlotPoints -> 10, MaxRecursion -> 2}

Plot3D[x y , {x, 0, 10}, {y, 0, 10}, plotOptions]

Why does this causes the error:

Plot3D::nonopt: Options expected (instead of plotOptions) beyond position 3 in 
Plot3D[x y,{x,0,10},{y,0,10},plotOptions]. An option must be a rule or a list of rules. >>

?

I would say that plotOptions is as list of rules...

If I use

Plot3D[x y , {x, 0, 10}, {y, 0, 10}, {PlotPoints -> 10, MaxRecursion -> 2}]

it works...

What is then the correct way of passing a list of options to a plot? One situation on when this happens is when I want to create several plots with the same options.

share|improve this question
5  
Try Plot3D[x y, {x, 0, 10}, {y, 0, 10},Evaluate@plotOptions] its because of the HoldAll attribute of Plot functions! –  PlatoManiac Feb 11 '13 at 10:59
    
Pff, it works! why is that? Can you provide an answer and respective explanation please? –  J. C. Leitão Feb 11 '13 at 11:01
    
The answer is that Plot3D has HoldAll attribute. I'll let @PlatoManiac post the answer. –  Ajasja Feb 11 '13 at 11:03
    
This is a good candidate for an FAQ. It's something novices can all too easily be mystified by, before they know anything about Hold, etc. –  murray Feb 11 '13 at 17:12

3 Answers 3

up vote 8 down vote accepted

Lets see the Attributes of Plot3D

Attributes[Plot3D]

{HoldAll, Protected, ReadProtected}

The HoldAll is the reason why your options are not read within the Plot3D command. In such situations (e.g NIntegrate, Plot,..) to resolve the values of a symbol (here options) within these commands we tend to use Evaluate to forcefully override this attribute.

So one solution is

Plot3D[x y, {x, 0, 10}, {y, 0, 10},Evaluate@plotOptions]

Another solution is to inject the options using With:

With[{iPlotOpts = plotOptions},
 Plot3D[x y, {x, 0, 10}, {y, 0, 10}, iPlotOpts]
]

Another way will be to get rid of this HoldAll globally using ClearAttributes[Plot3D, HoldAll]. Then you can just use Plot3D[x y , {x, 0, 10}, {y, 0, 10}, plotOptions]. But clearing attributes globally is a bad idea in general, as it disrupts the local scoping which is often a must for a function like Plot3D to work seamlessly! Try for example:

ClearAttributes[Plot3D, HoldAll]; x = 5; y = 10; 
Plot3D[x y, {x, 0, 10}, {y, 0, 10}]
share|improve this answer
2  
The last paragraph is extremely bad advice! Try for example: ClearAttributes[Plot3D, HoldAll]; x = 5; y = 10; Plot3D[x y, {x, 0, 10}, {y, 0, 10}]. Another solution is to inject the plot options using With –  Ajasja Feb 11 '13 at 12:12
    
@Ajasja While I was editing the answer the site became inaccessible (at least in Germany)! At that time I was just mentioning the bad side effect of ClearAttribute. Now I am back from lunch and did finish the editing ;) –  PlatoManiac Feb 11 '13 at 12:40
    
I emphasised your warning just in case:) –  Ajasja Feb 11 '13 at 12:56
    
Thanx @Ajasja... –  PlatoManiac Feb 11 '13 at 13:01

There are other easy ways to inject the evaluated plotOptions into Plot3D. One very simple way is to use With. Here, the fundamental difference between With and Module comes to light: With does not localize variables. It assigns values to names and you can refer to your values by using the names:

With[{plotOptions = {PlotPoints -> 10, MaxRecursion -> 2}},
 Plot3D[x y, {x, 0, 10}, {y, 0, 10}, plotOptions]
]

Another way is to make a function from your Plot3D call and pass your options as parameters

Plot3D[x y, {x, 0, 10}, {y, 0, 10}, #] &[{PlotPoints -> 10, MaxRecursion -> 2}]

In this way, you can of course remove the list braces

Plot3D[x y, {x, 0, 10}, {y, 0, 10}, ##] &[PlotPoints -> 10, MaxRecursion -> 2]
share|improve this answer

I can't comment on halirutan's answer, so this will have to suffice: the problem with his last suggestion is that

Plot3D[x y, {x, 0, 10}, {y, 0, 10}, #] &[PlotPoints -> 10, MaxRecursion -> 2]

is equivalent to

Plot3D[x y, {x, 0, 10}, {y, 0, 10}, PlotPoints -> 10]

i.e., only the first option setting is inserted. The proper way to go about it is to use SlotSequence (##) instead; to wit,

Plot3D[x y, {x, 0, 10}, {y, 0, 10}, ##] &[PlotPoints -> 10, MaxRecursion -> 2]

and both options shall then be inserted.

If you have an entire pile of options to insert, you could do something like

optList = {ColorFunction -> Hue, MaxRecursion -> 2, Mesh -> False, PlotPoints -> 10};
Plot3D[x y, {x, 0, 10}, {y, 0, 10}, ##] & @@ optList
share|improve this answer
    
The first half of this answer would have been better as a comment (or edit) to halirutan's answer. I made the bug-fix edit myself. However, +1 for the final line of code as that is a valuable method. –  Mr.Wizard Feb 26 '13 at 9:20

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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