Adjusting figure size (2019b)
5 views (last 30 days)
I am so frustrated by Matlab's axis size settings. I want to make a tight figure of specific width (e.g. 5 inches) and include a textbox outside of the plot. For some reason Matlab doesn't adjust the figure to properly include the textbox and part of it falls outside of the boundary. I followed the solution described here and replaced the left margin with the width of the textbox. The units are very confusing and everything messes up when trying to adjust one parameter (e.g. outerposition changes by itself when adjusting position).
In the sample figure below, Matlab's boundary is red and the tight boundary I want is blue.
Benjamin Kraus on 23 Nov 2021
On axes the OuterPosition and InnerPosition (which is equivalent to Position) are linked to one another. The difference between them is always automatically calculated based on the size of the axes and tick labels. If you set one, the other will change automatically. Unfortunately, this calculation only includes labels that are owned by and positioned by the axes, it ignores manually placed labels.
I think the way to achieve your goal is to leverage the Extents property on text objects. You start by creating the axes and the text object, then measure the Extents of the text, and then you can adjust the axes to make room.
What complicates this quite a bit is that position and extents are based on the container. For text objects, the container is the axes, so normalized units are relative to the size of the axes and the Extents are relative to the axes. For axes, the container is the figure, so normalized units are relative to the figure and position values are relative to the figure. The easiest solution is to work in pixel units, which are common for both.
% Create the picture
ax = axes;
t = text(0, 15, 'Some text here', 'HorizontalAlignment','right');
% Measure the text position in pixel units. Make sure to switch back
% to data units after measuring the extents so that the text position
% remains anchored to the axes.
t.Units = 'pixels';
textpos = t.Extent;
t.Units = 'data';
% The first value is the left edge of the text relative to the axes, so to
% find out how much of the text object is being clipped you need to account
% for both the left edge of the axes and the left edge of the text.
ax.Units = 'pixels';
axpos = ax.InnerPosition;
leftEdgeOfText = axpos(1)+textpos(1);
% Now you want to shift the axes enough to avoid clipping. You can add some
% additional padding here if desired.
padding = 5; % pixels
shiftAmount = max(0,padding-leftEdgeOfText);
% Update the left edge of the axes.
axpos(1) = axpos(1)+shiftAmount;
% Optionally compress the width of the axes so that it doesn't extend
% beyond the right of the axes.
axpos(3) = axpos(3)-shiftAmount;
% Update the axes position.
ax.InnerPosition = axpos;
ax.Units = 'normalized';