################################################
## msProcess package utility functions
##
## argNames
## matchObject
## msExtrema
## msPlot
## princomp2
## rescale
## zeroCross
##
################################################
###
# argNames
###
"argNames" <- function(x)
{
if (is.R()){
formalArgs(x)
} else{
switch(mode(x),
"function" = names(x)[ - length(x)],
call = names(x)[-1],
character = {
x <- getFunction(x)
names(x)[ - length(x)]
}
,
stop("mode must be 'function', 'call', or 'character'"))
}
}
###
# matchObject
###
"matchObject" <- function(what, ignore.case=TRUE)
{
for (i in seq(along=search())){
objs <- ls(, i)
imatch <- grep(pattern=paste("^", what, "$", sep=""), objs, ignore.case=ignore.case)
if (length(imatch))
return(objs[imatch])
}
stop("No matching object found in any database on the search() path")
invisible(NULL)
}
###
# msExtrema
###
"msExtrema" <- function(x, span=3)
{
# find local maxima
index1 <- peaks(x, span=span, strict=FALSE)
# find local minima
index2 <- peaks(-x, span=span, strict=FALSE)
# remove the interior of plateaus
index.max <- index1 & !index2
index.min <- index2 & !index1
# construct output
list(index.max=index.max, index.min=index.min)
}
###
# msPlot
###
"msPlot" <- function(matlines.=NULL, matpoints.=NULL, lines.=NULL, points.=NULL,
image.=NULL, abline.=NULL, text.=NULL, offset=NULL, recenter=FALSE,
offset.fun=function(x){3 * stdev(x, na.rm=TRUE)},
xlab="", ylab="", yref=TRUE, main="", add=FALSE, ...)
{
# define local functions
"checkArgStruct" <- function(x){
vars <- list(xy=c("x","y"), xyz=c("x","y","z"), hv=c("h","v"))
reqargs <- list(matlines=vars$xy, matpoints=vars$xy, lines=vars$xy,
points=vars$xy, abline=vars$hv, text=vars$xy, image=vars$xyz)
# validate structure of each data set
for (fun in names(x)){
if (is.element(fun,"abline")) comp <- any
else comp <- all
data <- x[[fun]]
req <- reqargs[[fun]]
if (!is.list(data))
stop(fun, " must be a list")
# data could be a single list like:
#
# z <- list(x=matrix, y=matrix, ...)
#
# or it could be a list of lists like:
#
# zz <- list(z, z)
#
# we need to probe all the way down to the matrix level
if (is.list(data[[1]])){
pass <- unlist(lapply(data,
function(x, req, comp){
(comp(is.element(req, names(x))) & is.list(x))
}, req=req, comp=comp ))
}
else pass <- (comp(is.element(req, names(data))) & is.list(data))
if (any(!pass))
stop(fun, " must be a list containing ", switch(fun, abline="one","all"),
" of the named objects: ", paste(req, collapse=" "))
}
invisible(NULL)
}
"transformXY" <- function(obj, recenter, offset, is.scaled)
{
# force x and y objects to be matrices.
# recenter y values if requested.
# offset y data if requested.
# initialize variables
z <- list(x=NULL,y=NULL)
# force vectors and matrices with
# a single row into a single column matrix
if (isVectorAtomic(obj$x))
z$x <- matrix(obj$x, ncol=1)
else
z$x <- as.matrix(obj$x)
if (isVectorAtomic(obj$y))
z$y <- matrix(obj$y, ncol=1)
else
z$y <- as.matrix(obj$y)
# recenter y data if requested
if (recenter)
z$y <- sweep(z$y, MARGIN=2, colMins(z$y))
# offset y data if requested
if (is.scaled && offset > 0){
yoff <- offset * seq(0, numCols(z$y) - 1)
z$y <- sweep(z$y, MARGIN=2, yoff, FUN="+")
}
z
}
# collect data into groups
scaled <- list(matlines=matlines., matpoints=matpoints.)
unscaled <- list(lines=lines., points=points.)
other <- list(abline=abline., image=image., text=text.)
# initialize variables
exist.scaled <- !unlist(lapply(scaled, is.null))
exist.unscaled <- !unlist(lapply(unscaled, is.null))
exist.other <- !unlist(lapply(other, is.null))
is.scaled <- any(exist.scaled)
is.unscaled <- any(exist.unscaled)
is.other <- any(exist.other)
# concatenate data lists
if (is.scaled)
data <- scaled[exist.scaled]
else
data <- unscaled[exist.unscaled]
if (is.other)
data <- c(data, other[exist.other])
# append add to the image function
if (is.element("image", names(data)))
data$image$add <- TRUE
# check input arguments
if (is.scaled && is.unscaled)
stop("Cannot mixed scaled and unscaled plot types")
if (!is.scaled && !is.unscaled)
return(invisible(NULL)) # do nothing if no data supplied
if (!is.function(offset.fun))
stop("offset.fun input must be a function")
checkArgStruct(data)
# define offset
if (is.scaled && is.null(offset)){
flatdata <- unlist(data)
nms <- names(flatdata)
token <- "^(matlines|matpoints|lines|points|abline|image|text).y"
ydata <- flatdata[if (is.R()) grep(token, nms) else regMatch(nms, token)]
if (length(ydata))
offset <- offset.fun(as.numeric(ydata))
else
offset <- 0
}
# initialize variables
xlim <- ylim <- NULL
xy <- c("x","y")
funs <- names(data)
# transform XY data
for (i in seq(along=data)){
scale.data <- any(is.element(funs[i], names(scaled)))
## TODO: check for consistent number of columns
if (!is.atomic(data[[i]][[1]])){ # list of lists
for (j in seq(along=data[[i]])){
obj <- data[[i]][[j]]
if (all(is.element(xy, names(obj))))
data[[i]][[j]][xy] <- transformXY(obj, recenter, offset, scale.data)
# update limits
xlim <- range(c(xlim, range(data[[i]][[j]]$x)))
ylim <- range(c(ylim, range(data[[i]][[j]]$y)))
}
}
else{ # single list
obj <- data[[i]]
if (all(is.element(xy, names(obj))))
data[[i]][xy] <- transformXY(obj, recenter, offset, scale.data)
# update limits
xlim <- range(xlim, data[[i]]$x, na.rm=TRUE)
ylim <- range(ylim, data[[i]]$y, na.rm=TRUE)
}
}
# create an empty plot with sufficiently large limits
if (!add){
if (is.element("abline", names(data))){
xlim <- range(xlim, data$abline$v, na.rm=TRUE)
ylim <- range(ylim, data$abline$h, na.rm=TRUE)
}
plot(xlim, ylim, type="n", xlab=xlab, ylab=ylab, main=main, ...)
}
# initialize y-axis label vector
if (yref)
xstart <- ystart <- ygroup <- NULL
# plot the data
for (fun in names(data)){
if (!is.atomic(data[[fun]][[1]])){ # list of lists
dum <- lapply(data[[fun]],
function(x, fun) do.call(fun, args=x), fun=fun)
if (yref && is.element(fun, c("matlines","lines"))){
xstart <- c(xstart, unlist(lapply(data[[fun]], function(z) z$x[1])))
ystart <- c(ystart, unlist(lapply(data[[fun]], function(z) z$y[1,])))
ygroup <- c(ygroup, rep(length(data[[fun]]),numCols(data[[fun]][[1]]$y)))
}
}
else{
if (yref && is.element(fun, c("matlines","lines"))){
xstart <- c(xstart, data[[fun]]$x[1])
ystart <- c(ystart, data[[fun]]$y[1,])
ygroup <- c(ygroup, rep(1,numCols(data[[fun]]$y)))
}
do.call(fun, args=data[[fun]])
}
}
# add yref labels for matlines and lines entities
if (!add && yref){
xstart <- rep(xstart,length(ystart))[seq(along=ystart)]
yrefmin <- ifelse1(ylim[1] > 0, min(ystart), 0)
yoffset <- cumsum(c(yrefmin, rep(offset,length(ygroup)-1)))
y1 <- rep(yoffset, ygroup[1])
color <- if (!is.atomic(data[[1]][[1]])){ # list of lists
data[[1]][[1]]$col
} else { # single list
data[[1]]$col
}
if (is.null(color)) color <- rep(seq(ygroup),ygroup[1])
for (i in seq(along=ystart)){
lines(approx(c(par("usr")[1], xstart[i]), c(y1[i], ystart[i]), n=5),
pch=".", cex=2, type="p",col=color[i],lty=1)
}
}
invisible(offset)
}
###
# princomp2
###
# note: adapted from function fx.pca.matrix in package dimeR
# In S-PLUS, PCA can be computed no matter whether samples or features are more.
# In R, PCA can be computed only if there are more samples than features.
# If there are more features than samples, PCA can be computed
# more efficiently from the transposed x.
# samples are rows and feature are columns
"princomp2" <-
function(x, ...)
{
d <- dim(x)
n <- d[1]
p <- d[2]
# transpose and center x by feature
center <- colMeans(x)
txc <- t(x) - center
# compute eigen in the transposed space
if (!is.R())
ans <- eigen(cov.wt(txc, cor=FALSE, center=FALSE)$cov, symmetric=TRUE)
else
ans <- eigen(cov.wt(txc, cor=FALSE, center=FALSE, method="ML")$cov, symmetric=TRUE)
# compute sdev for the original samples
ans$values <- sqrt(ans$values*p/n)
names(ans) <- c("sdev", "loadings")[match(c("values", "vectors"), names(ans))]
ans$sdev[is.na(ans$sdev)] <- 0
ans$sdev[ans$sdev<0] <- 0
# convert loadings to the original space
ans$loadings <- txc %*% ans$loadings
ans$loadings <- apply(ans$loadings, 2, function(x) x/sqrt(sum(x^2)))
oldClass(ans$loadings) <- "loadings"
# compute scores for the original samples
ans$scores <- t(txc) %*% ans$loadings
cnames <- paste("Comp.", 1:n, sep = "")
if(!length(rnames <- dimnames(x)[[2]]))
rnames <- paste(if (!is.R()) "X" else "V", 1:p, sep = "")
names(ans$sdev) <- cnames
dimnames(ans$loadings) <- list(rnames, cnames)
dimnames(ans$scores) <- list(dimnames(ans$scores)[[1]], cnames)
ans$center <- center
names(ans$center) <- rnames
ans$scale <- rep(1, p)
ans$n.obs <- n
# ans$terms <- Terms
ans$call <- match.call()
# ans$factor.sdev <- ans$sdev
ans$coef <- ans$loadings
oldClass(ans) <- "princomp"
ans
}
###
# rescale
###
"rescale" <- function(x, range.=c(0,1), ...)
{
if (!isVectorAtomic(x) && !is(x,"signalSeries") && !is.matrix(x))
stop("Input must a vector, signalSeries, or matrix")
checkVectorType(x,"numeric")
if (length(range.) != 2)
stop("Range must be a two-element numeric vector")
range. <- sort(range.)
drange <- diff(range.)
minx <- min(x)
x <- x - minx
maxx <- max(x)
x <- x / maxx * drange + range.[1]
z <- list(...)
if (length(z)){
z <- lapply(z, function(x, minx, xscale, offset)
(x - minx) * xscale + offset,
minx=minx, xscale=drange/maxx, offset=range.[1])
return(c(list(x), z))
}
else
return(x)
}
###
# zeroCross
###
"zeroCross" <- function(x, slope="positive")
{
checkVectorType(x,"numeric")
checkScalarType(slope,"character")
slope <- match.arg(slope,c("positive","negative"))
slope <- match.arg(lowerCase(slope), c("positive","negative"))
ipost <- ifelse1(slope == "negative", sort(which(c(x, 0) < 0 & c(0, x) > 0)),
sort(which(c(x, 0) > 0 & c(0, x) < 0)))
offset <- apply(matrix(abs(x[c(ipost-1, ipost)]), nrow=2, byrow=TRUE), MARGIN=2, order)[1,] - 2
ipost + offset
}
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.