Get rid of the white space around matlab figure's pdf output
Asked Answered
W

17

53

I'd like to use PDF versions of my matlab plots in a LaTeX document. I'm saving the figures using the "saveas" command with the PDF option but I get huge white space around my plots in the pdf files. Is this normal? How can I get rid of it? Automatically, of course, since I have "a lot" of plots.

Wiener answered 27/9, 2010 at 7:7 Comment(3)
Same question: #5151302Pinkham
I have pdfcrop in my workflow to get rid of the whitespace after the fact. Helps with a lot of other programs as well that output PDFs as full sheets of paper.Sadiras
Have you called customer support? Matlab is expensive commercial software, after all.Bindle
M
14

Exporting Figures for Publication is a good starting point. Instead of -deps use -dpdf for pdf output.

You can fix the bounding box issue using the code below.

set(gcf, 'PaperSize', [6.25 7.5]);
set(gcf, 'PaperPositionMode', 'manual');
set(gcf, 'PaperPosition', [0 0 6.25 7.5]);

set(gcf, 'PaperUnits', 'inches');
set(gcf, 'PaperSize', [6.25 7.5]);
set(gcf, 'PaperPositionMode', 'manual');
set(gcf, 'PaperPosition', [0 0 6.25 7.5]);

set(gcf, 'renderer', 'painters');
print(gcf, '-dpdf', 'my-figure.pdf');
print(gcf, '-dpng', 'my-figure.png');
print(gcf, '-depsc2', 'my-figure.eps');

You can read more about this on Tobin's article.

Mehala answered 27/9, 2010 at 7:38 Comment(1)
Readers might also be interested in this, as a more up to date reference: Creating and Exporting Publication-Quality GraphicsDelphinedelphinia
T
9

The answers above seem too complicated. This function uses a figure handle and a string to print the stuff in a pdf file without the huge margins.

function printpdf(h,outfilename)

set(h, 'PaperUnits','centimeters');
set(h, 'Units','centimeters');
pos=get(h,'Position');
set(h, 'PaperSize', [pos(3) pos(4)]);
set(h, 'PaperPositionMode', 'manual');
set(h, 'PaperPosition',[0 0 pos(3) pos(4)]);
print('-dpdf',outfilename);

For example, to print the current figure you can call it with:

printpdf(gcf,'trash')

However, if you really want a pdf figure like a Matlab-generated eps, that is, only the rectangular convex hull of the plot (or set of subplots), here's the more sophisticated version:

function printpdf(h,outfilename)

% first use the same non-relative unit system for paper and screen (see
% below)
set(h,'PaperUnits','centimeters');

% now get all existing plots/subplots
a=get(h,'Children');
nfigs=length(a);

% bounds will contain lower-left and upper-right corners of plots plus one
% line to make sure single plots work
bounds=zeros(nfigs+1,4);
bounds(end,1:2)=inf;
bounds(end,3:4)=-inf;

% generate all coordinates of corners of graphs and store them in
% bounds as [lower-left-x lower-left-y upper-right-x upper-right-y] in
% the same unit system as paper (centimeters here)
for i=1:nfigs
    set(a(i),'Unit','centimeters');
    pos=get(a(i),'Position');
    inset=get(a(i),'TightInset');
    bounds(i,:)=[pos(1)-inset(1) pos(2)-inset(2) ...
        pos(1)+pos(3)+inset(3) pos(2)+pos(4)+inset(4)];
end

% compute the rectangular convex hull of all plots and store that info
% in mypos as [lower-left-x lower-left-y width height] in centimeters
auxmin=min(bounds(:,1:2));
auxmax=max(bounds(:,3:4));
mypos=[auxmin auxmax-auxmin];

% set the paper to the exact size of the on-screen figure using
% figure property PaperSize [width height]
set(h,'PaperSize',[mypos(3) mypos(4)]);

% ensure that paper position mode is in manual in order for the
% printer driver to honor the figure properties
set(h,'PaperPositionMode', 'manual');

