Convirtiendo matrices MATLAB a formato LaTeX

En este post vamos a ver cómo convertir una matriz de MATLAB a un string en formato LaTeX, proponiendo en primera instancia un código muy simple y poco robusto, y posteriormente les compartiré un código desarrollado por Toby Driscoll que puede descargarse desde el File Exchange de MathWorks.

Sabrá que las matrices/arreglos en LaTeX suelen tener la sintaxis:

\begin{matrix}
a & b & c \\
d & e & f \\
g & h & i
\end{matrix}

Así, la idea en principio parece muy básica: recorrer todos los elementos de la matriz MATLAB por filas y columnas e ir formando el string final que se retornará como salida.

Vamos mostrando el código:

function out = matrix2latex(M,fmt)
%
% Argumentos de entrada:
%
% M - Matriz
% fmt - Cadena para especificar el formato ('%0.4f' default)
%
if nargin<2, fmt='%0.4f'; end;
out = ['begin{matrix}',sprintf('\n')];
for ii=1:size(M,1)
for jj=1:size(M,2)
ce = sprintf([fmt,blanks(2),'&',blanks(2)],M(ii,jj));
out = [out,ce]; %#ok
end
out = [out(1:end-3),'\\',sprintf('\n')];
end
out = [out(1:end-3), sprintf('\n\\end{matrix}')];
end

Esta función debe ejecutarse, pasando como argumento la matriz de la cual quiere obtenerse la representación LaTeX.

>> A=rand(3)

A =

0.1067 0.7749 0.0844
0.9619 0.8173 0.3998
0.0046 0.8687 0.2599

>> matrix2latex(A)

ans =

begin{matrix}
0.1067 & 0.7749 & 0.0844 \\
0.9619 & 0.8173 & 0.3998 \\
0.0046 & 0.8687 & 0.2599
\end{matrix}

¿Bastante bien, cierto?, sí, hasta cierto punto, pero es una porción de código sin testear más allá de algunos casos básicos considerados.

Por ello les adjunto enseguida un código compartido por Toby Driscoll en File Exchange el cual contiene al menos sentencias que verifican que los argumentos pasados sean del tipo esperado, y eso es bastante bueno, al menos para empezar.


function s = latex(M,varargin)
%LATEX Print a matrix in LaTeX tabular format.
% LATEX(M) prints out the numeric matrix M in a LaTeX tabular
% format. The '&' character appears between entries in a row, '\\'
% is appended to the ends of rows, and each entry is set in math
% mode. Complex numbers are understood, and exponentials will be
% converted to a suitable format.
%
% LATEX(M,'nomath') does not include the $$ needed to put each
% entry in math mode (e.g., for use with the amsmath matrix modes).
%
% LATEX(M,FMT) uses a format specifier FMT of the SPRINTF type for
% each entry.
%
% LATEX(M,FMT1,FMT2,...) works through the given format specifiers
% on each row of M. If fewer are given than the column size of M,
% the last is used repeatedly for the rest of the row.
%
% S = LATEX(M,...) does not display output but returns a character
% array S.
%
% Examples:
% latex( magic(4) )
% latex( magic(4), '%i', 'nomath' )
% latex( magic(4), '%i', '%.2f' )
%
% See also SPRINTF, SYM/LATEX.

% Copyright 2002 by Toby Driscoll. Last updated 12/06/02.

if ~isa(M,'double')
error('Works only for arrays of numbers.')
elseif ndims(M) > 2
error('Works only for 2D arrays.')
end

if nargin < 2
fmt = {'%#.5g'};
mathstr = '$';
else
fmt = varargin;
idx = strmatch('nomath',fmt);
if isempty(idx)
mathstr = '$';
else
mathstr = '';
fmt = fmt([1:idx-1 idx+1:end]);
if isempty(fmt), fmt = {'%#.5g'}; end
end
end

% Extend the format specifiers.
[m,n] = size(M);
if n > length(fmt)
[fmt{end:n}] = deal(fmt{end});
end

% Create one format for a row.
rowfmt = '';
for p = 1:n
% Remove blanks.
thisfmt = deblank(fmt{p});

% Add on imaginary part if needed.
if ~isreal(M(:,p))
% Use the same format as for the real part, but force a + sign for
% positive numbers.
ifmt = thisfmt;
j = findstr(ifmt,'%');
if ~any(strcmp(ifmt(j+1),['-';'+';' ';'#']))
ifmt = [ifmt(1:j) '+' ifmt(j+1:end)];
else
ifmt(j+1) = '+';
end
ifmt = [ifmt 'i'];
thisfmt = [thisfmt ifmt];
end

% Add to row.
rowfmt = [rowfmt mathstr thisfmt mathstr ' & '];
end

% After last column, remove column separator and put in newline.
rowfmt(end-1:end) = [];
rowfmt = [rowfmt '\\\\\n'];

% Use it.
A = M.';
if isreal(M)
S = sprintf(rowfmt,A);
else
S = sprintf(rowfmt,[real(A(:)) imag(A(:))].');
end

% Remove extraneous imaginary part for real entries.
if ~isreal(M)
zi = sprintf(ifmt,0);
S = strrep(S,zi,blanks(length(zi)));
end

% Remove NaNs.
S = strrep(S,'$NaN$','--');
S = strrep(S,'NaN','--');

% Convert 'e' exponents to LaTeX form. This is probably really slow, but
% what can you do without regular expressions?
S = strrep(S,'e','E');
ex = min(findstr(S,'E'));
while ~isempty(ex)
% Find first non-digit character. Where is ISDIGIT?
j = ex+2;
while ~isempty(str2num(S(j))) & ~strcmp(S(j),'i')
j = j+1;
end

% This strips off leading '+' and zeros.
num = sprintf('%i',str2num(S(ex+1:j-1)));

ee = ['\times 10^{' num '}'];
S = [S(1:ex-1) ee S(j:end)];

ex = ex + min(findstr(S(ex+1:end),'E'));
end

% For good form, remove that last '\\'.
S(end-2:end-1) = ' ';

% Display or output?
if nargout==0
disp(S)
else
s = S;
end

La ejecución de la función anterior es prácticamente similar a nuestra función propuesta:

>> A=rand(3)

A =

0.5499 0.6221 0.4018
0.1450 0.3510 0.0760
0.8530 0.5132 0.2399

>> latex(A)
$0.54986$ & $0.62206$ & $0.40181$ \\
$0.14495$ & $0.35095$ & $0.075967$ \\
$0.85303$ & $0.51325$ & $0.23992$

La salida, un tanto similar, si, cosas más cosas menos, pero la idea central es la misma.

Y bueno, en el siguiente link podrá encontrar más funciones similares que exportan cosas de MATLAB a código LaTeX, lo cual nunca está de más.

http://www.mathworks.com/matlabcentral/fileexchange/?term=latex&sort=ratings_desc

Comentarios

Comments powered by Disqus