function latextable(X,varargin)
% LATEXTABLE produces a table for usage with LaTeX from a numeric array
% Copyright (c) 2009, Andrew E. Slaughter
% All rights reserved.
%
% Redistribution and use in source and binary forms, with or without
% modification, are permitted provided that the following conditions are met:
% * Redistributions of source code must retain the above copyright
% notice, this list of conditions and the following disclaimer.
% * Redistributions in binary form must reproduce the above copyright
% notice, this list of conditions and the following disclaimer in the
% documentation and/or other materials provided with the distribution.
% * Neither the name of the <organization> nor the
% names of its contributors may be used to endorse or promote products
% derived from this software without specific prior written permission.
%
% THIS SOFTWARE IS PROVIDED BY <copyright holder> ''AS IS'' AND ANY
% EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
% WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
% DISCLAIMED. IN NO EVENT SHALL <copyright holder> BE LIABLE FOR ANY
% DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
% (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
% LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
% ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
% (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
% SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
%__________________________________________________________________________
% SYNTAX:
% latextable(X);
% latextable(X,'PropertyName',PropertyValue,...)
%
% DESCRIPTION:
% latextable(X) produces a gerneic table without headers and asks the
% for a name and location for saving the file, X must be an 2-D
% array of numbers or a cell array, see below.
% latextable(X,'PropertyName',PropertyValue,...) allows for custom
% inputs to be used for producing the table.
%
% INPUT "X":
% The input may be a purely numeric array or a cell array of mixed
% components. The following examples illustrate the type of input
% accepted.
% >> X = [1,2; 3,4];
% >> X = {1,'2';'One',4};
%
% FUNCTION PROPERTIES:
% 'Horiz' - Cell array containing labels for horizontal direction, the
% cell array must have the same horizontal dimension (colums) as the
% "X" input but can contain one or many rows. The default is an empty
% cell, thus no labels.
% 'Vert' - Cell array containing labels for vertical direction, the
% cell array must have the same vertical dimension (rows) as the
% "X" input but can contain one or many columns. The default is an
% empty cell, thus no labels.
% 'Vline' - numeric array prescribing locations of vertical lines, the
% line is inserted after the specified column. For example, using
% [1,2] inserts lines after the 1st and 2nd columns. A value of NaN
% at the end ([...,NaN]) places a line at the end of the table. The
% default is [], no vertical lines. The column numbers include the
% labels as columns.
% 'Hline' - numeric array prescribing locations of horizontal lines,
% which operates similar to 'Vline', the default is [0,NaN]
% 'format' - specifies the numeric format, e.g. %3.1f.
% 'name' - string specifing the filename
% 'save' - string specifing the name to save the supplied setup
% 'load' - the setup to be loaded, all properties prior to usage are
% overwritten, those after are applied. Note, the 'default' is
% automatically used. To view the available settings, type the
% following into the command-line: "getpref('latextable_settings')"
%
% EXAMPLES:
% >> latextable(rand(3,3),'Horiz',{'1','2','3'},'Hline',[0,1,NaN]);
% >> latextable(rand(3,3),'Hline',[],'save','nolines');
% >> latextable(rand(5,5),'load','nolines');
%
% PROGRAM OUTLINE:
% 1 - INITILIZE PROGRAM
% 2 - CONVERT INPUT INTO A SINGLE COLUMN OF '&' DELIMINATED STRINGS
% 3 - ADD VERTICAL HEADINGS TO STRINGS
% 4 - BUILD HEADER ROW(S)
% 5 - COMBINE ROWS AND ADD HORIZONTAL LINES
% 6 - BUILD COLUMN INSTRUCTIONS
% 7 - OUTPUT DATA TO FILE
% 8 - APPLY PREFERENCES
% SUBFUNCTION: subfunction_options
% SUBFUNCTION: convertdata
% APPPYPREF applies the last used directory and property settings
%__________________________________________________________________________
% 1 - INITILIZE PROGRAM
a = subfunction_options(varargin);
% 2 - CONVERT INPUT INTO A SINGLE COLUMN OF '&' DELIMINATED STRINGS
r = size(X,1); c = size(X,2);
A = convertdata(X,a.format);
% 3 - ADD VERTICAL HEADINGS TO STRINGS
Hprfx = '';
if ~isempty(a.vert) && size(a.vert,1) == r;
for i = 1:r
A{i,1} = [sprintf('%s & ',a.vert{i,:}),A{i}];
end
Hprfx(1:size(a.vert,2)) = '&';
end
% 4 - BUILD HEADER ROW(S)
H = {};
if ~isempty(a.horiz)&& size(a.horiz,2) == c ;
for i = 1:size(a.horiz,1)
H{i,1} = sprintf('%s & ',a.horiz{i,:});
H{i} = [Hprfx,' ',regexprep(H{i},'& ','\\\',c)];
end
end
% 5 - COMBINE ROWS AND ADD HORIZONTAL LINES
ROWS = [H;A]; h = a.hline; nr = length(ROWS);
for i = 1:length(h);
if h(i) == 0;
ROWS = ['\hline'; ROWS(1:nr)];
h = h + 1; nr = nr + 1;
elseif isnan(h(i));
ROWS{nr+1} = '\hline';
nr = nr + 1;
else
ROWS = [ROWS(1:h(i));'\hline';ROWS(h(i)+1:nr)];
h = h + 1; nr = nr + 1;
end
end
% 6 - BUILD COLUMN INSTRUCTIONS
col(1:c+size(a.vert,2)) = 'c';
v = a.vline;
for i = 1:length(v);
if v(i) == 0; col = ['|',col];
elseif isnan(v(i)); col = [col,'|'];
else
col = regexprep(col,'c','c|',v(i));
end
end
% 7 - OUTPUT DATA TO FILE
fid = fopen(a.name,'w');
fprintf(fid,'%s\n',['\begin{tabular}{',col,'}']);
for i = 1:length(ROWS); fprintf(fid,'%s\n',ROWS{i}); end
fprintf(fid,'%s\n','\end{tabular}');
fclose(fid);
% 8 - APPLY PREFERENCES
applypref(a);
%--------------------------------------------------------------------------
% SUBFUNCTION: subfunction_options
function [a] = subfunction_options(in)
% SUBFUNCTION_OPTIONS seperates user inputed property modifiers
% 1 - SET THE DEFAULT SETTINGS
% 1.1 - Standard settings
a.horiz = {}; a.vert = {};
a.hline = [0,NaN]; a.vline = [];
a.format = '%3.1f';
a.name = '';
a.save = ''; a.load = '';
% 1.2 - Gather/set user defaults
if ~ispref('latextable_settings','default');
setpref('latextable_settings','default',a);
else
a = getpref('latextable_settings','default');
end
% 2 - SEPERATE THE DATA FROM OPTIONS
list = fieldnames(a); k = 1; n = length(in);
while k < n
% 2.1 - Get modifier tag, associated data, and initilize for next loop
opt = in{k}; value = in{k+1}; match = ''; k = k + 2;
% 2.2 - Compare modifier tag with available options
if ischar(opt);
match = strmatch(lower(opt),lower(list),'exact');
if ~isempty(match); a.(list{match}) = value; end
end
% 2.3 - Load preferences (overwrites existing)
if strcmpi(opt,'load') && ispref('latextable_save',value);
a = getpref('latextable',value);
end
% 2.4 - Produce an error message if modifier is not found
if isempty(match);
mes = ['The property modifier, ',opt,', was not recoignized.'];
disp(mes);
end
end
% 3 - DETERMINE OUTPUT LOCATION
% 3.1 - Locate the last used directory
if isempty(a.name);
if ispref('latextable','lastdir');
loc = getpref('latextable','lastdir');
else
loc = cd;
end
% 3.2 - Prompt the user for the path
[nm,pth] = uiputfile('*.tex','Save as...',loc);
if isnumeric(nm); return; end
a.name = [pth,nm];
end
% 4 - CORRECT VERTICAL AND HORIZONTAL ARRAYS WITH A SINGLETON DIMENSION
if size(a.horiz,2) == 1; a.horiz = a.horiz'; end
if size(a.vert,1) == 1; a.vert = a.vert'; end
%--------------------------------------------------------------------------
function A = convertdata(X,form)
% CONVERTDATA changes numeric and cell arrays into strings for each row
% X must be a numeric array or a cell array, with a string of numeric value
% in each entry.
% Define the size of the array
r = size(X,1); c = size(X,2);
% For completely numeric arrays
if isnumeric(X);
for i = 1:r;
A{i,1} = sprintf([form,' & '],X(i,:));
A{i} = regexprep(A{i},'& ','\\\',c);
end
% For cell arrays
elseif iscell(X);
for i = 1:r;
A{i,1} = num2str(X{i,1},form);
for j = 2:c;
A{i,1} = [A{i,1},' &',num2str(X{i,j},form)];
end
A{i,1} = [A{i,1},'\\'];
end
end
%--------------------------------------------------------------------------
function applypref(a)
% APPPYPREF applies the last used directory and property settings
% 7.1 - Store the last used directory
pth = fileparts(a.name);
if ~ispref('latextable','lastdir');
addpref('latextable','lastdir',pth);
else
setpref('latextable','lastdir',pth);
end
% 7.2 - Save the options
if ~isempty(a.save);
apply = a.save; a.save = [];
if ~ispref('latextable_settings',apply);
addpref('latextable_settings',apply,a);
else
qst = ['The settings, ',apply,' already exist, do you ',...
'want to overwrite?'];
qans = questdlg(qst,'Overwrite?','Yes');
if strcmpi(qans,'yes');
setpref('latextable_settings',apply,a);
end
end
end