% use the PaperPosition four-element vector [left, bottom, width, height]
% to control the location on printed page; place it using horizontal and
% vertical negative offsets equal to the lower-left coordinates of the
% rectangular convex hull of the plot, and increase the size of the figure
% accordingly
set(h,'PaperPosition',[-mypos(1) -mypos(2) ...
    mypos(3)+mypos(1) mypos(4)+mypos(2)]);

% print stuff
print('-dpdf',outfilename);
Tardiff answered 17/7, 2013 at 19:53 Comment(1)
For an example of how the rendered pdf differs between these two functions, please see these two screenshots. First code block, Second code block (rectangular convex hull only). Note how in the second image the plot is right up against the bottom left corner. Note also that these appear to be true vector images (not raster), which for me is what I needed, though I would like even less whitespace. Anyway thanks Antonio!Delphinedelphinia
W
6

In addition to the other suggestions here, you might also try to use the LooseInset property as described in http://UndocumentedMatlab.com/blog/axes-looseinset-property/ to remove extra space around your plot axes.

Womanish answered 27/9, 2010 at 22:7 Comment(1)
That option merely tightens the space around the plot in the figure window. When you do something like print('trash','-dpdf') you get the figure printed over an A4/Letter sheet of paper...Tardiff
H
6

I suffered a bit with regards to this b4 finding an easy answer. Save as a .eps, and then convert the .eps to .pdf. In Mac OS this can be done in Preview.

Halinahalite answered 20/11, 2012 at 19:54 Comment(0)
R
5

I just spent some time trying most of these options, but my friend Espen pointed out the simplest: if you're using the graphicx package in LaTeX, go with the standard Matlab pdf output and use the trim option in \includegraphics. An example in a Beamer slide:

\includegraphics[trim = 0.1in 2.5in 0.1in 2.5in, clip, scale=0.5]{matlabgraphic.pdf}

The order of trim parameters here is left, bottom, right, top. The key is to trim the top and bottom a lot to get rid of the extra space. More at Wikibooks.

Rebuff answered 12/4, 2014 at 16:26 Comment(1)
I've done that occasionally but you can save a lot of hassle if you know your pdf figure doesn't contain white margins. Then you can do something like \includegraphics[width=1.0\textwidth]{matlabgraphic.pdf} without worrying about clipping and trimming the figure. A recent paper I wrote with coauthors had no fewer than 30 graphs and because they were produced by someone else I had to use your method; it was a real pain.Tardiff
S
5

For raster image outputs (e.g png), the following is in my Makefile:

convert -trim input.png input-trimmed.png

This requires imagemagick.

Update: For all my recent publications I used https://github.com/altmany/export_fig and it is the best solution I found so far (along with many other solutions to other problems in a single package). I feel a tool that is at least as powerful as this should already be an official part of Matlab. I use it as:

export_fig -transparent fig.pdf

Which exports the current Figure, cropping the output by default.

Require ghostcript

Schmaltzy answered 8/8, 2015 at 10:14 Comment(1)
That function is vastly superior to printpdf.m, even if a bit more complicated.Tardiff
D
3

I liked @Antonio's method the best but it still left too much whitespace, and I was looking for a single plot solution that exported to vector pdfs for usage in LaTeX.

  • I made something based on his script and added the option to export only the plot box (omitting the axes).

  • Note that unlike Antonio's script, this only works on figures without subplots.

  • The code below will export any single plot figure handle as a vector PDF, either with or without axes.


