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.

I'm sorry but I'm not sure how to phrase this question well. Frequently I have a function that produces and returns a Plot[] or array of Plot[]'s, which I can then display with Show[], or combine with Plot[]'s from another function and then use Show[].

Normally to tell which curve is which on a graph with many curves, you have a legend. Except here, the function produced an arbitrary number of plots, and also I maybe later want to combine them with other Plot[]'s in Show[], so they all have the same color in the legend.

Is there a way to make Show[] give them different colors so I can tell them apart? I can think of some very contrived ways to do this (make some sort of global variable that keeps track of how many plots have been created, and uses this as a counter to change the color to be used for the next plot), but they're very ugly and I imagine there must be a better way in elegant MM.

Does anyone know of one?

Thank you!

Edit: An example of the code:

(*Creates and returns a plot.*)
PlotSomething[freq0_] := (
Plot[Sin[freq0*x], {x,0,3.14}])

(*Call the above plotting function several times, create and return an array of Plots.*)
MakePlotArray[numplots_] := (
plottable = {};For[i = 1, i <= numplots, i++,
AppendTo[plottable, PlotSomething[i]];
];
Return[plottable];)

(*How can I make these plots have different colors and labels?*)
Show[MakePlotArray[5]]
share|improve this question
    
Please include code to produce "an arbitrary number of plots" in the same manner that you have in your application. –  rm -rf Mar 11 at 17:53
    
@rm-rf Of course, sorry. Let me do that. What I mean by 'arbitrary' is different every time I call the function, depending on the arguments. –  YungHummmma Mar 11 at 17:54
    
It could be much better if you provide a boilerplate that doesn't need external resources (files, functions). Just a small simulation of random data able to run stand-alone. –  belisarius Mar 11 at 18:15
1  
@belisarius Sorry, I didn't think about making it directly runnable, just to show what I meant. I've modified it to make it standalone and produce what I mean. –  YungHummmma Mar 11 at 18:44
    
@YungHummmma Much better now. Thanks. –  belisarius Mar 11 at 18:59

3 Answers 3

I don't know if there's an elegant way. The colors are embedded in the plots, and changing them after the fact takes some work. I basically do what the OP alluded to, but as postprocessing. Collect the colors in the graph and remap them according to some color function.

plots = Table[
  Plot[Evaluate[Table[Sin[(4(3-j)-i)x], {i, 4-j}]], {x, 0, 2 Pi}],
  {j, 3}];

remapColors[plots_, colorFunction_ : (Hue[#, 0.6, 0.6] &)] := 
 Module[{n=0, colors, ncolors},
  colors=DeleteDuplicates @ Cases[First@#, _RGBColor | _Hue, Infinity] &/@ plots;
  ncolors=Length @ Flatten @ colors;
  MapThread[#1 /. (#1 -> colorFunction[Rescale[++n, {1, ncolors}]] &/@ #2) &,
   {plots, colors}]
 ]

Show[
 remapColors[plots, ColorData["Rainbow"]]
 ]

Mathematica graphics

Caveat: If the plots contain styles that have colors, such as a styled Tootlip, those colors will be remapped, too.

share|improve this answer
    
Yeah, I guess that's the best way to do it. Just to be clear, I also don't really care about the colors exactly -- I just want to be able to tell which curve is which in a legend off to the side, when I combine all these Plots. I also don't really care about doing it this way -- I guess a better way would be to return the arrays before plotting them, and then pass them to a function to plot them all at once (thus letting me make them different colors and label them easily)? –  YungHummmma Mar 11 at 19:09
1  
@YungHummmma I think plotting them all at once is the easiest way (perhaps the only way) to get the legends to automatically match the curves. –  Michael E2 Mar 11 at 19:18

Small mod to the above to draw a legend..

 remapColors[plots_, colorFunction_ : (Hue[#, 0.6, 0.6] &)] := 
     Module[{n = 0, colors, ncolors},
       colors = 
        DeleteDuplicates@Cases[First@#, _RGBColor | _Hue, Infinity] & /@ 
          plots;
     ncolors = Length@Flatten@colors;
     newcolors = Table[ colorFunction@(i/ncolors) , {i, ncolors }];
     MapThread[#1 /. (#1 -> newcolors[[++n]] & /@ #2) &, {plots, colors}]]

 legend[col_] := 
     Graphics[Table[{{col[[i]], z = .1 + .1 i; Line[{{7, z}, {8, z}}]}, 
        Text[Style[ToString[i]], {8.6, z}]}, {i, Length[col]}]]
 Show[{remapColors[plots, ColorData["Rainbow"]], legend@newcolors}, 
         PlotRange -> {{0, 9}, Automatic}]

enter image description here

Really preferable to assemble the data into a single plot if feasible of course.

Caveat: If your base plots have colors specified via PlotStyle they end up with extra unused colors which then end up in the legend.. I don't see a straightforward way around that.

share|improve this answer

I am also going to propose a post-processing approach, but I will base my answer on my existing restylePlot function from Is it possible to change the color of plot in Show?
That function again for reference:

restylePlot[plot_Graphics, styles_List, op : OptionsPattern[Graphics]] :=
 Module[{x = styles}, Show[
   MapAt[# /. {__, ln__Line} :> {Directive @ Last[x = RotateLeft@x], ln} &, plot, 1],
   op
 ]]

Five plots all generated with the default style:

 plots = Table[Plot[BesselJ[n, x], {x, 0, 10}], {n, 5}];

enter image description here

Basic application of restylePlot:

combined = 
  restylePlot[
    Show[plots],
    ColorData[3, "ColorList"],
    BaseStyle -> Thick
  ]

enter image description here

Note:

  • BaseStyle in can be used to affect all lines at once
  • The color list given as the second argument will be used cyclically

To add a legend you may use Jens' legendMaker code from Creating legends for plots with multiple lines? as follows:

legend =
  legendMaker[
    Array[TraditionalForm @ BesselJ[#, x] &, 5], 
    PlotStyle -> ColorData[3, "ColorList"]
  ]

enter image description here

Show[
 combined,
 Prolog -> Inset[Style[legend, 18], {1, -0.18}],
 ImageSize -> 600
]

enter image description here

These steps can of course be automated but I leave that as an exercise for the reader.

share|improve this answer

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.