Friday, January 13, 2012

Generating Publication Quality Figures in Matlab


Updated* See Step 7 - Post Processing

Matlab is wonderful for visualizing solutions quickly for the purposes of debugging or exploring numerical solutions. It is pretty bad at figure formatting though. In fact, I don't feel comfortable putting Matlab figures directly into documents because they look so unprofessional. Matlab does have the workspace toolbox thing, but that's not the best. Mostly because the export is exactly the same size as the figure on the screen and setting that size is really inconvenient so axis of adjacent figures don't usually line up well.

This is how I do it:
First we are assuming either the correct sizing for a figure that will fit on half a page so that 2 can be side by side on a 6.25 (or 6.5) inch text width OR that I have one elongated figure that fills the whole width - like a contour plot.

1) Specify the dimensions

% For Normal Figures
height=1.0/1.618; % width/golden ratio
width=1;

% For Wide Figures
% height=1.0/1.618; % width/golden ratio
% width=2;

scale=300; % 3.13 inches

I choose the golden ratio because it's considered aesthetically pleasing to the eye. It works well for large figures, but it might not be perfect for small figures. Just remember if you want to scale from a known dimension in inches use a converter to convert to pixels. 300 pixels is 3.13 inches

You can also position the figure on the screen
xpos=50;
ypos=500;

2) Define the function to be plotted. For the example, I generate one on the spot but this could be an import function
x=0:.01:2*pi;
f1=cos(x);
f2=sin(x);

3) Generate the figure. This doesn't just mean plot the data. The figure is comprised of the figure dimensions, the plot area, the bounding box, etc.. We also want to set the fonts and position

figure; % Create Figure
axes('FontName','Times New Roman') % Set axis font style
box('on'); % Define box around whole figure
set(gcf,'Position',[xpos ypos scale*width scale*height]) % Set figure format

4) Plot the data

hold on
plot1=plot(x,f1,'Color',[1 0 0]);
plot2=plot(x,f2,'Color',[0 0 1]);

by plotting each function as a different plot command and defining plot1 and plot2, we have unique control over the format of each data set.

5) Set Plot properties. This is different than setting figure properties and refers to the data set format

set(plot1,'LineWidth',1,'LineStyle','-');
set(plot2,'LineWidth',1,'LineStyle','--');

% Set Axis Limits
xlim([min(x), max(x)])
ylim([min(f1), max(f1)])

% Create xlabel
xlabel('\xi','FontSize',11,'FontName','Times New Roman','FontAngle','italic');

% Create ylabel
ylabel('\eta','FontSize',11,'FontName','Times New Roman','FontAngle','italic','rot',0);

% Create Legend
hleg1 = legend('$\cos(x)$','$\sin(x)$');

% Set Legend Properties
set(hleg1,'Interpreter','latex')
set(hleg1,'Location','SouthWest')
set(hleg1,'box','on')

There are more properties that can be set, but i just took the ones I use most.

6) Export figure
fig = gcf;
style = hgexport('factorystyle');
style.Bounds = 'loose';
hgexport(fig,'Example_Figure.eps',style,'applystyle', true);
drawnow;

print -depsc2 -tiff myfile.eps

There is something weird here: i don't think i have to use both the hgexport (like clicking File-Save As) and print but I don't get the right format without using both.

7) Post processing. This is really unfortunate. The problem is that Matlab doesn't embed fonts in eps files correctly (or at all). There are functions such as export_fig and exportfig that claim to do this, but I've not had any luck. Part of it is that I don't have time to mess with all the settings and syntax that comes with using other packages. Part of it is my frustration with the whole nonsense.

An option many people seem to use is Adobe Illustrator. The process goes: Open the eps and convert the text to outlines. I think this replaces the text with lines and fills so that the letters appear, but aren't actually text anymore. That's a good idea, but I spent some time poking around the trial and couldn't figure out how to set the damn page dimensions so the exported eps was back to its original size. It would always export it with a big white space around it. I think there's something about the clipping box but I don't have time to mess with this garbage. I'm a scientist, not a graphic designer.

Next option: ACD Canvas. Open the eps in canvas and convert to canvas object. Magically (expected), it imports the eps figure with the correct dimensions! Then select all and "convert to path." I'm not completely sure what goes on behind the scenes with this operation, but it appears to take whatever is selected and lump it all into some kind of vector graphic. Again, the text is no longer dependent on a font. The problem with this is that there is no more editing so make sure it's what you want before you convert it. This works fine and produces nice figures.

