[R] panel.arrows problem in custom panel function

Gavin Simpson gavin.simpson at ucl.ac.uk
Thu Aug 7 16:55:16 CEST 2008


Dear List,

I am writing a custom panel function and xyplot method to plot the
results of a procrustes analysis from the vegan package.

I am having trouble getting the call to panel.arrows to work as I wish
when conditioning. The attached file contains the function definitions
for the xyplot method and the custom panel and prepanel functions I am
using. This example, using data and functions from the vegan package
illustrates the problem.

require(vegan)
require(lattice)
data(varespec)
vare.dist <- vegdist(wisconsin(varespec))
library(MASS)  ## isoMDS
mds.null <- isoMDS(vare.dist, tol=1e-7)
mds.alt <- isoMDS(vare.dist, initMDS(vare.dist), maxit=200, tol=1e-7)
vare.proc <- procrustes(mds.alt, mds.null)
vare.proc
groups <- factor(c(rep(1,16), rep(2,8)), labels = c("grazed","ungrazed"))
source("xyplot.procrustes.R")
xyplot(vare.proc, y ~ x | groups, data = as.data.frame(groups), kind = 1)

The resulting plot has too many arrows on each panel - some points have
multiple arrows emanating from they. panel.procrustes() is defined as:

`panel.procrustes` <- function(x, y, kind, choices, rotation, X,
                               ar.col, length = 0.05, ...) {
    tp <- trellis.par.get()
    if(missing(ar.col))
        ar.col <- tp$superpose.symbol$col[1]
    if(kind == 1) {
        panel.abline(h = 0, lty = "dashed")
        panel.abline(v = 0, lty = "dashed")
        if(ncol(rotation) == 2) {
            ## Sometimes rotation[1,1] is 2.2e-16 above one
            rotation[1,1] <- min(rotation[1,1], 1)
            panel.abline(0, tan(acos(rotation[1, 1])), lty = "solid")
            panel.abline(0, 1/tan(acos(-rotation[1, 1])), lty = "solid")
        } else {
            Y <- cbind(x,y) %*% t(rotation)
            for (k in seq_len(ncol(Y))) {
                tmp <- matrix(0, nrow = 2, ncol = ncol(Y))
                tmp[, k] <- range(Y[, k])
                tmp <- tmp %*% rotation
                panel.lines(tmp[, choices], lty = 1)
                panel.text(tmp[2, choices[1]], tmp[2, choices[2]],
                           as.character(k))
            }
        }
        panel.xyplot(x, y, type = "p", ...)
        ## Problem here
        panel.arrows(x0 = x, y0 = y,
                     x1 = X[,1], y1 = X[,2],
                     length = length, col = ar.col, ends = "last", ...)
        ##
    } else if(kind == 2) {
        quant <- quantile(y)
        panel.xyplot(x, y, type = "h", ...)
        panel.abline(h = quant[2:4], lty = c(2,1,2))
    }
}

The bit I am having trouble with is the call to panel.arrows. The
plotting of the points (line above the panel.arrows call) works fine
with the conditioning, but I'm not getting the panel.arrows call to
condition correctly.

So, to my question: how does one tell panel.arrows to plot only the
arrows for the relevant conditioning variable?

TIA

G

-- 
%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%
 Dr. Gavin Simpson             [t] +44 (0)20 7679 0522
 ECRC, UCL Geography,          [f] +44 (0)20 7679 0565
 Pearson Building,             [e] gavin.simpsonATNOSPAMucl.ac.uk
 Gower Street, London          [w] http://www.ucl.ac.uk/~ucfagls/
 UK. WC1E 6BT.                 [w] http://www.freshwaters.org.uk
%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%
-------------- next part --------------
`xyplot.procrustes` <- function(object, formula, data = NULL,
                                kind = 1, choices = 1:2,
                                xlab, ylab, main, ...) {
    require(lattice) || stop("requires package 'lattice'")
    if (missing(main))
        main <- "Procrustes errors"
    if(kind == 1) {
        dat <- data.frame(x = object$Yrot[, choices[1]],
                          y = object$Yrot[, choices[2]])
        if(missing(xlab))
            xlab <- paste("Dimension", choices[1])
        if(missing(ylab))
            ylab <- paste("Dimension", choices[2])
        aspect <- "iso"
    } else {
        res <- residuals(object)
        dat <- data.frame(x = seq_along(res), y = res)
        if (missing(xlab))
            xlab <- "Index"
        if (missing(ylab))
            ylab <- "Procrustes residual"
        aspect <- "fill"
    }
    if (!is.null(data))
        dat <- cbind(dat, data)
    if (missing(formula)) {
        v <- colnames(dat)
        formula <- as.formula(paste(v[2], "~", v[1]))
    }
    xyplot(formula, data = dat,
           choices = choices,
           kind = kind,
           rotation = object$rotation,
           X = object$X[, choices],
           aspect = aspect,
           xlab = xlab, ylab = ylab, main = main,
           panel = panel.procrustes,
           prepanel = prepanel.procrustes, ...)
}

`panel.procrustes` <- function(x, y, kind, choices, rotation, X,
                               ar.col, length = 0.05, ...) {
    tp <- trellis.par.get()
    if(missing(ar.col))
        ar.col <- tp$superpose.symbol$col[1]
    if(kind == 1) {
        panel.abline(h = 0, lty = "dashed")
        panel.abline(v = 0, lty = "dashed")
        if(ncol(rotation) == 2) {
            ## Sometimes rotation[1,1] is 2.2e-16 above one
            rotation[1,1] <- min(rotation[1,1], 1)
            panel.abline(0, tan(acos(rotation[1, 1])), lty = "solid")
            panel.abline(0, 1/tan(acos(-rotation[1, 1])), lty = "solid")
        } else {
            Y <- cbind(x,y) %*% t(rotation)
            for (k in seq_len(ncol(Y))) {
                tmp <- matrix(0, nrow = 2, ncol = ncol(Y))
                tmp[, k] <- range(Y[, k])
                tmp <- tmp %*% rotation
                panel.lines(tmp[, choices], lty = 1)
                panel.text(tmp[2, choices[1]], tmp[2, choices[2]],
                           as.character(k))
            }
        }
        panel.xyplot(x, y, type = "p", ...)
        panel.arrows(x0 = x, y0 = y,
                     x1 = X[,1], y1 = X[,2],
                     length = length, col = ar.col, ends = "last", ...)
    } else if(kind == 2) {
        quant <- quantile(y)
        panel.xyplot(x, y, type = "h", ...)
        panel.abline(h = quant[2:4], lty = c(2,1,2))
    }
}

`prepanel.procrustes` <- function(x, y, X, choices, kind, ...) {
    if(kind == 1) {
        xlim <- range(x, X[, choices[1]])
        ylim <- range(y, X[, choices[2]])
    } else {
        xlim <- range(x)
        ylim <- range(y)
    }
    list(ylim = ylim, xlim = xlim)
}


More information about the R-help mailing list