-
Notifications
You must be signed in to change notification settings - Fork 97
/
Copy pathcapscale.R
160 lines (156 loc) · 5.86 KB
/
capscale.R
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
`capscale` <-
function (formula, data, distance = "euclidean", sqrt.dist = FALSE,
comm = NULL, add = FALSE, dfun = vegdist,
metaMDSdist = FALSE, na.action = na.fail, subset = NULL, ...)
{
if (!inherits(formula, "formula"))
stop("needs a model formula")
if (missing(data)) {
data <- parent.frame()
}
else {
data <- eval(match.call()$data, environment(formula),
enclos = .GlobalEnv)
}
formula <- formula(terms(formula, data = data))
## The following line was eval'ed in environment(formula), but
## that made update() fail. Rethink the line if capscale() fails
## mysteriously at this point.
X <- eval(formula[[2]], envir=environment(formula),
enclos = globalenv())
## see if user supplied dissimilarities as a matrix
if ((is.matrix(X) || is.data.frame(X)) &&
isSymmetric(unname(as.matrix(X))))
X <- as.dist(X)
if (!inherits(X, "dist")) {
comm <- X
vdata <- as.character(formula[[2]])
dfun <- match.fun(dfun)
if (metaMDSdist) {
commname <- as.character(formula[[2]])
X <- metaMDSdist(comm, distance = distance, zerodist = "ignore",
commname = commname, distfun = dfun, ...)
commname <- attr(X, "commname")
comm <- eval.parent(parse(text=commname))
} else {
X <- dfun(X, distance, ...)
}
} else { # vdata name
if (missing(comm))
vdata <- NULL
else
vdata <- deparse(substitute(comm))
}
inertia <- attr(X, "method")
if (is.null(inertia))
inertia <- "unknown"
inertia <- paste(toupper(substr(inertia, 1, 1)),
substring(inertia, 2), sep = "")
inertia <- paste(inertia, "distance")
if (!sqrt.dist)
inertia <- paste("squared", inertia)
## postpone info on euclidification till we have done so
## evaluate formula: ordiParseFormula will return dissimilarities
## as a symmetric square matrix (except that some rows may be
## deleted due to missing values)
d <- ordiParseFormula(formula,
data,
na.action = na.action,
subset = substitute(subset),
X = X)
## ordiParseFormula subsets rows of dissimilarities: do the same
## for columns ('comm' is handled later). ordiParseFormula
## returned the original data, but we use instead the potentially
## changed X and discard d$X.
if (!is.null(d$subset)) {
X <- as.matrix(X)[d$subset, d$subset, drop = FALSE]
}
## Delete columns if rows were deleted due to missing values
if (!is.null(d$na.action)) {
X <- as.matrix(X)[-d$na.action, -d$na.action, drop = FALSE]
}
X <- as.dist(X)
k <- attr(X, "Size") - 1
if (sqrt.dist)
X <- sqrt(X)
if (max(X) >= 4 + .Machine$double.eps) {
inertia <- paste("mean", inertia)
adjust <- sqrt(k)
X <- X/adjust
}
else {
adjust <- 1
}
nm <- attr(X, "Labels")
## wcmdscale, optionally with additive adjustment
X <- wcmdscale(X, x.ret = TRUE, add = add)
if(any(dim(X$points) == 0)) # there may be no positive dims
X$points <- matrix(0, NROW(X$points), 1)
## this may have been euclidified: update inertia
if (!is.na(X$ac) && X$ac > sqrt(.Machine$double.eps))
inertia <- paste(paste0(toupper(substring(X$add, 1, 1)),
substring(X$add, 2)),
"adjusted", inertia)
if (is.null(rownames(X$points)))
rownames(X$points) <- nm
sol <- ordConstrained(X$points, d$Y, d$Z, method = "capscale")
## update for negative eigenvalues
if (any(X$eig < 0)) {
negax <- X$eig[X$eig < 0]
sol$CA$imaginary.chi <- sum(negax)
sol$tot.chi <- sol$tot.chi + sol$CA$imaginary.chi
sol$CA$imaginary.rank <- length(negax)
sol$CA$imaginary.u.eig <- X$negaxes
}
if (!is.null(comm)) {
sol$vdata <- vdata
comm <- scale(comm, center = TRUE, scale = FALSE)
sol$colsum <- apply(comm, 2, sd)
## take a 'subset' of the community after scale()
if (!is.null(d$subset))
comm <- comm[d$subset, , drop = FALSE]
## NA action after 'subset'
if (!is.null(d$na.action))
comm <- comm[-d$na.action, , drop = FALSE]
if (!is.null(sol$pCCA) && sol$pCCA$rank > 0)
comm <- qr.resid(sol$pCCA$QR, comm)
if (!is.null(sol$CCA) && sol$CCA$rank > 0) {
v.eig <- t(comm) %*% sol$CCA$u/sqrt(k)
sol$CCA$v <- decostand(v.eig, "normalize", MARGIN = 2)
comm <- qr.resid(sol$CCA$QR, comm)
}
if (!is.null(sol$CA) && sol$CA$rank > 0) {
v.eig <- t(comm) %*% sol$CA$u/sqrt(k)
sol$CA$v <- decostand(v.eig, "normalize", MARGIN = 2)
}
} else {
## input data were dissimilarities, and no 'comm' defined:
## species scores make no sense and are made NA
sol$CA$v[] <- NA
if (!is.null(sol$CCA))
sol$CCA$v[] <- NA
sol$colsum <- NA
}
## centroids
sol$CCA$centroids <- getCentroids(sol, d$modelframe)
sol$call <- match.call()
sol$terms <- terms(formula, "Condition", data = data)
sol$terminfo <- ordiTerminfo(d, data)
sol$call$formula <- formula(d$terms, width.cutoff = 500)
sol$call$formula[[2]] <- formula[[2]]
sol$sqrt.dist <- sqrt.dist
if (!is.na(X$ac) && X$ac > 0) {
sol$ac <- X$ac
sol$add <- X$add
}
sol$adjust <- adjust
sol$inertia <- inertia
if (metaMDSdist)
sol$metaMDSdist <- commname
sol$subset <- d$subset
sol$na.action <- d$na.action
class(sol) <- c("capscale", "rda", "cca")
if (!is.null(sol$na.action))
sol <- ordiNAexclude(sol, d$excluded)
sol
}