Search code examples
rplotpolygonarea

How to plot points aligned at different angles and connect these by a line?


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


Solution

  • 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