Graham G Graham G - 1 month ago 5x
R Question

how to plot non-convex surface from set of n x 3 data

Is there a straight forward way to plot a non-convex surface in R?

I have used something like the following for convex surfaces and it works fine:

xyz <- cbind(y,x,z)
tbr <- t(surf.tri(xyz, delaunayn(xyz)))
rgl.triangles(xyz[tbr,1], xyz[tbr,2], xyz[tbr,3])

However, for non-convex surfaces, concave areas become filled. I think this is a problem with the function
as it uses the Qhull library which does not support constrained Delaunay triangulations or mesh generation of non-convex objects.

Any suggestions appreciated.


I have data as an ascii file but it has 3 columns and is 225 lines long. What is the best way of providing this?

Data available at:

The top of the plot should be concave! This is an image created using
of how the surface should look. It has been calculated using more grid points on a regular grid in polar coordinates, rather than using irregular collocation points.

Correct rendering of surface, but with more grid points.


The following solution is not perfect, but works if you have a copy of Matlab.

# Read in data - also at:
simDat <- read.csv("testDat.csv")
x   <- simDat[,1];y<-simDat[,2];z<-simDat[,3]
xyz <- cbind(simDat[,1],simDat[,2],simDat[,3])
triNodes <- delaunayn(xyz)
tbr1     <- t(surf.tri(xyz, triNodes ))
# Plot data from R generated triangles
rgl.triangles(xyz[tbr1,1], xyz[tbr1,2], xyz[tbr1,3])
# Import data generated by Matlab function delaunay()
#  - also at:
nodeDat_ML <- read.csv("testDatNodes.csv")
triNodes2  <- cbind(nodeDat_ML[,1], nodeDat_ML[,2], nodeDat_ML[,3],1)
tbr2 <- t(surf.tri(xyz, triNodes2))
# Plot data from Matlab generated triangles
rgl.triangles(xyz[tbr2,1], xyz[tbr2,2], xyz[tbr2,3])

The code produces the following two surfaces. The left plot is based on triangulation generated by the R function delaunayn(), and the right plot is based on triangulation generated from the Matlab function delaunay().

Plots from R and Matlab generated triangulations

The Matlab generated data is available at:

and the associated Matblab code is:

fname = 'testDat.csv';
tt = table2array(readtable(fname)); % get data
x =  tt(:,1);y = tt(:,2);z = tt(:,3);
tri = delaunay(x,y); % the triangulation data
trisurf(tri,x(:,1),y(:,1),z(:,1)); % surface plot

The result is not entirely perfect as the final plot (right) has a spurious triangle.

I hope the above will be useful to anyone with a similar problem.