Node is at the very heart of the data.tree package. All trees are constructed
by tying together Node objects.
# n1 <- Node$new("Node 1")An R6Class generator object
Assemble Node objects into a data.tree
structure and use the traversal methods to set, get, and perform operations on it. Typically, you construct larger tree
structures by converting from data.frame, list, or other formats.
Most methods (e.g. node$Sort()) also have a functional form (e.g. Sort(node))
For more details see the data.tree documentations, or the data.tree vignette: vignette("data.tree")
Node
nameGets or sets the name of a Node. For example Node$name <- "Acme".
printFormattersgets or sets the formatters used to print a Node.
Set this as a list to a root node.
The different formatters are h (horizontal), v (vertical), l (L), j (junction), and s (separator).
For example, you can set the formatters to list(h = "\u2500" , v = "\u2502", l = "\u2514", j = "\u251C", s = " ")
to get a similar behavior as in fs::dir_tree().
The defaults are: list(h = "--" , v = "\u00A6", l = "\u00B0", j = "\u00A6", s = " ")
parentGets or sets the parent Node of a Node. Only set this if you know what you are doing, as you might mess up the tree structure!
childrenGets or sets the children list of a Node. Only set this if you know what you are doing, as you might mess up the tree structure!
isLeafReturns TRUE if the Node is a leaf, FALSE otherwise
isRootReturns TRUE if the Node is the root, FALSE otherwise
countReturns the number of children of a Node
totalCountReturns the total number of Nodes in the tree
pathReturns a vector of mode character containing the names of the Nodes in the path from the root to this Node
pathStringReturns a string representing the path to this Node, separated by backslash
positionThe position of a Node within its siblings
attributesThe attributes defined on this specific node
attributesAllThe distinct union of attributes defined on all the nodes in the tree spanned by this Node
levelNameReturns the name of the Node, preceded by level times '*'. Useful for printing and not typically called by package users.
leavesReturns a list containing all the leaf Nodes
leafCountReturns the number of leaves are below a Node
levelReturns an integer representing the level of a Node. For example, the root has level 1.
heightReturns max(level) of any of the Nodes of the tree
isBinaryReturns TRUE if all Nodes in the tree (except the leaves) have count = 2
rootReturns the root of a Node in a tree.
siblingsReturns a list containing all the siblings of this Node
averageBranchingFactorReturns the average number of crotches below this Node
new()Create a new Node object. This is often used to create the root of a tree when creating a tree programmatically.
namethe name of the node to be created
checkEither
"check": if the name conformance should be checked and warnings should be printed in case of non-conformance (the default)
"no-warn": if the name conformance should be checked, but no warnings should be printed in case of non-conformance (if you expect non-conformance)
"no-check" or FALSE: if the name conformance should not be checked; use this if performance is critical. However, in case of non-conformance, expect cryptic follow-up errors
...A name-value mapping of node attributes
node <- Node$new("mynode", x = 2, y = "value of y")
node$y
AddChild()Creates a Node and adds it as the last sibling as a child to the Node on which this is called.
Node$AddChild(name, check = c("check", "no-warn", "no-check"), ...)namethe name of the node to be created
checkEither
"check": if the name conformance should be checked and warnings should be printed in case of non-conformance (the default)
"no-warn": if the name conformance should be checked, but no warnings should be printed in case of non-conformance (if you expect non-conformance)
"no-check" or FALSE: if the name conformance should not be checked; use this if performance is critical. However, in case of non-conformance, expect cryptic follow-up errors
...A name-value mapping of node attributes
AddSibling()Creates a new Node called name and adds it after this Node as a sibling.
Node$AddSibling(name, check = c("check", "no-warn", "no-check"), ...)namethe name of the node to be created
checkEither
"check": if the name conformance should be checked and warnings should be printed in case of non-conformance (the default)
"no-warn": if the name conformance should be checked, but no warnings should be printed in case of non-conformance (if you expect non-conformance)
"no-check" or FALSE: if the name conformance should not be checked; use this if performance is critical. However, in case of non-conformance, expect cryptic follow-up errors
...A name-value mapping of node attributes
RemoveChild()Remove the child Node called name from a Node and returns it.
node <- Node$new("myroot")$AddChild("mychild")$root
node$RemoveChild("mychild")
RemoveAttribute()Removes attribute called name from this Node.
namethe name of the node to be created
stopIfNotAvailableGives an error if stopIfNotAvailable and the attribute does not exist.
node <- Node$new("mynode")
node$RemoveAttribute("age", stopIfNotAvailable = FALSE)
node$age <- 27
node$RemoveAttribute("age")
node
Sort()Sort children of a Node or an entire data.tree structure
attributedetermines what is collected. The attribute can be
a.) the name of a field or a property/active of each Node in the tree, e.g. acme$Get("p") or acme$Get("position")
b.) the name of a method of each Node in the tree, e.g. acme$Get("levelZeroBased"), where e.g. acme$levelZeroBased <- function() acme$level - 1
c.) a function, whose first argument must be a Node e.g. acme$Get(function(node) node$cost * node$p)
...any parameters to be passed on the the attribute (in case it's a method or a function)
decreasingsort order
recursiveif TRUE, the method will be called recursively on the Node's children. This allows sorting an entire tree.
You can sort with respect to any argument of the tree. But note that sorting has side-effects, meaning that you modify the underlying, original data.tree object structure.
See also Sort for the equivalent function.
Revert()Reverts the sort order of a Node's children.
See also Revert for the equivalent function.
Prune()Prunes a tree.
Pruning refers to removing entire subtrees. This function has side-effects, it modifies your data.tree structure!
See also Prune for the equivalent function.
Climb()Climb a tree from parent to children, by provided criteria.
...an attribute-value pairlist to be searched. For brevity, you can also provide a character vector to search for names.
nodeThe root Node of the tree or subtree to climb
This method lets you climb the tree, from crutch to crutch. On each Node, the
Climb finds the first child having attribute value equal to the the provided argument.
Climb(node, ...)
data(acme)
#the following are all equivalent
Climb(acme, 'IT', 'Outsource')
Climb(acme, name = 'IT', name = 'Outsource')
Climb(acme, 'IT')$Climb('Outsource')
Navigate(acme, path = "IT/Outsource")
Climb(acme, name = 'IT')
Climb(acme, position = c(2, 1))
#or, equivalent:
Climb(acme, position = 2, position = 1)
Climb(acme, name = "IT", cost = 250000)
tree <- CreateRegularTree(5, 2)
tree$Climb(c("1", "1"), position = c(2, 2))$path
Navigate()Navigate to another node by relative path.
pathA string or a character vector describing the path to navigate
nodeThe starting Node to navigate
Get()Traverse a Tree and Collect Values
attributedetermines what is collected. The attribute can be
a.) the name of a field or a property/active of each Node in the tree, e.g. acme$Get("p") or acme$Get("position")
b.) the name of a method of each Node in the tree, e.g. acme$Get("levelZeroBased"), where e.g. acme$levelZeroBased <- function() acme$level - 1
c.) a function, whose first argument must be a Node e.g. acme$Get(function(node) node$cost * node$p)
...in case the attribute is a function or a method, the ellipsis is passed to it as additional arguments.
traversaldefines the traversal order to be used. This can be
Go to first child, then to its first child, etc.
Go to the first branch's leaf, then to its siblings, and work your way back to the root
Go to the first branch's leaf, then to its parent, and only then to the leaf's sibling
Collect root, then level 2, then level 3, etc.
Take a node, then the node's parent, then that node's parent in turn, etc. This ignores the pruneFun
You can also provide a function, whose sole parameter is a Node object. The function is expected to return the node's next node, a list of the node's next nodes, or NULL.
Read the data.tree vignette for a detailed explanation of these traversal orders.
pruneFunallows providing a prune criteria, i.e. a function taking a Node as an input, and returning TRUE or FALSE.
If the pruneFun returns FALSE for a Node, then the Node and its entire sub-tree will not be considered.
filterFunallows providing a a filter, i.e. a function taking a Node as an input, and returning TRUE or FALSE.
Note that if filter returns FALSE, then the node will be excluded from the result (but not the entire subtree).
formatif FALSE (the default), no formatting is being used. If TRUE, then the first formatter (if any) found along the ancestor path is being used for formatting
(see SetFormat). If format is a function, then the collected value is passed to that function, and the result is returned.
inheritFromAncestorsif TRUE, then the path above a Node is searched to get the attribute in case it is NULL.
simplifysame as sapply, i.e. TRUE, FALSE or "array". Additionally, you can specify "regular" if
each returned value is of length > 1, and equally named. See below for an example.
The Get method is one of the most important ones of the data.tree package. It lets you traverse a tree
and collect values along the way. Alternatively, you can call a method or a function on each Node.
a vector containing the atrributes collected during traversal, in traversal order. NULL is converted
to NA, such that length(Node$Get) == Node$totalCount
data(acme)
acme$Get("level")
acme$Get("totalCount")
acme$Get(function(node) node$cost * node$p,
filterFun = isLeaf)
#This is equivalent:
nodes <- Traverse(acme, filterFun = isLeaf)
Get(nodes, function(node) node$cost * node$p)
#simplify = "regular" will preserve names
acme$Get(function(x) c(position = x$position, level = x$level), simplify = "regular")
Do()Executes a function on a set of nodes
Node$Do(
fun,
...,
traversal = c("pre-order", "post-order", "in-order", "level", "ancestor"),
pruneFun = NULL,
filterFun = NULL
)funthe function to execute. The function is expected to be either a Method, or to take a Node as its first argument
...A name-value mapping of node attributes
traversaldefines the traversal order to be used. This can be
Go to first child, then to its first child, etc.
Go to the first branch's leaf, then to its siblings, and work your way back to the root
Go to the first branch's leaf, then to its parent, and only then to the leaf's sibling
Collect root, then level 2, then level 3, etc.
Take a node, then the node's parent, then that node's parent in turn, etc. This ignores the pruneFun
You can also provide a function, whose sole parameter is a Node object. The function is expected to return the node's next node, a list of the node's next nodes, or NULL.
Read the data.tree vignette for a detailed explanation of these traversal orders.
pruneFunallows providing a prune criteria, i.e. a function taking a Node as an input, and returning TRUE or FALSE.
If the pruneFun returns FALSE for a Node, then the Node and its entire sub-tree will not be considered.
filterFunallows providing a a filter, i.e. a function taking a Node as an input, and returning TRUE or FALSE.
Note that if filter returns FALSE, then the node will be excluded from the result (but not the entire subtree).
Set()Traverse a Tree and Assign Values
Node$Set(
...,
traversal = c("pre-order", "post-order", "in-order", "level", "ancestor"),
pruneFun = NULL,
filterFun = NULL
)...each argument can be a vector of values to be assigned. Recycled.
traversaldefines the traversal order to be used. This can be
Go to first child, then to its first child, etc.
Go to the first branch's leaf, then to its siblings, and work your way back to the root
Go to the first branch's leaf, then to its parent, and only then to the leaf's sibling
Collect root, then level 2, then level 3, etc.
Take a node, then the node's parent, then that node's parent in turn, etc. This ignores the pruneFun
You can also provide a function, whose sole parameter is a Node object. The function is expected to return the node's next node, a list of the node's next nodes, or NULL.
Read the data.tree vignette for a detailed explanation of these traversal orders.
pruneFunallows providing a prune criteria, i.e. a function taking a Node as an input, and returning TRUE or FALSE.
If the pruneFun returns FALSE for a Node, then the Node and its entire sub-tree will not be considered.
filterFunallows providing a a filter, i.e. a function taking a Node as an input, and returning TRUE or FALSE.
Note that if filter returns FALSE, then the node will be excluded from the result (but not the entire subtree).
library(data.tree)
acme <- Node$new("Acme Inc.")
accounting <- acme$AddChild("Accounting")$
AddSibling("Research")$
AddChild("New Labs")$
parent$
AddSibling("IT")$
AddChild("Outsource")
print(acme)
#> levelName
#> 1 Acme Inc.
#> 2 ¦--Accounting
#> 3 ¦--Research
#> 4 ¦ °--New Labs
#> 5 °--IT
#> 6 °--Outsource
## ------------------------------------------------
## Method `Node$new`
## ------------------------------------------------
node <- Node$new("mynode", x = 2, y = "value of y")
node$y
#> [1] "value of y"
## ------------------------------------------------
## Method `Node$AddChild`
## ------------------------------------------------
root <- Node$new("myroot", myname = "I'm the root")
root$AddChild("child1", myname = "I'm the favorite child")
child2 <- root$AddChild("child2", myname = "I'm just another child")
child3 <- child2$AddChild("child3", myname = "Grandson of a root!")
print(root, "myname")
#> levelName myname
#> 1 myroot I'm the root
#> 2 ¦--child1 I'm the favorite child
#> 3 °--child2 I'm just another child
#> 4 °--child3 Grandson of a root!
## ------------------------------------------------
## Method `Node$AddChildNode`
## ------------------------------------------------
root <- Node$new("myroot")
child <- Node$new("mychild")
root$AddChildNode(child)
## ------------------------------------------------
## Method `Node$AddSibling`
## ------------------------------------------------
#' root <- Node$new("myroot")
child <- root$AddChild("child1")
sibling <- child$AddSibling("sibling1")
## ------------------------------------------------
## Method `Node$AddSiblingNode`
## ------------------------------------------------
root <- Node$new("myroot")
child <- Node$new("mychild")
sibling <- Node$new("sibling")
root$AddChildNode(child)$AddSiblingNode(sibling)
## ------------------------------------------------
## Method `Node$RemoveChild`
## ------------------------------------------------
node <- Node$new("myroot")$AddChild("mychild")$root
node$RemoveChild("mychild")
#> levelName
#> 1 mychild
## ------------------------------------------------
## Method `Node$RemoveAttribute`
## ------------------------------------------------
node <- Node$new("mynode")
node$RemoveAttribute("age", stopIfNotAvailable = FALSE)
#> [1] FALSE
node$age <- 27
node$RemoveAttribute("age")
#> [1] TRUE
node
#> levelName
#> 1 mynode
## ------------------------------------------------
## Method `Node$Sort`
## ------------------------------------------------
data(acme)
acme$Do(function(x) x$totalCost <- Aggregate(x, "cost", sum), traversal = "post-order")
Sort(acme, "totalCost", decreasing = FALSE)
print(acme, "totalCost")
#> levelName totalCost
#> 1 Acme Inc. NA
#> 2 ¦--Accounting NA
#> 3 ¦--Research NA
#> 4 ¦ °--New Labs NA
#> 5 °--IT NA
#> 6 °--Outsource NA
## ------------------------------------------------
## Method `Node$Prune`
## ------------------------------------------------
data(acme)
acme$Do(function(x) x$cost <- Aggregate(x, "cost", sum))
Prune(acme, function(x) x$cost > 700000)
#> Error in if (!pruneFun(node$children[[i]])) { rm(list = names(node$children)[i], envir = node) node$children <- node$children[-i]}: missing value where TRUE/FALSE needed
print(acme, "cost")
#> levelName cost
#> 1 Acme Inc. NA
#> 2 ¦--Accounting NA
#> 3 ¦--Research NA
#> 4 ¦ °--New Labs NA
#> 5 °--IT NA
#> 6 °--Outsource NA
## ------------------------------------------------
## Method `Node$Climb`
## ------------------------------------------------
data(acme)
#the following are all equivalent
Climb(acme, 'IT', 'Outsource')
#> levelName
#> 1 Outsource
Climb(acme, name = 'IT', name = 'Outsource')
#> levelName
#> 1 Outsource
Climb(acme, 'IT')$Climb('Outsource')
#> levelName
#> 1 Outsource
Navigate(acme, path = "IT/Outsource")
#> levelName
#> 1 Outsource
Climb(acme, name = 'IT')
#> levelName
#> 1 IT
#> 2 °--Outsource
Climb(acme, position = c(2, 1))
#> levelName
#> 1 New Labs
#or, equivalent:
Climb(acme, position = 2, position = 1)
#> levelName
#> 1 New Labs
Climb(acme, name = "IT", cost = 250000)
#> NULL
tree <- CreateRegularTree(5, 2)
tree$Climb(c("1", "1"), position = c(2, 2))$path
#> NULL
## ------------------------------------------------
## Method `Node$Navigate`
## ------------------------------------------------
data(acme)
Navigate(acme$Research, "../IT/Outsource")
#> levelName
#> 1 Outsource
Navigate(acme$Research, c("..", "IT", "Outsource"))
#> levelName
#> 1 Outsource
## ------------------------------------------------
## Method `Node$Get`
## ------------------------------------------------
data(acme)
acme$Get("level")
#> Acme Inc. Accounting Research New Labs IT Outsource
#> 1 2 2 3 2 3
acme$Get("totalCount")
#> Acme Inc. Accounting Research New Labs IT Outsource
#> 6 1 2 1 2 1
acme$Get(function(node) node$cost * node$p,
filterFun = isLeaf)
#> $Accounting
#> integer(0)
#>
#> $`New Labs`
#> integer(0)
#>
#> $Outsource
#> integer(0)
#>
#This is equivalent:
nodes <- Traverse(acme, filterFun = isLeaf)
Get(nodes, function(node) node$cost * node$p)
#> $Accounting
#> integer(0)
#>
#> $`New Labs`
#> integer(0)
#>
#> $Outsource
#> integer(0)
#>
#simplify = "regular" will preserve names
acme$Get(function(x) c(position = x$position, level = x$level), simplify = "regular")
#> Acme Inc. Accounting Research New Labs IT Outsource
#> position 1 1 2 1 3 1
#> level 1 2 2 3 2 3
## ------------------------------------------------
## Method `Node$Do`
## ------------------------------------------------
data(acme)
acme$Do(function(node) node$expectedCost <- node$p * node$cost)
print(acme, "expectedCost")
#> levelName expectedCost
#> 1 Acme Inc. NA
#> 2 ¦--Accounting NA
#> 3 ¦--Research NA
#> 4 ¦ °--New Labs NA
#> 5 °--IT NA
#> 6 °--Outsource NA
## ------------------------------------------------
## Method `Node$Set`
## ------------------------------------------------
data(acme)
acme$Set(departmentId = 1:acme$totalCount, openingHours = NULL, traversal = "post-order")
acme$Set(head = c("Jack Brown",
"Mona Moneyhead",
"Dr. Frank N. Stein",
"Eric Nerdahl"
),
filterFun = function(x) !x$isLeaf
)
#> Warning: longer argument not a multiple of length of shorter
print(acme, "departmentId", "head")
#> levelName departmentId head
#> 1 Acme Inc. 6 Eric Nerdahl
#> 2 ¦--Accounting 1
#> 3 ¦--Research 3 Mona Moneyhead
#> 4 ¦ °--New Labs 2
#> 5 °--IT 5 Dr. Frank N. Stein
#> 6 °--Outsource 4