[Tex/LaTex] How to import matrix data (2d function) from matlab into pgfplots

importmatlab2tikzpgfplots

This question arised in Spectrum colormap for multiple curves, but since it is of general interest, I add a separate question and my answer here.

Suppose you have a matlab figure which needs to be converted to pgfplots. The matlab figure contains a 2d function f(x,y) which is typically visualized as a matrix.

Suppose it is given as

[X,Y] = meshgrid( linspace(-1,1,3), linspace(4,5,5) );
Z = X + Y;
surf(X,Y,Z)
shading interp

such that

octave:7> Z
Z =

   3.0000   4.0000   5.0000
   3.2500   4.2500   5.2500
   3.5000   4.5000   5.5000
   3.7500   4.7500   5.7500
   4.0000   5.0000   6.0000

and the outcome is

enter image description here

I would like to reproduce that in pgfplots. To this end, I saved the Z matrix as ascii and imported it into an \addplot3 table statement:

\documentclass{standalone}

\usepackage{pgfplots}

\pgfplotsset{compat=1.9}


\begin{document}

\begin{tikzpicture}
    \begin{axis}
    \addplot3[surf] table {
  3.0000   4.0000   5.0000
   3.2500   4.2500   5.2500
   3.5000   4.5000   5.5000
   3.7500   4.7500   5.7500
   4.0000   5.0000   6.0000

    };
    \end{axis}
\end{tikzpicture}
\end{document}

which leads to the unexpected result

enter image description here

How can I reproduce my intented surface plot?

Best Answer

pgfplots expects a different input format, namely a table of the form

X Y Z
. . .
. . .
. . .

in which the matrix data is serialized into a long stream. It resembles matlab's matrix(:) syntax.

Consequently, you can export you data by means of

data = [ X(:) Y(:) Z(:) ]
save -ascii P.dat data
% save P.dat data -ASCII

size(Z)

data =

  -1.00000   4.00000   3.00000
  -1.00000   4.25000   3.25000
  -1.00000   4.50000   3.50000
  -1.00000   4.75000   3.75000
  -1.00000   5.00000   4.00000
   0.00000   4.00000   4.00000
   0.00000   4.25000   4.25000
   0.00000   4.50000   4.50000
   0.00000   4.75000   4.75000
   0.00000   5.00000   5.00000
   1.00000   4.00000   5.00000
   1.00000   4.25000   5.25000
   1.00000   4.50000   5.50000
   1.00000   4.75000   5.75000
   1.00000   5.00000   6.00000

ans =

   5   3

and use

\documentclass{standalone}

\usepackage{pgfplots}

\pgfplotsset{compat=1.9}

\begin{document}

\begin{tikzpicture}
    \begin{axis}[colorbar,view={-60}{30}, colormap/jet,shader=interp]
    \addplot3[surf,mesh/rows=5,mesh/ordering=y varies] table {
 -1.00000000e+00 4.00000000e+00 3.00000000e+00
 -1.00000000e+00 4.25000000e+00 3.25000000e+00
 -1.00000000e+00 4.50000000e+00 3.50000000e+00
 -1.00000000e+00 4.75000000e+00 3.75000000e+00
 -1.00000000e+00 5.00000000e+00 4.00000000e+00
 0.00000000e+00 4.00000000e+00 4.00000000e+00
 0.00000000e+00 4.25000000e+00 4.25000000e+00
 0.00000000e+00 4.50000000e+00 4.50000000e+00
 0.00000000e+00 4.75000000e+00 4.75000000e+00
 0.00000000e+00 5.00000000e+00 5.00000000e+00
 1.00000000e+00 4.00000000e+00 5.00000000e+00
 1.00000000e+00 4.25000000e+00 5.25000000e+00
 1.00000000e+00 4.50000000e+00 5.50000000e+00
 1.00000000e+00 4.75000000e+00 5.75000000e+00
 1.00000000e+00 5.00000000e+00 6.00000000e+00
    };
    \end{axis}
\end{tikzpicture}
\end{document}

where the data table is the contents of P.dat (could have been imported using \addplot3[...] table {P.dat}; as well). The key is that we need to tell pgfplots how to read the file: we need to say at least one of the matrix dimensions (mesh/rows=5 here) and we need to say how it is linearized (mesh/ordering=y varies in our case because that's how the matrix is lineared by means of data(:)). The outcome is

enter image description here

The view argument is imprecise (I suppose it is of less importance here).


For the sake of completeness (the original question in Spectrum colormap for multiple curves was about line plots), I also show how to use patch type=line here in order to show each scanline as a line plot with individual color:

\documentclass{standalone}

\usepackage{pgfplots}

\pgfplotsset{compat=1.9}

\begin{document}

\begin{tikzpicture}
    \begin{axis}[colorbar,view={-60}{30}, colormap/jet,shader=interp]

    \addplot3[
        mesh,
        mesh/rows=5,mesh/ordering=y varies,
        patch type=line,
        point meta=x,
    ]
    table {
 -1.00000000e+00 4.00000000e+00 3.00000000e+00
 -1.00000000e+00 4.25000000e+00 3.25000000e+00
 -1.00000000e+00 4.50000000e+00 3.50000000e+00
 -1.00000000e+00 4.75000000e+00 3.75000000e+00
 -1.00000000e+00 5.00000000e+00 4.00000000e+00
 0.00000000e+00 4.00000000e+00 4.00000000e+00
 0.00000000e+00 4.25000000e+00 4.25000000e+00
 0.00000000e+00 4.50000000e+00 4.50000000e+00
 0.00000000e+00 4.75000000e+00 4.75000000e+00
 0.00000000e+00 5.00000000e+00 5.00000000e+00
 1.00000000e+00 4.00000000e+00 5.00000000e+00
 1.00000000e+00 4.25000000e+00 5.25000000e+00
 1.00000000e+00 4.50000000e+00 5.50000000e+00
 1.00000000e+00 4.75000000e+00 5.75000000e+00
 1.00000000e+00 5.00000000e+00 6.00000000e+00
    };
    \end{axis}
\end{tikzpicture}
\end{document}

Here, point meta plays the role of "color data". In this case, color data is from the x column that is: each scanline has the same color. If you want to have scan lines along y, you would need to transpose X, Y, and Z before exporting them to pgfplots.

enter image description here