UPDATE - Canvas costs money beyond the trial version. Boo. Inkscape is the solution! It's a free, open source program that will do this stuff MUCH easier than Adobe and even easier as Canvas. Open the eps file. Make sure the fonts imported correctly. If not, fix them! Then save as eps. The dialog box will offer some really cool stuff for latex but we don't need that right now. Make sure the box "Convert texts to paths" is selected and the "export area is drawing" is selected (I don't know about the "export area is page" that sounds counter to the previous box but I left mine checked). I don't know what the rest does so leave it or not. It doesn't seem to matter. The important part is that the text is converted to paths!

Beyond that, Inkscape (and the others) let you edit figures. For instance, Matlab will automatically adjust the position of the axis and labels depending on the number of digits in the label. That means the axis won't necessarily line up correctly in the document. Inkscape can adjust the axis dimensions and the location of the labels and titles so that they all look correctly! Awesome!

This isn't perfect but it works pretty well. If you're without a better option, then this is definitely a viable possibility. Here is the whole matlab code:

%% Figure Generator with Format
% =========================================================================
clear;clc;close all

% =========================================================================
% Specify Dimensions and Position on Screen
% =========================================================================
% -------------------------------------------------------------------------
% Figure Dimensions
% -------------------------------------------------------------------------

% For Normal Figures
height=1.0/1.618; % width/golden ratio
width=1;

% For Wide Figures
% height=1.0/1.618; % width/golden ratio
% width=2;

scale=300; % 3.13 inches
% -------------------------------------------------------------------------
% Figure Position on Screen
% -------------------------------------------------------------------------
xpos=50;
ypos=500;

% =========================================================================
% Define Functions to be Plotted
% =========================================================================
x=0:.01:2*pi;
f1=cos(x);
f2=sin(x);

% =========================================================================
% Generate Figure
% =========================================================================
% -------------------------------------------------------------------------
% Figure Properties
% -------------------------------------------------------------------------
figure; % Create Figure
axes('FontName','Times New Roman') % Set axis font style
box('on'); % Define box around whole figure
set(gcf,'Position',[xpos ypos scale*width scale*height]) % Set figure format

% -------------------------------------------------------------------------
% Plot Data
% -------------------------------------------------------------------------
hold on
plot1=plot(x,f1,'Color',[1 0 0]);
plot2=plot(x,f2,'Color',[0 0 1]);

% -------------------------------------------------------------------------
% Plot Properties
% -------------------------------------------------------------------------
set(plot1,'LineWidth',1,'LineStyle','-');
set(plot2,'LineWidth',1,'LineStyle','--');

% Set Axis Limits
xlim([min(x), max(x)])
ylim([min(f1), max(f1)])

% Create xlabel
xlabel('\xi','FontSize',11,'FontName','Times New Roman','FontAngle','italic');
% xlabel('$\xi$','FontSize',11,'FontName','Times New Roman','interpreter','LaTex','rot',0);

% Create ylabel
ylabel('\eta','FontSize',11,'FontName','Times New Roman','FontAngle','italic','rot',0);
% ylabel('$\eta$','FontSize',11,'FontName','Times New Roman','interpreter','LaTex','rot',0);

% Create Legend
hleg1 = legend('$\cos(x)$','$\sin(x)$');

% Set Legend Properties
set(hleg1,'Interpreter','latex')
set(hleg1,'Location','SouthWest')
set(hleg1,'box','on')

% =========================================================================
% Export Figure
% =========================================================================
fig = gcf;
style = hgexport('factorystyle');
style.Bounds = 'loose';
hgexport(fig,'Example_Figure.eps',style,'applystyle', true);
drawnow;

print -depsc2 -tiff myfile.eps

3 comments:

Hernia said...

I hope this gets back to you. Matlab file exchange has a wonderful, well-developed, well-supported library called 'export_fig'.

In particular it makes wonderful .eps files that need no post-processing work and you really don't need to do much of anything to make output look nice. They also behave wonderfully within MS Word.

The documentation is good and the only thing I've found that I've needed to make sure I use the 'painters' renderer:

export_fig P6graphic.eps -painters


Happy plotting!

Hernia said...

I hope this gets back to you. Matlab file exchange has a wonderful, well-developed, well-supported library called 'export_fig'.

In particular it makes wonderful .eps files that need no post-processing work and you really don't need to do much of anything to make output look nice. They also behave wonderfully within MS Word.

The documentation is good and the only thing I've found that I've needed to make sure I use the 'painters' renderer:

export_fig P6graphic.eps -painters


Happy plotting!

jbatters said...

Thanks for the tip! I have tried that function but it didn't fix the real problem: The font must be embedded or converted to path for journal publication. I don't remember if I tried the "painters" renderer though. Does that fix the problem?