Skip to main content

plotting - Isolating legend from Show combination of plots


Best explained by example. The code,


p1 = Plot[Sin[x], {x, 0, 10}, PlotLegends -> {"sin(x)"}];
p2 = Plot[Cos[x], {x, 0, 10}, PlotLegends -> {"cos(x)"}, PlotStyle -> Red];
p3 = Show[p1, p2]

Gives me this nice picture:


both



Now I want to isolate the plots and legends for export, so I can do,


p1[[1]]
p1[[2, 1]]

Which gives me:


plot


legend


But doing this on the combination p3,


p3[[1]]
p3[[2, 1]]


produces:


plot and one legend


only one legend


where only the legend from the first plot was extracted. Given two plots created separately with individual legends, is there a way to isolate the plot and legends? It seems like I can isolate the plots with p3[[1]][[1]], but haven't managed to combine the legends. I know I can create the legend manually separately, but I'm less keen on doing that.


Is there a way I can inspect the object p3 more closely to answer this question for myself? Currently it seems like trial and error by adding [[1]] indexing everywhere.



Answer




Is there a way I can inspect the object p3 more closely to answer this question for myself?




This is indeed the right question to ask. You can look at the expression structure using InputForm. This is often overwhelming, so we may need to do something to reduce the amount of information that is shown. One way is Short or Shallow.


Shallow[InputForm[p3]]

enter image description here


Shallow[InputForm[p3], 5]

enter image description here


Originally, all graphics were represented with Graphics expression. Show could combine only Graphics expressions. Anything else it could handle it converted to Graphics first.


Legending works by wrapping with Legended.


This is how you construct a legended plot manually:



Legended[
Plot[Sin[x], {x, 0, 10}, PlotStyle -> Blue],
LineLegend[{Blue}, {"sin x"}]
]

This is what is Plot produces automatically as well.


The first element in Legended will be the return value of Plot, a Graphics expression. The second element stays unevaluated as LineLegend[{Blue}, {"sin x"}], however, it displays as a legend. Just like Graphics[...], it does not evaluate to something, it simply displays in a certain way. The expression structure is not modified.


This is the first bit necessary to understand what is happening.


The second bit is that Show is now extended to handle Legended expressions. It does so by combining all the contained Graphics normally and placing them into an innermost Legended. However, the legend expressions (such as LineLegend) are not combined. Instead they are placed in a nested Legended structure which looks like


Legended[

Legended[
combinedGraphics,
legend1
],
legend2
]

Then it is the formatting of Legended that handles displaying this in a proper way.


Comments

Popular posts from this blog

plotting - How to draw lines between specified dots on ListPlot?

I would like to create a plot where I have unconnected dots and some connected. So far, I have figured out how to draw the dots. My code is the following: ListPlot[{{1, 1}, {2, 2}, {3, 3}, {4, 4}, {1, 4}, {2, 5}, {3, 6}, {4, 7}, {1, 7}, {2, 8}, {3, 9}, {4, 10}, {1, 10}, {2, 11}, {3, 12}, {4,13}, {2.5, 7}}, Ticks -> {{1, 2, 3, 4}, None}, AxesStyle -> Thin, TicksStyle -> Directive[Black, Bold, 12], Mesh -> Full] I have thought using ListLinePlot command, but I don't know how to specify to the command to draw only selected lines between the dots. Do have any suggestions/hints on how to do that? Thank you. Answer One possibility would be to use Epilog with Line : ListPlot[ {{1, 1}, {2, 2}, {3, 3}, {4, 4}, {1, 4}, {2, 5}, {3, 6}, {4, 7}, {1, 7}, {2, 8}, {3, 9}, {4, 10}, {1, 10}, {2, 11}, {3, 12}, {4, 13}, {2.5, 7}}, Ticks -> {{1, 2, 3, 4}, None}, AxesStyle -> Thin, TicksStyle -> Directive[Black, Bold, 12], Mesh -> Full, Epilog -> { Line[ ...

equation solving - Invert and fit implicitly defined curve

I need to fit an implicitly defined curve. I thought I could get some data out of Solve , and then using FindFit . Therefore, I would like to find the relation the parametric curve defined by $F(x,y)=0$: Solve[-(1/2) + 1/2 (0.41202 BesselK[0, 0.1 Sqrt[x^2 + y^2]] + (0.101483 x BesselK[1, 0.1 Sqrt[x^2 + y^2]])/Sqrt[x^2 + y^2]) == 0, y] But I can't get an output: Solve was unable to solve the system with inexact coefficients or the system obtained by direct rationalization of inexact numbers present in the system. Since many of the methods used by Solve require exact input, providing Solve with an exact version of the system may help. >> Edit: In particular, I would like to fit the data coming from the curve with the expression of another curve, and not with a function $f(x)$. In particular, since this clearly looks like a cardioid , I would like it to fit to something like it. What other strategies could I try?

dynamic - How can I make a clickable ArrayPlot that returns input?

I would like to create a dynamic ArrayPlot so that the rectangles, when clicked, provide the input. Can I use ArrayPlot for this? Or is there something else I should have to use? Answer ArrayPlot is much more than just a simple array like Grid : it represents a ranged 2D dataset, and its visualization can be finetuned by options like DataReversed and DataRange . These features make it quite complicated to reproduce the same layout and order with Grid . Here I offer AnnotatedArrayPlot which comes in handy when your dataset is more than just a flat 2D array. The dynamic interface allows highlighting individual cells and possibly interacting with them. AnnotatedArrayPlot works the same way as ArrayPlot and accepts the same options plus Enabled , HighlightCoordinates , HighlightStyle and HighlightElementFunction . data = {{Missing["HasSomeMoreData"], GrayLevel[ 1], {RGBColor[0, 1, 1], RGBColor[0, 0, 1], GrayLevel[1]}, RGBColor[0, 1, 0]}, {GrayLevel[0], GrayLevel...