classdef TexTab < Basic.Base
% TexTab allows you to create nicely formatted tables and export them to a picture file like PNG.
%
% The picture can easily be imported to email software and word processing software like
% Microsoft Word or Open Office / Libre Office. Exporting to .tex files is also possible.
%
% Converting to picture files is only possible if the following (freely
% available) Software is installed on your computer:
% - Miktex (ver. 2.9 or higher) http://miktex.org/2.9/setup
% Some additional packages are needed for table creation, so I recommend to allow MickTex to
% install additional packages and to have an internet connection when creating the first tables
% or to use the complete MickTex installation.
% - ImageMagick and Ghostscript http://www.imagemagick.org http://downloads.ghostscript.com/public/gs906w32.exe
%
% Creating tables is quite simple:
% - create a TexTab object
% - Assign the table content to the object's Data property
% - modify further properties to format the table
% - call the writePic or writeTex method to create the table.
%
% Example:
% Data = rand(10,2); % Create some data
% obj = IoFun.TexTab; % Create the TexTab object
% obj.Data = [{'x','y'};num2cell(Data)]; % Assign the data including a headline
% obj.BgColor(1,:) = {'bluem'}; % Format: Background color of the Headline is blue
% obj.FontStyle(1,:) = {'\Large'}; % Large Font for the headline
% [Alerts,~] = find(Data(:,2)>0.8); % Find high data values:
% obj.Color(Alerts+1,2) = {'red'}; % mark them with red colour
% obj.writePic('c:\temp\test.png'); % create the table and write it to a png file
% % This uses Miktex and Imagemagick and is time
% % consuming.
% clear
% a=IoFun.TexTab.png2data('c:\temp\test.png'); % Retrieve the Data from the png figure file.
% % This uses ImageMagick and is time consuming
%
% To merge cells in rows and columns combinedly, set your Data property like in the
% following example:
% obj.Data = {'a' '<' 'c'
% '^' '<' 'c'};
%
% To get started, check the methods example1 to example4 and watch the help of the properties
% and methods.
% Call the examples:
% obj = IoFun.TexTab;
% obj.example1;
%
% Convert underlying data from the png file to a csv txt file
% This uses ImageMagick and is time consuming
% IoFun.TexTab.png2csv('c:\temp\test.png','c:\temp\test.txt')
%
%
% (C) Alstom Transport Deutschland GmbH
% Salzgitter, Germany
% GBO2
% Marcel Rland
%
properties
% Fontweight defines the font weight for arbitrary cells.
% It should have the same size as the Data.
% The set.Data method formats Fontweight automatically.
% If left empty, normal font weight is chosen.
FontWeight
% BgColor defines the background color for arbitrary cells.
% It should have the same size as the Data.
% The set.Data method formats BgColor automatically.
% If left empty, the background color is white.
% Use valid Tex colors like 'red', 'green', the light blue color
% bluem or a self defined color (cf. property <ColorDef>)
% Example
% >> obj.BgColor
%
% ans =
%
% 'bluem' 'bluem'
% [] 'green'
% [] []
% [] []
% [] []
BgColor
% Color defines the text color for arbitrary cells.
% It should have the same size as the Data.
% The set.Data method formats Color automatically.
% Use valid Tex colors like 'red', 'green', the light blue color
% bluem or a self defined color (cf. property <ColorDef>)
% If left empty, the color is black.
Color
% CellFormat defines the general format of the table as defined in the Tex tabular
% environment.
% It should be a string describing the cell format in the following manner:
% For each column, use one of the letters l,r,c. For Lines between the columns pace a |
% The following list sums up the meaning of each character in the CellFormat property:
% | Vertical line before/behind a cell
% || Double vertical line before/behind a cell
% l Cell content is justified left
% r Cell content is justified right
% c Cell content is centered
% Example:
% |r||cc|l|
% This formats the table with 4 columns. The first
% column is aligned left followed by two centered columns and a left aligned column.
% The first column has a vertical line on its left side. On its right side, there is a
% doubled ine. Between the 2nd and the 3rd column there is no vertical line and the last
% column has a vertical line on its right and left.
% If CellFormat is empty, the default format is chosen: All cells are centered with single lines
% on both sides.
CellFormat
% FontStyle defines font styles for arbitrary cells.
% Fontstyle is a cell array with the same size as the Data Property. It is automatically
% formatted to that size when the Data property is set. You can use any Tex font style
% The following table shows some important font styles. A combination of font sytles
% is possible.
% '\bf' Bold
% '\rm' Roman
% '\tt' Typewriter
% '\it' Italic
% '\sl' Slanted
% '\sf' Sans serif
% '\tiny'
% '\small'
% '\large'
% '\Large'
% '\LARGE'
% '\huge' %This is not recommended since it creates problems with
% %the row hight and the types stick to the upper line of the box
% '\Huge' %This is not recommended since it creates problems with
% %the row hight and the types stick to the upper line of the box
FontStyle
% DefaultFont can be used to define a default font, which will be used for the
% whole table. If left empty, the standard font will be used.
% Currently the following fonts are tested.
% - 'uarial'
% - 'helvetica'
% Possibly there are further fonts that work. For further infomation,
% refer to http://www.tug.dk/FontCatalogue/
DefaultFont
% ColorDef can be used to define custom RGB colors.
% The color definition is stored as a struct with the custom color
% name as field name. Assign to this field a tree element vector with
% RGB color parts expressed by numbers between 0 and 1.
% Example:
% obj.ColorDef.myCol = [0.91, 0.8, 0.3]; %RGB color definition
% obj.ColorDef.myRed = [1, 0, 0]; %RGB color definition
ColorDef
% DefaultNumericalFormat Doubles generally will be converted automatically in this format
% See the help entry of sprintf for more details
DefaultNumericalFormat = '%5.3f'
% NumericalFormat This is a cell with conversion precisions for each double value in the Data
% property.
% See the help entry of sprintf for more details
NumericalFormat
% Density contains the resolution of the graphical output createt
% with the method writePic (using the convert command of
% ImageMagick). Low values yield in small size output files and high
% values assure a good output resolution.
%Density is expressed as a string in the following manner:
% obj.Density = '1600x1600'
Density = '600x600' % DPI
% UseInterpreter - If set true, mathmatical expressions will be interpretated, eg. \mu will
% create the sign. Additionally numericals with the value Inf will be converted to the
% infinity sign and NaNs will be converted to a self-defined NaN sign.
UseInterpreter = true
% LineStyle Choose the style of your lines
% LineStyle is cell array with one column containing the the style of each horizontal
% line in the column. The following line styles are allowed:
% 'normal'
% 'none'
% 'thick(x)' :line with the thickness x, expessed in px
LineStyle = []
% TODO:
% - alow dobble horizontal lines
% - fix bug with double vertical lines and merged loumns
% - allow bold vertical lines
% - allow to enter font sizes
% - line feeds in cells
end
properties (SetAccess = private, Hidden=true)
% TexString contains the tex string which will be written to file
% with the method writeTex
TexString
end
properties(Dependent=true)
% Data cell array containing the data as string or double.
% Strings may contain Latex formats also.
% The LATEX package colortbl is loaded automatically.
% Example:
% obj.Data = {'a' 'b' 'c' 'd'; 1 2 '<' pi;'a' '\textcolor{green}{b}' 'c' '\colorbox{red}{d}'}
%
% Data is dependent and shadowed by PrivateData in order to have access to other
% Properties like FontWeight from the set.Data method
Data
end
properties (Access=private)
PrivateData %Shadows the Data property.
end
methods
function obj = TexTab(varargin)
% Creates a TextTab object and checks, if third party software (ImageMagick and Miktex)
% is installed and accessible. Note that the correct installation
% of Ghostscript is noch checked. If you have any strange
% behaviour, check your Ghostscript istallation.
% Refer to the help entries of this class for more information.
[stat,~]=dos('texi2dvi -?');
if stat
obj.error('Zeisig:IoFun:TexTab:texi2dviNotFound');
end
[stat,~] = dos('dvips -?');
if stat
obj.error('Zeisig:IoFun:TexTab:dvipsNotFound');
end
[stat,~] = dos('convert -version');
if stat
obj.error('Zeisig:IoFun:TexTab:convertNotFound');
end
[stat,~] = dos('identify -version');
if stat
obj.error('Zeisig:IoFun:TexTab:identifyNotFound');
end
end
function example1(obj)
% Create your own table based on this example
% Creating a table can be done in the following manner:
% * create the object
% * write the data to the object's Data property
% Use the following charaters to merge cells:
% - < (merge horizontally)
% - ^ (merge vertically)
% * format the table by setting additional properties like:
% - ColorDef
% - BgColor
% - CellFormat
% - NumericalFormat
% - FontStyle
obj.Data = {'a' 'b' '<' '<'; % First line: merge the last 3 cells
1 2 '<' pi; % Second line: merge the second and the third line
'a' '\textcolor{green}{b}' 'c' 'd'}; % Use a tex command to set the second
% value's color to green
obj.ColorDef.blu = [0.1, 0.8, 0.95]; %RGB color definition: This color will be used in the following line
obj.BgColor(1,:) = {'blu'};
obj.ColorDef.myCol = [0.91, 0.8, 0.3]; %RGB color definition: This color will be used in the following line
obj.Color(3,1) = {'myCol'};
obj.Color(3,3) = {'red'}; %Use a predefined tex color
obj.writeTex('c:\temp\ex1.tex'); %Convert to tex (Optional)
obj.writePic('c:\temp\ex1.png'); %Convert to a png picture.
clear
Data = IoFun.TexTab.png2data('c:\temp\ex1.png'); %Retrieve the data from a png picture file
disp(Data);
IoFun.TexTab.png2csv('c:\temp\ex1.png','c:\temp\ex1.csv'); %wirite the picture's data to a csv file
end
function example2(obj)
% Create your own table based on this example
% Creating a table can be done in the following manner:
% * create the object
% * write the data to the object's Data property
% Use the following charaters to merge cells:
% - < (merge horizontally)
% - ^ (merge vertically)
% * format the table by setting additional properties like:
% - ColorDef
% - BgColor
% - CellFormat
% - NumericalFormat
% - FontStyle
data = rand(10,4);
[xmin,ymin] = find(data==min(min(data)));
Header1 = {'Messwerte' '<' '<' '<' '<'};
Header2 = {'n' 'x1' 'x2' '<' 'x3'};
Header3 = {'^' '^' 'a' 'b' '^'};
FirstCol = num2cell([1:10]'); %#ok<*NBRAK>
FirstCol(3:4) = {'^'};
FirstCol(6:8) = {'^'};
nHeader = 3;
nLeftCols = 1;
obj.Data = [Header1; Header2; Header3; FirstCol num2cell(data)];
obj.ColorDef.lightRed = [1 0.8 0.8]; %RGB color definition: This color will be used in the following line
obj.ColorDef.darkRed = [0.8 0.2 0];
obj.ColorDef.lightGreen = [0.8 1 0.8];
obj.ColorDef.darkGreen = [0 0.6 0];
obj.Data{5,2} = inf;
obj.BgColor(5,2) = {'lightRed'};
obj.Color(5,2) = {'red'};
obj.DefaultFont = 'uarial';
obj.CellFormat = '|l||c|c|c|r|'; %This line is optional, you can ommit it to use a default format
obj.NumericalFormat(:,1)={'%u'};
obj.NumericalFormat(:,3)={'%7.5f'};
obj.FontStyle(xmin+nHeader,ymin) = {'\bf'};
obj.Color(xmin+nHeader,ymin+nLeftCols) = {'darkGreen'};
obj.BgColor(xmin+nHeader,ymin+nLeftCols) = {'lightGreen'};
obj.FontStyle(1,:) = {'\Large'};
obj.FontStyle(2,:) = {'\bf'};
obj.BgColor(1,1) = {'bluem'};
% obj.writeTex('c:\temp\ex2.tex');
obj.writePic('c:\temp\ex2.png');
end
function example3(obj)
% Create your own table based on this example
% Creating a table can be done in the following manner:
% * create the object
% * write the data to the object's Data property
% Use the following charaters to merge cells:
% - < (merge horizontally)
% - ^ (merge vertically)
% * format the table by setting additional properties like:
% - ColorDef
% - BgColor
% - CellFormat
% - NumericalFormat
% - FontStyle
data = [ 0.6228 0.7449 0.1629 0.2296
0.7966 0.8923 0.8384 0.9361
0.7459 0.2426 0.1676 0.6832
0.1255 0.1296 0.5022 0.9621
0.8224 0.2251 0.9993 0.4380
0.0252 0.3500 0.3554 0.9403
0.4144 0.2871 0.0471 0.0058
0.7314 0.9275 0.2137 0.6103
0.7814 0.0513 0.3978 0.8011
0.3673 0.5927 0.3337 0.2330
0.9325 0.2905 0.3991 0.7425
0.7633 0.4026 0.5994 0.7579
0.8264 0.8621 0.8005 0.3891
0.5735 0.6147 0.1051 0.4293
0.7926 0.9912 0.8214 0.9563
0.3290 0.2037 0.8411 0.5730
0.2235 0.8272 0.3545 0.8497
0.3124 0.6759 0.4301 0.2763
0.5845 0.2489 0.5722 0.6223
0.8299 0.4758 0.7008 0.5884
0.9635 0.6198 0.1590 0.9852
0.0859 0.2606 0.2369 0.5595
0.5005 0.4457 0.7022 0.9336
0.5216 0.8440 0.3755 0.7203
0.0902 0.1962 0.9737 0.4840
0.9047 0.3039 0.9723 0.6390
0.8844 0.4833 0.6437 0.8876
0.4390 0.3378 0.8601 0.1987
0.7817 0.7985 0.4019 0.3954
0.1485 0.9875 0.6319 0.9922];
% [xmin,ymin] = find(data==min(min(data)));
Header1 = {'Messwerte' '<' '<' '<'};
Header2 = {'x_1' '<' 'x3' 'x4'};
obj.Data = [Header1; Header2;num2cell(data)];
obj.FontStyle(1,:) = {'\Large'};
obj.FontStyle(2,:) = {'\bf'};
obj.BgColor(1,:) = {'bluem'};
obj.writePic('c:\temp\ex3.png');
end
function example4(obj)
% Create your own table based on this example
% This example shows how to use different line styles and merge cells in rows and
% columns
obj.Data = {'Title' '<' '<' '<' '<'
'Subtitle' '<' '<' '<' '<'
'a' '<' 'c' 'd' '<'
'^' '<' 'c' 'd' 'e'
'a' 'b' 'c' 'd' 'e'
'a' 'b' 'c' 'd' 'e'};
obj.LineStyle{2} = 'thick(2)';
obj.LineStyle{1} = 'none';
obj.writePic('c:\temp\ex4.png');
end
function obj = set.Data(obj,Data)
% Automatically initializes other properties
% The data iself is stored in the PrivateData property.
if isnumeric(Data)
% warning('Zeisig:IoFun:TexTab:ConvertingDataToCell','Converting Data to cell.');
Data = num2cell(Data);
end
obj.PrivateData = Data;
obj.FontWeight = cell(size(Data));
obj.FontStyle = cell(size(Data));
obj.LineStyle = repmat({'normal'},size(obj.Data,1),1);
obj.BgColor = cell(size(Data));
obj.Color = cell(size(Data));
obj.NumericalFormat = repmat({obj.DefaultNumericalFormat},size(Data));
n = size(obj.Data,2);
if isempty(obj.CellFormat)
obj.CellFormat = [repmat('|c',1,n) '|'];
end
end
function Data = get.Data(obj)
Data = obj.PrivateData;
end
function obj = set.ColorDef(obj,ColorDef)
% Perform some input checks
FN = fieldnames(ColorDef);
for i = FN'
if ~isnumeric(ColorDef.(char(i)))
obj.error('Zeisig:IoFun:TexTab:ColorDefNotNumeric');
end
if any(size(ColorDef.(char(i)))~=[1,3])
obj.error('Zeisig:IoFun:TexTab:ColorDefWrongSize');
end
if any (ColorDef.(char(i))>1)
obj.error('Zeisig:IoFun:TexTab:ColorDefValuesToohigh');
end
obj.ColorDef = ColorDef;
end
end
function writeTex(obj,filename)
% obj.writeTex(filename)
% Writes a .tex file expressing the table specified by obj.
% Specify the filename by it's full path.
%Calls obj.update to write a .tex file to disk
obj.update;
[fid] = fopen(filename,'w+');
if fid == -1
error('Could not open file.');
end
fprintf(fid,'%c',obj.TexString);
fclose(fid);
disp(filename);
end
function writePic(obj,filename)
% Creates a picture file of the TexTab object.
% automatically updates the object, creates some temp files in c:\temp,
% converts them to a png file and deletes the temporary files.
% This method uses the following external software, which are called with the dos command:
% * texi2dvi
% * dvips
% * convert
% So make sure you have them installed (MikTex and ImageMagick with correct installation of
% Ghostscript). Additionally Windows' path must be set correctly
% to the corresponding binary directories.
% Usage:
% obj.writePic(filename)
% The picture format is chosen according to the filename. The following formats are
% possible:
% * png
% * jpg
% * gif
%
% If you write a .png file, the pure data is written to the png file as a Property
% (Key: MyMetaData)
% You can read this metadata in a dos shell with the following command (using ImageMagick):
% identify -verbose test.png
% Or you can use the free tool TweakPNG.
% Use the following static methods to acces the data directly in Matlab or convert it to a csv file.
%
% See also:
% png2data
% png2csv
obj.update;
[~,TempDir]=dos('echo %temp%'); %Get the temp directory specified by Windows
TempDir(TempDir==char(10))=[];
obj.writeTex(fullfile(TempDir,'tmp.tex'));
if nargin<2
filename = 'tab.png';
end
wd = pwd;
disp('Converting to PNG. This may be time consuming.');
try %#ok<TRYNC>
cd (TempDir);
disp('...Creating temporary dvi file.');
[stat,Res] = dos('texi2dvi -q tmp.tex');
if stat
disp(Res);
end
disp('...Creating temporary ps file.');
[stat,Res] = dos('dvips -q -E tmp.dvi');
if stat
disp(Res);
end
% [stat,Res] = dos(sprintf('convert -density %s tmp.ps %s',obj.Density,filename));
% Prepare Meta data to be stored in png file
% Desired format is a single csv string
nums = cellfun(@isnumeric,obj.Data);
Data = obj.Data;
Data_ = Data;
Data_(~nums)=cell(size(find(~nums)));
Data_ = cellfun(@num2str,Data_,'uniformoutput',false);
Data(nums) = Data_(nums);
[r,c] = size(Data);
seps = repmat({','},size(Data));
seps(:,end) = repmat({';'},r,1);
MetaData = cell(r,2*c);
MetaData(:,1:2:2*c-1) = Data;
MetaData(:,2:2:2*c) = seps;
MetaData = cell2str(MetaData);
MetaData(MetaData==10) = [];
disp('...Converting temporary ps file to desired picture file.');
[stat,Res] = dos(sprintf('convert -density %s -units PixelsPerInch -set MyMetaData "%s" tmp.ps %s',obj.Density,MetaData,filename));
if stat %-units PixelsPerInch: Hint of M. Stiepel to get a correct picture size in the exif data
disp(Res);
end
disp('...Deleting temporary files.');
[stat,Res] = dos('del tmp.tex');
if stat
disp(Res);
end
[stat,Res] = dos('del tmp.dvi');
if stat
disp(Res);
end
[stat,Res] = dos('del tmp.log');
if stat
disp(Res);
end
[stat,Res] = dos('del tmp.aux');
if stat
disp(Res);
end
[stat,Res] = dos('del tmp.ps');
if stat
disp(Res);
end
end
disp(filename);
cd(wd);
end
end
methods (Access = private)
function obj = update(obj)
% This method updates the object to the correct value of obj.TexStr
% It parses obj.Data and all format properties to a valid tex strring.
if strcmp(obj.Data(:,1),'<')
obj.error('Zeisig:IoFun:TexTab:ArrowInFirstColumn');
end
if isempty(obj.LineStyle)
obj.LineStyle = repmat({'normal'},size(obj.Data,1),1);
end
for Prop = {'FontWeight','BgColor','FontStyle','NumericalFormat','Color'}
if any(size(obj.(char(Prop)))>size(obj.Data))
obj.error('Zeisig:IoFun:TexTab:PropertyTableExceedsSize',char(Prop))
end
end
cr = char(10);
Colorstr = [cr '\definecolor{bluem}{rgb}{0.7,0.8,0.95}' cr];
if ~isempty(obj.ColorDef)
colors = fieldnames(obj.ColorDef);
for i = 1:length(colors)
CurrColName = colors{i};
CurrColVal = obj.ColorDef.(colors{i});
CurrColStr = sprintf('%4.2f,%4.2f,%4.2f',CurrColVal(:));
Colorstr = sprintf('%s\\definecolor{%s}{rgb}{%s}\n',...
Colorstr,...
CurrColName,...
CurrColStr);
end
end
if ~isempty(obj.DefaultFont)
switch lower(obj.DefaultFont)
case 'uarial' %Near to arial (No Math Support)
DefFontStr = sprintf('%s{%s}\n%s\n%s','\usepackage[scaled]',...
obj.DefaultFont,...
'\renewcommand*\familydefault{\sfdefault}',...
'\usepackage[T1]{fontenc}');
case {'arev','cmbright'} %arev (Math Support)
DefFontStr = sprintf('%s{%s}\n\n%s','\usepackage',...
obj.DefaultFont,...
'\usepackage[T1]{fontenc}');
otherwise
DefFontStr = sprintf('%s{%s}\n%s\n%s','\usepackage[scaled]',...
obj.DefaultFont,...
'\renewcommand*\familydefault{\sfdefault}',...
'\usepackage[T1]{fontenc}');
end
else
DefFontStr = '';
end
TabFormat = sprintf('\\begin{tabular}{%s}',obj.CellFormat);
Header = ['\documentclass{article}' cr ...
'\usepackage{colortbl}' cr ...
'\usepackage{multirow}' cr ...
'\usepackage{array}' cr ...
'\usepackage{tabularx}' cr ...
'\makeatletter' cr ... %Thanks to http://tex.stackexchange.com/questions/3445/latex-tables-how-do-i-make-bold-horizontal-lines-typically-hline
'\def\hlinewd#1{%' cr ...
'\noalign{\ifnum0=`}\fi\hrule \@height #1 %' cr ...
'\futurelet\reserved@a\@xhline}' cr ...
'\makeatother' cr ...
DefFontStr ...
Colorstr ...
'\begin{document}' cr ...
'\pagestyle{empty}' cr ...
'{' cr ...
'\setlength{\extrarowheight}{3pt}' cr... %Package array; to correct row hight, when \hline is used, cf.http://nepsweb.co.uk/docs/tableTricks.pdf
TabFormat cr ...
'\hline' cr];
Footer = [cr '\end{tabular}' cr ...
'}' cr ...
'\end{document}' cr];
PreTable = obj.Data;
%Convert numerical data
id = find(cellfun(@isnumeric,PreTable));
if ~isempty(id)
for i = id'
PreTable{i} = num2str(PreTable{i},obj.NumericalFormat{i});
end
end
if obj.UseInterpreter
PreTable = regexprep(PreTable,'Inf','\\infty');
PreTable = regexprep(PreTable,'NaN','\\o');
end
%Convert escape characters
if obj.UseInterpreter
PreTable = regexprep(PreTable,'(.*_.*|.*\\.*)','\$$1\$');
else
PreTable = regexprep(PreTable,'_','\\_');
end
PreTable = regexprep(PreTable,'','{\\ss}');
PreTable = regexprep(PreTable,'','\\"u');
PreTable = regexprep(PreTable,'','\\"U');
PreTable = regexprep(PreTable,'','\\"o');
PreTable = regexprep(PreTable,'','\\"O');
PreTable = regexprep(PreTable,'','\\"a');
PreTable = regexprep(PreTable,'','\\"A');
%Bold cells
if ~isempty(obj.FontWeight)
[idx,idy] = find(~cellfun(@isempty,obj.FontWeight));
for i = 1:length(idx)
PreTable{idx(i),idy(i)} = ['\textbf{' PreTable{idx(i),idy(i)} '}'];
end
end
%FontStyles
if ~isempty(obj.FontStyle)
[idx,idy] = find(~cellfun(@isempty,obj.FontStyle));
for i = 1:length(idx)
PreTable{idx(i),idy(i)} = [obj.FontStyle{idx(i),idy(i)} ' ' PreTable{idx(i),idy(i)}];
end
end
%Background Color
if ~isempty(obj.BgColor)
[idx,idy] = find(~cellfun(@isempty,obj.BgColor));
for i = 1:length(idx)
PreTable{idx(i),idy(i)} = sprintf('\\cellcolor{%s}{%s}',obj.BgColor{idx(i),idy(i)}, PreTable{idx(i),idy(i)});
end
end
%Text Color
if ~isempty(obj.Color)
[idx,idy] = find(~cellfun(@isempty,obj.Color));
for i = 1:length(idx)
PreTable{idx(i),idy(i)} = sprintf('\\color{%s}{%s}',obj.Color{idx(i),idy(i)}, PreTable{idx(i),idy(i)});
end
end
%% Merge cells in a row
additionalCellsWithoutSublines = cell(size(obj.Data));
[idRow,idCol] = find(~cellfun(@isempty,regexp(PreTable,'<'))); %find mergable cells
if ~isempty(idRow)
[~,id] = sort(idRow,1,'ascend'); %Columns should be contiguous
idRow = idRow(id);
idCol = idCol(id);
id = [find(diff([idCol(1);idCol])~=1)]; %Vector with first ids of '<' cells
n = diff([id; length(idCol)+1]) + 1; %Vector with corresponding number of contiguous '<' cells
% CellJust=regexp(obj.CellFormat,'\|*','split'); %Justification string ('c','l','r')
% CellJust(cellfun(@isempty,CellJust))=[];
% if length(CellJust)~=size(obj.Data,2);
% CellJust = repmat({'c'},1,size(obj.Data,2));
% end
CellJust = regexprep(obj.CellFormat,'\|','');
CellVertBars = regexp(obj.CellFormat,'[clr]','split');
% j = 1;
for i = 1:length(id)
CellContent = PreTable{idRow(id(i)),idCol(id(i))-1};
if idRow(id(i))+1<=size(PreTable,1) &&...
strcmp(PreTable{idRow(id(i))+1,idCol(id(i))-1},'^') %cell left down containes a ^ => Nested \multicolumn, \multirow
vertVec = PreTable(idRow(id(i))+1:end,idCol(id(i))-1);
if ~any(strcmp(PreTable{idRow(id(i)),idCol(id(i))-1},{'^' '<'}))
idvertMerge = find(strcmp(vertVec,'^'));
nRows = 2; %Start searching in the second line
if length(idvertMerge)>1
delta = 1;
while delta==1
if nRows<=length(idvertMerge)
delta = idvertMerge(nRows)-idvertMerge(nRows-1);
else
delta = 0;
end
nRows = nRows + 1;
end
nRows = nRows - 1;
end
% fprintf('%u...%u\n',i,nRows);
CellContent = sprintf('\\multirow{%u}{*}{%s}',...
nRows, ...
CellContent);
end
if isempty(additionalCellsWithoutSublines{idRow(id(i))})
j = 1;
additionalCellsWithoutSublines{idRow(id(i)),j} = [idCol(id(i))-1:idCol(id(i))+n(i)-2];
else
j = j + 1;
additionalCellsWithoutSublines{idRow(id(i)),j} = [idCol(id(i))-1:idCol(id(i))+n(i)-2];
% LastadditionalRow = idRow(id(i));
end
else
end
if idCol(id(i))==2 %The multiple cell is in the first column
PreTable{idRow(id(i)),idCol(id(i))-1} = sprintf('\\multicolumn{%u}{%s%s%s}{%s}',...
n(i), ...
CellVertBars{idCol(id(i))-1}, ...
CellJust(idCol(id(i))-1), ...
CellVertBars{idCol(id(i))+n(i)-1}, ...
CellContent);
else
PreTable{idRow(id(i)),idCol(id(i))-1} = sprintf('\\multicolumn{%u}{%s%s}{%s}',...
n(i), ...
CellJust(idCol(id(i))-1), ...
CellVertBars{idCol(id(i))+n(i)-1}, ...
CellContent);
end
end
end
idRowMultiCol = idRow;
idColMultiCol = idCol;
PreTable = regexprep(PreTable,'(?<=\{)\^(?=\})','');
%% Merge cells in a column
[idRow,idCol] = find(~cellfun(@isempty,regexp(PreTable,'\^'))); %find mergable cells
[~,id] = sort(idCol,1,'ascend'); %Columns should be contiguous
idRow = idRow(id);
idCol = idCol(id);
id = [find(diff([1;idRow])>1);find(diff([1;idCol])>0)]; %Vector with first ids of '^' cells
id = unique(id);
n=zeros(length(idRow),1);
n(1) = 2;
j = 1;
for i = 2:length(idRow)
if (idCol(i)==idCol(i-1))&& ((idRow(i)-idRow(i-1))==1)
n(j) = n(j)+1;
else
j = j+1;
n(j) = 2;
end
end
n(j+1:end) = [];
for i = 1:length(id)
PreTable{idRow(id(i))-1,idCol(id(i))} = sprintf('\\multirow{%u}{*}{%s}',...
n(i), ...
PreTable{idRow(id(i))-1,idCol(id(i))});
end
PreTable = regexprep(PreTable,'\^','');
idRowMultiLine = idRow;
idColMultiLine = idCol;
PreTable = [cellfunMr(@horzcat,PreTable(:,[1:end-1]),'&') PreTable(:,end)]; %Toolbox.Alstom
PreTable(cellfun(@isempty,PreTable))={'&'};
for i = 1:length(idRowMultiCol)
PreTable{idRowMultiCol(i),idColMultiCol(i)} = ''; %Remove the & for the multicolumn
end
for i = 1:size(PreTable,1)
if any(i==idRowMultiLine-1)||~isempty(additionalCellsWithoutSublines{i})
j = i==idRowMultiLine-1;
ColWithoutSubLine = [[idColMultiLine(j)]' additionalCellsWithoutSublines{i,:}];
ColWithSubLine = 1:size(obj.Data,2);
ColWithSubLine(ColWithoutSubLine) = [];
clear ClineCommand;
ClineCommand = cell(1,length(ColWithSubLine));
ClineCommand{1} = '\\';
for k = 1:length(ColWithSubLine)
ClineCommand{k+1} = sprintf(' \\cline{%u-%u}',ColWithSubLine(k),ColWithSubLine(k));
end
PreTable(i,size(obj.Data,2)+1) = {cell2str(ClineCommand)}; %{sprintf('\\\\ \\cline{%u-%u}',idColMultiLine(j)+1,size(obj.Data,2))};
else
switch regexp(obj.LineStyle{i},'[^\(\)\d]*','match','once')
case 'normal'
PreTable(i,size(obj.Data,2)+1) = {'\\ \hline'};
case 'none'
PreTable(i,size(obj.Data,2)+1) = {'\\'};
case 'thick'
Thickness = regexp(obj.LineStyle{i},'(?<=\()\d*(?=)','match','once');
PreTable(i,size(obj.Data,2)+1) = {sprintf('\\\\ \\hlinewd{%spt}',Thickness)};
otherwise
disp('Warning: assumed normal linestyle.');
end
end
end
%Convert to string and add header and footer
Table = cell2str(PreTable);
Table = regexprep(Table,'&(?=\\\\ \\hline)',''); %Remove Remaining cell breaks at the end of a line (Remaining due to the multicolumn algorithm)
Table = regexprep(Table,'&(?=\\\\ \\cline)',''); %Remove Remaining cell breaks at the end of a line (Remaining due to the multicolumn algorithm)
Table = regexprep(Table,'&(?=\\\\)',''); %Remove Remaining cell breaks at the end of a line (Remaining due to the multicolumn algorithm)
% Table = regexprep(Table,char(10),['\\\\\\hline' cr]);
obj.TexString = [Header Table Footer];
end
end
methods (Static=true)
function [Data_,CsvData] = png2data(Filename)
% [Data_,CsvData] = png2data(Filename);
% Gets TexTab metadata from a .png file created by this class.
% Data is a cell array
% CsvData is a string with csv data, which can be written directly to a csv file.
%
% See also:
% png2csv
[~,~,ext] = fileparts(Filename);
if ~strcmpi(ext,'.png')
warning('Zeisig:IoFun:TexTab:MetadataOnlyForPng','Metadata is supported only for .png files.');
else
Command = sprintf('identify -verbose %s',Filename);
[~,PngInfo] = dos(Command);
Data = regexp(PngInfo,['(?<=MyMetaData:\s)[^' char([10 13]) ']*'],'match','once');
if isempty(Data)
warning('Zeisig:IoFun:TexTab:NoMetadata','No Metadata found.');
else
CsvData = regexprep(Data,';',char(10));
Lines = regexp(Data, ';','split');
Cells = regexp(Lines(1:end-1),',','split');
Data_ = reshape([Cells{:}],length(Cells),length(Cells{1}));
Data_ = Data_';
end
end
end
function png2csv(Source,Dest)
% png2csv(Source,Dest)
% Gets TexTab metadata from a .png file created by this class and writes a csv file
% containing this metadata.
% Source ist the png file
% Dest is the csv file.
%
% See also:
% png2data
[~,Data] = IoFun.TexTab.png2data(Source);
fid = fopen(Dest,'w+');
if fid==-1
error('Could not create CSV file. Try to close all programms which have might have opened the file.');
end
fprintf(fid,'%c',Data);
fclose(fid);
end
end
end
function ResCell = cellfunMr(fname,C,D,varargin)
%function ResCell = cellfunMr(fname,C,D,varargin)
%Is the same as Matlab's buid-in cellfun function, but
%it accepts scalar values for the input parameter D or C.
%
%See also:
%cellfun
if ~iscell(D)
D = {D};
elseif ~iscell(C)
C = {C};
end
if length(D)== 1
D= repmat(D,size(C));
elseif length(C) == 1
C = repmat(C,size(D));
end
try
ResCell = cellfun(fname,C,D);
catch ME
if strcmp(ME.identifier,'MATLAB:cellfun:NotAScalarOutput')
ResCell = cellfun(fname,C,D,'uniformoutput',false);
end
end
end
function str = cell2str(cell)
% function str = cell2str(cell)
% Creates a string from a cell string. Each line of the str is finished with a char(10).
cr = char(10);
str = '';
for i = 1:size(cell,1)
str = [str cr cell{i,:}]; %#ok<AGROW> %This function is not intended for huge cells
end
str(1)=[];
end