# [S] SUMMARY: Convex hulls on discriminant plots

Marc R. Feldesman (feldesmanm@pdx.edu)
Wed, 20 May 1998 20:16:04 -0700

Several people replied to my message about how to construct convex hulls
around the perimeters of groups in a linear discriminant analysis. I've
included my original question below, and the definitive response from Brian
Ripley.

>> <snip. my useless preamble to the problem>

:I've computed a linear discriminant using the updated (4/30/98) VR function
:lda. I have a list called lda.predicted, which is the results of applying
:the predict function to the lda object. I also have a plot of LD1 vs LD2.
:None of this required any hard thinking.

:I would like to place convex hulls around the perimeter of points in each
:group. I've tried using apply and tapply together (to get the results
:repeated by group) but I get an error each time telling me that chull()
:isn't a function. I'm using something like:

:chull.dat<-apply(lda.predict, 2, function(x) tapply(x, lda.predict\$class,
:+chull(lda.predict\$x[,1], lda.predict\$x[,2])))

Brian Ripley's reply is reproduced in full below. Among other things, I
learned that chull() isn't really a function, which is why I was having
problems. Others pointed out that my use of tapply above was incorrect in
that it expects the third argument to be a function, which Brian explained
isn't really a function. Various other suggestions were offered, but the
only one that actually worked for the problem at hand is illustrated
handily by the sequence of function calls below.

>Yes! Here is an example, using the Iris data from V&R chapter 13
>
>ir <- rbind(iris[,,1], iris[,,2], iris[,,3])
>ir.species <- c(rep("s",50), rep("c",50), rep("v",50))
>
>ir.lda <- lda(log(ir), ir.species)
>ir.ld <- predict(ir.lda, dimen=2)\$x
>eqscplot(ir.ld, type="n", xlab="first linear discriminant",
> ylab="second linear discriminant")
>text(ir.ld, labels=ir.species)
>
>tapply(seq(along=ir.species), ir.species, function(i) {
> hull <- chull(ir.ld[i,])
> polygon(ir.ld[i[hull],1], ir.ld[i[hull],2], density=0)
> i[hull]
>})
>
>This uses the true class (ir.species). If you really want the predicted
>class, replace it by that.
>
>Your confusing message is probably due to the fact that chull is not
>an S function, it is an old-S function and some functions have problems
>with those. You can always wrap them in an S function.
>--

Dr. Marc R. Feldesman
email: feldesmanm@pdx.edu
email: feldesman@ibm.net
pager: 503-870-2515
fax: 503-725-3905

"If ignorance is bliss then why aren't there more happy people?" Lawrence
Peter