Search code examples
r3drgl

Using RGL to plot 3d line segments in R


I having some problems with an application of the rgl 3d graphing package.

I'm trying to draw some line segments. And my data is arranged in a dataframe called 'markers' with six columns, one for each of the starting x, y, and z values, and one for each of the ending x, y, and z values.

startX  startY startZ endX   endY    endZ
69.345  45.732     20  115 39.072 1.92413
80.270  38.480     30  175 44.548 0.36777
99.590  33.596     20  175 35.224 0.06929
32.120  41.218     20  115 39.294 2.81424
11.775  37.000     30  175 35.890 1.38047
76.820  44.104     22  115 44.992 4.14674
85.790  23.384     18  115 36.112 0.40508
80.040  17.464     20  175 31.080 2.59038
103.615 38.850     22  115 39.220 3.18201
41.200  31.006     30  175 36.260 3.48049
88.665  43.956     30  115 39.738 0.50635
109.365 23.976     20  175 33.374 3.99750

This should be a piece of cake. Just feed those values to the segment3d() command and I should get the plot I want. Only I can't figure out how to correctly pass the respective starting and ending pairs into segment3d().

I've tried just about everything possible ($ notation, indexing, concatenating, using a loop, apply and sapply, etc.), including reading the documentation. It's great, it says for the arguments x, y, and z: "Any reasonable way of defining the coordinates is acceptable." Ugh... it does refer you to the xyz.coords utility.

So I went over that documentation. And I think I understand what it does; I can even use it to standardize my data e.g.

starts <- xyz.coords(markers$startX, markers$startY, markers$startZ)

ends <- xyz.coords(markers$endX, markers$endY, markers$endZ)

But then I'm still not sure what to do with those two lists.

segments3d(starts, ends)
segments3d(starts + ends) 
segments3d((starts, ends), (starts, ends), (starts, ends))
segments3d(c(starts, ends), c(starts, ends), c(starts, ends))
segments3d(c(starts$x, ends$x), c(starts$y, ends$y), c(starts$z, ends$z))

I mean I know why the above don't work. I'm basically just trying things at this point as this is making me feel incredibly stupid, like there is something obvious—I mean facepalm level obvious—I'm missing.

I went through the rgl documentation itself looking for an example, and the only place I found them using segment3d() in any manner resembling what I'm trying to do, they used the '+' notation I tried above. Basically they built 2 matrices and added the second to the first.


Solution

  • Something like this should work.

    library(rgl)
    open3d(scale=c(1/5,1,1))
    segments3d(x=as.vector(t(markers[,c(1,4)])),
               y=as.vector(t(markers[,c(2,5)])),
               z=as.vector(t(markers[,c(3,6)])))
    axes3d()
    title3d(xlab="X",ylab="Y",zlab="Z")
    

    enter image description here

    The problem is that segments3d(...) takes the x (and y and z) values in pairs. So rows 1-2 are the first segment, rows 3-4 are the second segment, etc. You need to interleave, e.g. $startx and $endx, etc. The code above does that.