23
$\begingroup$

I have multiple ListPlot in a Show where i want to add PlotLegends, but adding the PlotLegend attribute inside of each ListPlot adds a legend without any color representation, which is useless.

How do i deal with this in Mathematica 9?

Code sample:

dataamountofruns1 = Import["/Statistics/initial_test/initial_1_stat.csv", "CSV"]; dataamountofruns2 = Import["/Statistics/initial_test/initial_2_stat.csv", "CSV"]; dataamountofruns3 = Import["/Statistics/initial_test/initial_3_stat.csv", "CSV"]; Show[ ListPlot[dataamountofruns1, PlotStyle -> Blue,], ListPlot[dataamountofruns2, PlotStyle -> Green], ListPlot[dataamountofruns3, PlotStyle -> Orange], AxesStyle -> Black, FrameLabel -> {"Generation", "Population"}, Frame -> True, FrameTicks -> All, ImageSize -> 600, Background -> Transparent, PlotRange -> All, BaseStyle -> {12, FontFamily -> "Helvetica"} ] 

enter image description here

$\endgroup$
1
  • 2
    $\begingroup$ It would be very useful if you could provide at least a small sample of the three .csv files, so as we could play with them. $\endgroup$ Commented Jul 1, 2014 at 11:56

5 Answers 5

13
$\begingroup$

Here is the example of how to make this with Epilog:

(* These are the list and a function to fit it that will be plotted *) lst = Transpose[{RandomReal[{0, 3}, 30], RandomReal[{-0.03, 0.03}, 30]}] /. {x_, y_} -> {x, x*Exp[-x] + y}; ft = FindFit[lst, a + b*x*Exp[-c*x], {a, b, c}, x]; (* End ofg the list and fitting function *) (* The show statements begins *) Show[{ ListPlot[lst, PlotRange -> {{0, 3.5}, Automatic} ], Plot[a + b*x*Exp[-c*x] /. ft, {x, 0, 3}, PlotRange -> {{0, 3.5}, Automatic}, PlotStyle -> Red] }, (* The legends in the Epilog are starting here *) Epilog -> Inset[Framed[Column[{ PointLegend[{Blue}, {" Data"}], LineLegend[{Red}, \ {"f(x)=\!\(\*SuperscriptBox[\(x\[ExponentialE]\), \(-x\)]\)"}] }], RoundingRadius -> 5], Scaled[{0.8, 0.85}]] (* End of the Legends *) ] 

It should look like this: enter image description here

The same might be done using the Prolog. The difference is only visible, if the legends overlaps with the plots.

Another way is to place Legends into each Plot or ListPlot statement. The example using the same list and fitting function is given below. Then it lacks the common frame.

 Show[{ ListPlot[lst, PlotRange -> {{0, 3.5}, Automatic}, (* The PointLegend starts *) PlotLegends -> Placed[PointLegend[{" data"}, LabelStyle -> {Blue, 10}], Scaled[{0.69, 0.9}]] (* The PointLegend ends *) ], Plot[a + b*x*Exp[-c*x] /. ft, {x, 0, 3}, PlotRange -> {{0, 3.5}, Automatic}, PlotStyle -> Red, (* The LineLegend starts *) PlotLegends -> Placed[LineLegend[{Row[{Style["f(x)=", Italic], Style[NumberForm[a + b*x*Exp[-c*x] /. ft, {2, 1}], Italic]}]}, LabelStyle -> {Red, 10}], Scaled[{0.8, 0.8}]]] (* The LineLegend ends *) }] 

It should look like the following: enter image description here

Edit: To address the question about the spacing between the legends. It is easy to do in the case of the second method, since in this case there are two different legends, each having been created within its own Plot statement. Thea are then placed one under the other, and the point in which the second one is placed was chosen by me. Like this I can easily choose another point instead. Please see the example below. There the parameter z defines the displacement of the second legend from its initial position. Play with the slider to see its effect:

 lst = Transpose[{RandomReal[{0, 3}, 30], RandomReal[{-0.03, 0.03}, 30]}] /. {x_, y_} -> {x, x*Exp[-x] + y}; ft = FindFit[lst, a + b*x*Exp[-c*x], {a, b, c}, x]; Manipulate[ Show[{ListPlot[lst, PlotRange -> {{0, 3.5}, Automatic},(*The PointLegend starts*) PlotLegends -> Placed[PointLegend[{" data"}, LabelStyle -> {Blue, 10}], Scaled[{0.69, 0.9}]] (*The PointLegend ends*)], Plot[a + b*x*Exp[-c*x] /. ft, {x, 0, 3}, PlotRange -> {{0, 3.5}, Automatic}, PlotStyle -> Red,(*The LineLegend starts*) PlotLegends -> Placed[LineLegend[{Row[{Style["f(x)=", Italic], Style[NumberForm[a + b*x*Exp[-c*x] /. ft, {2, 1}], Italic]}]}, LabelStyle -> {Red, 10}], Scaled[{0.8, 0.8 - z}]]] (*The LineLegend ends*)}], {z, 0, 0.5}] 

