Annotation box left corner position

278 views (last 30 days)
Hi all
I have created a figure divided to 16 subplots using the commands:
hf = figure('units','normalized','outerposition',[0 0 0.5 1]); %%To adjust the aspect ratio 1:2
ha = tight_subplot(4,4,[0.045 0.025],0.05,[0.057 0.01]);%%Create the customized subplots.
ha = reshape(ha',4,4); %%ha(i,j) means subplot in column i and row j.
%%Rest of the code ...
axes(ha(i,j));
%%4 plots in every subplots
pbaspect([1 1 1]) %%To make each subplot square shape.
dim = [0,0,0.5,0.5];
annotation(hf,'textbox',dim,'String',LEGEND(5:8),'FitBoxToText','on');
My confusion is that why the specified dim above place the annotation box where it is depicted in the attached picture. If that is the position of the left corner, then what would be the actual position of the real left corner of the attached picture? My goal is to calculate the left corner position of annotation boxes programmatically and place one box in each subplot.
Thank you!

Accepted Answer

Kelly Kearney
Kelly Kearney on 26 May 2016
A few things are happening here. First, by default, the alignment of the text in an annotation text box is in the upper right corner. That positioning is done before the box is trimmed to the text, which leaves the text floating pretty far from the desired location. You can change this easily by adjusting the vertical alignment.
hf = figure;
for ia = 1:4
ha(ia) = subplot(2,2,ia);
end
pos = get(ha, 'position');
dim = cellfun(@(x) x.*[1 1 0.5 0.5], pos, 'uni',0);
annotation(hf, 'textbox', dim{1}, 'String', 'test 1');
annotation(hf, 'textbox', dim{2}, 'String', 'test 2', 'FitBoxToText','on');
annotation(hf, 'textbox', dim{3}, 'String', 'test 3', 'verticalalignment', 'bottom');
annotation(hf, 'textbox', dim{4}, 'String', 'test 4', 'FitBoxToText','on', 'verticalalignment', 'bottom');
The second issue has to do with the positions of the axes themselves. You'll notice that even when you fix the alignment issue, the horizontal location of the annotations overlap with the axis lines:
hf = figure;
for ia = 1:4
ha(ia) = subplot(2,2,ia);
end
arrayfun(@(x) pbaspect(x, [1 1 1]), ha);
drawnow;
pos = get(ha, 'position');
dim = cellfun(@(x) x.*[1 1 0.5 0.5], pos, 'uni',0);
for ia = 1:4
annotation(hf, 'textbox', dim{ia}, 'String', num2str(ia,'test%d'), 'vert', 'bottom', 'FitBoxToText','on');
end
This is because the axis position reflects the full potential position of the axis, rather than the space actually taken up once data aspect and plot box ratios are adjusted. I wrote a function, called plotboxpos.m, that calculates the actual space taken up by a 2D axis. If you substitute that in place of position, you can now align your annotation boxes where you want them:
hf = figure;
for ia = 1:4
ha(ia) = subplot(2,2,ia);
end
arrayfun(@(x) pbaspect(x, [1 1 1]), ha);
drawnow;
pos = arrayfun(@plotboxpos, ha, 'uni', 0);
dim = cellfun(@(x) x.*[1 1 0.5 0.5], pos, 'uni',0);
for ia = 1:4
annotation(hf, 'textbox', dim{ia}, 'String', num2str(ia,'test%d'), 'vert', 'bottom', 'FitBoxToText','on');
end
  6 Comments
Kelly Kearney
Kelly Kearney on 29 Jul 2020
With annotations, textbox positions are always specified in terms of normalized figure size. So assuming the aspect ratios of the axes and figures aren't always in sync with each other, you'd have to add a resize listener to redo the calculations on resize.
However, a simpler option would be to just use a text object with normalized coordinates, rather than textbox annotations. For example, pinning to the upper right:
figure;
plot(1:10, rand(10,1)*2);
axis tight equal;
text(1,1, 'testing', ...
'units', 'normalized', ...
'horizontalalignment','right', ...
'verticalalignment', 'top');
Adam Danz
Adam Danz on 18 Oct 2020
Thanks for the great explanation, Kelly.
I was exploring the FitBoxToText property and wanted to share another version of your demo that compares Top and Bottom alignment and adds a red ellipse at the textbox anchor to demonstrate your point about how the FitBoxToText property changes the apparent position but not the acutal position property.
hf = figure;
for ia = 1:8
ha(ia) = subplot(4,2,ia);
end
pos = get(ha, 'position');
dim = cellfun(@(x) x.*[1 1 0.5 0.5], pos, 'uni',0);
annotation(hf, 'textbox', dim{1}, 'String', 'test 1a');title(ha(1),'Basic')
annotation(hf, 'textbox', dim{2}, 'String', 'test 1b');title(ha(2),'Basic')
annotation(hf, 'textbox', dim{3}, 'String', 'test 2a', 'FitBoxToText','on');title(ha(3),'Fit')
annotation(hf, 'textbox', dim{4}, 'String', 'test 2b', 'FitBoxToText','on');title(ha(4),'Fit')
annotation(hf, 'textbox', dim{5}, 'String', 'test 3a', 'verticalalignment', 'Top'); title(ha(5),'VA Top')
annotation(hf, 'textbox', dim{6}, 'String', 'test 3b', 'verticalalignment', 'Bottom'); title(ha(6),'VA Bottom')
annotation(hf, 'textbox', dim{7}, 'String', 'test 4a','verticalalignment','top' ,'FitBoxToText','on');title(ha(7),'fit + VA Top')
annotation(hf, 'textbox', dim{8}, 'String', 'test 4b','verticalalignment','Bottom' ,'FitBoxToText','on');title(ha(8),'fit + VA Bottom')
% mark anchors
for i = 1:numel(dim)
annotation(hf, 'ellipse', [dim{i}(1:2),.01,.01],'Color','r')
end

Sign in to comment.

More Answers (1)

Alexandre Riebel
Alexandre Riebel on 24 Jul 2020
I have a simpler solution to this question:
for i = 1:4
a(i) = subplot(2,2,i);
b(i) = annotation('textbox','String',"test",'Position',a(i).Position,'Vert','bottom','FitBoxToText','on')
end
Basically this code is just fitting a textbox to the plot area of each subplot, then ensuring that the text is in the bottom of that textbox, then resizing the textbox to fit the text. If you want the textbot at the top of the plot, switch 'bottom' to 'top' and if you want the textbox in the middle or left side of the plot use 'HorizontalAlignment'.

Categories

Find more on Graphics Object Programming 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!