6

I am writing a proposal and need a 3D plot something like this:

enter image description here

but preferably more attractive. I need the size of each point to reflect the abundance of the species and an outline of the volume created by connecting the points.

Sample data:

input<-data.frame(
label=c("sp1","sp2","sp3","sp4"),
trait_x=c(6,6,6,1),
trait_y=c(7,7,7,1),
trait_z=c(8,8,8,1),
point_size=c(6,7,8,1)
)
input
  label trait_x trait_y trait_z point_size
1   sp1       6       7       8        6
2   sp2       6       7       8        7
3   sp3       6       7       8        8
4   sp4       1       1       1        1

Any suggestion on how to make such a graph more attractive (perhaps including gridlines? I do not want any numbers on the axes however)

I have played around with scatterplot3d, but it doesn't plot all my points and I personally find that the cube has a strange look to it... like it is not quite accurate...

library(scatterplot3d)
x<-input$trait_x
y<-input$trait_y
z<-input$trait_z
scatterplot3d(x,y,z,xlim=c(0,10),ylim=c(0,10),zlim=c(0,10))

enter image description here

D Mac
  • 3,727
  • 1
  • 25
  • 32
Elizabeth
  • 6,391
  • 17
  • 62
  • 90
  • Can you show what you have tried? – user1317221_G Apr 21 '13 at 10:08
  • Sure, just adding it now. – Elizabeth Apr 21 '13 at 10:27
  • 1
    Is it more of an illustration than an exact plot? If you only have four blobs on it it might be easier to just draw it with a graphics package. The other option is the rgl package that does dynamic 3d graphics. – Spacedman Apr 21 '13 at 10:34
  • Yes exactly. It is just an illustration to show a concept. Having said that I want to find something that shows that I am ready to analyse something far more complex if needed. – Elizabeth Apr 21 '13 at 11:25

1 Answers1

14

This should get you started using package rgl. Note: On re-read I see I am using your xyz coords a little different than you did, but the concept is the same.

input<-data.frame( # I adjusted the values for better appearance in demo
label=c("sp1","sp2","sp3","sp4"),
trait_x=c(6,7,11,1),
trait_y=c(10,7,9,1),
trait_z=c(4,7,6,1),
point_size=c(6,7,8,1)
)
names(input) <- c("name", "x", "y", "z", "radius")
input$radius <- input$radius*0.2

require("rgl")

spheres3d(input[,2:4], radius = input[,5], col = c("red", "green", "blue", "orange"), alpha = 0.5)
axes3d(box = TRUE)
title3d(xlab = "x_trait", ylab = "y_trait", zlab = "z_trait")
text3d(input[1,2:4], texts = "species X")
# next line is clunky but you can do it more elegantly
segs <- rbind(input[1:2,2:4], input[2:3,2:4], input[3:4,2:4], input[c(4,1),2:4])
segments3d(segs)

Now you can rotate your diagram interactively and then use rgl.snapshot to get a hardcopy (using antialias arguments in spheres3d will improve the diagram).

enter image description here

Bryan Hanson
  • 6,055
  • 4
  • 41
  • 78
  • Very pretty! Thanks Bryan. Instead of connecting the centres of each point with lines do you know of anyway to show the volume that these points create in the 3D space (i.e. what is known as convex hull volume...basically placing shrink wrap around all the points and showing the 'cloud' of space the points occupy) Sorry my explanation is a bit rough. Do you know what I mean though? – Elizabeth Apr 21 '13 at 16:05
  • I know what you are talking about but have never done it. I'm pretty sure it is implemented in a number of packages: `install.packages("sos"); library("sos"); findFn("convex hull")`. But remember your points are really spheres around a point, so think carefully about what such a shrink wrap would represent in terms of the science. Depending upon the meaning of your dimensions and the sphere size, maybe something like an ellipsoid would be more appropriate (but mostly I mention that because I know how to do that!). – Bryan Hanson Apr 21 '13 at 20:33
  • True. You have more than answered my question but I am going to be cheeky now and ask how to apply an ellipsoid to the existing graph, get rid of the numbers on the axes. :) – Elizabeth Apr 21 '13 at 20:51
  • 1
    Checking `?axes3d` looks like setting `ticks = FALSE` or some combo of arguments will give you just a simple bounding box. Using an ellipsoid assumes all these points are independent measures of the same space/parameters (but I think yours are made up for a demo, so you can call them independent!). But, to do it, `install.packages("ChemoSpec"); library("ChemoSpec")` then see `?makeEllipsoid` If you pass your points to that function, you'll get back xyz coords of the enclosing ellipsoid which you can add to your `rgl` plot using `points3d` and plot the points very tiny, or use transparency. – Bryan Hanson Apr 21 '13 at 22:01