You should see the following:

enter image description here

In principle one can change the spacing also within the first approach. Under the Epilog-Inset... You find the statement Column there. In principle, one should be able to insert the statement Spacer between the first and the second argument of the Column as follows: Column[{statement1, Spacer[z],statement2}] and play with the numeric value of z. However, this did not work for me. Looks as a bug, though I am not sure. If you only need to increase the distance between the lines in the legend you might choose to enter something invisible between the first and the second argument of the Column. For example, you can do it as follows:

Manipulate[ Show[{ListPlot[lst, PlotRange -> {{0, 3.5}, Automatic}], Plot[a + b*x*Exp[-c*x] /. ft, {x, 0, 3}, PlotRange -> {{0, 3.5}, Automatic}, PlotStyle -> Red]},(*The legends in the Epilog are starting here*) Epilog -> Inset[Column[{PointLegend[{Blue}, {" Data"}], Style["", z], LineLegend[{Red}, \ {"f(x)=\!\(\*SuperscriptBox[\(x\[ExponentialE]\), \(-x\)]\)"}]}], Scaled[{0.8, 0.85}]] (*End of the Legends*)], {z, 10, 50}] 

Here I added an empty string, but the distance varies due to the variation of the size of the absent text. Play with the slider to see the effect.

Have fun!

$\endgroup$
2
  • $\begingroup$ Is there any way to set the line spacing in the legends? $\endgroup$ Commented Sep 6, 2019 at 22:23
  • 1
    $\begingroup$ @H. R. Please have a look at the edits $\endgroup$ Commented Sep 16, 2019 at 9:24
9
$\begingroup$

You could combine all your data into list plot and then use PlotLegends. If you wish.need to use Show you could use Legended.

Here is an example with toy data:

