% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/dend_utils.R
\name{dend_node_apply}
\alias{dend_node_apply}
\alias{edit_node}
\title{Apply functions on every node in a dendrogram}
\usage{
dend_node_apply(dend, fun)

edit_node(dend, fun = function(d, index) d)
}
\arguments{
\item{dend}{A \code{dendrogram} object.}

\item{fun}{A self-defined function.}
}
\value{
\code{dend_node_apply()} returns a vector or a list, depends on whether \code{fun} returns a scalar or more complex values.

\code{edit_node()} returns a \code{dendrogram} object.
}
\description{
Apply functions on every node in a dendrogram
}
\details{
\code{dend_node_apply()} returns a vector or a list as the same length as the number of nodes in the dendrogram.

The self-defined function can have one single argument which is the sub-dendrogram at a certain node.
E.g. to get the number of members at every node:

\if{html}{\out{<div class="sourceCode">}}\preformatted{dend_node_apply(dend, function(d) attr(d, "members"))
}\if{html}{\out{</div>}}

The self-defined function can have a second argument, which is the index of current sub-dendrogram in
the complete dendrogram. E.g. \code{dend[[1]]} is the first child node of the complete dendrogram and
\code{dend[[c(1, 2)]]} is the second child node of \code{dend[[1]]}, et al. This makes that at a certain node,
it is possible to get information of its child nodes and parent nodes.

\if{html}{\out{<div class="sourceCode">}}\preformatted{dend_node_apply(dend, function(d, index) \{
    dend[[c(index, 1)]] # is the first child node of d, or simply d[[1]]
    dend[[index[-length(index)]]] # is the parent node of d
    ...
\})
}\if{html}{\out{</div>}}

Note for the top node, the value of \code{index} is \code{NULL}.

In \code{edit_node()}, if \code{fun} only has one argument, it is basically the same as \code{\link[stats:dendrapply]{stats::dendrapply()}},
but it can have a second argument which is the index of the node in the dendrogram,
which makes it possible to get information of child nodes and parent nodes for
a specific node.

As an example, we first assign random values to every node in the dendrogram:

\if{html}{\out{<div class="sourceCode">}}\preformatted{mat = matrix(rnorm(100), 10)
dend = as.dendrogram(hclust(dist(mat)))
dend = edit_node(dend, function(d) \{attr(d, 'score') = runif(1); d\})
}\if{html}{\out{</div>}}

Then for every node, we take the maximal absolute difference to all its child nodes
and parent node as the attribute \code{abs_diff}.

\if{html}{\out{<div class="sourceCode">}}\preformatted{dend = edit_node(dend, function(d, index) \{
    n = length(index)
    s = attr(d, "score")
    if(is.null(index)) \{  # d is the top node
        s_children = sapply(d, function(x) attr(x, "score"))
        s_parent = NULL
    \} else if(is.leaf(d)) \{ # d is the leaf
        s_children = NULL
        s_parent = attr(dend[[index[-n]]], "score")
    \} else \{
        s_children = sapply(d, function(x) attr(x, "score"))
        s_parent = attr(dend[[index[-n]]], "score")
    \}
    abs_diff = max(abs(s - c(s_children, s_parent)))
    attr(d, "abs_diff") = abs_diff
    return(d)
\})
}\if{html}{\out{</div>}}
}
\examples{
mat = matrix(rnorm(100), 10)
dend = as.dendrogram(hclust(dist(mat)))
# number of members on every node
dend_node_apply(dend, function(d) attr(d, "members"))
# the depth on every node
dend_node_apply(dend, function(d, index) length(index))
}
