Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

plot Ellipse bounding a percentage of points

Tags:

r

I am using ellipsoidhull() function to derive an ellipse that bounds all the points in x,y coordinates. I then use point.in.polygon() function to predict if a new set of X,Y co-ordinates fall inside/outside the ellipse.

Instead of plotting an ellipse that bounds all the points in (x,y), is it possible to use say 80% of the points? The 80% of the points may be chosen to form the most compact or smallest elliptical area.

> xy

x       y 
3.076   5.208
3.046   5.123
2.993   5.108
3.062   5.134
3.168   5.223
3.138   5.284
3.166   5.319
3.226   5.411
3.262   5.417
3.215   5.234
3.086   5.019
3.199   5.167
3.274   5.596
3.293   5.608
3.195   5.396
3.294   5.374
2.974   5.539
3.268   5.377
3.192   5.298
3.08    4.916
3.117   4.985
3.128   5.118
3.21    5.373
3.184   5.282
3.27    5.291
3.074   5.175

> Query
X       Y
3.03    5.008
2.99    5.018
2.987   4.944
2.994   4.899
2.911   4.963
2.913   4.942
2.966   4.969
3.079   5.011
3.096   5.268
2.992   5.169
3.205   5.466
3.257   5.776
3.154   5.563
3.16    5.192
3.12    5.446
3.271   5.719
3.154   5.478
3.143   5.454
3.123   5.439
3.075   5.224
3.264   5.56
3.288   5.404
3.237   5.499
3.207   5.47
3.207   5.459
3.11    5.23
3.301   5.605
3.139   4.823


library(cluster)
exy <- ellipsoidhull(as.matrix(xy))
ellipse <- predict(exy)
library("sp")
point.in.polygon(Query$X, Query$Y, ellipse.FAM[,1], ellipse.FAM[,2])
like image 689
user645600 Avatar asked Dec 31 '25 18:12

user645600


1 Answers

Presumably you were using cluster::ellipsoidhull. In a different package the car::dataEllipse function calculates a center, shape and radius value and passes to ellipse. For the "presumed Normal" situation, which it seems you might be assuming, the relevant code is:

library(car)
dataEllipse
function(x,y, ....
...
else {
        shape <- var(cbind(x, y))
        center <- c(mean(x), mean(y))
    }
    for (level in levels) {
        radius <- sqrt(dfn * qf(level, dfn, dfd)

Then 'ellipse' calculates its individual points which get passed to lines. The code to do that final calculation is

ellipse <-
function (center, shape, radius, ....)
....
 angles <- (0:segments) * 2 * pi/segments
    unit.circle <- cbind(cos(angles), sin(angles))
    ellipse <- t(center + radius * t(unit.circle %*% chol(shape)))
    colnames(ellipse) <- c("x", "y")

So the combination of these two functions works with your data:

getEparams <-function(x,y, level) { dfn <- 2
        dfd <- length(x) - 1
        shape <- var(cbind(x, y))
        center <- c(mean(x), mean(y))
        radius <- sqrt(dfn * qf(level, dfn, dfd))
        return(list(center=center, shape=shape, radius=radius) ) }

ellcalc <- function (center, shape, radius, segments=51){segments=segments
    angles <- (0:segments) * 2 * pi/segments
    unit.circle <- cbind(cos(angles), sin(angles))
    ellipse <- t(center + radius * t(unit.circle %*% chol(shape)))
    colnames(ellipse) <- c("x", "y")
    return(ellipse)}

evals <- getEparams(Query$X, Query$Y, 0.80)
plot(ellcalc(evals[["center"]], evals[["shape"]], evals[["radius"]]))
title(main='Output of plot(ellcalc(evals[["center"]], evals[["shape"]], 
                           evals[["radius"]]))\nStackOverflow Demonstration')
 points(Query$X, Query$Y, cex=0.3, col="red")

You could obviously save or pass the results of the ellcalc call to any object you wanted

enter image description here

like image 188
IRTFM Avatar answered Jan 02 '26 10:01

IRTFM



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!