1

I am trying to simulate the shape of the rings from a trunk section in R, but each time that I want to approach the real shape it get more difficult. I started doing it with four radii measurements, and I got a nice solution (see here). However, now I want to plot more than four radii but at different angles, and connect these points with a line simulating the rings like this sketch that I did: enter image description here

My first approach was to rotate the matrix of data, but I could not make that all radii started in the same position (0,0). I also tried to rate the axes without success.

That is why I would like to ask for some direction to do it, and finally calculate the area of each ring.
Any help will be welcome

d.b
  • 32,245
  • 6
  • 36
  • 77
Darwin PC
  • 871
  • 3
  • 23
  • 34

1 Answers1

2

I am using the spline.poly function from here.

spline.poly

spline.poly <- function(xy, vertices, k=3, ...) {
    # Assert: xy is an n by 2 matrix with n >= k.

    # Wrap k vertices around each end.
    n <- dim(xy)[1]
    if (k >= 1) {
        data <- rbind(xy[(n-k+1):n,], xy, xy[1:k, ])
    } else {
        data <- xy
    }

    # Spline the x and y coordinates.
    data.spline <- spline(1:(n+2*k), data[,1], n=vertices, ...)
    x <- data.spline$x
    x1 <- data.spline$y
    x2 <- spline(1:(n+2*k), data[,2], n=vertices, ...)$y

    # Retain only the middle part.
    cbind(x1, x2)[k < x & x <= n+k, ]
}

DATA

df = data.frame(A = c(1, 4, 5, 8, 10),
                B = c(1, 3, 7, 9, 10),
                C = c(2, 6, 8, 9, 10),
                D = c(1, 3, 4, 7, 9),
                E = c(1, 2, 3, 4, 5))

DRAW

#Calculate angles based on number of columns
angles = 0:(NCOL(df) - 1) * 2*pi/NCOL(df)

#Calculate x and y corresponding to each radial distance
toplot = lapply(1:NCOL(df), function(i){
    data.frame(x = df[,i]*cos(angles[i]),
               y = df[,i]*sin(angles[i]))
})

#Split toplot and merge back together the same rows
toplot2 = lapply(toplot, function(x) data.frame(x, ID = sequence(NROW(x))))
toplot2 = do.call(rbind, toplot2)
toplot2 = split(toplot2, toplot2$ID)

#Create empty plot    
graphics.off()
plot(do.call(rbind, toplot), type = "n", axes = FALSE, ann = FALSE, asp = 1)

#Allow drawing outside the plot region just in case
par(xpd = TRUE)

#Draw polygons
lapply(toplot2, function(a){
    polygon(spline.poly(xy = cbind(a$x, a$y), vertices = 100, k = 3))
})

#Draw points    
lapply(toplot, function(a){
    points(a)
})

#Draw radial lines    
lapply(toplot, function(a){
   lines(a)
})

enter image description here

AREA

area_data = lapply(toplot2, function(a){
   spline.poly(xy = cbind(a$x, a$y), vertices = 100, k = 3)
})
library(geometry)
lapply(area_data, function(P) polyarea(P[,1], P[,2]))
#$`1`
#[1] 4.35568

#$`2`
#[1] 38.46985

#$`3`
#[1] 96.41331

#$`4`
#[1] 174.1584

#$`5`
#[1] 240.5837
d.b
  • 32,245
  • 6
  • 36
  • 77