Editor's Note: This file was selected as MATLAB Central Pick of the Week
Alters a figure so that it has the minimum size necessary to
enclose all axes in the figure without excess space around them.
Works for figures containing multiple axes as subplots.
Note that tightfig will expand the figure to completely encompass all
axes if necessary.
Returns an error if the figure contains any 3D axes which have been zoomed.
1.7.0.0 | Actually uploaded new file this time! |
|
1.6.0.0 | Now works better with newer Matlab plotting code (i.e. colorbars and legends now handled properly in newer Matlab) |
|
1.5.0.0 | Added suggested improvement for minimum bound by Ben |
|
1.3.0.0 | Corrected bug noted by commenter Thomas, also tidied up some other parts of code and comments. |
Inspired by: Get rid of the white margin in saveas output
Inspired: ExportPngInkscape(filename,dpi,handle), Average Temperature, JacobD10/tightfigadv, subtightplot, Spreadfigures, Backer-Upper Truck Simulator with Fuzzy Control, Space-Time Adaptive Processing for Airborne Radar by J.Ward
Create scripts with code, output, and formatted text in a single executable document.
Szymon Kulpinski (view profile)
Very useful function! Thank you!
I couldn't use more than one colorbar in my subplots. I resolved this issue by changing line 63 of the code:
orginal : [cbarpos, cbarti] = colorbarpos (hcbar);
changed: [cbarpos, cbarti] = colorbarpos (hcbar(cbind));
Hopefully this will be useful to someone :)
Sebastian (view profile)
Takuya Miyashita (view profile)
T A (view profile)
It appears I spoke too soon, what I'm seeing is an issue with tightfig when altering the rotation and alignment of an axis label. Sample code below, note that if the "set(..." line is commented out, it looks OK, otherwise the right y-axis label is cut out. Using a pause or drawnow before calling tightfig does NOT seem to help, though if I don't invoke tightfig until after this runs, then it does help.
figure
yyaxis left
plot(rand(5,2))
xlabel('x')
ylabel('y1')
yyaxis right
plot(rand(5,2))
ylabel('y2')
set(get(gca,'YLabel'),'VerticalAlignment','bottom','Rotation',-90)
tightfig
Josh Güsewell (view profile)
Nicolas (view profile)
Nicolas Harcke (view profile)
Hi Richard, this is a very nice function. Sadly I have a little problem with it because it cuts of the plot title when moving the axes. Might you please help me with this issue? Thanks a lot.
Travis Yeager (view profile)
I am unsure why I am receiving this error.
Error using cellfun
Input #2 expected to be a cell array, was char
instead.
Error in tightfig>colorbarpos (line 200)
maxlabellen = max ( cellfun
(@numel, tlabels,
'UniformOutput', true) );
Error in tightfig (line 63)
[cbarpos, cbarti] = colorbarpos
(hcbar);
Error in AllPhysicsFiguresForPaper (line 485)
tightfig;
Selim ilhan (view profile)
John Evans (view profile)
Thank You! This works.
fung lam (view profile)
Fernando (view profile)
Bryce Inman (view profile)
Current version produces error when multiple subplots have colorbars. It looks like the colorbarpos call on line 63 passes an array of colorbars in this case, which causes the strfind error on line 181. This can be fixed by changing line 63 to:
[cbarpos, cbarti] = colorbarpos (hcbar(cbind));
Brad Stiritz (view profile)
Very helpful function, thank you. However, the current version re-renders my charts just a little bit "too tight" for my taste. Ideally, I would like to be able to rapidly determine function parameters that I like better, for my visual preferences.
Code does not currently facilitate easy user tweaking. Current version has multiple arbitrary "magic number" values hard-coded in-line, which (with respect) is not considered good coding style. Cf. e.g. "Code Complete" 2nd edition. Please consider refactoring all those literal numbers into named constants, and define with explanatory comments, in a block at the top of the function.
Respectfully submitted, thank you for your consideration.
Alexey R. (view profile)
Richard Crozier (view profile)
@Jason Nicholson and others, I've now updated to work with colorbars and legends in newer matlab.
Jason Nicholson (view profile)
Great function.
Note there is still a bug that cuts out the colorbar. Updating this would be helpful. Thanks.
joker holy (view profile)
Very helpful,thanks a lot
Anders Søbye (view profile)
Leon Aksman (view profile)
Leon Aksman (view profile)
Jacob D (view profile)
Following comments from Bela Bacsi, Shaun, Vivas, Thomas Edwards, João and Arnold (and possibly others), I decided to add another submission (tightfigadv) to FileExchange which makes use of text objects within figures to find outer bounds.
https://au.mathworks.com/matlabcentral/fileexchange/65004-jacobd10-tightfigadv
The changes to the code seemed too much to post as another comment here.
The submission is also linked to GitHub which is updated on FEX daily and allows for pull requests to be sent.
Darwin Te (view profile)
Giuseppe Trainiti (view profile)
Joaquin Blanco (view profile)
(L) (L) (L)
i love you !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
can we marry?
Yulia Moiseeva (view profile)
OMG, life saver!
loic tadrist (view profile)
Bader Ben-Slimane (view profile)
Oskar Elek (view profile)
Thank you! Works as advertised for plots and fcontours, even with multiple subs.
shawn poppin (view profile)
Michele Girardi (view profile)
Alexander Bratch (view profile)
Falk Lieder (view profile)
Jay St. Pierre (view profile)
Great tool.
Any idea why it has trouble with figures that contain annotation text boxes? My workaround is to run 'tightfig' before I invoke the 'annotation' command.
Isaac Li (view profile)
Awesome function for all cartesian plots.
However, it doesn't work with polarplot function. when polarplot is presented they get squeezed as if they don't exist.
Ray Lee (view profile)
It would be nice to also reduce the margins among subplots.
Bela Bacsi (view profile)
Update posted by Jacob D is unfortunately insufficient for colorbars with labels and tick labels, as resizing doesn't consider their size and can crop them.
Colorbars don't have an OuterPosition property (Matlab 2016a). Their Label is a Text object, so its Extent property can be used to calculate its Position, so that can be adjusted for. However, I don't know any way to get the tick labels' extent (and that of the multiplier, shown above them, such as x10^-4), so those might end up being cropped. Any ideas how to get to them?
Casey Ta (view profile)
K E (view profile)
In R2015b, I had to change Jacob D's edit as follows:
ti = [get(hax_ti,'TightInset'); ...
zeros(size(pos)-[sum([hax_ti_ind{:}]) 0])];
But otherwise it works now with legends so thanks!
Roman Gabl (view profile)
Jacob D (view profile)
In the code I posted previously, the following line can be commented or left out:
% hax = sort(hax,'descend');
Axes should already be first after the concatenation.
Jacob D (view profile)
To fix the issue where tightfig doesn't adjust for legends and colorbars in HG2 just use the following three sections of code in replacement of the current tightfig code:
%% Section 1 replacement
% get all the axes handles note this will also fetch legends and
% colorbars as well
hax = findall(hfig, 'type', 'axes');
% Concatenate HG2 objects into hax as graphics array and sort
hax = [hax; findall(hfig, 'type', 'legend')];
hax = [hax; findall(hfig, 'type', 'colorbar')];
hax = sort(hax,'descend'); % Make sure Axes are first in the list
%% Section 2 replacement
% get various position parameters of the axes
hax_ti_ind = arrayfun(@(x) (isa(x,'matlab.graphics.axis.Axes')),...
hax,'UniformOutput',false);
hax_ti=hax([hax_ti_ind{:}]); % Returns only Axes handles
if numel(hax) > 1
% fsize = cell2mat(get(hax, 'FontSize'));
pos = cell2mat(get(hax, 'Position'));
ti = [cell2mat(get(hax_ti,'TightInset')); ...
zeros(size(pos)-[sum([hax_ti_ind{:}]) 0])];
else
% fsize = get(hax, 'FontSize');
pos = get(hax, 'Position');
ti = get(hax_ti,'TightInset');
end
%% Section 3 replacement
for i = 1:numel(hax_ti)
set(hax(i), 'LooseInset', ti(i,:));
Neetha Das (view profile)
Luchen Li (view profile)
Bhavesh Dharmani (view profile)
Doesn't work for 'boxplot'.
Jørgen Grythe (view profile)
I was looking for the easiest way to remove extra margins on my figure, can't really get any easier than writing tightfig(fig)
Shaun (view profile)
Unfortunately it cuts out colorbars when using 2015b. I'm guessing this is due to the new plotting system, where colorbars are no longer axes objects, but I don't have the expertise to fix it.
Haixuan (view profile)
Vivas (view profile)
Vivas (view profile)
Doesn't work very well for bode plots. Axis label overlaps with ticks on x axis
Sophia Bethany Coban (view profile)
@ADITHYAN, for imshow, you can use iptsetpref('ImshowBorder','tight');
source: http://www.shawnlankton.com/2007/06/matlab-figures-without-borders-and-toolbars/
ADITHYAN (view profile)
Useful function!
When I use this function with imshow, there is still a white space on the left of the image.
It would be nice if you can fix this. Thanks.
Paul Quelet (view profile)
Works wonderfully.
compterbs (view profile)
Thank you, no problem now for trimming Latex figs
Angelo Tafuni (view profile)
Now I don't have to worry about trimming in LaTeX. Great job!
reza vahid (view profile)
I solved PDE with numerical method and I have 3 component (U,x,y) that (x,y)=[-1,1]*[-1,1]
and U is answer PDE< How can I use this function ?
Please any tip or example send to me through email:
vrh59ir@gmail.com
Shuqin (view profile)
very helpful! Thanks for sharing.
pietro (view profile)
It works fine but not when the figures are docked because it modifies the figure properties and not the axis ones. Anyway it is a great function. Hopefully it will work also when the figure are docked.
Thomas Edwards (view profile)
I had a colorbar addded to my figure of multiple subplots. The annoying thing was that the exponent of the colorbar was cut-off on the edge of the figure. Using tightfig fixed this for me so that the exponent would fit in the figure. Very useful!
João (view profile)
Great. Although it sometimes clips the edges off fonts that are really close to the limits (I was not able to understand in which conditions it does this, but it happened unfrequently)
Daniel (view profile)
arnold (view profile)
it doesn't take into account an xlabel of a boxplot. Just cuts it away. Ylabel seems fine though.
Chad Greene (view profile)
I use this frequently; thanks for sharing. I recommend adding this to the end of the function to suppress unwanted outputs:
if nargout==0; clear hfig; end
arnold (view profile)
I'll see when I find the time to look into it.
Something else I just noticed: Using plotyy and setting both y-labels, title, xlabel etc and tightfig. to wrap things up. Tightfig seems to fast somehow. It messes up the figure window. It works if I include a pause(0.2) before tightfig. Strange..... but the workaround is no problem of course.
Richard Crozier (view profile)
@arnold, I'll implement this if you suggest how to identify them. Unfortunately I don't have time to do a lot of research on this right now.
arnold (view profile)
too bad it doesn't recognize my x-labels when using hierarchicalboxplot. It would be most useful if it were looking for all elements in a figure, not just axes.
Pablo Deossa (view profile)
very useful!
Suntaree (view profile)
awesome
Gergely Takács (view profile)
grega (view profile)
Mike Shen (view profile)
K E (view profile)
Perfect. Very useful if you are using the Windows clipboard to copy figures into Word and need to trim off the excess whitespace beforehand.
Richard Crozier (view profile)
Hi Jurgan, from the description for crop.m I gather it crops whitespace from a bitmap (i.e. non vector type) image file which is already saved to disk, e.g. a jpeg, bitmap, png etc. It does not appear to act on figures.
I suppose you could get similar functionality to tightfig by first saving your figure to disk in one of these formats, then running crop.m on it. I prefer the tightfig workflow personally.
Jurgen (view profile)
I see, I have export_fig. Based on what you said then maybe CROP (http://www.mathworks.nl/matlabcentral/fileexchange/20427-crop-whitespace-from-an-image) is worth comparing :)
Richard Crozier (view profile)
Jurgen, most of the functions you mention adjust the space between and around individual axes in subplots, and at least some have to be called on creation of a subplot. tightfig crops the white space around the outside of all the axes (and legends) in any figure without adjusting the rest of the plots at all. tightfig also identifies if you have a 3D zoomed axes in your figure and ignores it, since such figures cannot be cropped. tightfig is also well commented so you can understand it's workings.
Actually you failed to identify the one other function on the file exchange I know which does also have this functionality, export_fig.m.
Jurgen (view profile)
How does this compare to: spaceplots, subplot1, tight_subplot, subplot_tight and subplotplus?
Ben (view profile)
Hi, I found this very useful. However, I have one suggestion: in the line
ti(ti < 0) = 0.1
You should consider
ti(ti < 0.1) = 0.1
instead.
I had a graph where the top line of the outer box was being cutoff by saveas after I used tightfig, presumably because it had some ti in (0,0.1).
Richard Crozier (view profile)
Thanks Thomas, I've submitted a new version with the fix.
Thomas (view profile)
Great work... i was just going to implement it myself... but here it is ;) Thank you.
Just a minor issue:
Restoring the original axes units fails when there is only a single axes object in the figure:
set(hax(i), 'Units', origaxunits{i});
... since origaxunits is no cell array then. A simple if else does the trick.