How to resize figure without moving contents

12 views (last 30 days)
To standardized my figure export process I use a custom defined printfigs.m call at the end of each script. One of the key things it does is timestamp and add a path to each figure at the top so that I can have a record of which script generated which figure.
To prevent this from overlapping any title's, annotations, or other parts of the figure, I want to resize the figure by adding a margin to the top that I can then use to place my annotation without potentially obstructing anything in the figure. I want a code that can take any figure and stretch the margins without disturbing it's contents.
To accomplish this, I've written this little code which I've been using for the bast two years on 2016b with little issue, but now it fails in 2018b quite frequently.
function [] = resizeFig(t, l, b, r)
fh = gcf();
set(findall(fh,'-property','Units'),'Units', 'pixels'); %%Set Object Sizes to Pixels
set(fh,'position',get(fh,'position')+[0,0,l+r,t+b]); % extends range of figure only
%%Grab Re-Sizeable Objects
objs = findobj(fh,'-property','position'); % grabs all objects with position properties
oPos = get(objs,'position'); % grabs position of moveable objects
ind = cellfun(@(C) size(C,2)==4,oPos); % finds objects that take 4 vector position input
objs = objs(ind);
oPos = oPos(ind);
%%Resize Objects within Figure
nPos = cellfun(@(C) C+[l,b,0,0],oPos,'uniformoutput',false); % displace positions left and down
for i = 1:length(objs)
set(objs(i),'position',nPos{i});%+[dleft,dbot,0,0]);
end
%%Set objects back to normalized/rescaleable
set(findall(fh,'-property','Units'),'Units', 'normalized');
end
Now I do hope there is a smarter way to do this to improve performance, but more importantly the line:
oPos = get(obs,'position');
tends to fail with this error:
Error using matlab.graphics.Graphics/get
No public property 'Position' for class
'ToolbarStateButton'.
this surprises me since the previous line is purposefully chosen to define objs as only those with the position property, though it now complains that it doesn't have that property. The same occurs if I use findall instead of findobj.
What has changed since 2016b and 2018b to cause this to fail?

Accepted Answer

Greg
Greg on 10 Oct 2018
Edited: Greg on 10 Oct 2018
Two things are actually happening. The first is somewhat nitpicky: there is no public property Position for the ToolbarStateButton. The use of findobj is allowed to see the existence of the (let's assume private) property Position, but your use of set is not allowed because it must be public to be set.
The second thing that happened is R2018b introduced some improved (?) (I think so, but you likely disagree right now) axes interaction default functionality. Most of the simple interactions are now ToolbarStateButton objects in a fancy floating-and-auto-appearing axes toolbar, instead of static buttons in the figure toolbar. These new ToolbarStateButton objects apparently have the non-public Position property.
Note: In my tests, findobj did not return the ToolbarStateButton components. I had to use findall.
To fix your code, simply delete the toolbar.
addToolbarExplorationButtons(fh); % Put the old menu buttons back just in case you need them
delete(ah.Toolbar); % ah is an axes handle in the figure
findobj(...);
  3 Comments
Greg
Greg on 10 Oct 2018
I suspect DefaultFigureToolbar has nothing to do with it, but haven't run any tests to confirm.
There are lots of different possible approaches to this task.
  • If you're running it programmatically in line with figure generation, you could set the figure visibility to 'off' to prevent user interaction.
  • You could stick to top or right margins whereby the left and bottom of each component are good as-is after changing to units other than normalized.
  • You could create a new figure, put a panel of the original figure's size in it, and copy components into the panel.
  • Probably a lot of other really bad ideas, but they would technically do what you're attempting.
Alexander Laut
Alexander Laut on 11 Oct 2018
Edited: Alexander Laut on 11 Oct 2018
I think I found my issue, in my code elsewhere I was calling:
set(0, 'ShowHiddenHandles', 'on')
I think I wrote this into one of my codes like 3 years ago as I was playing around with hiding figures until my code was finished so my printfigs function would by default show them all before export to png.
Heres a test code I wrote that should clarify my issue:
clc;clear variables; close all
% Default Setup (Works; with or without toolbar)
% set(0,'ShowHiddenHandles','off');
% set(0,'defaultfiguretoolbar','auto');
% Alternative Setup (Works; no toolbar)
% set(0,'ShowHiddenHandles','off');
% set(0,'defaultfiguretoolbar','none');
% Alternative Setup (Fails; when toolbar initiated)
set(0,'ShowHiddenHandles','on');
set(0,'defaultfiguretoolbar','auto');
% Generate Test Scenario
figure();
axis();
fprintf('try hovering over figure with mouse to initiate toolbar...\n')
pause(3)
objs = findobj(gcf(),'-property','position'); % grabs objects with position
objs_pos = get(objs,'position'); % grabs positions of objects
disp('Completed without error!')

Sign in to comment.

More Answers (0)

Categories

Find more on Specifying Target for Graphics Output in Help Center and File Exchange

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!