Attractive 3D plot in R
Asked Answered
W

1

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

Weinman answered 21/4, 2013 at 10:5 Comment(4)
Can you show what you have tried?Apprentice
Sure, just adding it now.Weinman
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.Obsession
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.Weinman
C
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

Cocoa answered 21/4, 2013 at 13:4 Comment(4)
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?Weinman
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!).Cocoa
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. :)Weinman
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.Cocoa

© 2022 - 2024 — McMap. All rights reserved.