Patapunfate
Patapunfate

Reputation: 307

Matlab: change order of entries in Figure legend

I have a Figure file where I would like to change the order of the entries (e.g., put the first entry as third one). I saved this Figure.fig long time ago so I am not sure if I can recover the original code.

Here I show you my plot:

My plot

I want the legend elements to be in a decreasing order ( as in the picture) but due to a mistake my second entry is referring to the wrong plot (it says "25 years" but the plot is actually referred to the lowest trend, corresponding to the "9 years" trend).

Can I switch the order of the entries in the Legend directly from the Properties Editor of the Figure in Matlab? If yes, how (I did not see any "Order" property or similar)? Otherwise is there any other simple approach to switch the order of the entries in the Legend?

Upvotes: 3

Views: 16219

Answers (5)

Samuel Miller
Samuel Miller

Reputation: 31

In 2021b, you can reorder the undocumented PlotChildren property of the Legend object, but you have to set the AutoUpdate property to 'off' first:

hLegend = legend({'Group A', 'Group C', 'Group B'});
hLegend.AutoUpdate = 'off';
hLegend.PlotChildren = hLegend.PlotChildren([1,3,2]);

This does not affect the stacking order of graphics objects in the plot. Be aware: when AutoUpdate is set to 'off', legend items will no longer be automatically added or deleted when new graphics objects are added to the axes.

Upvotes: 3

JMikes
JMikes

Reputation: 662

Based on my experience and the comments elsewhere on excaza's answer, it appears that their solution using an undocumented function may no longer work beyond R2017a.

The following uses the same example plot as in excaza's original answer but does not require undocumented functionality and seems to work using (atleast) R2021a. It leverages the ability to specify a subset of graphics objects to add legend labels to. This functionality appears to preserve the order with which you pass in those graphics objects.

For example,

x = 1:10;
y1 = x;
y2 = 2*x;
y3 = 3*x;
y4 = x.^2;
plot(x, y1, x, y2, x, y3, x, y4);
labels = {'y = x', 'y = 2*x', 'y = 3*x', 'y = x.^2'};
legend(labels)

Produces, Plot with original legend order

Retrieving the graphics handles allows for the legend to be recreated with a different order,

neworder = [3, 1, 4, 2];
ax = gca;
children = ax.Children;
legend(children(neworder), labels(neworder))

Amends the previous plot producing,

Plot with amended legend order

Note that unlike another answer to a similar question, this does not require explicitly returning graphics handles as they are plotted and keeping track of them. The handles are simply retrieved from the axes using ax.Children.

Upvotes: 0

Kyle Marquis
Kyle Marquis

Reputation: 1

I found a Matlab R2020 solution that can be used to re-order legend entries without messing up the order in which they are plotted on top of each other. I found it from https://matplotlib.org/1.3.1/users/legend_guide.html , and it's really simple, all you need to do is call

legend([p2, p1], ["line 2", "line 1"])

with p1 being the line object created when you plot p1 = plot(...) and together with uistack, I am able to change which objects get plotted on top of which, but then reorder the legend so it makes sense. Example

uistack(psave_d,'top') % Brings certain line to front
legend([psave_a, psave_b, psave_g, psave_c, psave_d, psave_e, psave_f, psave_pde], ["k_y=0.000001 W/m/K","k_y=0.0001 W/m/K","k_y=0.001 W/m/K","k_y=0.01 W/m/K","k_y=0.1 W/m/K","k_y=1 W/m/K","k_y=10 W/m/K","Isothermal PDE Numerical Model"])

If anyone needs more detail, I can gladly provide it. Cheers

Upvotes: 0

Suever
Suever

Reputation: 65430

Another alternative for those using a version of MATLAB older than R2014b is to retrieve the handles to the plot objects by specifying an output to plot. You can then re-arrange the handles in the order you want prior to passing them to legend.

x = 1:10;
y1 = x;
y2 = 2*x;
y3 = 3*x;
y4 = x.^2;

hplots = plot(x, y1, x, y2, x, y3, x, y4);
labels = {'y = x', 'y = 2*x', 'y = 3*x', 'y = x.^2'};

% Indices specifying the order in which you want the legend entries to appear
neworder = [3 1 4 2];
legend(hplots(neworder), labels(neworder));

Update

To properly handle when loading from a file, you can get all of the Children of the axes to get the plot objects and get the current legend to get the labels. You can then reorder them similar to the above approach.

load('filename.fig');

labels = get(legend(), 'String');
plots = flipud(get(gca, 'children'));

% Now re-create the legend
neworder = [3 1 4 2];
legend(plots(neworder), labels(neworder))

Upvotes: 9

sco1
sco1

Reputation: 12214

If your figure was generated in R2014b or newer you can utilize the undocumented 'PlotChildren' property to manipulate the order of the legend entries without requiring a new legend call.

For example:

x = 1:10;
y1 = x;
y2 = 2*x;
y3 = 3*x;
y4 = x.^2;

plot(x, y1, x, y2, x, y3, x, y4);
lh = legend('y = x', 'y = 2*x', 'y = 3*x', 'y = x.^2');

Produces:

start

Which you can then manipulate:

neworder = [3, 1, 4, 2];
lh.PlotChildren = lh.PlotChildren(neworder);

Producing:

yay

If you don't have the handle to the legend object, it is a child of the figure object containing the axes object your data is plotted on. You can find the handle to your legend object using one of the following findobj approaches:

% Handle to figure object known
lg = findobj(figureobj, 'Type', 'legend');

% Handle to figure object unknown
lh = findobj(gcf, 'Type', 'legend');

Note that gcf generally returns the handle to the last figure that the user clicked on, but this is not necessarily always the case.


Self promotion edit: This method is included in a set of legend manipulation tools maintained on GitHub by the StackOverflow MATLAB community.

Upvotes: 8

Related Questions