9

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?

9

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

  • Hi Christian. I got this example working, but am still having troubles with my data set. I am a bit confused about the X, Y and Z axis considering my data is only X and Y. In my case, the x axis and y axis data can be generated in MATLAB using the following: tau = linspace(0.001,1,20); data = cell2mat(arrayfun(@(x)exp(-x.*tau),[1:0.1:2]','UniformOutput',0)); data now contains 20 columns of data, all to be plotted vs tau, as done in MATLAB using plot(tau,data). From here I have tried a few things but still cant reproduce the MATLAB plot in pgfplots. Thanks. – Steve Hatcher Sep 3 '14 at 5:16
  • It sounds as if you can use [X,Y] = meshgrid([1:0.1:2], linspace(0.001,1,20)); Z = exp(-X.*Y) and proceed according to my answer. The procedure with mesh grid combined with matrix operations is matlab's way to generate two dimensional functions -- arrayfun is "useful for functions that do not accept array arguments. If the function does accept array arguments it is better to call the function directly." (from its documentation). Alternatively, you can generate the missing X and Y matrices using repmat (if I remember correctly). – Christian Feuersänger Sep 3 '14 at 18:26
  • Hi Christian, thanks for your time. I apologize as I must not have been very clear in my question. My MATLAB code was just to generate 2-d data for the purpose of this question. In reality, my data comes out in the form of x, y1, y2, y3, y4. Of which the x is the x axis, and y are the individual plots I want superimpose on 1 plot in pgfplots. In this case there is no Z, so I do not know how to proceed from here. I have uploaded an example here: pastebin.com/R8nC0zq4, if you could show me how to produce the plot using this example it will clear it up for me. Thanks – Steve Hatcher Sep 12 '14 at 0:12
  • @SteveHatcher I think we have to state that my solution is difficult to fit to your use-case. Perhaps we should go back to the first step and re-answer your question tex.stackexchange.com/questions/197934/… with our improved understanding? Perhaps we address your needs if you open another question like that, add your pastebin link and show the matlab code. This will allow me to step back and rethink about the problem. Maybe someone else contributes a good (different) solution which is better to apply than mine. – Christian Feuersänger Sep 12 '14 at 15:35
  • Hi Christian. Sure, I will post a new question and this time be more clear about what I want. Thanks for your solution though, it actually solved something which I would have asked down the track. – Steve Hatcher Sep 12 '14 at 15:55

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.