rplotgeometryconvex-hullqhull

Plot convex hull given by quickhull algorithm in R (convhulln function)


I need to plot the convex hull given by quickhull algorithm in R. Here is an example.

library(geometry)
x1 <- rnorm(100, 0.8, 0.3)
y1 <- rnorm(100, 0.8, 0.3)
ConVexHull<-convhulln(cbind(x1,y1),"FA")

ConVexHull$hull gives a m-by-dimension index matrix of which each row defines a dim-dimensional “triangle”.

I know how to plot using chull function but I am not sure if chull gives the same hull as given by convhulln

  Plot_ConvexHull<-function(xcoord, ycoord, lcolor){
  hpts <- chull(x = xcoord, y = ycoord)
  hpts <- c(hpts, hpts[1])
  lines(xcoord[hpts], ycoord[hpts], col = lcolor)
} 
xrange <- range(c(x1))
yrange <- range(c(y1))
par(tck = 0.02, mgp = c(1.7, 0.3, 0))
plot(x1, y1, type = "p", pch = 1, col = "black", xlim = c(xrange), ylim =    c(yrange))
Plot_ConvexHull(xcoord = x1, ycoord = y1, lcolor = "black")

Solution

  • Reproducible example:

    library(geometry)
    
    set.seed(0)
    
    x1 <- rnorm(100, 0.8, 0.3)
    y1 <- rnorm(100, 0.8, 0.3)
    
    xdf <- data_frame(x1, y1)
    
    (ConVexHull <- convhulln(cbind(x1,y1), "FA"))
    ## $hull
    ##      [,1] [,2]
    ## [1,]   63   59
    ## [2,]   10   53
    ## [3,]   10   63
    ## [4,]   80   59
    ## [5,]   80   15
    ## [6,]   37   53
    ## [7,]   37   15
    ## 
    ## $area
    ## [1] 4.258058
    ## 
    ## $vol
    ## [1] 1.271048
    

    Those are the from/to edge pairs in $hull, so we shall build said set of vertex pairs:

    data.frame(
      do.call(
        rbind,
        lapply(1:nrow(ConVexHull$hull), function(i) {
          rbind(xdf[ConVexHull$hull[i,1],], xdf[ConVexHull$hull[i,2],])
        })
      )
    ) -> h_df
    

    and, prove they are, indeed, correct:

    ggplot() +
      geom_point(data=xdf, aes(x1, y1), color="red") +
      geom_point(data=h_df, aes(x1, y1), shape=21, fill=NA, color="black", size=3)
    

    enter image description here

    They are, however, not in "order":

    ggplot() +
      geom_point(data=xdf, aes(x1, y1), color="red") +
      geom_point(data=h_df, aes(x1, y1), shape=21, fill=NA, color="black", size=3) +
      geom_path(data=h_df, aes(x1, y1), color="blue")
    

    enter image description here

    So, we need to get them in order (sort them) if you want to have a path or polygon around the points (which was the meaning of the comment / link by the anonymous user).

    We can sort them clockwise:

    h_df <- h_df[order(-1 * atan2(h_df$y1 - mean(range(h_df$y1)), h_df$x1 - mean(range(h_df$x1)))),]
    h_df <- rbind(h_df, h_df[1,])
    

    (remove the -1 for the reverse)

    and, we have a lovely outer wrapper:

    ggplot() +
      geom_point(data=xdf, aes(x1, y1), color="red") +
      geom_point(data=h_df, aes(x1, y1), shape=21, fill=NA, color="black", size=3) +
      geom_path(data=h_df, aes(x1, y1), color="blue")
    

    enter image description here