| 42333 |
ripley |
1 |
% File src/library/stats/man/dendrogram.Rd
|
| 68948 |
ripley |
2 |
% Part of the R package, https://www.R-project.org
|
| 79012 |
kalibera |
3 |
% Copyright 1995-2020 R Core Team
|
| 68633 |
maechler |
4 |
% Copyright 2002-2015 The R Foundation
|
| 42333 |
ripley |
5 |
% Distributed under GPL 2 or later
|
|
|
6 |
|
| 27474 |
ripley |
7 |
\name{dendrogram}
|
|
|
8 |
\title{General Tree Structures}
|
| 56186 |
murdoch |
9 |
\alias{dendrogram}% the class
|
| 27474 |
ripley |
10 |
\alias{as.dendrogram}
|
| 41244 |
ripley |
11 |
\alias{as.dendrogram.dendrogram}
|
| 29701 |
maechler |
12 |
\alias{as.dendrogram.hclust}
|
| 53892 |
maechler |
13 |
\alias{as.hclust.dendrogram}
|
| 27474 |
ripley |
14 |
\alias{cut.dendrogram}
|
|
|
15 |
\alias{[[.dendrogram}
|
| 53892 |
maechler |
16 |
\alias{merge.dendrogram}
|
| 66629 |
maechler |
17 |
\alias{nobs.dendrogram}
|
| 53892 |
maechler |
18 |
\alias{plot.dendrogram}
|
| 27474 |
ripley |
19 |
\alias{print.dendrogram}
|
|
|
20 |
\alias{rev.dendrogram}
|
|
|
21 |
\alias{str.dendrogram}
|
| 30228 |
maechler |
22 |
\alias{is.leaf}
|
| 27474 |
ripley |
23 |
\description{
|
|
|
24 |
Class \code{"dendrogram"} provides general functions for handling
|
|
|
25 |
tree-like structures. It is intended as a replacement for similar
|
|
|
26 |
functions in hierarchical clustering and classification/regression
|
|
|
27 |
trees, such that all of these can use the same engine for plotting or
|
|
|
28 |
cutting trees.
|
|
|
29 |
}
|
|
|
30 |
\usage{
|
|
|
31 |
as.dendrogram(object, \dots)
|
| 66839 |
maechler |
32 |
\method{as.dendrogram}{hclust}(object, hang = -1, check = TRUE, \dots)
|
| 27474 |
ripley |
33 |
|
| 53892 |
maechler |
34 |
\method{as.hclust}{dendrogram}(x, \dots)
|
|
|
35 |
|
| 27474 |
ripley |
36 |
\method{plot}{dendrogram}(x, type = c("rectangle", "triangle"),
|
| 30912 |
ripley |
37 |
center = FALSE,
|
|
|
38 |
edge.root = is.leaf(x) || !is.null(attr(x,"edgetext")),
|
| 30884 |
maechler |
39 |
nodePar = NULL, edgePar = list(),
|
| 30912 |
ripley |
40 |
leaflab = c("perpendicular", "textlike", "none"),
|
|
|
41 |
dLeaf = NULL, xlab = "", ylab = "", xaxt = "n", yaxt = "s",
|
| 46113 |
maechler |
42 |
horiz = FALSE, frame.plot = FALSE, xlim, ylim, \dots)
|
| 27474 |
ripley |
43 |
|
|
|
44 |
\method{cut}{dendrogram}(x, h, \dots)
|
|
|
45 |
|
| 66648 |
maechler |
46 |
\method{merge}{dendrogram}(x, y, \dots, height,
|
| 66655 |
maechler |
47 |
adjust = c("auto", "add.max", "none"))
|
| 53892 |
maechler |
48 |
|
| 66631 |
maechler |
49 |
\method{nobs}{dendrogram}(object, \dots)
|
| 66629 |
maechler |
50 |
|
| 27474 |
ripley |
51 |
\method{print}{dendrogram}(x, digits, \dots)
|
|
|
52 |
|
|
|
53 |
\method{rev}{dendrogram}(x)
|
|
|
54 |
|
| 40832 |
maechler |
55 |
\method{str}{dendrogram}(object, max.level = NA, digits.d = 3,
|
| 27474 |
ripley |
56 |
give.attr = FALSE, wid = getOption("width"),
|
| 57963 |
maechler |
57 |
nest.lev = 0, indent.str = "",
|
|
|
58 |
last.str = getOption("str.dendrogram.last"), stem = "--",
|
| 56287 |
ripley |
59 |
\dots)
|
| 30228 |
maechler |
60 |
|
|
|
61 |
is.leaf(object)
|
| 27474 |
ripley |
62 |
}
|
|
|
63 |
\arguments{
|
|
|
64 |
\item{object}{any \R object that can be made into one of class
|
|
|
65 |
\code{"dendrogram"}.}
|
| 60892 |
ripley |
66 |
\item{x, y}{object(s) of class \code{"dendrogram"}.}
|
| 29701 |
maechler |
67 |
\item{hang}{numeric scalar indicating how the \emph{height} of leaves
|
|
|
68 |
should be computed from the heights of their parents; see
|
|
|
69 |
\code{\link{plot.hclust}}.}
|
| 66839 |
maechler |
70 |
\item{check}{logical indicating if \code{object} should be checked for
|
|
|
71 |
validity. This check is not necessary when \code{x} is known to be
|
|
|
72 |
valid such as when it is the direct result of \code{hclust()}. The
|
| 69446 |
ripley |
73 |
default is \code{check=TRUE}, e.g.\sspace{}for protecting against memory
|
| 66839 |
maechler |
74 |
explosion with invalid inputs.}
|
| 27474 |
ripley |
75 |
\item{type}{type of plot.}
|
|
|
76 |
\item{center}{logical; if \code{TRUE}, nodes are plotted centered with
|
|
|
77 |
respect to the leaves in the branch. Otherwise (default), plot them
|
|
|
78 |
in the middle of all direct child nodes.}
|
|
|
79 |
\item{edge.root}{logical; if true, draw an edge to the root node.}
|
|
|
80 |
\item{nodePar}{a \code{list} of plotting parameters to use for the
|
|
|
81 |
nodes (see \code{\link{points}}) or \code{NULL} by default which
|
|
|
82 |
does not draw symbols at the nodes. The list may contain components
|
| 54147 |
maechler |
83 |
named \code{pch}, \code{cex}, \code{col}, \code{xpd},
|
|
|
84 |
and/or \code{bg} each of
|
| 27474 |
ripley |
85 |
which can have length two for specifying separate attributes for
|
| 54147 |
maechler |
86 |
\emph{inner} nodes and \emph{leaves}. Note that the default of
|
|
|
87 |
\code{pch} is \code{1:2}, so you may want to use \code{pch = NA} if
|
|
|
88 |
you specify \code{nodePar}.}
|
| 27474 |
ripley |
89 |
\item{edgePar}{a \code{list} of plotting parameters to use for the
|
| 30228 |
maechler |
90 |
edge \code{\link{segments}} and labels (if there's an
|
|
|
91 |
\code{edgetext}). The list may contain components
|
|
|
92 |
named \code{col}, \code{lty} and \code{lwd} (for the segments),
|
|
|
93 |
\code{p.col}, \code{p.lwd}, and \code{p.lty} (for the
|
|
|
94 |
\code{\link{polygon}} around the text) and \code{t.col} for the text
|
|
|
95 |
color. As with \code{nodePar}, each can have length two for
|
|
|
96 |
differentiating leaves and inner nodes.
|
|
|
97 |
}
|
| 30884 |
maechler |
98 |
\item{leaflab}{a string specifying how leaves are labeled. The
|
|
|
99 |
default \code{"perpendicular"} write text vertically (by default).\cr
|
|
|
100 |
\code{"textlike"} writes text horizontally (in a rectangle), and \cr
|
|
|
101 |
\code{"none"} suppresses leaf labels.}
|
|
|
102 |
\item{dLeaf}{a number specifying the \bold{d}istance in user
|
|
|
103 |
coordinates between the tip of a leaf and its label. If \code{NULL}
|
|
|
104 |
as per default, 3/4 of a letter width or height is used.}
|
|
|
105 |
\item{horiz}{logical indicating if the dendrogram should be drawn
|
| 27474 |
ripley |
106 |
\emph{horizontally} or not.}
|
|
|
107 |
\item{frame.plot}{logical indicating if a box around the plot should
|
|
|
108 |
be drawn, see \code{\link{plot.default}}.}
|
|
|
109 |
\item{h}{height at which the tree is cut.}
|
| 66629 |
maechler |
110 |
\item{height}{height at which the two dendrograms should be merged. If not
|
| 53892 |
maechler |
111 |
specified (or \code{NULL}), the default is ten percent larger than
|
|
|
112 |
the (larger of the) two component heights.}
|
| 66648 |
maechler |
113 |
\item{adjust}{a string determining if the leaf values should be
|
|
|
114 |
adjusted. The default, \code{"auto"}, checks if the (first) two
|
| 81927 |
smeyer |
115 |
dendrograms both start at \code{1}; if they do, \code{"add.max"} is
|
| 66648 |
maechler |
116 |
chosen, which adds the maximum of the previous dendrogram leaf
|
|
|
117 |
values to each leaf of the \dQuote{next} dendrogram. Specifying
|
|
|
118 |
\code{adjust} to another value skips the check and hence is a tad
|
|
|
119 |
more efficient.}
|
| 46113 |
maechler |
120 |
\item{xlim, ylim}{optional x- and y-limits of the plot, passed to
|
|
|
121 |
\code{\link{plot.default}}. The defaults for these show the full
|
|
|
122 |
dendrogram.}
|
| 30884 |
maechler |
123 |
\item{\dots, xlab, ylab, xaxt, yaxt}{graphical parameters, or arguments for
|
| 27474 |
ripley |
124 |
other methods.}
|
| 40281 |
ripley |
125 |
\item{digits}{integer specifying the precision for printing, see
|
| 27474 |
ripley |
126 |
\code{\link{print.default}}.}
|
| 50092 |
ripley |
127 |
\item{max.level, digits.d, give.attr, wid, nest.lev, indent.str}{arguments
|
|
|
128 |
to \code{str}, see \code{\link{str.default}()}. Note that
|
| 30884 |
maechler |
129 |
\code{give.attr = FALSE} still shows \code{height} and \code{members}
|
|
|
130 |
attributes for each node.}
|
| 53892 |
maechler |
131 |
\item{last.str, stem}{strings used for \code{str()} specifying how the
|
|
|
132 |
last branch (at each level) should start and the \emph{stem}
|
| 57963 |
maechler |
133 |
to use for each dendrogram branch. In some environments, using
|
|
|
134 |
\code{last.str = "'"} will provide much nicer looking output, than
|
|
|
135 |
the historical default \code{last.str = "`"}.}
|
| 27474 |
ripley |
136 |
}
|
|
|
137 |
\details{
|
|
|
138 |
The dendrogram is directly represented as a nested list where each
|
|
|
139 |
component corresponds to a branch of the tree. Hence, the first
|
|
|
140 |
branch of tree \code{z} is \code{z[[1]]}, the second branch of the
|
| 53892 |
maechler |
141 |
corresponding subtree is \code{z[[1]][[2]]}, or shorter
|
|
|
142 |
\code{z[[c(1,2)]]}, etc.. Each node of the tree
|
| 27474 |
ripley |
143 |
carries some information needed for efficient plotting or cutting as
|
| 30228 |
maechler |
144 |
attributes, of which only \code{members}, \code{height} and
|
|
|
145 |
\code{leaf} for leaves are compulsory:
|
| 27474 |
ripley |
146 |
\describe{
|
|
|
147 |
\item{\code{members}}{total number of leaves in the branch}
|
|
|
148 |
\item{\code{height}}{numeric non-negative height at which the node
|
|
|
149 |
is plotted.}
|
|
|
150 |
\item{\code{midpoint}}{numeric horizontal distance of the node from
|
| 29796 |
maechler |
151 |
the left border (the leftmost leaf) of the branch (unit 1 between
|
| 61160 |
ripley |
152 |
all leaves). This is used for \code{plot(*, center = FALSE)}.}
|
| 27474 |
ripley |
153 |
\item{\code{label}}{character; the label of the node}
|
| 30228 |
maechler |
154 |
\item{\code{x.member}}{for \code{cut()$upper},
|
|
|
155 |
the number of \emph{former} members; more generally a substitute
|
| 42961 |
ripley |
156 |
for the \code{members} component used for \sQuote{horizontal}
|
|
|
157 |
(when \code{horiz = FALSE}, else \sQuote{vertical}) alignment.}
|
| 27474 |
ripley |
158 |
\item{\code{edgetext}}{character; the label for the edge leading to
|
|
|
159 |
the node}
|
| 30228 |
maechler |
160 |
\item{\code{nodePar}}{a named list (of length-1 components)
|
|
|
161 |
specifying node-specific attributes for \code{\link{points}}
|
|
|
162 |
plotting, see the \code{nodePar} argument above.}
|
|
|
163 |
\item{\code{edgePar}}{a named list (of length-1 components)
|
|
|
164 |
specifying attributes for \code{\link{segments}} plotting of the
|
|
|
165 |
edge leading to the node, and drawing of the \code{edgetext} if
|
|
|
166 |
available, see the \code{edgePar} argument above.}
|
| 27474 |
ripley |
167 |
\item{\code{leaf}}{logical, if \code{TRUE}, the node is a leaf of
|
|
|
168 |
the tree.}% This will often be a \code{\link{character}} which can
|
|
|
169 |
% be used for plotting instead of the \code{text} attribute.}
|
|
|
170 |
}
|
|
|
171 |
|
|
|
172 |
\code{cut.dendrogram()} returns a list with components \code{$upper}
|
|
|
173 |
and \code{$lower}, the first is a truncated version of the original
|
|
|
174 |
tree, also of class \code{dendrogram}, the latter a list with the
|
|
|
175 |
branches obtained from cutting the tree, each a \code{dendrogram}.
|
|
|
176 |
|
|
|
177 |
There are \code{\link{[[}}, \code{\link{print}}, and \code{\link{str}}
|
|
|
178 |
methods for \code{"dendrogram"} objects where the first one
|
| 65131 |
maechler |
179 |
(extraction) ensures that selecting sub-branches keeps the class,
|
|
|
180 |
i.e., returns a dendrogram even if only a leaf.
|
|
|
181 |
On the other hand, \code{\link{[}} (\emph{single} bracket) extraction
|
|
|
182 |
returns the underlying list structure.%, useful, e.g., for inspection.
|
| 27474 |
ripley |
183 |
|
|
|
184 |
Objects of class \code{"hclust"} can be converted to class
|
| 53892 |
maechler |
185 |
\code{"dendrogram"} using method \code{as.dendrogram()}, and since R
|
|
|
186 |
2.13.0, there is also a \code{\link{as.hclust}()} method as an inverse.
|
| 27474 |
ripley |
187 |
|
| 29799 |
maechler |
188 |
\code{rev.dendrogram} simply returns the dendrogram \code{x} with
|
|
|
189 |
reversed nodes, see also \code{\link{reorder.dendrogram}}.
|
|
|
190 |
|
| 66629 |
maechler |
191 |
The \code{\link{merge}(x, y, ...)} method merges two or more
|
| 53892 |
maechler |
192 |
dendrograms into a new one which has \code{x} and \code{y} (and
|
| 66648 |
maechler |
193 |
optional further arguments) as branches. Note that before \R 3.1.2,
|
|
|
194 |
\code{adjust = "none"} was used implicitly, which is invalid when,
|
| 87653 |
smeyer |
195 |
e.g., the dendrograms are from \code{as.dendrogram(hclust(..))}.
|
| 53892 |
maechler |
196 |
|
| 66629 |
maechler |
197 |
\code{\link{nobs}(object)} returns the total number of leaves (the
|
| 66631 |
maechler |
198 |
\code{members} attribute, see above).
|
| 66629 |
maechler |
199 |
|
| 60892 |
ripley |
200 |
\code{is.leaf(object)} returns logical indicating if \code{object} is a
|
| 30228 |
maechler |
201 |
leaf (the most simple dendrogram).
|
| 60892 |
ripley |
202 |
|
| 30228 |
maechler |
203 |
\code{plotNode()} and \code{plotNodeLimit()} are helper functions.
|
| 27474 |
ripley |
204 |
}
|
|
|
205 |
\note{
|
| 53892 |
maechler |
206 |
\describe{
|
|
|
207 |
\item{\code{plot()}:}{When using \code{type = "triangle"},
|
|
|
208 |
\code{center = TRUE} often looks better.}
|
|
|
209 |
\item{\code{str(d)}:}{If you really want to see the \emph{internal}
|
|
|
210 |
structure, use \code{str(unclass(d))} instead.}
|
|
|
211 |
}
|
| 27474 |
ripley |
212 |
}
|
| 35940 |
ripley |
213 |
\section{Warning}{
|
| 68633 |
maechler |
214 |
Some operations on dendrograms such as \code{merge()} make use of
|
| 70613 |
maechler |
215 |
recursion. For deep trees it may be necessary to increase
|
|
|
216 |
\code{\link{options}("expressions")}: if you do, you are likely to need
|
|
|
217 |
to set the C stack size (\code{\link{Cstack_info}()[["size"]]}) larger
|
|
|
218 |
than the default where possible.
|
| 35940 |
ripley |
219 |
}
|
| 30228 |
maechler |
220 |
\seealso{
|
| 53892 |
maechler |
221 |
\code{\link{dendrapply}} for applying a function to \emph{each} node.
|
|
|
222 |
\code{\link{order.dendrogram}} and \code{\link{reorder.dendrogram}};
|
|
|
223 |
further, the \code{\link{labels}} method.
|
| 30228 |
maechler |
224 |
}
|
| 27474 |
ripley |
225 |
\examples{
|
| 41508 |
ripley |
226 |
require(graphics); require(utils)
|
|
|
227 |
|
| 27474 |
ripley |
228 |
hc <- hclust(dist(USArrests), "ave")
|
|
|
229 |
(dend1 <- as.dendrogram(hc)) # "print()" method
|
| 30884 |
maechler |
230 |
str(dend1) # "str()" method
|
| 80080 |
hornik |
231 |
str(dend1, max.level = 2, last.str = "'") # only the first two sub-levels
|
| 57963 |
maechler |
232 |
oo <- options(str.dendrogram.last = "\\\\") # yet another possibility
|
| 80080 |
hornik |
233 |
str(dend1, max.level = 2) # only the first two sub-levels
|
| 61168 |
ripley |
234 |
options(oo) # .. resetting them
|
| 27474 |
ripley |
235 |
|
| 61160 |
ripley |
236 |
op <- par(mfrow = c(2,2), mar = c(5,2,1,4))
|
| 27474 |
ripley |
237 |
plot(dend1)
|
|
|
238 |
## "triangle" type and show inner nodes:
|
| 61160 |
ripley |
239 |
plot(dend1, nodePar = list(pch = c(1,NA), cex = 0.8, lab.cex = 0.8),
|
|
|
240 |
type = "t", center = TRUE)
|
|
|
241 |
plot(dend1, edgePar = list(col = 1:2, lty = 2:3),
|
|
|
242 |
dLeaf = 1, edge.root = TRUE)
|
|
|
243 |
plot(dend1, nodePar = list(pch = 2:1, cex = .4*2:1, col = 2:3),
|
|
|
244 |
horiz = TRUE)
|
| 27474 |
ripley |
245 |
|
| 54147 |
maechler |
246 |
## simple test for as.hclust() as the inverse of as.dendrogram():
|
| 53892 |
maechler |
247 |
stopifnot(identical(as.hclust(dend1)[1:4], hc[1:4]))
|
|
|
248 |
|
| 61160 |
ripley |
249 |
dend2 <- cut(dend1, h = 70)
|
| 79012 |
kalibera |
250 |
## leaves are wrong horizontally in R 4.0 and earlier:
|
| 27474 |
ripley |
251 |
plot(dend2$upper)
|
| 61160 |
ripley |
252 |
plot(dend2$upper, nodePar = list(pch = c(1,7), col = 2:1))
|
| 27474 |
ripley |
253 |
## dend2$lower is *NOT* a dendrogram, but a list of .. :
|
| 61160 |
ripley |
254 |
plot(dend2$lower[[3]], nodePar = list(col = 4), horiz = TRUE, type = "tr")
|
| 27474 |
ripley |
255 |
## "inner" and "leaf" edges in different type & color :
|
| 61168 |
ripley |
256 |
plot(dend2$lower[[2]], nodePar = list(col = 1), # non empty list
|
| 61160 |
ripley |
257 |
edgePar = list(lty = 1:2, col = 2:1), edge.root = TRUE)
|
| 27474 |
ripley |
258 |
par(op)
|
| 53892 |
maechler |
259 |
d3 <- dend2$lower[[2]][[2]][[1]]
|
|
|
260 |
stopifnot(identical(d3, dend2$lower[[2]][[c(2,1)]]))
|
| 61160 |
ripley |
261 |
str(d3, last.str = "'")
|
| 30228 |
maechler |
262 |
|
| 66629 |
maechler |
263 |
## to peek at the inner structure "if you must", use '[..]' indexing :
|
| 65131 |
maechler |
264 |
str(d3[2][[1]]) ## or the full
|
|
|
265 |
str(d3[])
|
|
|
266 |
|
| 53892 |
maechler |
267 |
## merge() to join dendrograms:
|
|
|
268 |
(d13 <- merge(dend2$lower[[1]], dend2$lower[[3]]))
|
|
|
269 |
## merge() all parts back (using default 'height' instead of original one):
|
|
|
270 |
den.1 <- Reduce(merge, dend2$lower)
|
|
|
271 |
## or merge() all four parts at same height --> 4 branches (!)
|
| 56287 |
ripley |
272 |
d. <- merge(dend2$lower[[1]], dend2$lower[[2]], dend2$lower[[3]],
|
|
|
273 |
dend2$lower[[4]])
|
| 53892 |
maechler |
274 |
## (with a warning) or the same using do.call :
|
|
|
275 |
stopifnot(identical(d., do.call(merge, dend2$lower)))
|
| 61160 |
ripley |
276 |
plot(d., main = "merge(d1, d2, d3, d4) |-> dendrogram with a 4-split")
|
| 53892 |
maechler |
277 |
|
| 46113 |
maechler |
278 |
## "Zoom" in to the first dendrogram :
|
|
|
279 |
plot(dend1, xlim = c(1,20), ylim = c(1,50))
|
|
|
280 |
|
| 61160 |
ripley |
281 |
nP <- list(col = 3:2, cex = c(2.0, 0.75), pch = 21:22,
|
|
|
282 |
bg = c("light blue", "pink"),
|
| 30228 |
maechler |
283 |
lab.cex = 0.75, lab.col = "tomato")
|
| 61160 |
ripley |
284 |
plot(d3, nodePar= nP, edgePar = list(col = "gray", lwd = 2), horiz = TRUE)
|
| 30228 |
maechler |
285 |
%% now add some "edgetext" :
|
|
|
286 |
addE <- function(n) {
|
|
|
287 |
if(!is.leaf(n)) {
|
| 61160 |
ripley |
288 |
attr(n, "edgePar") <- list(p.col = "plum")
|
| 30228 |
maechler |
289 |
attr(n, "edgetext") <- paste(attr(n,"members"),"members")
|
|
|
290 |
}
|
|
|
291 |
n
|
| 27474 |
ripley |
292 |
}
|
| 30228 |
maechler |
293 |
d3e <- dendrapply(d3, addE)
|
| 61160 |
ripley |
294 |
plot(d3e, nodePar = nP)
|
|
|
295 |
plot(d3e, nodePar = nP, leaflab = "textlike")
|
| 30228 |
maechler |
296 |
|
| 61160 |
ripley |
297 |
%% BUG: edge labeling *and* leaflab = "textlike" both fail with horiz = TRUE:
|
|
|
298 |
%% BUG plot(d3e, nodePar = nP, leaflab = "textlike", horiz = TRUE)
|
| 30228 |
maechler |
299 |
}
|
| 27474 |
ripley |
300 |
\keyword{multivariate}
|
|
|
301 |
\keyword{tree}% FIXME: want as.dendrogram.tree() etc!
|
|
|
302 |
\keyword{hplot}% only for plot.()
|