2

I'm trying to create 3D plots of simulated tree roots in R. Here is an example of a root system growing over time:

image 1

This is essentially a 3D network of cylinders, where the cylinder diameter (and, optionally, color) represents the size of the root. The available data includes:

  • x, y, z of the root centroid
  • direction of "parent" root (e.g. +x, -x, +y, -y, +z, -z), although this information could be captured in several different ways, including by calculating the x, y, z of the parent directly prior to plotting.
  • size of root

Example 3D data is here, but here is my first attempt at it in just 2D using ggplot2::geom_spoke:

dat <- data.frame(x = c(0,1,-1,0,1,-1),
              y = c(-1,-1,-1,-2,-2,-2),
              biomass = c(3,1.5,1.5,1,1,1), 
              parent.dir = c("+y","-x","+x","+y","+y","+y"))
dat$parent.dir <- as.numeric(as.character(factor(dat$parent.dir, 
                                             levels = c("-x", "+x", "-y", "+y"),
                                             labels = c(pi, 0, pi*3/2, pi/2)))) 

ggplot(dat, aes(x = x, y = y)) +
  geom_point(x = 0, y = 0, size = 20) +
  geom_spoke(radius = 1,
         aes(angle = parent.dir,
             size  = biomass)) + 
  coord_equal()

enter image description here

I prefer a solution based in the ggplot2 framework, but I realize that there are not a ton of 3D options for ggplot2. One interesting approach could be to creatively utilize the concept of network graphs via the ggraph and tidygraph packages. While those packages only operate in 2D as far as I know, their developer has also had some interesting related ideas in 3D that could also be applied.

The rgl library in seems to be the go-to for 3D plots in R, but an rgl solution just seems so much more complex and lacks the other benefits of ggplot2, such as faceting by year as in the example, easily adjusting scales, etc.

Example data is here:

Kevin
  • 491
  • 3
  • 10
  • "Not a ton" in my understanding is close or equal to "none". The `lattice` plotting paradigm has all the features that you ask for: facetting and adjustment of scales. You still need to post a (complete) data example (not just a handwaving sketch) if you don't want this question closed. See [MCVE] and search SO for "R great reproducible example" for tips on data presentations that "work". – IRTFM Feb 24 '18 at 21:37
  • I don't have any example code as I don't even know what package can do something like this. This question is intended to gather ideas. Is there a better place to post a question like this? – Kevin Feb 24 '18 at 22:27
  • Well, not here. Requests for package recommendations are reason for closure. – IRTFM Feb 24 '18 at 23:45
  • I've added example data and a working 2D example to start from. – Kevin Feb 25 '18 at 15:52
  • Here's how I would approach it: The lattice package has a `panel.3dscatter`-function which is really set up to plot points. It's available as an ordinary function (rather than requiring understanding `ggproto` methods). I would copy it to a function named `panel.3dsegments`, change the points plotting grid calls to segments calls and add whatever extra parameters to the arguments list that would be needed to support your data scheme. (It already has code that constructs 3d-segments, although it is only used to support a histogram like construction.) – IRTFM Feb 25 '18 at 18:35
  • Looking at your data file, I'm unable to find sufficient elements to complete the parameters that would be needed. I thought you wanted segments of varying width and length. And the "size" seems to vary over 3 orders of magnitude so I'm not sure that will be easy to visualize. – IRTFM Feb 25 '18 at 21:16

1 Answers1

1

I don't understand the format of your data so I'm sure this isn't the display you want, but it shows how to draw a bunch of cylinders in rgl:

root <- read.csv("~/temp/root.csv")
segments <- data.frame(row.names = unique(root$parent.direction),
                       x = c(-1,0,1,0,0),
                       y = c(0,1,0,0,-1),
                       z = c(0,0,0,0.2,0))
library(rgl)
open3d()
for (i in seq_len(nrow(root))) {
        rbind(root[i,2:4], 
              root[i,2:4] - segments[root$parent.direction[i],]) %>%
        cylinder3d(radius = root$size[i]^0.3, closed = -2, sides = 20) %>%
        shade3d(col = "green")
}
decorate3d() 

This gives the following display (rotatable in the original):

Lots of cylinders

You can pass each cylinder through addNormals if you want it to look smooth, or use sides = <some big number> in the cylinder3d to make them look rounder.

user2554330
  • 37,248
  • 4
  • 43
  • 90