MATLAB Answers

1

axes title of all open figures

Asked by Rafael Kübler on 31 May 2017
Latest activity Commented on by Jan
on 9 Jun 2017
Hello together,
having for example two open figures, where each figure has a plot in it with a title. I want an easy way without a loop, to get the titles of the plots. Sofar my idea is, to get all open figures (in the example this are two) by
openFigures = findobj('Type', 'figure');
now i have an array of to 2x1 matlab.ui.Figures. To get the Title of the first figure i can use:
title1 = openFigures(1).Children(2).Title.String
(I'm using the index 2 after Children because the index 1 is the legend.)
So my question is how to get both titles in one command like:
titles = openFigures(1:2).Children(2).Title.String
This Syntax does not work though.
Do you have any idea without using a loop?
Thank you for your help Rafael

  0 Comments

Sign in to comment.

2 Answers

Answer by Adam
on 31 May 2017
Edited by Adam
on 31 May 2017
 Accepted Answer

It can be done, but sometimes you have to ask yourself why you specifically want to avoid a for loop because the alternative can often be a lot worse, especially in the case of Matlab where you cannot chain together parentheses and other forms of brackets such as
get( hTitles, 'String' ){:} % Invalid syntax
So you end up with lots of lines of code having to keep getting one level of results at a time and unpacking them from a cell array to a regular object array and on and on down the chain, and with the assumption mentioned below that axes are the only children of the figure, although you can filter out other children.
So this works...but is it better than a for loop? I would say not personally. Certainly you cannot do it in one command:
% Setup figures for testing
hFig(1) = figure;
imagesc( magic(20) );
title( 'magic20' )
hFig(2) = figure;
imagesc( magic(50) );
title( 'magic50' )
% Extract the title strings
ch = get( hFig, 'Children' );
hAxes = [ ch{:} ]; % Assumes axes are the only children
hTitles = get( hAxes, 'title' );
hTitles = [ hTitles{:} ];
titles = get( hTitles, 'String' );

  0 Comments

Sign in to comment.


Jan
Answer by Jan
on 31 May 2017

It will not work without a loop.
If you really need this, store the handles of the titles during the creation already. Then the access will be much more reliable than relying on the axes to be the 2nd child. If you store the title handles explicitely, the problem does not appear.
The was asked repeatedly in the forum, usually concerning sub-fields in structs. What do you expect as benefit in avoiding the loop?

  6 Comments

Adam
on 9 Jun 2017
I always keep hold of any graphics handles that I want to subsequently use so this has never really been a problem for me. A syntax like that might be nice, but Matlab has never allowed intermediate level indexing like that when you end up with arrays as the result of the first part of the statement.
findobj is one of those functions you should almost never be having to use - it is always better to just keep hold of the handles yourself than have to re-find them afterwards.
but keeping track of all the handles i have created can be prone to errors, when deleting some figures and createing new ones. It means to edit a variable which stores all handles constantly.
I'm making a kind of interactive analyse tool for signals, where i can constantly add, delete or edit figures. I store all handles in a variable so far. But i'd like to be able, to use some functions of my analyse tool on figures, which haven't been created by the tool itself, and where the handles have not been stored there.
But i guess this is the only way to do it.
Jan
on 9 Jun 2017
An object oriented approach helps here. You do not need to use OO commands, but only the idea of treating a figure as an object. It would be very complicated to keep a global list of all needed handles for a specific job. But if the handles are stored in a separate field of the "handles" struct inside a figure, it is enough to call a function with a set of figure handles and let it obtain the handles in each figure dynamically. Then the concerned handles are stored locally and you have only 1 location in your code, where changes must be applied.
This is implemented in Matlab already, see e.g. the list of "Children" for each object. But this is designed for other purposes and you cannot rely on the order of Children. Therefore openFigures(1).Children(2).Title is a really bad idea, because it will fail if you decide later (perhaps in some years, or your successor) to insert an additional element like a logo. Then it matters if the additional element is inserted on the top or bottom of the code, and if the wrong location is chosen, error messages will appear at a completely different location. Try to avoid such magic remote dependencies.
Better mark all concerned axes by a specific (unique!) ID:
specID = 'AutoTitleFeature_007';
figure;
axes('Tag', specID);
title('Axes 1');
figure;
axes('Tag', specID);
title('Axes 2');
function TitleList = GetTheTitles
specID = 'AutoTitleFeature_007';
openFigs = allchild(groot); % See PS below
TitleList = {};
for iFig = 1:numel(openFigures)
axesList = findobj(openFigs(iFig), 'flat', 'Type', 'axes', ...
'Tag', specID);
axesTitle = get(axesList, 'Title');
TitleList = cat(1, TitleList, axesTitle(:));
end
This looks more complicated at first, but it will be much easier, if you expand or change the code later.
But as said above: I'd prefer a method, which stores the handles o9f the concerned titles explicitely in the handles struct of each figure. Then it will not matter, if the axes are direct children of the figure or if you decide later on to create them in a uipanel.
PS. findobj('Type', 'figure') checks all graphic objects. If you have some GUIs with many axes, uipanels and some thousand line objects, this will take some time. findobj(allchild(groot), 'flat', 'Type', 'figure') is much faster, but currently groot can have figures as children only.

Sign in to comment.