Annotation box left corner position

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!

 Respuesta aceptada

Kelly Kearney
Kelly Kearney el 26 de Mayo de 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 comentarios

Questions from Mahmoud:
1- I really couldn't get the logic of your code and how you managed to do this. I appreciate if you could elaborate more or refer me to a reading.
2- I still don't know why the box position [0,0,x,x] doesn't refer to the left corner of the figure and instead it goes to somewhere in the middle of the figure.
3- Your code put all the boxes at the left corner of each subplot. What if I want to change their position?
---
Let's go through this with some simpler examples, just using an empty figure and no axes. First, a simple textbox, positioned in the lower left hand corner using the dim value in your example.
hf = figure;
dim = [0 0 0.5 0.5];
han = annotation(hf, 'textbox', dim, 'String', 'Test 1');
Notice that the coordinates you gave define the dimensions of the box, not the text itself. The next example uses the exact same coordinates, but with the fit-to-text option turned on:
han = annotation(hf, 'textbox', dim, 'String', 'Test 2', ...
'FitBoxToText', 'on');
Now the text is in the same place as the previous example, but the empty part of the box (below and to the right of the text) has been removed.
If you want the text itself to be in the lower left, you need to change the alignment.
han = annotation(hf, 'textbox', dim, 'String', 'Test 3', ...
'VerticalAlignment', 'bottom');
Now if you turn on the fit-to-text, the bit that gets trimmed away is the empty space above the text. Again, the only thing that changes is the width and height of the box, not the position of the text.
han = annotation(hf, 'textbox', dim, 'String', 'Test 4', ...
'VerticalAlignment', 'bottom', 'FitBoxToText', 'on');
Note that in all four of the examples above, I used the exact same coordinates for dim, the position of the box.
If I want to move the box so the lower left corner is somewhere else, just change the first two elements of dim to match those coordinates.
xy = [0.5, 0.6];
% Draw an invisible axis with coordinates matching the figure
% (Just so I can plot the corner point)
axes('visible', 'off', 'position', [0 0 1 1], 'xlim', [0 1], 'ylim', [0 1]);
line(xy(1), xy(2), 'marker', 'x');
newdim = [xy dim(3:4)];
% New annotation textbox
han = annotation(hf, 'textbox', newdim, 'String', 'Test 5', ...
'VerticalAlignment', 'bottom', 'FitBoxToText', 'on');
Finally, what if we wanted to align the upper right of the textbox with a point? First, calculate the position of the box's lower left corner:
newdim = [xy(1)-dim(3), xy(2)-dim(4) dim(3:4)];
Remember the alignment issue... if you use the bottom left alignment from before, your text will be far from the desired location:
han = annotation(hf, 'textbox', newdim, 'String', 'Test 6', ...
'VerticalAlignment', 'bottom', 'FitBoxToText', 'on');
han2 = annotation(hf, 'textbox', newdim, 'String', '', ...
'VerticalAlignment', 'bottom', 'FitBoxToText', 'on', 'Linestyle', ':');
But if we change the text alignment to be in the upper right, everything looks good:
han = annotation(hf, 'textbox', newdim, 'String', 'Test 7', ... 'VerticalAlignment', 'top','HorizontalAlignment', 'right', 'FitBoxToText', 'on');
(Well, drat, I've hit my image upload limit... guess you'll have to try this one on your own!)
Mahmoud Zeydabadinezhad
Mahmoud Zeydabadinezhad el 27 de Mayo de 2016
Excellent job!
Star Strider
Star Strider el 27 de Mayo de 2016
Mahmoud Zeydabadinezhad’s ‘Answer’ moved here:
Hi Kelly,
Thank you for the solution and efforts. Although, it solved my problem for now but there are a few things:
1- I really couldn't get the logic of your code and how you managed to do this. I appreciate if you could elaborate more or refer me to a reading.
2- I still don't know why the box position [0,0,x,x] doesn't refer to the left corner of the figure and instead it goes to somewhere in the middle of the figure.
3- Your code put all the boxes at the left corner of each subplot. What if I want to change their position?
Thank you! Mahmoud
Taylor Begay
Taylor Begay el 24 de Jul. de 2019
Hi Kelly,
Is there any way to 'pin' the annotation to the a corner of a subplot that results in the annotation not shifting/moving when the figure window is enlarged to fill the entire screen? When the figure is generated straight from the code you wrote, it works, however, when I maximize the figure window, the annotation is no longer in the position it initially was.
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');
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

Iniciar sesión para comentar.

Más respuestas (1)

Alexandre Riebel
Alexandre Riebel el 24 de Jul. de 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'.

Categorías

Community Treasure Hunt

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

Start Hunting!

Translated by