Splot points over pm3d surface in gnuplot

I have plotted a sphere using gnuplot in parametric mode. I am trying to plot 3d data from a file, which will surround the sphere. It seems that the points with overlap with the sphere are hidden even though they should be in front of the shape.

Here's my script:

unset border
unset colorbox
unset key
unset tics

set view equal
set isosamples 64

set pm3d depthorder interpolate 0,0
set palette rgb 3,3,3

set parametric
r = 19

splot 'saturn.txt' linecolor rgb 'black', 
r*sin(u)*cos(v) + 40, r*sin(u)*sin(v) + 40, r * cos(u) + 40.5 w pm3d

Here is the data file, saturn.txt on pastebin

The image below shows my problem. On the left is the full set of data plotted without the sphere. In the middle it can be seen that there are points missing from in front of the sphere. The view on the right shows that these points are definitely in front of the sphere. Is there any way I can plot both at the same time without the points in front of the sphere being hidden?

image showing the problem

I found the answer, in this gnuplotting article:

set hidden3d front

Why exactly that works is a mystery to me. I couldn't find anything relevant in the gnuplot manual about it.

Here's the final plot:

i modified your code a bit.


it's generally better practice to use the data argument than to use predictor variables extracted from a data frame via $:


we can use expand.grid() and predict() to get the regression results in a clean way:

perot <- seq(1000,40000,by=1000)
gore <-  seq(1000,400000,by=2000)

if you want the facets evaluated at the locations of the observations, you can use perot <- sort(unique(ex1222$perot96)); gore <- sort(unique(ex1222$gore2000)) instead.

pframe <- with(ex1222,expand.grid(perot96=perot,gore2000=gore))
mlrpred <- predict(mlr,newdata=pframe)

now convert the predictions to a matrix:

nrz <- length(perot)
ncz <- length(gore)
z <- matrix(mlrpred,nrow=nrz)

i chose to go from light red (#ffcccc, red with quite a bit of blue/green) to dark red (#cc0000, a bit of red with nothing else).

jet.colors <- colorramppalette( c("#ffcccc", "#cc0000") ) 

you could also use grep("red",colors(),value=true) to see what reds r has built in.

# generate the desired number of colors from this palette
nbcol <- 100
color <- jet.colors(nbcol)

# compute the z-value at the facet centres
zfacet <- z[-1, -1] + z[-1, -ncz] + z[-nrz, -1] + z[-nrz, -ncz]
# recode facet z-values into color indices
facetcol <- cut(zfacet, nbcol)

persp(perot, gore, z,
      col=color[facetcol],theta=-30, lwd=.3,
      xlab="perot 96", ylab="gore 2000", zlab="predicted votes for buchanan")

you say you're "not super happy with the readability" of the plot, but that's not very specific ... i would spend a while with the ?persp page to see what some of your options are ...

another choice is the rgl package:

## see ?persp3d for discussion of colour handling
vertcol <- cut(z, nbcol)
persp3d(perot, gore, z,
      xlab="perot 96", ylab="gore 2000", zlab="predicted votes for buchanan")

it might also be worth taking a look at scatter3d from the car package (there are other posts on so describing how to tweak some of its graphical properties).


the type of plot you are trying to make may be difficult to visualize well. i can give you two suggestions: one is what you want, and one is what you should probably do instead...

plotting 4-d data:

in order to do this, you will have to plot a series of x,y,t points and somehow represent the error value e at each point. you could do this by changing the color or size of the point. in this example, i'll plot a sphere at each point with a diameter that varies based on the error (a diameter of 1 equates to the maximum expected error). the color represents the time. i'll be using the sample data you added to the question (formatted as a 5-by-4 matrix with the columns containing the x, y, t, and e data):

data = [4 5 2 45; 4 5 6 54; 7 8 2 32; 7 8 9 98; 7 8 1 121];
[x, y, z] = sphere;  % coordinate data for sphere
max_error = 121;     % maximum expected error
for i = 1:size(data, 1)
  c = 0.5*data(i, 4)/max_error;  % scale factor for sphere
  x = x.*c+data(i, 1);           % new x coordinates for sphere
  y = y.*c+data(i, 2);           % new y coordinates for sphere
  z = z.*c+data(i, 3);           % new z coordinates for sphere
  surface(x, y, z, 'edgecolor', 'none');  % plot sphere
  hold on
grid on
axis equal
view(-27, 16);

and here's what it would look like:

the problem: although the plot looks kind of interesting, it's not very intuitive. also, plotting lots of points in this way will get cluttered and it will be hard to see them all well.

more intuitive 3-d plot:

it may be better to instead make a 3-d plot of the data, since it may be easier to interpret. here, the x-axis represents the iteration number and the y-axis represents each individual network:

plot3(1:2, [1 1], [2 45; 6 54]);           % plot data for network 4-5
hold on
plot3(1:3, [2 2 2], [2 32; 9 98; 1 121]);  % plot data for network 7-8
xlabel('iteration number');
set(gca, 'ytick', [1 2], 'yticklabel', {'network 4-5', 'network 7-8'})
grid on
legend('time', 'error')
view(-18, 30)

this produces a much clearer plot:

in 2d (using plot) it is true, that an empty line leads to disconnected line parts, see e.g.

set autoscale fix
set offset 0.5,0.5,0.5,0.5
plot 'box.dat' using 1:3 w l

in 3d (with splot) a newline separates two lines of a surface. the same points of neighboring lines are then connected to form a surface. in order to get disconnected line segments in 3d you must use two newlines:

# box.dat
0 0 0 
1 0 0

0 0 1  
1 0 1

you can give using a format specification; here we need to tell the seperator ','. the following works for me:

splot 'data.csv' using 1:2:3 '%lf,%lf,%lf,%lf' with linespoints pt 6 ps 2 lw 3

except that the first line is ignored, which is probably right?

Tags: 3D Plot Gnuplot