function SaveFigureAsVectorPDF(InputFigureHandle, OutFileName, ShouldPrintAxes)
    %% Check input parameters
    [NumberOfFigures, ~] = size(InputFigureHandle);    

    if(NumberOfFigures ~= 1)
        error('This function only supports one figure handle.');

    end

    if(isempty(OutFileName))
        error('No file path provided to save the figure to.');

    end

    cUnit = 'centimeters';

    %% Copy the input figure so we can mess with it    
    %Make a copy of the figure so we don't modify the properties of the
    %original.
    FigureHandleCopy = copy(InputFigureHandle);

    %NOTE:  Do not set this figure to be invisible, for some bizarre reason
    %       it must be visible otherwise Matlab will just ignore attempts 
    %       to set its properties.
    % 
    %       I would prefer it if the figure did not briefly flicker into
    %       view but I am not sure how to prevent that.

    %% Find the axis handle
    ChildAxisHandles     = get(FigureHandleCopy, 'Children');
    NumberOfChildFigures = length(ChildAxisHandles);

    if(NumberOfChildFigures ~= 1)
       %note that every plot has at least one child figure
       error('This function currently only supports plots with one child figure.');

    end

    AxisHandle = ChildAxisHandles(1);

    %% Set Units
    % It doesn't matter what unit you choose as long as it's the same for
    % the figure, axis, and paper. Note that 'PaperUnits' unfortunately
    % does not support 'pixels' units.

    set(FigureHandleCopy,   'PaperUnits',   cUnit);
    set(FigureHandleCopy,   'Unit',         cUnit);
    set(AxisHandle,         'Unit',         cUnit); 

    %% Get old axis position and inset offsets 
    %Note that the axes and title are contained in the inset
    OldAxisPosition = get(AxisHandle,   'Position');
    OldAxisInset    = get(AxisHandle,   'TightInset');

    OldAxisWidth    = OldAxisPosition(3);
    OldAxisHeight   = OldAxisPosition(4);

    OldAxisInsetLeft    = OldAxisInset(1);
    OldAxisInsetBottom  = OldAxisInset(2);
    OldAxisInsetRight   = OldAxisInset(3);
    OldAxisInsetTop     = OldAxisInset(4);

    %% Set positions and size of the figure and the Axis 
    if(~ShouldPrintAxes)

        FigurePosition = [0.0, 0.0, OldAxisWidth, OldAxisHeight];

        PaperSize = [OldAxisWidth, OldAxisHeight];

        AxisPosition = FigurePosition;      

    else
        WidthWithInset  = OldAxisWidth   + OldAxisInsetLeft + OldAxisInsetRight;
        HeightWithInset = OldAxisHeight  + OldAxisInsetTop  + OldAxisInsetBottom;

        FigurePosition = [0.0, 0.0, WidthWithInset,  HeightWithInset];

        PaperSize = [WidthWithInset, HeightWithInset];

        AxisPosition = [OldAxisInsetLeft, OldAxisInsetBottom, OldAxisWidth, OldAxisHeight];

    end

    set(FigureHandleCopy,   'Position', FigurePosition);
    set(AxisHandle,         'Position', AxisPosition);

    %Note:  these properties do not effect the preview but they are
    %       absolutely necessary for the pdf!!
    set(FigureHandleCopy,   'PaperSize',        PaperSize);
    set(FigureHandleCopy,   'PaperPosition',    FigurePosition);

    %% Write the figure to the PDF file
    print('-dpdf', OutFileName);

    set(FigureHandleCopy, 'name', 'PDF Figure Preview', 'numbertitle', 'off');

    %If you want to see the figure (e.g., for debugging purposes), comment
    %the line below out.
    close(FigureHandleCopy);

end

Sample images:

With axes:

Sample PDF screenshot with axes

Without axes:

Sample PDF screenshot without axes

Testing code:

%% Generates a graph and saves it to pdf

FigureHandle = figure;

plot(1:100);

title('testing');

%with axes
SaveFigureAsVectorPDF(FigureHandle, 'withaxes.pdf', true);

%without axes
SaveFigureAsVectorPDF(FigureHandle, 'withoutaxes.pdf', false);
Delphinedelphinia answered 27/9, 2010 at 7:7 Comment(1)
Note that figure legends count as a "Child" of the figure.Delphinedelphinia
P
3

I also encountered with this problem. Finally, I used the following method solved it which can save one matlab figure automatically as a proper pdf size.

you can do it in MATLAB through:

h = figure; % For example, h = openfig('sub_fig.fig'); Or you just ploted one figure: plot(1:10);
set(h,'Units','Inches');
pos = get(h,'Position');
set(h,'PaperPositionMode','Auto','PaperUnits','Inches','PaperSize',[pos(3),pos(4)]);
print(h,'your_filename','-dpdf','-r0');

Hope it helps.

Paternalism answered 11/4, 2015 at 5:9 Comment(0)
L
2

On the MATLAB file exchange I found an extremely helpful function provided by Jürg Schwizer:

