450 if ~isempty(varargin)
451 this.
Caption= sprintf(caption,varargin[:]);
453 this.Caption= caption;
469 for i = 1:length(
this)
485 for i = 1:length(
this)
487 if strcmp(
t.Format,
" txt ")
488 t.printPlain(outfile);
489 elseif any(strcmp(
t.Format,[
" tex ",
" pdf "]))
492 error(
" Unsupported format: %s ",
t.Format);
508 f = fopen(
" tmpout ",
" w+ ");
511 str = fileread(
" tmpout ");
525 if nargin < 2 || isempty(filename)
526 initdir = getpref(
" PrintTable ",
" LastDir ",pwd);
527 choices = [
" *.txt ",
" Text files (*.txt) ";...
528 " *.tex ",
" LaTeX files (*.tex) ";...
529 " *.pdf ",
" PDF files (*.pdf) "];
530 [fname, path, extidx] = uiputfile(choices, ...
531 sprintf(
" Save table '%s' as ",this.
Caption), initdir);
536 setpref(
" PrintTable ",
" LastDir ",path);
537 ext = choices[extidx,1](2:end);
538 filename = fullfile(path, fname);
541 fname = fname(1:end-4);
545 [path, fname, ext] = fileparts(filename);
547 ext = [
" . " this.
Format];
548 elseif ~any(strcmp(ext,[
" .txt ",
" .tex ",
" .pdf "]))
549 error(
" Valid file formats are *.txt, *.tex, *.pdf ");
555 if ~isempty(path) && exist(path,
" dir ") ~= 7
567 if strcmp(ext,
" .pdf ")
568 this.pdfExport(path, fname);
571 fid = fopen(filename,
" w ");
605 hlp = num2cell(
data(
k,:));
606 this.
addRow(titles[
k],hlp[:],varargin[:]);
613 error(
" Not enough input arguments. ");
615 hasformat = iscell(varargin[end]);
616 if iscell(varargin[1])
617 error(
" Invalid input argument. Cells cannot be added to the PrintTable, and if you wanted to specify a sprintf format you forgot the actual value to add. ");
621 if isempty(this.
data)
622 [this.
data[1], this.
mathmode] = this.stringify(varargin);
623 this.
contlen= ones(1,length(this.data[1]));
626 newlen = length(varargin);
630 if length(this.data[1]) ~= newlen
631 error(
" Inconsistent row length. Current length: %d, passed: %d ",length(this.data[1]),newlen);
634 [this.data[end+1], this.
mathmode(end+1,:)] = this.stringify(varargin);
637 this.updateContentLengthAt(length(this.data));
640 texcmdfun = @(s)~isempty([strfind(s,
" \ ") strfind(s,
" _ ") strfind(s,
" ^ ")]);
642 || any(cellfun(texcmdfun,this.data[end]));
666 if idx < 1 || idx > length(this.
data)
667 error(
" Invalid row index: %d ",idx);
670 this.updateContentLengths;
682 direction =
" ascend ";
692 if isempty(this.
data)
694 elseif colnr < 1 || colnr > length(this.
data[1])
695 error(
" Please specify a valid column number ");
699 for k = 1:length(this.
data)
700 vals[
k] = this.
data[
k][colnr];
703 [~, sidx] =
sort(vals);
705 if strcmpi(direction,
" descend ")
710 for k = 1:length(this.
data)
711 copy[
k] = this.
data[sidx(
k)];
741 transposed = this.
clone;
745 transposed.data[
k] = hlp(
k,:);
747 transposed.contlen= cellfun(@(row)max(cellfun(@(el)length(el),row)),...
750 transposed.TexMathModeDetection= this.fTexMMode;
762 copy.data= this.
data;
765 copy.fTexMMode= this.fTexMMode;
779 if isempty(this.
data)
780 error(
" No table rows exists to append to. Why would you want to do that? ");
785 if ~isa(table,
" PrintTable ")
786 error(
" Argument must be a PrintTable instance ");
792 columns = 1:length(table.
data[1]);
794 if length(this.
data[1]) ~= length(columns)
795 error(
" Invalid column number: Have %d but want to append %d ",length(this.
data[1]),length(columns));
802 for k=start:length(table.
data)
803 joined.data[end+1] = table.
data[
k](columns);
809 if ~isempty(joined.Caption)
828 #if 0 //mtoc++: 'set.ColSep'
830 if ~isempty(value) && ~isa(value,
" char ")
831 error("
ColSep must be a
char array. ");
843 #if 0 //mtoc++: 'set.HasHeader'
845 if ~islogical(value) || ~isscalar(value)
855 #if 0 //mtoc++: 'set.HasRowHeader'
857 if ~islogical(value) || ~isscalar(value)
867 #if 0 //mtoc++: 'set.Caption'
869 if ~isempty(value) && ~ischar(value)
870 error("
Caption must be a character array. ");
879 #if 0 //mtoc++: 'set.Format'
881 if ~any(strcmp([
" txt ",
" tex ",
" pdf "],value))
882 error("
Format must be either "" txt "" or "" tex "" . ");
888 if isscalar(value) && value > 0 && round(value) == value
895 function value = get.
NumRows(this)
896 value = length(this.
data);
898 value = max(0,value-1);
911 #if 0 //mtoc++: 'set.TexMathModeDetection'
913 if this.fTexMMode ~= value
914 if ~islogical(value) || ~isscalar(value)
917 this.fTexMMode= value;
918 this.updateContentLengths;
926 #if 0 //mtoc++: 'get.TexMathModeDetection'
928 value = this.fTexMMode;
938 function updateContentLengthAt(idx) {
939 fun = @(str,num)length(str) + 2*num;
941 ismm = num2cell(this.
mathmode(idx,:));
942 this.
contlen= max([this.
contlen; cellfun(fun,this.data[idx],ismm)]);
946 function updateContentLengths() {
947 if ~isempty(this.data)
948 this.
contlen= ones(1,length(this.data[1]));
949 for idx = 1:length(this.data)
950 this.updateContentLengthAt(idx);
956 function printPlain(outfile) {
958 fprintf(outfile," Table "" %s "" :\n ",this.
Caption);
960 for ridx = 1:length(this.data)
961 this.printRow(ridx,outfile,this.
ColSep);
962 fprintf(outfile," \n ");
966 for i = 1:length(this.data[ridx])
967 ttabs = ttabs + ceil((length(this.ColSep)*(i~=1)+this.
contlen(i))/this.
TabCharLen);
969 fprintf(outfile," %s\n ",repmat(" _ ",1,(ttabs+1)*this.TabCharLen));
980 function printTex(outfile) {
983 warning(
" PrintTable:TexExport ",...
984 " No TexMathModeDetection enabled but LaTeX commands have been detected. Export might produce invalid LaTeX code. ");
988 if ~isempty(this.Caption)
989 fprintf(outfile," %%
PrintTable '%s' generated on %s\n ",this.Caption,datestr(clock));
991 fprintf(outfile," %%
PrintTable generated on %s\n ",datestr(clock));
994 d = d(find(~strcmp([d(:).file],"
PrintTable.m "),1));
996 fprintf(outfile," %% Created in %s:%d at %s\n ",d.name,d.line,which(d.file));
1003 if ~isempty(this.data)
1004 cols = length(this.data[1]);
1008 if strcmp(this.Format," tex ") || ~this.TightPDF
1010 elseif ~isempty(this.Caption)
1011 /* Enable this if you want, but i found no straight way of putting the caption
1012 * above the table (for the given time&resources :-))
1013 *fprintf(outfile,'Table: %s\n',this.Caption); */
1015 if this.HasRowHeader
1016 aligns = [" r
" repmat(" l ",1,cols-1)];
1018 aligns = repmat(" l ",1,cols);
1020 fprintf(outfile," \\begin{tabular}{%s}\n
",aligns);
1021 /* Print all rows */
1022 for ridx = 1:length(this.data)
1023 fprintf(outfile," \t\t ");
1024 this.printRow(ridx,outfile," &
");
1025 fprintf(outfile," \\\\\n
");
1026 if ridx == 1 && this.HasHeader
1027 fprintf(outfile," \t\t\\hline\\\\\n
");
1030 fprintf(outfile, " \t\\end{tabular}\n
");
1031 /* Only add surroundings for pure tex output or full-sized PDF
1033 if strcmp(this.Format," tex
") || ~this.TightPDF
1034 if ~isempty(this.Caption)
1035 fprintf(outfile," \t\\caption{%s}\n
",this.Caption);
1037 fprintf(outfile, " \\end{table}\n
");
1047 function pdfExport(path,fname) {
1048 [status, msg] = system(" pdflatex --version
");
1050 error(" pdfLaTeX not found or not working:\n%s
",msg);
1053 if ~isempty(this.Caption)
1054 cap = [ this.Caption ];
1056 fprintf(" Exporting %s to PDF
using '%s'...\n
",cap,msg(1:strfind(msg,sprintf(" \n
"))-1));
1059 texfile = fullfile(path, [fname " .tex
"]);
1060 fid = fopen(texfile," w
");
1061 fprintf(fid," \\documentclass{article}\n\\begin{document}\n
");
1063 fprintf(fid," \\newsavebox{\\tablebox}\n\\begin{lrbox}{\\tablebox}\n
");
1065 fprintf(fid, " \\thispagestyle{empty}\n
");
1067 /* Print actual tex table */
1070 fprintf(fid, [" \\end{lrbox}\n\\pdfhorigin=0pt\\pdfvorigin=0pt\n
"...
1071 " \\pdfpagewidth=\\wd\\tablebox\\pdfpageheight=\\ht\\tablebox\n
"...
1072 " \\advance\\pdfpageheight by \\dp\\tablebox\n
"...
1073 " \\shipout\\box\\tablebox\n
"]);
1075 fprintf(fid," \\end{document}
");
1077 [status, msg] = system(sprintf(" pdflatex -interaction=nonstopmode -output-directory=
'%s' %s
",path,texfile));/* #ok */
1080 delete(fullfile(path, [fname " .pdf
"]));
1081 fprintf(2," PDF export failed, pdflatex finished with errors. See the <a href=
'matlab:edit( "" %s "" )'>LaTeX logfile</a>
for details.\n
",fullfile(path, [fname " .log
"]));
1083 delete(fullfile(path, [fname " .log
"]));
1084 fprintf(" done!\n
");
1086 delete(texfile,fullfile(path, [fname " .aux
"]));
1090 function printRow(rowidx,outfile,sep) {
1091 row = this.data[rowidx];
1092 /* Check if mathmode has been determined */
1093 if ~isempty(this.mathmode)
1094 ismm = this.mathmode(rowidx,:);
1096 ismm = false(size(row));
1098 /* Check if we are producing tex-based output */
1099 istex = any(strcmp(this.Format,[" tex
", " pdf
"]));
1101 for i = 1:length(row)-1
1103 if istex && this.fTexMMode && ismm(i)
1104 str = [" $
" str " $
"];/* #ok */
1107 fillstabs = floor((sl*(i~=1)+length(str))/this.TabCharLen);
1108 tottabs = ceil((sl*(i~=1)+this.contlen(i))/this.TabCharLen);
1109 fprintf(outfile," %s%s
",[str repmat(char(9),1,tottabs-fillstabs)],sep);
1112 if istex && this.fTexMMode && ismm(end)
1113 str = [" $
" str " $
"];
1115 fprintf(outfile," %s
",str);
1125 function [str , ismm ] = stringify(data) {
1127 /* Format cell array given */
1128 if iscell(data[end])
1129 /* if format cell is only one item but have more values,
1130 * apply same format string */
1131 if length(data[end]) == 1 && length(data)-1 > 1
1132 data[end] = repmat(data[end],1,length(data)-1);
1133 elseif this.HasRowHeader && length(data[end]) == length(data)-2
1134 data[end] = [" %s
" data[end]];
1135 elseif length(data[end]) ~= length(data)-1
1136 error(" Either provide a single format
string or one
for each column.
");
1138 str = cell(1,length(data)-1);
1139 /* Apply sprintf pattern to each element */
1141 if this.HasRowHeader
1142 str(1) = this.stringify(data(1));
1145 for i=start:length(data)-1
1147 if nargin(data[end][i]) > 1
1148 tmpstr = data[end][i](data[i],i);
1150 tmpstr = data[end][i](data[i]);
1153 tmpstr = sprintf(data[end][i],data[i]);
1155 tmpstr = strrep(tmpstr,char(10),);
1156 /* Strip tab chars if set */
1157 if this.StripInsertedTabChars
1158 str[i] = strrep(tmpstr,char(9),);
1163 else /* convert to strings if no specific format is given */
1165 str = cell(1,length(data));
1166 for i=1:length(data)
1169 el = strrep(el,char(10),);
1170 /* Use char array directly and strip tab characters if desired */
1171 if this.StripInsertedTabChars
1172 str[i] = strrep(el,char(9),);
1176 elseif isinteger(el)
1178 str[i] = [" [
" this.implode(el(:)," ,
"," %d
") " ]
"];
1180 str[i] = sprintf(" %d
",el);
1182 elseif isnumeric(el)
1184 if isvector(el) && length(el) < 100
1185 str[i] = [" [
" this.implode(el(:)," ,
"," %g
") " ]
"];
1187 str[i] = [" [
" this.implode(size(el)," x
"," %d
") " " class(el) " ]
"];
1193 str[i] = sprintf(" %g
",el);
1197 str[i] = func2str(el);
1198 elseif isa(el," handle ")
1201 elseif islogical(el)
1203 str[i] = this.implode(el(:)," ,
"," %d
");
1205 str[i] = sprintf(" %d
",el);
1208 error(" Cannot automatically convert an argument of type %s
for PrintTable display.
",class(el));
1212 /* Detect if any of the cell contents are numerical values */
1213 fun = @(arg)~isempty(arg) && arg(1) ~= " $
" && arg(end) ~= " $
" ...
1214 && (~isnan(str2double(arg)) || ~isempty(strfind(arg," \
")) || ~isempty(strfind(arg," _
")) || ~isempty(strfind(arg," ^
")));
1215 ismm = cellfun(fun,str);
1225 function str = implode(data,glue,format) {
1234 if isa(data," cell ")
1236 for idx = 2:length(data)
1237 str = [str glue data[idx]];/* #ok */
1240 elseif isnumeric(data)
1241 /* first n-1 entries */
1243 str = sprintf([format glue],data(1:end-1));
1245 /* append last, no glue afterwards needed */
1246 str = [str sprintf(format,data(end))];
1248 error(" Can only pass
cell arrays of strings or a vector with sprintf format pattern
");
1255 public: /* ( Static ) */
1257 static function [res , doublet ] = test_PrintTable() {
1260 t.addRow(" A
"," B
"," C
");
1261 t.addRow(" 123
",456E10," 789
");
1262 t.addRow(1234567," 12345
"," 789
");
1263 t.addRow(" 1234567
",123456," 789
");
1264 t.addRow(" 34
"," \sin(x)+4
"," somestring
");
1265 t.addRow(" foo
"," bar
",datestr(clock));
1266 t.addRow(123.45678,pi,789,[" %2.3f
"," $%4.4g$
"," decimal: %d
"]);
1268 /* If HasHeader is set, the format args can be omitted for the first column. */
1269 t.HasRowHeader= true;
1270 t.addRow(123.45678,pi,789,[" $%4.4g$
"," decimal: %d
"]);
1271 t.HasRowHeader= false;
1273 t.addRow(" 12345678
"," \latexcommand{foo}+5
"," 789
");
1274 t.addRow(" yet
"," 123
"," 789
");
1275 t.addRow(123.45678,pi,789,[" %2.3f
",@(v)sprintf(" functioned pi=%g!
",v-3)," decimal: %d
"]);
1276 t.addRow(2,2,2,[@(v,colidx)sprintf(" callback
using column index: %d!
",v^colidx)]);
1277 t.addRow(" single
",pi," fun with colidx
",[" %s
",@(v,colidx)sprintf(" value at column %d: %g!
",colidx,v)," %s
"]);
1284 t.StripInsertedTabChars= false;
1285 t.addRow(" next col with tabs
",char(9)," StripInsertedTabChars off (destroys layout)
",[" %s
"," >
\t>%s>
\t>
"," %s
"]);
1287 t.removeRow(t.NumRows);
1304 t.TexMathModeDetection= false;
1306 t.TexMathModeDetection= true;
1326 static function [res , doublet ] = test_PrintTable_Misc() {
1327 t = PrintTable(" This is
PrintTable Misc Features test, created on %s
",datestr(now));
1328 t.HasRowHeader= true;
1330 t.addRow(" A
"," B
"," C
");
1331 t.addRow(" header-autofmt
",456,789,[" %d
"]);
1332 t.addRow(1234.345,456,789,[" %2.2E
"," %d
"," %d
"]);
1333 t.addRow(" header-expl-fmt
",456,pi,[" %s
"," %d
"," %2.2f
"]);
1334 t.addRow(" nofmt-header
",456,pi,[" %d
"," %f
"]);
1335 t.addRow(" 1234567
"," 12345
"," 789
");
1336 t.addRow(" foo
"," bar
",datestr(clock));
1337 t.addRow(123.45678,pi,789,[" %2.3f
"," %4.4g
"," decimal: %d
"]);
1338 t.addRow(12345678," 123
"," 789
");
1339 t.addRow(12345.6789," 123
"," 789
");
1355 t2 = PrintTable(" dummy
");
1356 t2.addRow(" A
"," B
"," C
"," D
"," E
");
1357 t2.addRow(" header1
",456,789,1,34,[" %d
"]);
1358 t2.addRow(12345.6789," 123
"," 789
"," foo
"," bar
");
1359 t2.addRow(" header2
",4656,35789,351,4);
1365 ta = t.append(t2,[1 3 5]);
1370 ta = t.append(t2,[4 2 1]);
1373 /* Empty table append test */
1388 static function [res , doublet ] = test_PrintTable_LaTeX_Export() {
1389 t = PrintTable(" LaTeX/PDF export demo, %s
",datestr(now));
1390 t.HasRowHeader= true;
1392 t.addRow(" A
"," B
"," C
");
1393 t.addRow(" Data 1
",456,789,[" %d
"]);
1394 t.addRow(1234.345,456,789,[" $%2.2E$
"," $%d$
"," $%d$
"]);
1395 t.addRow(" header-expl-fmt
",456,pi,[" %s
"," %d
"," %2.2f
"]);
1396 t.addRow(" 1234567
"," 12345
"," 789
");
1398 t.addRow(" x=4
"," \sin(x)
",sin(x),[" %s
"," %f
"]);
1399 /* Explicit wrapping directly or with $$ per format string */
1400 t.addRow(" x=4
"," 25 (5*5)=
",5*5,[" $%s$
"," %d
"]);
1401 /* (have HasRowHeader, thus the first format string is not necessary (but yet
1402 * possible to define)) */
1403 t.addRow(" $x=4,\alpha=.2$
"," \alpha\exp(x)\cos(x)
",.2*exp(x)*cos(x),[" $%s$
"," %f
"]);
1407 t.saveToFile(" myLaTeXexportedPrintTable.tex
",true);
1410 t.saveToFile(" mytable_tightpdf.pdf
",true);
1412 /* Whole page PDF */
1414 t.TexMathModeDetection= true;
1415 t.saveToFile(" mytable_fullpage.pdf
",true);
1427 static function [res , doublet ] = test_PrintTable_Failed_LaTeX_Export() {
1428 t = PrintTable(" LaTeX/PDF export demo (THIS MUST FAIL!), %s
",datestr(now));
1429 t.HasRowHeader= true;
1431 t.TexMathModeDetection= false;
1432 t.addRow(" A
"," B
"," C
");
1433 t.addRow(" Data 1
",456,789,[" %d
"]);
1434 t.addRow(1234.345,456,789,[" $%2.2E$
"," $%d$
"," $%d$
"]);
1435 t.addRow(" header-expl-fmt
",456,pi,[" %s
"," %d
"," %2.2f
"]);
1436 t.addRow(1234567," 12345
",45.3463E-4);
1438 /* This is the offending latex line */
1439 t.addRow(" x=4
"," \sin(x)
",sin(x),[" %s
"," %f
"]);
1440 /* Explicit wrapping directly or with $$ per format string */
1441 t.addRow(" x=4
"," 25 (5*5)=
",5*5,[" $%s$
"," %d
"]);
1442 t.addRow(" $x=4,\alpha=.2$
"," \alpha\exp(x)\cos(x)
",.2*exp(x)*cos(x),[" $%s$
"," %f
"]);
1445 t.saveToFile(" mytable_tightpdf_nodetection.pdf
",true);
1447 fprintf(2," TEST FAILED AS EXPECTED, WARNING HAS BEEN ISSUED. ALL GOOD.\n
");
1455 private: /* ( Static ) */
1457 static function l = getDefaultTabCharLen() {
1459 /* Use default value 8 */
1462 jDesktop = com.mathworks.mde.desk.MLDesktop.getInstance;
1463 /* Display of output in command window */
1464 if ~isempty(jDesktop.getClient(" Command Window
"))
1465 /* Display of output in console etc */
1466 l = com.mathworks.services.Prefs.getIntegerPref(" CommandWindowSpacesPerTab
",-1);
1468 l = com.mathworks.services.Prefs.getIntegerPref(" EditorSpacesPerTab
",defaultLen);
1471 [c, l] = system(" echo -n $
"" \
t "" | wc -L
");
1478 /* Not checked yet for windows command line, but i guess this will be a rare
1479 * occasion. Please share if you encounter this situation. */
logical HasHeader
Flag that determines if the first row should be used as table header.
static function [ res , double t ] = test_PrintTable()
A simple test for PrintTable.
function saveToFile(char filename,logical openfile)
Prints the current table to a file.
data
The string cell data.
char ColSep
A char sequence to separate the different columns.
function clear()
Clears the current PrintTable contents and caption.
A MatLab cell array or matrix.
function copy = clone()
Returns a new instance of PrintTable with the same content.
function addMatrix(titles, data, varargin)
haslatexcommand
Flag to maximize user convenience; this is set whenever a row adding resulted in a string containing ...
integer TabCharLen
Equivalent length of a tab character in single-space characters.
char Caption
A caption for the table.
reshape
hanges the dimensions of the handle object array to the specified dimensions. See the MATLAB reshape ...
function display()
Overload for the default builtin display method.
A MatLab function handle.
Matlab's base handle class (documentation generation substitute)
mathmode
Flag matrix to indicate if a cell value is numeric or not.
function print(integer outfile)
Prints the current table to a file pointer.
function this = sort(integer colnr,char direction)
Sorts this table in alphanumeric order.
function removeRow(integer idx)
Removes a row from the PrintTable.
logical HasRowHeader
Flag that determines if there is a row header for the table.
function joined = append(PrintTable table,rowvec< integer > columns)
Appends the cell contents from another table to this table.
A variable number of input arguments.
logical TexMathModeDetection
Flag that tells the PrintTable to surround numerical values with dollar signs "$$" to obtain a more s...
logical TightPDF
Flag that indicates if exported tables in PDF format should be sized to the actual table size or be c...
contlen
Maximum content length for each colummn.
PrintTable: Class that allows table-like output spaced by tabs for multiple rows. ...
function char str = toString()
Returns a character array representation of the current table.
function addRow(varargin)
Adds a row to the current table.
PrintTable(char caption,cell varargin)
Creates a new PrintTable instance.
integer NumRows
The number of rows in the current table.
function transposed = ctranspose()
A MatLab character array.
enum Format
The output format of the table when using the print method.
static function [ res , double t ] = test_PrintTable_Misc()
A simple test for PrintTable.
logical StripInsertedTabChars
Flag that determines if inserted tab characters are stripped from any string to preserve the correct ...