How to plot a surface from a set of data?

If you have octave installed, you can triangulate the data from within your LaTeX document using the \addplot shell functionality and plot it using the patch plot style.

\documentclass[border= 5mm]{standalone}
\usepackage{pgfplots}

\begin{document}
    \begin{tikzpicture}
    \begin{axis}
        \addplot3 [patch, patch table={triangles.txt}
   ] shell {echo "data=dlmread('data.txt');
    tri=delaunay(data(:,1), data(:,2));
    dlmwrite('triangles.txt',tri-1,' ');
    disp(data)" | octave --silent};
    \end{axis}
    \end{tikzpicture}
\end{document}

You can also grid the data:

\documentclass[border= 5mm]{standalone}
\usepackage{pgfplots}

\begin{document}
    \begin{tikzpicture}
    \begin{axis}
    \addplot3 [surf, mesh/cols=50, z buffer=sort, restrict z to domain=0:inf, shader=faceted interp] shell {
    echo "
        data=dlmread('data.txt');
        res=\pgfkeysvalueof{/pgfplots/mesh/cols};
        [xx,yy] = meshgrid(linspace(min(data(:,1)), max(data(:,1)),res), linspace(min(data(:,2)), max(data(:,2)),res));
        zz=griddata(data(:,1),data(:,2),data(:,3),xx,yy);
        zz(isnan(zz))=-999;
        disp([xx(:) yy(:) zz(:)])
    " | octave --silent};   
    \addplot3 [only marks] file {data.txt};
    \end{axis}
    \end{tikzpicture}
\end{document}

Gnuplot could be used to interpolate scattered data, but the available interpolation functions don't work particularly well for this dataset.

\documentclass[border= 5mm]{standalone}
\usepackage{pgfplots}

\begin{document}
    \begin{tikzpicture}
    \begin{axis}
    \addplot3 [surf] gnuplot [raw gnuplot] {
        set dgrid3d 30,30 spline;
        splot 'data.txt';       
    };
    \addplot3 [only marks] table {data.txt};
    \end{axis}
    \end{tikzpicture}
\end{document}

enter image description here

Check out this kind of a closed surface, produced with the Asymptote. A brief description:

  • The data are stored in a file s.dat;
  • since the data are not based on a regular grid, a 2d triangulation is used on x,y points;
  • a surface is constructed from corresponding 3d triangles;
  • z-value and two colors, pzmin and pzmax are used to color it.

irrsurf.tex

\begin{filecontents*}{s.dat}
#x       y       z
2.17    0.001   0.82044815
2.17    0.002   0.82345825
2.17    0.004   0.82679255
2.17    0.008   0.83334715
2.17    0.016   0.84395915
2.17    0.032   0.8584953
2.21    0.001   0.77582165
2.21    0.003   0.78520505
2.21    0.009   0.80205985
2.21    0.027   0.83085105
2.24    0.001   0.7227885
2.24    0.002   0.73391615
2.24    0.005   0.7543979
2.24    0.015   0.78798745
2.24    0.003   0.74176635
2.24    0.009   0.77064805
2.24    0.027   0.81042375
2.26    0.001   0.66545585
2.26    0.003   0.7012046
2.26    0.005   0.721067
2.26    0.009   0.7447984
2.26    0.015   0.76715245
2.26    0.027   0.794177
2.27    0.001   0.62916195
2.27    0.003   0.6774642
2.27    0.009   0.72961785
2.27    0.027   0.7861086
2.28    0.001   0.5750828
2.28    0.003   0.65059675
2.28    0.005   0.6802631
2.28    0.009   0.7145367
2.28    0.015   0.74447695
2.28    0.027   0.7774403
2.29    0.001   0.51357255
2.29    0.002   0.581053
2.29    0.003   0.6173075
2.29    0.009   0.6972096
2.29    0.027   0.76793225
2.31    0.001   0.36997965
2.31    0.002   0.474415
2.31    0.003   0.53649295
2.31    0.009   0.6587164
2.31    0.016   0.70870255
2.31    0.027   0.7482423
2.31    0.05    0.7912395
2.34    0.001   0.2204104
2.34    0.002   0.316308
2.34    0.003   0.39256745
2.34    0.004   0.45240835
2.34    0.009   0.5883453
2.34    0.016   0.6590771
2.34    0.027   0.71444205
2.34    0.05    0.7690014
2.38    0.001   0.13286995
2.38    0.002   0.1828288
2.38    0.004   0.2980268
2.38    0.008   0.4507145
2.38    0.016   0.58417075
2.38    0.032   0.6833616
\end{filecontents*}
\documentclass[10pt,a4paper]{article}
\usepackage{lmodern}
\usepackage[inline]{asymptote}
\begin{document}
\begin{figure}
\begin{asy}
settings.outformat="pdf";
settings.prc=false;
settings.render=0;

import graph3;
size3(200,200,80,IgnoreAspect);
size(300,300,IgnoreAspect);

file fin=input("s.dat");
real[][] A=fin.dimension(0,3);
A=transpose(A);

real xmin=min(A[0]);
real xmax=max(A[0]);
real ymin=min(A[1]);
real ymax=max(A[1]);
real zmin=min(A[2]);
real zmax=max(A[2]);

currentprojection=orthographic(
camera=(18.8549512615229,-2.05615180783542,61.9196974622481),
up=Z,
target=0.5((xmin,ymin,zmin)+(xmax,ymax,zmax)),
zoom=0.7);

pair[] p=new pair[A[0].length]; // conversion to pairs x,y 
for(int i=0;i<p.length;++i){    //   to get a triangulation
  p[i]=(A[0][i],A[1][i]);       // 
}                               // 
int[][] trn=triangulate(p);     //

pen pzmin=rgb(0,1,0);           // pen for min z
pen pzmax=rgb(0.8,0.8,1);       // pen for max z

pen[] zpen(triple a,triple b,triple c){  // return z-pen for three vertices
  pen[]zp=new pen[3];
  real t;
    t=(a.z-zmin)/(zmax-zmin);  
      zp[0]=(1-t)*pzmin+t*pzmax+opacity(0.9);
    t=(b.z-zmin)/(zmax-zmin);  
      zp[1]=(1-t)*pzmin+t*pzmax+opacity(0.9);
    t=(c.z-zmin)/(zmax-zmin);  
      zp[2]=(1-t)*pzmin+t*pzmax+opacity(0.9);
  return zp;
}

triple a,b,c;
for(int i=0; i < trn.length; ++i) {
  a=(A[0][trn[i][0]],A[1][trn[i][0]],A[2][trn[i][0]]);
  b=(A[0][trn[i][1]],A[1][trn[i][1]],A[2][trn[i][1]]);
  c=(A[0][trn[i][2]],A[1][trn[i][2]],A[2][trn[i][2]]);
  draw(surface(a--b--c--cycle),zpen(a,b,c));        // draw i-th triangle
}

defaultpen(fontsize(10pt));

xaxis3(Label("$x$",align=-3Z),Bounds, xmin,xmax,InTicks(Step=0.05,step=0.01));
yaxis3(Label("$y$",align=-3Z),Bounds, ymin,ymax,InTicks(Step=0.01,step=0.002));
zaxis3(Label("$z$",align=-3Y),Bounds, zmin,zmax,InTicks());
\end{asy}
\caption{Surface constructed from an array of irregularly spaced points.}
\end{figure}
\end{document}

To process it with latexmk, create file latexmkrc:

sub asy {return system("asy '$_[0]'");}
add_cus_dep("asy","eps",0,"asy");
add_cus_dep("asy","pdf",0,"asy");
add_cus_dep("asy","tex",0,"asy");

and run latexmk -pdf irrsurf.tex.


pgfplots supports two input formats for closed surfaces: either a regular grid (i.e. matrix form with N rows and M cols) or free-form patches where you have to triangulate the surface and provide the patches either as adjacency matrix or one patch after the other.

You can find details about both formats in the manual sections for the surfplot handler or the patch plot handler.

It cannot triangular your data automatically. Consequently, you would need a 3rd party tool to convert it. This can be mathematica as in your screenshot. Judging from that screenshot, it seems that mathematica has interpolated it on a regular grid. If you export that grid in a CSV file, you can immediately read that file by means of pgfplots.