plot2svg( filename, figHandle );

Outputs the figure as a vector graphic (.svg) and the individual figure components as pixel graphics (defaults to .png). This enables you to do all kinds of stuff to your figure (remove labels, move colorbars, etc), but if you're interested in removing the white background, just open the .svg file with e.g. inkscape, ungroup the items and export the items you're interested in as a new figure.

Lambency answered 20/9, 2013 at 15:34 Comment(0)
T
2

For those using linux one really simple solution is to write in a shell: ps2pdf14 -dPDFSETTINGS=/prepress -dEPSCrop image.eps

Trainload answered 12/7, 2014 at 7:1 Comment(0)
P
1

You can also do it in latex itself.

  1. open the eps file with notpad
  2. go to first line (%!PS-Adobe-3.1 EPSF-3.0)

If the last number is 3, search "rf" and then comment that line typing % at the beginning of the line

else if the last number is 2, search "pr" and then comment that line typing % at the beginning of the line

Persistence answered 11/4, 2014 at 15:2 Comment(1)
this looks like editing the raw image file, rather than anything to do with latex? You might also want to indicate that the % is a comment in PS (AFAIR)Golter
J
1

The following 2 step approach worked for me (using pdfcrop). Assuming you have all the pdf-tools installed and PDFcrop (http://pdfcrop.sourceforge.net/)

In MATLAB, type

print -deps -r600 figure.eps

And then in command line

./cropEpsFigure.sh figure

Using the following file: cropEpsFigure.sh

#!/bin/bash
/usr/texbin/epstopdf "$1.eps"
/usr/texbin/pdfcrop "$1.pdf"
/usr/local/bin/pdftops -eps "$1-crop.pdf"`
Joannajoanne answered 5/6, 2014 at 10:7 Comment(0)
D
1

For Linux users the following command might help

ps2epsi <input.eps> <output.eps>

as suggested here

and if you are intended to use in latex, use Latex command \includegraphics* instead of \includegraphics

Delectable answered 7/7, 2014 at 12:23 Comment(1)
how does this help with PDFs?Golter
P
0

This works for displaying purposes:

set(gca, 'LooseInset', get(gca, 'TightInset'));

Should work for printing as well.

Pinkham answered 20/5, 2011 at 9:21 Comment(1)
Nope, no luck: >> set(gca, 'LooseInset', get(gca, 'TightInset')); >> print(gcf, '-dpdf', 'my-figure.pdf'); >> print(gcf, '-dpng', 'my-figure.png'); does not workSonya
R
0

save the plot into .eps format in Matlab, then execute esptopdf command under Linux. This does not require any extra coding. Only a Linux machine is needed.

Ripen answered 7/7, 2014 at 2:38 Comment(0)
C
0

Using pdfcrop is another solution. Simply cd to the folder where all your pdf are saved and run

for i in *;do pdfcrop "$i";done

The only problem is pdfcrop is not available for Windows. So I run it from Windows Subsystem for Linux (WSL).

Conurbation answered 24/12, 2020 at 2:45 Comment(0)
L
-2

You can use this command with Inkscape if you have existing pdfs with extra whitespace.

Inkscape.exe --file SomePDFWithWhitespace.pdf --export-pdf=SomePDFWithWhitespaceRemoved.pdf --export-area-drawing

Though note that this method still leaves some whitespace because the "drawing area" of the exported figure itself contains some whitespace.

The effects of using Inkscape are shown below:

Before: (figure saved using File -> Save As)

PDF saved using File -> Save As

After: (using Inkscape)

PDF Cropped using the inkscape command shown above

Landahl answered 4/9, 2012 at 8:24 Comment(3)
You might want to include the actual command needed when you answer a question.Zwieback
I would really appreciate this solution, but couldn't find it.. If anybody knows about it, please post it.Lambency
@Lambency This command will do it, though note that it leaves a bit of unnecessary whitespace: Inkscape.exe --file SomePDFWithWhitespace.pdf --export-pdf=SomePDFWithWhitespaceRemoved.pdf --export-area-drawingDelphinedelphinia

© 2022 - 2024 — McMap. All rights reserved.