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.

Usually, when I plot multiple curves in Mathematica

Plot[{x,x^2,x^3},{x,0,1}]

they are given different colors. However, if I try to construct a list inside the Plot[] function,

Plot[Table[x^n, {n, 1, 3}], {x, 0, 1}]

this doesn't work and all the curves come out the same color. The standard advice (e.g. here, here and here), which works but which I don't fully understand, is to wrap the Table[] with an Evaluate[]:

Plot[Evaluate[Table[x^n, {n, 1, 3}]], {x, 0, 1}]

or equivalently

f[x_,n_]:=x^n;
Plot[Evaluate[Table[f[x,n], {n, 1, 3}]], {x, 0, 1}]

This work in this case, because f[x_]:=x^n is a simple function. However, suppose I have a complicated function g[y] which uses its argument y as an iterator:

g[y_] := Total[Table[1, {z, 1, Round[y + 1]}]]

Mathematica is not smart enough to recognize that this is equivalent to g[y)]:=Round[y]+1, and usually such a simplification will not be possible anyways. g[y] cannot be evaluated symbolically, because of the iterator, although it's still plenty fast when given a machine number. Then trying to plot various curves using a table constructed with g[y] without Evaluate[]

Plot[Table[g[x*n], {n, 1, 3}], {x, 0, 1}]

will make all the curves the same color. Adding Evaluate[]

Plot[Evaluate[Table[g[x*n], {n, 1, 3}]], {x, 0, 1}]

causes Mathematica to throw an error message about using a bad iterator. (Table::iterb: "Iterator {z,1,Round[1+x]} does not have appropriate bounds).

Why, exactly, is Evaluate[] necessary in the simple case? Is it true that Plot[] is interpreting the table as a multi-valued function? Why?

How can we achieve the same result in the complicated case where the technique fails?

share|improve this question
add comment

3 Answers 3

up vote 12 down vote accepted

You could use the splitstyle function from this question :

splitstyle[styles__]:=Module[{st=Directive/@{styles}},{{Last[st=RotateLeft@st],#}}&];

g[y_]:=Total[Table[1,{z,1,Round[y+1]}]];

Plot[Table[g[x*n],{n,1,3}],{x,0,1},PlotStyle->splitstyle[Red,Green,Blue]]

enter image description here

Or to use the standard colours:

Plot[Table[g[x*n],{n,1,3}],{x,0,1},PlotStyle->splitstyle@@ColorData[1]/@{1,2,3}]

enter image description here

share|improve this answer
    
Brilliant! I'm going to accept this because it doesn't require any modification of the primary argument of Plot[], just the inclusion of an option. (Of course, my decision has nothing to do with my spat with R.M about whether a fuller explanation of how Plot[] behaves would lead to a better answer... :) However, I'd like to point out to everyone that DGrady's answer is more compact, so if you don't mind modifying g[y] you should use his method. Thanks! –  Jess Riedel Jul 23 '12 at 20:56
    
+1; that's a really clever trick. Didn't see why it could be so useful until I looked at the question you linked to. –  DGrady Jul 23 '12 at 22:08
1  
@Simon: Is it explained anywhere exactly what is happening when you set the PlotStyle option to a function rather than a directive? This techniques doesn't seem to work for DiscretePlot. –  Jess Riedel Jul 24 '12 at 11:33
    
@JessRiedel, I'm not sure if it's documented or not. I couldn't find it. Essentially Plot produces one or more Line primitives, and if you supply a function to PlotStyle it applies that function to each Line. For example you could use PlotStyle->(Point@@#&) to convert the lines to points. It appears that other plotting functions just ignore any PlotStyle which isn't a graphics directive. –  Simon Woods Jul 24 '12 at 18:49
add comment

Evaluate is necessary in this simple case because

Plot has attribute HoldAll, and evaluates f only after assigning specific numerical values to x

and because Plot determines automatic styles based on the unevaluated form of f. When you call Plot[Table[ ... ], ...], Plot looks at its first argument, Table[ ... ], without evaluating it and notes that it has a length of 1, and it constructs style specifications based on that information. You can override this behavior of Plot by applying Evaluate to its first argument.

A simple way to accomplish what you want is to redefine g so that it wraps its output with Hold:

g[y_] := Hold@Total[Table[1, {z, 1, Round[y + 1]}]]
Plot[Evaluate@Table[g[n*x], {n, 1, 3}], {x, 0, 1}]

This works because the evaluated form of the first argument to Plot is now

{Hold[Total[Table[1, {z, 1, Round[x + 1]}]]], Hold[Total[Table[1, {z, 1, Round[2 x + 1]}]]], Hold[Total[Table[1, {z, 1, Round[3 x + 1]}]]]}

which does have a length of 3, and it doesn't produce an error because each of these three forms is held unevaluated until they are inside an environment that has a value bound to x.

Note that this variation

g[y_] := Total[Table[1, {z, 1, Round[y + 1]}]]
Plot[Evaluate@Table[Hold@g[n*x], {n, 1, 3}], {x, 0, 1}]

does not work, because it prevents g from being evaluated at all - we want g to be expanded with different values of n.

Evaluate@Table[Hold@g[n*x], {n, 1, 3}]
(* == {Hold[g[n x]], Hold[g[n x]], Hold[g[n x]]} *)
share|improve this answer
1  
+1 Very nice answer. –  Simon Woods Jul 23 '12 at 20:26
    
Thanks very much! This is very close to a perfect answer, except that it requires me to redefine g[y]. Ideally we wouldn't need to do this because g might be a black box. We could just define h[y_]:=Hold[g[y]] and use that, although this is still slightly awkward. –  Jess Riedel Jul 23 '12 at 20:47
    
@Jess It's a good point, and I don't think there's a way around it with this approach. I'm glad you found the explanation clear, though! –  DGrady Jul 23 '12 at 22:10
1  
I didn't know that Plot would work with expressions inside Hold! Where is this documented? –  Mr.Wizard Jul 24 '12 at 10:06
1  
@Mr.Wizard You know, that's a really good point - I found this through experimentation and didn't think about it too much, but it does mean that Plot must be using ReleaseHold at some point in the evaluation. And not all the plotting functions behave the same way: DiscretePlot[Evaluate@Table[g[n*x], {n, 1, 3}], {x, 0, 1, 0.1}] produces empty axes, for example. Just when you think you understand something... –  DGrady Jul 24 '12 at 18:28
add comment

For completeness, I'm going to give a solution which is hacky, but slightly less hacky than the one described by R.M in a comment on the main post. Here it is:

Show[
    Plot[g[x*#], {x, 0, 1}, PlotRange -> {0, 5}, PlotStyle -> ColorData[1]@#]] &
     /@Table[n, {n, 1, 3}]
]

The advantage of this is that I don't need to modify g[y] and I also don't need to be quite as clever as Simon. There are significant disadvantages though. I had to add PlotRange -> {0, 5} because the default display range is now chosen by looking at just one of the curves. An ideal solution would retain the ability of Plot[] to consider all curves at the same time and automatically choose a good default plot range.

share|improve this answer
    
Unless I'm missing something, this doesn't address the issue of all the plots being in the same style? –  Simon Woods Jul 24 '12 at 18:48
    
Oh, whoops. I forgot the important but, where you use the index n to pull the style out of a list of directives. Thanks for spotting that. –  Jess Riedel Jul 24 '12 at 19:49
add comment

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.