data1 = MapThread[ 1/(1 + Exp[- #1 + #2]) &, {Range[0, 20, 1], RandomReal[{0, 1}, 21]}]; data2 = MapThread[ 1/(1 + Exp[- 1.4 #1 + #2]) &, {Range[0, 20, 1], RandomReal[{0, 1}, 21]}]; data3 = MapThread[ 1/(1 + Exp[-0.6 #1 + #2]) &, {Range[0, 20, 1], RandomReal[{0, 1}, 21]}]; 

Combining data:

 ListPlot[{data1, data2, data3}, PlotMarkers -> {Automatic, 10}, PlotLegends -> {"a", "b", "c"}] 

enter image description here

Using Show

Legended[Show[ MapThread[ ListPlot[#1, PlotStyle -> #2] &, {{data1, data2, data3}, op = {Directive[Red, AbsolutePointSize[7]], Directive[Green, AbsolutePointSize[7]], Directive[Blue, AbsolutePointSize[7]]}}]], PointLegend[op, {"a", "b", "c"}]] 

enter image description here

$\endgroup$
6
$\begingroup$

Another simple solution following your first idea

"adding the PlotLegend attribute inside of each ListPlot adds a legend without any color representation"

You can force Mathematica to show a colour-coded legend for a single dataset by specifying the format of the legend using one of the "LineLegend","SwatchLegend","PointLegend", etc... commands.

In your code it would look like this (using LineLegend)

... Show[ ListPlot[dataamountofruns1, PlotStyle -> Blue, PlotLegends -> LineLegend[{"A"}]], ListPlot[dataamountofruns2, PlotStyle -> Green, PlotLegends -> LineLegend[{"B"}]], ListPlot[dataamountofruns3, PlotStyle -> Orange, PlotLegends -> LineLegend[{"C"}]], AxesStyle -> Black, FrameLabel -> {"Generation", "Population"}, ...] 

Should generate something like this...

Legend example

Typically I use something like this when I need to combine the outputs of Plots and LinePlots

$\endgroup$
1
  • $\begingroup$ Welcome to Mathematica.SE! 1) As you receive help, try to give it too, by answering questions in your area of expertise. 2) Take the tour and check the help center! 3) When you see good questions and answers, vote them up by clicking the vote triangles, because the credibility of the system is based on the reputation gained by users sharing their knowledge. Also, please remember to accept the answer, if any, that solves your problem, by clicking the checkmark sign! $\endgroup$ Commented Sep 12, 2016 at 17:34
3
$\begingroup$

In earlier versions (and also v.9), to use a legend with Show use ShowLegend :-

dataamountofruns1 = Table[4 Log[x], {x, 1, 700}]; dataamountofruns2 = Table[3 Log[x], {x, 1, 700}]; dataamountofruns3 = Table[2 Log[x], {x, 1, 700}]; Needs["PlotLegends`"]; ShowLegend[Show[ ListPlot[dataamountofruns1, PlotStyle -> Blue], ListPlot[dataamountofruns2, PlotStyle -> Green], ListPlot[dataamountofruns3, PlotStyle -> Orange], AxesStyle -> Black, FrameLabel -> {"Generation", "Population"}, Frame -> True, FrameTicks -> All, ImageSize -> 600, Background -> Transparent, PlotRange -> All, BaseStyle -> {12, FontFamily -> "Helvetica"}], {{{Graphics[{Blue, Rectangle[{0, 0}]}], Style["Initial 1", 12, FontFamily -> "Helvetica"]}, {Graphics[{Green, Rectangle[{0, 0}]}], Style["Initial 2", 12, FontFamily -> "Helvetica"]}, {Graphics[{Orange, Rectangle[{0, 0}]}], Style["Initial 3", 12, FontFamily -> "Helvetica"]}}, LegendPosition -> {0.25, -0.35}, LegendTextSpace -> 1.5, LegendSize -> {0.4, 0.25}, LegendShadow -> False, LegendBorderSpace -> 0.5}] 

enter image description here

In version 9, as demonstrated by ubpdqn, Legended can be used :-

dataamountofruns1 = Table[4 Log[x], {x, 1, 700}]; dataamountofruns2 = Table[3 Log[x], {x, 1, 700}]; dataamountofruns3 = Table[2 Log[x], {x, 1, 700}]; Legended[Show[ ListPlot[dataamountofruns1, PlotStyle -> Blue], ListPlot[dataamountofruns2, PlotStyle -> Green], ListPlot[dataamountofruns3, PlotStyle -> Orange], AxesStyle -> Black, FrameLabel -> {"Generation", "Population"}, Frame -> True, FrameTicks -> All, ImageSize -> 560, Background -> Transparent, PlotRange -> All, BaseStyle -> {12, FontFamily -> "Helvetica"}], Placed[SwatchLegend[{Blue, Green, Orange}, {Style["Initial 1", 12], Style["Initial 2", 12], Style["Initial 3", 12]}, LegendMargins -> {{15, 15}, {5, 5}}, LegendFunction -> Framed, LabelStyle -> (FontFamily -> "Helvetica")], {{0.7, 0.1}, {0, 0}}]] 

enter image description here

$\endgroup$
3
  • $\begingroup$ Quite interesting your solution @Chris Degnen, is it possible to have the legend not framed in the box? And maybe with a line instead of a rectangle in case I have not only ListPlot but also Plot in Show. I've just realized that it is better to use Legended now, isn't it? $\endgroup$ Commented Sep 12, 2024 at 13:43
  • 1
    $\begingroup$ Yes, with Legended you can omit the frame by removing LegendFunction -> Framed and show lines by replacing SwatchLegend with LineLegend. These are all parameters to Legended so they're independent from the Show element which can contain listplots and plots. $\endgroup$ Commented Sep 12, 2024 at 14:04
  • $\begingroup$ @ Chris Degnen. I haven't quite managed to get what I was aiming at. For this reason, I posted a new question. link text. If you like, please, you can help me with that. $\endgroup$ Commented Sep 13, 2024 at 9:36
2
$\begingroup$

I don't have your actual data to work with them but I think that this is what you want

S0 = ListLinePlot[{dataamountofruns1, dataamountofruns2, dataamountofruns3}, Joined -> False, PlotStyle -> {Blue, Green, Orange}, Axes -> False, AxesStyle -> Black, FrameLabel -> {"Generation","Population"}, Frame -> True, FrameTicks -> All, ImageSize -> 600, Background -> Transparent, PlotRange -> All, BaseStyle -> {12, FontFamily -> "Helvetica"}, PlotLegends -> Placed[{Style["data1", FontFamily -> "Helvetica", 18], Style["data2", FontFamily -> "Helvetica", 18], Style["data3", FontFamily -> "Helvetica", 18]}, Scaled[{0.85, 0.25}]]] 
$\endgroup$

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.