An elegant way to plot a numeric function that returns a list, and have each element in a different color

13

3

I have a function that takes a numeric argument and returns a list of numbers. I want to plot each element of the list in a different color.

If I use this command,

Plot[f[x],{x,-1,1}]

all the elements are plotted in the same color. The function takes only a numeric argument (its definition is f[x_?NumericQ]:=...) so I can't use Evaluate like in this question.

So far I've been using this command:

Plot[{f[x][[1]],f[x][[2]],f[x][[3]],f[x][[4]]},{x,-1,1}]

Which works fine (since the function evaluates very fast, I don't mind there are redundant evaluations here, see this question). However this is not very elegant, and considering I have 16 elements to plot, it gets downright ugly.

Is there a more elegant way to plot each element in a different color?

Joe

Posted 2012-11-14T18:49:59.723

Reputation: 1 451

Question was closed 2015-06-29T08:50:30.810

The two highest voted answers below are effectively duplicates of answers to (8637). For this reason I argue that this question is a duplicate of that one. Please vote to close if you agree or comment here if you do not.

– Mr.Wizard – 2015-05-25T13:59:51.200

1How about Plot[Evaluate[f[x]], ...]? – wxffles – 2012-11-14T19:08:16.710

1@wxffles if you have f[x_?NumericQ]:=... (as indicated in the question) then that doesn't work. – acl – 2012-11-14T19:19:30.963

1Identical question asked prior to mathematica.SE existence. – Sasha – 2012-11-14T19:29:46.553

@Sasha - in the question you linked to the problem is to avoid redundant evaluations of the function, since it is expensive to evaluate (just like in this question, which is already mentioned above). In my question I don't mind redundant evaluations, my problem is coding style. These are two different issues.

– Joe – 2012-11-15T08:27:12.367

Answers

14

This seems to work:

With[{n = Length@f[0]},
  Plot[Evaluate[Hold[f[x][[#]]] & /@ Range[n]], {x, 0, 1}]]

wxffles

Posted 2012-11-14T18:49:59.723

Reputation: 13 711

The essence of this method was previously posted here: (8643)

– Mr.Wizard – 2015-05-25T13:58:06.617

7Interesting, Hold is invisible to Plot. +1 – Rojo – 2012-11-14T20:22:24.557

7

PlotStyle settings as functions

With @acl's example function

 f[x_?NumericQ] := {x, x^2, Sin@x, Cos@x, ArcTan[x]}

 i = 1; 
 Plot[f[x], {x, -Pi, Pi}, 
  PlotStyle -> ({Thick, {Red, Green, Blue, Orange,Brown}[[i++]], {##}} &)]

enter image description here

or, a variation:

i = 1;
Plot[f[x], {x, -Pi, Pi}, PlotStyle -> 
 ({Thick, ColorData[5, "ColorList"][[;; Length[f[1]]]][[Mod[i++,Length[f[1]], 1]]], 
     Arrow @@@ {##}} &)]

enter image description here

Update: ... or use DownValues of the function:

 Plot[Evaluate@DownValues[f][[All, 2]], {x, -Pi, Pi},  PlotStyle -> Thick]

enter image description here

kglr

Posted 2012-11-14T18:49:59.723

Reputation: 302 076

Incidentally this is essentially the same method Simon Woods posted here: (8644)

– Mr.Wizard – 2014-04-27T20:58:36.187

Thank you @Mr.Wizard. Wasn't aware of that Q/A and the one linked there; just added two more Q/As to my favorites list. – kglr – 2014-04-27T21:37:44.497

2Unfortunately like Simon's code this no longer works in version 10 or 10.1. – Mr.Wizard – 2015-05-25T13:41:21.107

@Mr.Wizard, all good undocumented things come to an end:( Some in the same bag of tricks still work, e.g. BoundaryStyle and MeshStyle as in this answer.

– kglr – 2015-05-25T15:05:35.557

2This is very cool! But I think it fails if your functions get discontinuous. Try with 1/x}. +1 – Rojo – 2012-11-14T20:14:17.207

@Rojo, this trick is still a new discovery for me, so it has many gaps. I think the case you mention can be adressed partially using something like Mod[i++, Length[f[1]], 1] instead of i++ as the part index, bu then you get the two parts of 1/x colored differently. – kglr – 2012-11-14T20:26:51.420

3Using the downvalues isn't a robust solution, because it completely disregards additional caveats to the definitions. For example, plot: Clear@f;f[x_?NumericQ] /; x < 0 := -{x, x^2, Sin@x, Cos@x, ArcTan[x]} f[x_?NumericQ] := {x, x^2, Sin@x, Cos@x, ArcTan[x]} – rm -rf – 2012-11-15T02:08:06.630

@rm-rf, oops -- It did feel too clean to be robust.(I was trying to remove the condition ?NumericQ from the DownValues when I bumped into this.) thanks. – kglr – 2012-11-15T03:01:54.307

4

Here is a variation of wxffles' method using Indexed rather than undocumented behavior of Hold within Plot. Hold still works in v10.1 but I think this is more likely to remain working; note that sadly kguler's answer no longer works due to changes in undocumented behavior.

f[x_?NumericQ] := {x, x^2, Sin@x, Cos@x, ArcTan[x]}

Plot[Indexed[f[x], #2] & ~MapIndexed~ f[0], {x, -4, 4}, Evaluated -> True]

enter image description here

Alternatives to Indexed are described here:

Mr.Wizard

Posted 2012-11-14T18:49:59.723

Reputation: 259 163

2

This is horrendous, but:

f[x_?NumericQ] := {x, x^2, Sin@x, Cos@x, ArcTan[x]}
length = Length@f[0];
Show@Table[
  Plot[f[x][[i]], {x, -1, 1}, 
   PlotStyle -> {ColorData["SunsetColors"][i/length]}],
  {i, 1, length}
  ]

Mathematica graphics

acl

Posted 2012-11-14T18:49:59.723

Reputation: 19 146

2

f[x_?NumericQ] := {x, x^2, Sin@x, Cos@x, ArcTan[x], ArcCos[x], 
  x^3/3, -x + 4/x}

And now

Block[{Plot, Part, x},
 Plot[f[x]~Part~# &~Array~8, {x, 0, 1}]
 ]

or

Plot[If[x \[Element] Reals, f[x][[#]]] &~Array~8, {x, 0, 1}, 
 Evaluated -> True]

Using what @wxffles just showed us in his answer

Plot[Hold@f[x][[#]] &~Array~8, {x, 0, 1}, Evaluated -> True]

Stealing @kguler's idea but impelmenting it more manually

Module[{i = 0}, 
 Plot[f[x], {x, 0, 1}] /. 
  l_Line :> {ColorData[1, "ColorList"][[++i]], l}]

Rojo

Posted 2012-11-14T18:49:59.723

Reputation: 40 993

Infix with part for no good reason – Rojo – 2012-11-14T20:08:08.773

-1

You have to trick mma in thinking that your subsequent datapoints are separate datasets to be able to use PlotStyle with multiple colors.

Dummy data:

vals = Range[0, 2 \[Pi], 1/6 \[Pi]];
results = Sin[#] & /@ vals;

Getting this data in a the right format:

data = Partition[Transpose[{vals, results}], 1];

Then it's just making a rule for the colors and plot the whole thing:

ListPlot[data, 
 PlotStyle -> 
  MapThread[
   Rule, {Range[Length[vals]], 
    Table[ColorData["Crayola"][[3, 1,RandomInteger[{1, 134}]]],{Length[vals]}]}]]

Aart Goossens

Posted 2012-11-14T18:49:59.723

Reputation: 1 570

1By using ListPlot you're not taking advantage of the adaptive sampling algorithm of Plot. – Joe – 2012-11-15T08:52:40.183