# How to make an arbitrary number of plots have different labels/colors/etc?

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]]

-
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
@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

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"]]
]


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

-
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
@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}]


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.

-

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}];


Basic application of restylePlot:

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


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"]
]


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


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

-