How to tell legends from axes in Matlab?
Asked Answered
N

3

6

The following stackoverflow qestion:

Matlab: How to obtain all the axes handles in a figure handle?

identifies how to get handles to all of the axes from a figure in Matlab. However, this list will also contain handles to legends, at least in R2008a, which appear to also be axes. How can I tell (programatically) the legends from the real plot axes in a vector of axes handles?

Needham answered 30/1, 2012 at 22:47 Comment(1)
Note that you also need to take care with colorbar axes.Heeley
H
12

From linkaxes, the code you want is:

ax = findobj(gcf,'type','axes','-not','Tag','legend','-not','Tag','Colorbar');

This will return the handles of all the data axes in the current figure.

Heeley answered 30/1, 2012 at 23:47 Comment(11)
But what if someone malicious changed the tags of the axes?Iodometry
@Jonas, I respectfully disagree. If you write the code yourself, just keep the handles. If you adapt to 3rd party code then anything that can go wrong, will go wrong.Iodometry
I wish to use the code to set all the colour limits in a figure to the same range, without having to get all the handles to each subplot in advance. So in this case the expediency of this solution trumps the risk that the tags have been changed (and also pointed out that Colorbars are also really axes). In this way I can either take in a figure handle, or take in a list of axes handles and have it work both ways. Thanks for all the answers.Needham
@Andrey: Normally, I'd agree with you. However, in this case, setting the axes tag to 'legend' also breaks TMW code. This is where I usually draw the line between accommodating other people and telling them that they should do things differently.Vintager
@Jonas, if they maliciously change the tags of the axes, then they need to keep track of the data axes themselves. There is no general way to detect the purpose of a set of axes automatically.Heeley
@Jonas, Nzbuu, I understand your opinions. By the way, this solution is definitely elegant. Nzbuu, regarding your last comment, you can detect the 'String' property for legends. Since "regular" axes don't have it, even a really malicious user can't change it. Check out (2) in my answer. ThanksIodometry
@Andrey: However, a non-malicious user might create a non-standard legend by adding custom axes, and give them the tag "legend" so as to label them with TMW standards :). BTW: I like your solutions. One of your upvotes is from me.Vintager
@Jonas, thanks. I also learned a lot from your posts. What are those TMW standards that you are talking about? BTW - non malicious users rock :)Iodometry
@Andrey: TMW=The MathWorks, the company that makes Matlab.Vintager
I can't take credit for my answer: it's taken from the linkaxes source code. Since that's an official part of base MATLAB, doing anything that would cause it to fail should be considered harmful.Heeley
Looking more closely at the linkaxes source code, it may be that the isappdata function is helpful in detecting non-data axes.Heeley
I
6

1) By default the Tag property of legend is 'Legend'. Of course, there is no promise that it is not changed.

 get(l)

 ....
 BusyAction: 'queue'
      HandleVisibility: 'on'
               HitTest: 'on'
         Interruptible: 'off'
              Selected: 'off'
    SelectionHighlight: 'on'
                   **Tag: 'legend'**
                  Type: 'axes'
         UIContextMenu: 200.0018
              UserData: [1x1 struct]

 ....

2) Another difference (which is more robust) is that regular axes do not have String property, but legends do. I am not sure whether there are other types of objects that also have String property. For example:

  plot(magic(3));legend('a','v','b');
  allAxesInFigure = findall(f,'type','axes')
  b = isprop(allAxesInFigure,'String')

You can verify it by calling:

get(gca,'String')
??? Error using ==> get
There is no 'String' property in the 'axes' class.

But on the other hand, for legends there is such a property. That is why it is more robust.

 plot(magic(3)); l = legend('a','b','c');
 get(l,'String')

ans = 'a' 'b' 'c'

3) I would recommend to solve this in a broader context. Just keep track of the legends and axes you create by storing their handles. That is, instead of coding like:

 plot(magic(3));
 legend('a','v','b');
 plot(magic(5));
 legend('a','v','b','c','d');

Code like this:

 p(1) = plot(magic(3));
 l(1) = legend('a','v','b');
 p(2) = plot(magic(5));
 l(2) = legend('a','v','b','c','d');
Iodometry answered 30/1, 2012 at 22:58 Comment(2)
Thanks Andrey, your answer is excellent but I think Nzbuu is closer to the answer I was looking for.Needham
@crobar, thats ok, I understand. Indeed there is some elegance in the solution of Nzbuu :)Iodometry
T
0

Just slightly modifying the code of my answer at the stackoverflow question you mentioned:

axesHandles = get(fig, 'Children');
classHandles = handle(axesHandles);
count = length(axesHandles);
isLegend = false(1, count);
for i = 1:count
    isLegend(i) = strcmp(class(classHandles(i)), 'scribe.legend') == 1;
end
legendHandles = axesHandles(isLegend);

Unfortunately, this solution depends on implementation details.

Trolly answered 27/8, 2013 at 10:29 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.