Title: | General Purpose Hierarchical Data Structure |
---|---|
Description: | Create tree structures from hierarchical data, and traverse the tree in various orders. Aggregate, cumulate, print, plot, convert to and from data.frame and more. Useful for decision trees, machine learning, finance, conversion from and to JSON, and many other applications. |
Authors: | Russ Hyde [ctb] (improve dependencies), Chris Hammill [ctb] (improve getting), Facundo Munoz [ctb] (improve list conversion), Markus Wamser [ctb] (fixed some typos), Pierre Formont [ctb] (additional features), Kent Russel [ctb] (documentation), Noam Ross [ctb] (fixes), Duncan Garmonsway [ctb] (fixes), Christoph Glur [aut, cre] (R interface) |
Maintainer: | Christoph Glur <[email protected]> |
License: | GPL (>= 2) |
Version: | 1.1.0 |
Built: | 2024-09-07 06:32:05 UTC |
Source: | CRAN |
acme's tree representation is accessed through its root, acme.
data(acme)
data(acme)
A data.tree root Node
cost, only available for leaf nodes. Cost of the project.
p probability that a project will be undertaken.
Node
, recursively.The Aggregate
method lets you fetch an attribute from a Node
's children, and then aggregate them
using aggFun
. For example, you can aggregate cost by summing costs of child Nodes
. This is especially useful in the
context of tree traversal, when using post-order traversal mode.
Aggregate(node, attribute, aggFun, ...)
Aggregate(node, attribute, aggFun, ...)
node |
the |
attribute |
determines what is collected. The
|
aggFun |
the aggregation function to be applied to the children's |
... |
any arguments to be passed on to attribute (in case it's a function) |
As with Get
, the attribute can be a field, a method or a function. If the attribute on a child
is NULL
, Aggregate
is called recursively on its children.
data(acme) #Aggregate on a field Aggregate(acme, "cost", sum) #This is the same as: HomeRolledAggregate <- function(node) { sum(sapply(node$children, function(child) { if (!is.null(child$cost)) child$cost else HomeRolledAggregate(child) })) } HomeRolledAggregate(acme) #Aggregate using Get print(acme, "cost", minCost = acme$Get(Aggregate, "cost", min)) #use Aggregate with a function: Aggregate(acme, function(x) x$cost * x$p, sum) #cache values along the way acme$Do(function(x) x$cost <- Aggregate(x, "cost", sum), traversal = "post-order") acme$IT$cost
data(acme) #Aggregate on a field Aggregate(acme, "cost", sum) #This is the same as: HomeRolledAggregate <- function(node) { sum(sapply(node$children, function(child) { if (!is.null(child$cost)) child$cost else HomeRolledAggregate(child) })) } HomeRolledAggregate(acme) #Aggregate using Get print(acme, "cost", minCost = acme$Get(Aggregate, "cost", min)) #use Aggregate with a function: Aggregate(acme, function(x) x$cost * x$p, sum) #cache values along the way acme$Do(function(x) x$cost <- Aggregate(x, "cost", sum), traversal = "post-order") acme$IT$cost
This can be useful for some conversions.
AreNamesUnique(node)
AreNamesUnique(node)
node |
The root |
TRUE
if all Node$name == TRUE
for all nodes in the tree
as.igraph.Node
data(acme) AreNamesUnique(acme) acme$name <- "IT" AreNamesUnique(acme)
data(acme) AreNamesUnique(acme) acme$name <- "IT" AreNamesUnique(acme)
data.tree
structure to a data.frame
If a node field contains data of length > 1, then that is converted into a string in the data.frame.
## S3 method for class 'Node' as.data.frame( x, row.names = NULL, optional = FALSE, ..., traversal = c("pre-order", "post-order", "in-order", "level", "ancestor"), pruneFun = NULL, filterFun = NULL, format = FALSE, inheritFromAncestors = FALSE ) ToDataFrameTree(x, ..., pruneFun = NULL) ToDataFrameTable(x, ..., pruneFun = NULL) ToDataFrameNetwork( x, ..., direction = c("climb", "descend"), pruneFun = NULL, format = FALSE, inheritFromAncestors = FALSE ) ToDataFrameTypeCol(x, ..., type = "level", prefix = type, pruneFun = NULL)
## S3 method for class 'Node' as.data.frame( x, row.names = NULL, optional = FALSE, ..., traversal = c("pre-order", "post-order", "in-order", "level", "ancestor"), pruneFun = NULL, filterFun = NULL, format = FALSE, inheritFromAncestors = FALSE ) ToDataFrameTree(x, ..., pruneFun = NULL) ToDataFrameTable(x, ..., pruneFun = NULL) ToDataFrameNetwork( x, ..., direction = c("climb", "descend"), pruneFun = NULL, format = FALSE, inheritFromAncestors = FALSE ) ToDataFrameTypeCol(x, ..., type = "level", prefix = type, pruneFun = NULL)
x |
The root |
row.names |
|
optional |
logical. If |
... |
the attributes to be added as columns of the data.frame. See |
traversal |
any of 'pre-order' (the default), 'post-order', 'in-order', 'level', or 'ancestor'. See |
pruneFun |
allows providing a prune criteria, i.e. a function taking a |
filterFun |
a function taking a |
format |
if |
inheritFromAncestors |
if FALSE, and if the attribute is a field or a method, then only a |
direction |
when converting to a network, should the edges point from root to children ("climb") or from child to parent ("descend")? |
type |
when converting type columns, the |
prefix |
when converting type columns, the prefix used for the column names. Can be NULL to omit prefixes. |
ToDataFrameTree: a data.frame
, where each row represents a Node
in the tree or sub-tree
spanned by x
, possibly pruned according to pruneFun
.
ToDataFrameTable: a data.frame
, where each row represents a leaf Node
in the tree or sub-tree
spanned by x
, possibly pruned according to pruneFun
.
ToDataFrameNetwork: a data.frame
, where each row represents a Node
in the tree or sub-tree
spanned by x
, possibly pruned according to pruneFun
. The first column is called 'from', while the
second is called 'to', describing the parent to child edge (for direction "climb") or the child to parent edge (for direction "descend").
If AreNamesUnique
is TRUE, then the Network is
based on the Node$name
, otherwise on the Node$pathString
ToDataFrameTypeCol: a data.frame
in table format (i.e. where each row represents a leaf in the tree or sub-tree
spanned by x
), possibly pruned according to pruneFun
. In addition to ...
, each distinct
type
is output to a column.
data(acme) acme$attributesAll as.data.frame(acme, row.names = NULL, optional = FALSE, "cost", "p") ToDataFrameTree(acme, "cost", "p") ToDataFrameNetwork(acme, "cost", "p", direction = "climb") ToDataFrameTable(acme, "cost", "p") ToDataFrameTypeCol(acme) #use the pruneFun: acme$Do(function(x) x$totalCost <- Aggregate(x, "cost", sum), traversal = "post-order") ToDataFrameTree(acme, "totalCost", pruneFun = function(x) x$totalCost > 300000) #inherit acme$Set(floor = c(1, 2, 3), filterFun = function(x) x$level == 2) as.data.frame(acme, row.names = NULL, optional = FALSE, "floor", inheritFromAncestors = FALSE) as.data.frame(acme, row.names = NULL, optional = FALSE, "floor", inheritFromAncestors = TRUE) #using a function as an attribute: acme$Accounting$Head <- "Mrs. Numright" acme$Research$Head <- "Mr. Stein" acme$IT$Head <- "Mr. Squarehead" ToDataFrameTable(acme, department = function(x) x$parent$name, "name", "Head", "cost") #complex TypeCol acme$IT$Outsource$AddChild("India") acme$IT$Outsource$AddChild("Poland") acme$Set(type = c('company', 'department', 'project', 'project', 'department', 'project', 'project', 'department', 'program', 'project', 'project', 'project', 'project' ) ) print(acme, 'type') ToDataFrameTypeCol(acme, type = 'type')
data(acme) acme$attributesAll as.data.frame(acme, row.names = NULL, optional = FALSE, "cost", "p") ToDataFrameTree(acme, "cost", "p") ToDataFrameNetwork(acme, "cost", "p", direction = "climb") ToDataFrameTable(acme, "cost", "p") ToDataFrameTypeCol(acme) #use the pruneFun: acme$Do(function(x) x$totalCost <- Aggregate(x, "cost", sum), traversal = "post-order") ToDataFrameTree(acme, "totalCost", pruneFun = function(x) x$totalCost > 300000) #inherit acme$Set(floor = c(1, 2, 3), filterFun = function(x) x$level == 2) as.data.frame(acme, row.names = NULL, optional = FALSE, "floor", inheritFromAncestors = FALSE) as.data.frame(acme, row.names = NULL, optional = FALSE, "floor", inheritFromAncestors = TRUE) #using a function as an attribute: acme$Accounting$Head <- "Mrs. Numright" acme$Research$Head <- "Mr. Stein" acme$IT$Head <- "Mr. Squarehead" ToDataFrameTable(acme, department = function(x) x$parent$name, "name", "Head", "cost") #complex TypeCol acme$IT$Outsource$AddChild("India") acme$IT$Outsource$AddChild("Poland") acme$Set(type = c('company', 'department', 'project', 'project', 'department', 'project', 'project', 'department', 'program', 'project', 'project', 'project', 'project' ) ) print(acme, 'type') ToDataFrameTypeCol(acme, type = 'type')
Node
to a dendrogram
Convert a data.tree
structure to a dendrogram
## S3 method for class 'Node' as.dendrogram( object, heightAttribute = DefaultPlotHeight, edgetext = FALSE, ... )
## S3 method for class 'Node' as.dendrogram( object, heightAttribute = DefaultPlotHeight, edgetext = FALSE, ... )
object |
The Node to convert |
heightAttribute |
The attribute (field name or function) storing the height |
edgetext |
If TRUE, then the for non-leaf nodes the node name is stored as the dendrogram's edge text. |
... |
Additional parameters |
An object of class dendrogram
Other Conversions from Node:
ToNewick()
data(acme) acmed <- as.dendrogram(acme) plot(acmed, center = TRUE) #you can take an attribute for the height: acme$Do( function(x) x$myPlotHeight <- (10 - x$level)) acmed <- as.dendrogram(acme, heightAttribute = "myPlotHeight") plot(acmed, center = TRUE) #or directly a function acmed <- as.dendrogram(acme, heightAttribute = function(x) 10 - x$level) plot(acmed)
data(acme) acmed <- as.dendrogram(acme) plot(acmed, center = TRUE) #you can take an attribute for the height: acme$Do( function(x) x$myPlotHeight <- (10 - x$level)) acmed <- as.dendrogram(acme, heightAttribute = "myPlotHeight") plot(acmed, center = TRUE) #or directly a function acmed <- as.dendrogram(acme, heightAttribute = function(x) 10 - x$level) plot(acmed)
data.tree
structure to an igraph networkThis requires the igraph package to be installed.
Also, this requires the names of the Nodes
to be unique within
the data.tree
structure.
as.igraph.Node( x, vertexAttributes = character(), edgeAttributes = character(), directed = FALSE, direction = c("climb", "descend"), ... )
as.igraph.Node( x, vertexAttributes = character(), edgeAttributes = character(), directed = FALSE, direction = c("climb", "descend"), ... )
x |
The root |
vertexAttributes |
A vector of strings, representing the attributes
in the |
edgeAttributes |
A vector of strings, representing the attributes
in the |
directed |
Logical scalar, whether or not to create a directed graph. |
direction |
when converting to a network, should the edges point from root to children ("climb") or from child to parent ("descend")? |
... |
Currently unused. |
an igraph
object
AreNamesUnique
data(acme) library(igraph) ig <- as.igraph(acme, "p", c("level", "isLeaf")) plot(ig)
data(acme) library(igraph) ig <- as.igraph(acme, "p", c("level", "isLeaf")) plot(ig)
data.tree
structure to a list-of-list structureConvert a data.tree
structure to a list-of-list structure
## S3 method for class 'Node' as.list( x, mode = c("simple", "explicit"), unname = FALSE, nameName = ifelse(unname, "name", ""), childrenName = "children", rootName = "", keepOnly = NULL, pruneFun = NULL, ... ) ToListSimple(x, nameName = "name", pruneFun = NULL, ...) ToListExplicit( x, unname = FALSE, nameName = ifelse(unname, "name", ""), childrenName = "children", pruneFun = NULL, ... )
## S3 method for class 'Node' as.list( x, mode = c("simple", "explicit"), unname = FALSE, nameName = ifelse(unname, "name", ""), childrenName = "children", rootName = "", keepOnly = NULL, pruneFun = NULL, ... ) ToListSimple(x, nameName = "name", pruneFun = NULL, ...) ToListExplicit( x, unname = FALSE, nameName = ifelse(unname, "name", ""), childrenName = "children", pruneFun = NULL, ... )
x |
The Node to convert |
mode |
How the list is structured. "simple" (the default) will add children directly as nested lists.
"explicit" puts children in a separate nested list called |
unname |
If TRUE, and if |
nameName |
The name that should be given to the name element |
childrenName |
The name that should be given to the children nested list |
rootName |
The name of the node. If provided, this overrides |
keepOnly |
A character vector of attributes to include in the result. If |
pruneFun |
allows providing a prune criteria, i.e. a function taking a |
... |
Additional parameters passed to |
data(acme) str(ToListSimple(acme)) str(ToListSimple(acme, keepOnly = "cost")) str(ToListExplicit(acme)) str(ToListExplicit(acme, unname = TRUE)) str(ToListExplicit(acme, unname = TRUE, nameName = "id", childrenName = "descendants"))
data(acme) str(ToListSimple(acme)) str(ToListSimple(acme, keepOnly = "cost")) str(ToListExplicit(acme)) str(ToListExplicit(acme, unname = TRUE)) str(ToListExplicit(acme, unname = TRUE, nameName = "id", childrenName = "descendants"))
data.tree
data structureConvert an object to a data.tree
data structure
as.Node(x, ...)
as.Node(x, ...)
x |
The object to be converted |
... |
Additional arguments |
Other as.Node:
as.Node.data.frame()
,
as.Node.dendrogram()
,
as.Node.list()
,
as.Node.phylo()
,
as.Node.rpart()
SplitNode
from the party package to a data.tree
structure.Convert a a SplitNode
from the party package to a data.tree
structure.
## S3 method for class 'BinaryTree' as.Node(x, ...)
## S3 method for class 'BinaryTree' as.Node(x, ...)
x |
The BinaryTree |
... |
additional arguments (unused) |
library(party) airq <- subset(airquality, !is.na(Ozone)) airct <- ctree(Ozone ~ ., data = airq, controls = ctree_control(maxsurrogate = 3)) tree <- as.Node(airct) tree print(tree, "label", criterion = function(x) round(x$criterion$maxcriterion, 3), statistic = function(x) round(max(x$criterion$statistic), 3) ) FindNode(tree, 6)$path
library(party) airq <- subset(airquality, !is.na(Ozone)) airct <- ctree(Ozone ~ ., data = airq, controls = ctree_control(maxsurrogate = 3)) tree <- as.Node(airct) tree print(tree, "label", criterion = function(x) round(x$criterion$maxcriterion, 3), statistic = function(x) round(max(x$criterion$statistic), 3) ) FindNode(tree, 6)$path
data.frame
to a data.tree
structureConvert a data.frame
to a data.tree
structure
## S3 method for class 'data.frame' as.Node( x, ..., mode = c("table", "network"), pathName = "pathString", pathDelimiter = "/", colLevels = NULL, na.rm = TRUE ) FromDataFrameTable( table, pathName = "pathString", pathDelimiter = "/", colLevels = NULL, na.rm = TRUE, check = c("check", "no-warn", "no-check") ) FromDataFrameNetwork(network, check = c("check", "no-warn", "no-check"))
## S3 method for class 'data.frame' as.Node( x, ..., mode = c("table", "network"), pathName = "pathString", pathDelimiter = "/", colLevels = NULL, na.rm = TRUE ) FromDataFrameTable( table, pathName = "pathString", pathDelimiter = "/", colLevels = NULL, na.rm = TRUE, check = c("check", "no-warn", "no-check") ) FromDataFrameNetwork(network, check = c("check", "no-warn", "no-check"))
x |
The data.frame in the required format. |
... |
Any other argument implementations of this might need |
mode |
Either "table" (if x is a data.frame in tree or table format) or "network" |
pathName |
The name of the column in x containing the path of the row |
pathDelimiter |
The delimiter used to separate nodes in |
colLevels |
Nested list of column names, determining on what node levels the attributes are written to. |
na.rm |
If |
table |
a |
check |
Either
|
network |
A
|
The root Node
of the data.tree
structure
Other as.Node:
as.Node.dendrogram()
,
as.Node.list()
,
as.Node.phylo()
,
as.Node.rpart()
,
as.Node()
data(acme) #Tree x <- ToDataFrameTree(acme, "pathString", "p", "cost") x xN <- as.Node(x) print(xN, "p", "cost") #Table x <- ToDataFrameTable(acme, "pathString", "p", "cost") x xN <- FromDataFrameTable(x) print(xN, "p", "cost") #More complex Table structure, using colLevels acme$Set(floor = c(1, 2, 3), filterFun = function(x) x$level == 2) x <- ToDataFrameTable(acme, "pathString", "floor", "p", "cost") x xN <- FromDataFrameTable(x, colLevels = list(NULL, "floor", c("p", "cost")), na.rm = TRUE) print(xN, "floor", "p", "cost") #Network x <- ToDataFrameNetwork(acme, "p", "cost", direction = "climb") x xN <- FromDataFrameNetwork(x) print(xN, "p", "cost")
data(acme) #Tree x <- ToDataFrameTree(acme, "pathString", "p", "cost") x xN <- as.Node(x) print(xN, "p", "cost") #Table x <- ToDataFrameTable(acme, "pathString", "p", "cost") x xN <- FromDataFrameTable(x) print(xN, "p", "cost") #More complex Table structure, using colLevels acme$Set(floor = c(1, 2, 3), filterFun = function(x) x$level == 2) x <- ToDataFrameTable(acme, "pathString", "floor", "p", "cost") x xN <- FromDataFrameTable(x, colLevels = list(NULL, "floor", c("p", "cost")), na.rm = TRUE) print(xN, "floor", "p", "cost") #Network x <- ToDataFrameNetwork(acme, "p", "cost", direction = "climb") x xN <- FromDataFrameNetwork(x) print(xN, "p", "cost")
dendrogram
to a data.tree Node
Convert a dendrogram
to a data.tree Node
## S3 method for class 'dendrogram' as.Node( x, name = "Root", heightName = "plotHeight", check = c("check", "no-warn", "no-check"), ... )
## S3 method for class 'dendrogram' as.Node( x, name = "Root", heightName = "plotHeight", check = c("check", "no-warn", "no-check"), ... )
x |
The dendrogram |
name |
The name of the root Node |
heightName |
The name under which the dendrogram's height is stored |
check |
Either
|
... |
Additional parameters |
The root Node
of a data.tree
Other as.Node:
as.Node.data.frame()
,
as.Node.list()
,
as.Node.phylo()
,
as.Node.rpart()
,
as.Node()
hc <- hclust(dist(USArrests), "ave") dend1 <- as.dendrogram(hc) tree1 <- as.Node(dend1) tree1$attributesAll tree1$totalCount tree1$leafCount tree1$height
hc <- hclust(dist(USArrests), "ave") dend1 <- as.dendrogram(hc) tree1 <- as.Node(dend1) tree1$attributesAll tree1$totalCount tree1$leafCount tree1$height
list
structure to a data.tree
structureConvert a nested list
structure to a data.tree
structure
## S3 method for class 'list' as.Node( x, mode = c("simple", "explicit"), nameName = "name", childrenName = "children", nodeName = NULL, interpretNullAsList = FALSE, check = c("check", "no-warn", "no-check"), ... ) FromListExplicit( explicitList, nameName = "name", childrenName = "children", nodeName = NULL, check = c("check", "no-warn", "no-check") ) FromListSimple( simpleList, nameName = "name", nodeName = NULL, interpretNullAsList = FALSE, check = c("check", "no-warn", "no-check") )
## S3 method for class 'list' as.Node( x, mode = c("simple", "explicit"), nameName = "name", childrenName = "children", nodeName = NULL, interpretNullAsList = FALSE, check = c("check", "no-warn", "no-check"), ... ) FromListExplicit( explicitList, nameName = "name", childrenName = "children", nodeName = NULL, check = c("check", "no-warn", "no-check") ) FromListSimple( simpleList, nameName = "name", nodeName = NULL, interpretNullAsList = FALSE, check = c("check", "no-warn", "no-check") )
x |
The |
mode |
How the list is structured. "simple" (the default) will interpret any list to be a child. "explicit"
assumes that children are in a nested list called |
nameName |
The name of the element in the list that should be used as the name, can be NULL if mode = explicit and the children lists are named, or if an automatic name (running number) should be assigned |
childrenName |
The name of the element that contains the child list (applies to mode 'explicit' only). |
nodeName |
A name suggestion for x, if the name cannot be deferred otherwise. This is for example the case for the root with mode explicit and named lists. |
interpretNullAsList |
If |
check |
Either
|
... |
Any other argument to be passed to generic sub implementations |
explicitList |
A |
simpleList |
A |
Other as.Node:
as.Node.data.frame()
,
as.Node.dendrogram()
,
as.Node.phylo()
,
as.Node.rpart()
,
as.Node()
kingJosephs <- list(name = "Joseph I", spouse = "Mary", born = "1818-02-23", died = "1839-08-29", children = list( list(name = "Joseph II", spouse = "Kathryn", born = "1839-03-28", died = "1865-12-19"), list(name = "Helen", born = "1840-17-08", died = "1845-01-01") ) ) FromListExplicit(kingJosephs) kingJosephs <- list(head = "Joseph I", spouse = "Mary", born = "1818-02-23", died = "1839-08-29", list(head = "Joseph II", spouse = "Kathryn", born = "1839-03-28", died = "1865-12-19"), list(head = "Helen", born = "1840-17-08", died = "1845-01-01") ) FromListSimple(kingJosephs, nameName = "head") kingJosephs <- list(spouse = "Mary", born = "1818-02-23", died = "1839-08-29", `Joseph II` = list(spouse = "Kathryn", born = "1839-03-28", died = "1865-12-19"), Helen = list(born = "1840-17-08", died = "1845-01-01") ) FromListSimple(kingJosephs, nodeName = "Joseph I")
kingJosephs <- list(name = "Joseph I", spouse = "Mary", born = "1818-02-23", died = "1839-08-29", children = list( list(name = "Joseph II", spouse = "Kathryn", born = "1839-03-28", died = "1865-12-19"), list(name = "Helen", born = "1840-17-08", died = "1845-01-01") ) ) FromListExplicit(kingJosephs) kingJosephs <- list(head = "Joseph I", spouse = "Mary", born = "1818-02-23", died = "1839-08-29", list(head = "Joseph II", spouse = "Kathryn", born = "1839-03-28", died = "1865-12-19"), list(head = "Helen", born = "1840-17-08", died = "1845-01-01") ) FromListSimple(kingJosephs, nameName = "head") kingJosephs <- list(spouse = "Mary", born = "1818-02-23", died = "1839-08-29", `Joseph II` = list(spouse = "Kathryn", born = "1839-03-28", died = "1865-12-19"), Helen = list(born = "1840-17-08", died = "1845-01-01") ) FromListSimple(kingJosephs, nodeName = "Joseph I")
party
from the partykit package to a data.tree
structure.Convert a a party
from the partykit package to a data.tree
structure.
## S3 method for class 'party' as.Node(x, ...)
## S3 method for class 'party' as.Node(x, ...)
x |
The party object |
... |
other arguments (unused) |
library(partykit) data("WeatherPlay", package = "partykit") ### splits ### # split in overcast, humidity, and windy sp_o <- partysplit(1L, index = 1:3) sp_h <- partysplit(3L, breaks = 75) sp_w <- partysplit(4L, index = 1:2) ## query labels character_split(sp_o) ### nodes ### ## set up partynode structure pn <- partynode(1L, split = sp_o, kids = list( partynode(2L, split = sp_h, kids = list( partynode(3L, info = "yes"), partynode(4L, info = "no"))), partynode(5L, info = "yes"), partynode(6L, split = sp_w, kids = list( partynode(7L, info = "yes"), partynode(8L, info = "no"))))) pn ### tree ### ## party: associate recursive partynode structure with data py <- party(pn, WeatherPlay) tree <- as.Node(py) print(tree, "splitname", count = function(node) nrow(node$data), "splitLevel") SetNodeStyle(tree, label = function(node) paste0(node$name, ": ", node$splitname), tooltip = function(node) paste0(nrow(node$data), " observations"), fontname = "helvetica") SetEdgeStyle(tree, arrowhead = "none", label = function(node) node$splitLevel, fontname = "helvetica", penwidth = function(node) 12 * nrow(node$data)/nrow(node$root$data), color = function(node) { paste0("grey", 100 - as.integer( 100 * nrow(node$data)/nrow(node$root$data)) ) } ) Do(tree$leaves, function(node) { SetNodeStyle(node, shape = "box", color = ifelse(node$splitname == "yes", "darkolivegreen4", "lightsalmon4"), fillcolor = ifelse(node$splitname == "yes", "darkolivegreen1", "lightsalmon"), style = "filled,rounded", penwidth = 2 ) } ) plot(tree)
library(partykit) data("WeatherPlay", package = "partykit") ### splits ### # split in overcast, humidity, and windy sp_o <- partysplit(1L, index = 1:3) sp_h <- partysplit(3L, breaks = 75) sp_w <- partysplit(4L, index = 1:2) ## query labels character_split(sp_o) ### nodes ### ## set up partynode structure pn <- partynode(1L, split = sp_o, kids = list( partynode(2L, split = sp_h, kids = list( partynode(3L, info = "yes"), partynode(4L, info = "no"))), partynode(5L, info = "yes"), partynode(6L, split = sp_w, kids = list( partynode(7L, info = "yes"), partynode(8L, info = "no"))))) pn ### tree ### ## party: associate recursive partynode structure with data py <- party(pn, WeatherPlay) tree <- as.Node(py) print(tree, "splitname", count = function(node) nrow(node$data), "splitLevel") SetNodeStyle(tree, label = function(node) paste0(node$name, ": ", node$splitname), tooltip = function(node) paste0(nrow(node$data), " observations"), fontname = "helvetica") SetEdgeStyle(tree, arrowhead = "none", label = function(node) node$splitLevel, fontname = "helvetica", penwidth = function(node) 12 * nrow(node$data)/nrow(node$root$data), color = function(node) { paste0("grey", 100 - as.integer( 100 * nrow(node$data)/nrow(node$root$data)) ) } ) Do(tree$leaves, function(node) { SetNodeStyle(node, shape = "box", color = ifelse(node$splitname == "yes", "darkolivegreen4", "lightsalmon4"), fillcolor = ifelse(node$splitname == "yes", "darkolivegreen1", "lightsalmon"), style = "filled,rounded", penwidth = 2 ) } ) plot(tree)
phylo
object from the ape package to a Node
Convert a phylo
object from the ape package to a Node
## S3 method for class 'phylo' as.Node( x, heightName = "plotHeight", replaceUnderscores = TRUE, namesNotUnique = FALSE, ... )
## S3 method for class 'phylo' as.Node( x, heightName = "plotHeight", replaceUnderscores = TRUE, namesNotUnique = FALSE, ... )
x |
The phylo object to be converted |
heightName |
If the phylo contains edge lengths, then they will be converted to a height and stored in a field named according to this parameter (the default is "height") |
replaceUnderscores |
if TRUE (the default), then underscores in names are replaced with spaces |
namesNotUnique |
if TRUE, then the |
... |
any other parameter to be passed to sub-implementations |
Other ape phylo conversions:
GetPhyloNr()
,
as.phylo.Node()
Other as.Node:
as.Node.data.frame()
,
as.Node.dendrogram()
,
as.Node.list()
,
as.Node.rpart()
,
as.Node()
#which bird familes have the max height? library(ape) data(bird.families) bf <- as.Node(bird.families) height <- bf$height t <- Traverse(bf, filterFun = function(x) x$level == 25) Get(t, "name")
#which bird familes have the max height? library(ape) data(bird.families) bf <- as.Node(bird.families) height <- bf$height t <- Traverse(bf, filterFun = function(x) x$level == 25) Get(t, "name")
rpart
object to a data.tree
structureConvert an rpart
object to a data.tree
structure
## S3 method for class 'rpart' as.Node(x, digits = getOption("digits") - 3, use.n = FALSE, ...)
## S3 method for class 'rpart' as.Node(x, digits = getOption("digits") - 3, use.n = FALSE, ...)
x |
the |
digits |
the number of digits to be used for numeric values in labels |
use.n |
logical. Add cases to labels, see |
... |
any other argument to be passed to generic sub implementations |
a data.tree
object. The tree contains a field rpart.id
which
references back to the original node id in the row names of the rpart
object.
Other as.Node:
as.Node.data.frame()
,
as.Node.dendrogram()
,
as.Node.list()
,
as.Node.phylo()
,
as.Node()
if (require(rpart)) { fit <- rpart(Kyphosis ~ Age + Number + Start, data = kyphosis) as.Node(fit) }
if (require(rpart)) { fit <- rpart(Kyphosis ~ Age + Number + Start, data = kyphosis) as.Node(fit) }
Node
to a phylo object from the ape package.This method requires the ape package to be installed and loaded.
as.phylo.Node(x, heightAttribute = DefaultPlotHeight, ...)
as.phylo.Node(x, heightAttribute = DefaultPlotHeight, ...)
x |
The root |
heightAttribute |
The attribute (field name or function) storing the height |
... |
any other argument |
Other ape phylo conversions:
GetPhyloNr()
,
as.Node.phylo()
library(ape) data(acme) acmephylo <- as.phylo(acme) #plot(acmephylo)
library(ape) data(acme) acmephylo <- as.phylo(acme) #plot(acmephylo)
Calculate the average number of branches each non-leaf has
averageBranchingFactor(node)
averageBranchingFactor(node)
node |
The node to calculate the average branching factor for |
name
is a reserved word, as defined in NODE_RESERVED_NAMES_CONST
.Checks whether name
is a reserved word, as defined in NODE_RESERVED_NAMES_CONST
.
CheckNameReservedWord(name, check = c("check", "no-warn", "no-check"))
CheckNameReservedWord(name, check = c("check", "no-warn", "no-check"))
name |
the name to check |
check |
Either
|
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.
#node$Climb(...) Climb(node, ...)
#node$Climb(...) Climb(node, ...)
node |
The root |
... |
an attribute-value pairlist to be searched. For brevity, you can also provide a character vector to search for names. |
the Node
having path ...
, or NULL
if such a path does not exist
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
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
The method also clones object attributes (such as the formatters), if desired.
If the method is called on a non-root, then the parent relationship is not cloned,
and the resulting Node
will be a root.
Clone(node, pruneFun = NULL, attributes = FALSE)
Clone(node, pruneFun = NULL, attributes = FALSE)
node |
the root node of the tree or sub-tree to clone |
pruneFun |
allows providing a prune criteria, i.e. a function taking a |
attributes |
if FALSE, then R class attributes (e.g. formatters and grViz styles) are not cloned. This makes the method faster. |
the clone of the tree or sub-tree
SetFormat
data(acme) acmeClone <- Clone(acme) acmeClone$name <- "New Acme" # acmeClone does not point to the same reference object anymore: acme$name #cloning a subtree data(acme) itClone <- Clone(acme$IT) itClone$isRoot
data(acme) acmeClone <- Clone(acme) acmeClone$name <- "New Acme" # acmeClone does not point to the same reference object anymore: acme$name #cloning a subtree data(acme) itClone <- Clone(acme$IT) itClone$isRoot
Create a tree for demo and testing
CreateRandomTree(nodes = 100, root = Node$new("1"), id = 1)
CreateRandomTree(nodes = 100, root = Node$new("1"), id = 1)
nodes |
The number of nodes to create |
root |
the previous node (for recursion, typically use default value) |
id |
The id (for recursion) |
Create a tree for demo and testing
CreateRegularTree(height = 5, branchingFactor = 3, parent = Node$new("1"))
CreateRegularTree(height = 5, branchingFactor = 3, parent = Node$new("1"))
height |
the number of levels |
branchingFactor |
the number of children per node |
parent |
the parent node (for recursion) |
For example, you can sum up values of siblings before
this Node
.
Cumulate(node, attribute, aggFun, ...)
Cumulate(node, attribute, aggFun, ...)
node |
The node on which we want to cumulate |
attribute |
determines what is collected. The
|
aggFun |
the aggregation function to be applied to the children's |
... |
any arguments to be passed on to attribute (in case it's a function) |
data(acme) acme$Do(function(x) x$cost <- Aggregate(x, "cost", sum), traversal = "post-order") acme$Do(function(x) x$cumCost <- Cumulate(x, "cost", sum)) print(acme, "cost", "cumCost")
data(acme) acme$Do(function(x) x$cost <- Aggregate(x, "cost", sum), traversal = "post-order") acme$Do(function(x) x$cumCost <- Cumulate(x, "cost", sum)) print(acme, "cost", "cumCost")
Node
given the height of the root.This function puts leafs at the bottom (not hanging), and makes edges equally long.
Useful for easy plotting with third-party packages, e.g. if you have no specific height
attribute, e.g. with as.dendrogram.Node
, ToNewick
,
and as.phylo.Node
DefaultPlotHeight(node, rootHeight = 100)
DefaultPlotHeight(node, rootHeight = 100)
node |
The node |
rootHeight |
The height of the root |
data(acme) dacme <- as.dendrogram(acme, heightAttribute = function(x) DefaultPlotHeight(x, 200)) plot(dacme, center = TRUE)
data(acme) dacme <- as.dendrogram(acme, heightAttribute = function(x) DefaultPlotHeight(x, 200)) plot(dacme, center = TRUE)
The distance is measured as the number of edges that need to be traversed to reach node2 when starting from node1.
Distance(node1, node2)
Distance(node1, node2)
node1 |
the first node in the tree |
node2 |
the second node in the same tree |
data(acme) Distance(FindNode(acme, "Outsource"), FindNode(acme, "Research"))
data(acme) Distance(FindNode(acme, "Outsource"), FindNode(acme, "Research"))
Executes a function on a set of nodes
# OO-style: # node$Do(fun, # ..., # traversal = c("pre-order", "post-order", "in-order", "level", "ancestor"), # pruneFun = NULL, # filterFun = NULL) # traditional: Do(nodes, fun, ...)
# OO-style: # node$Do(fun, # ..., # traversal = c("pre-order", "post-order", "in-order", "level", "ancestor"), # pruneFun = NULL, # filterFun = NULL) # traditional: Do(nodes, fun, ...)
nodes |
The nodes on which to perform the Get (typically obtained via |
fun |
the function to execute. The function is expected to be either a Method, or to take a Node as its first argument |
... |
any additional parameters to be passed on to fun |
data(acme) traversal <- Traverse(acme) Do(traversal, function(node) node$expectedCost <- node$p * node$cost) print(acme, "expectedCost")
data(acme) traversal <- Traverse(acme) Do(traversal, function(node) node$expectedCost <- node$p * node$cost) print(acme, "expectedCost")
Scans the entire sub-tree spanned by node
and returns the first Node
having the name
specified. This is mainly useful for trees whose name is unique.
If AreNamesUnique
is FALSE
, i.e. if there is more than one Node
called name
in the tree, then it is undefined which one will be returned.
Also note that this method is not particularly fast. See examples for a faster way to
index large trees, if you need to do multiple searches. See Traverse
if
you need to find multiple Nodes
.
FindNode(node, name)
FindNode(node, name)
node |
The root |
name |
The name of the |
The first Node
whose name matches, or NULL
if no such Node
is
found.
AreNamesUnique, Traverse
data(acme) FindNode(acme, "Outsource") #re-usable hashed index for multiple searches: if(!AreNamesUnique(acme)) stop("Hashed index works for unique names only!") trav <- Traverse(acme, "level") names(trav) <- Get(trav, "name") nameIndex <- as.environment(trav) #you could also use hash from package hash instead! #nameIndex <- hash(trav) nameIndex$Outsource nameIndex$IT
data(acme) FindNode(acme, "Outsource") #re-usable hashed index for multiple searches: if(!AreNamesUnique(acme)) stop("Hashed index works for unique names only!") trav <- Traverse(acme, "level") names(trav) <- Get(trav, "name") nameIndex <- as.environment(trav) #you could also use hash from package hash instead! #nameIndex <- hash(trav) nameIndex$Outsource nameIndex$IT
Simple function that can be used as a format function when converting trees to a data.frame
FormatFixedDecimal(x, digits = 3)
FormatFixedDecimal(x, digits = 3)
x |
a numeric scalar or vector |
digits |
the number of digits to print after the decimal point |
A string corresponding to x, suitable for printing
data(acme) print(acme, prob = acme$Get("p", format = function(x) FormatFixedDecimal(x, 4)))
data(acme) print(acme, prob = acme$Get("p", format = function(x) FormatFixedDecimal(x, 4)))
This utility method can be used as a format function when converting trees to a data.frame
FormatPercent(x, digits = 2, format = "f", ...)
FormatPercent(x, digits = 2, format = "f", ...)
x |
A number |
digits |
The number of digits to print |
format |
The format to use |
... |
Any other argument passed to formatC |
A string corresponding to x, suitable for printing
formatC
data(acme) print(acme, prob = acme$Get("p", format = FormatPercent))
data(acme) print(acme, prob = acme$Get("p", format = FormatPercent))
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
.
# OO-style: #node$Get(attribute, # ..., # traversal = c("pre-order", "post-order", "in-order", "level", "ancestor"), # pruneFun = NULL, # filterFun = NULL, # format = FALSE, # inheritFromAncestors = FALSE) # traditional: Get(nodes, attribute, ..., format = FALSE, inheritFromAncestors = FALSE, simplify = c(TRUE, FALSE, "array", "regular"))
# OO-style: #node$Get(attribute, # ..., # traversal = c("pre-order", "post-order", "in-order", "level", "ancestor"), # pruneFun = NULL, # filterFun = NULL, # format = FALSE, # inheritFromAncestors = FALSE) # traditional: Get(nodes, attribute, ..., format = FALSE, inheritFromAncestors = FALSE, simplify = c(TRUE, FALSE, "array", "regular"))
nodes |
The nodes on which to perform the Get (typically obtained via |
attribute |
determines what is collected. The
|
... |
in case the |
format |
if |
inheritFromAncestors |
if |
simplify |
same as |
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")
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")
Get an attribute from a Node.
GetAttribute( node, attribute, ..., format = FALSE, inheritFromAncestors = FALSE, nullAsNa = TRUE )
GetAttribute( node, attribute, ..., format = FALSE, inheritFromAncestors = FALSE, nullAsNa = TRUE )
node |
The |
attribute |
determines what is collected. The
|
... |
in case the |
format |
if |
inheritFromAncestors |
if |
nullAsNa |
If TRUE (the default), then NULL is returned as NA. Otherwise it is returned as NULL. |
data(acme) GetAttribute(acme$IT$Outsource, "cost")
data(acme) GetAttribute(acme$IT$Outsource, "cost")
Node
has after conversion to a phylo objectUse this function when plotting a Node as a phylo, e.g. to set custom labels to plot.
GetPhyloNr(x, type = c("node", "edge"))
GetPhyloNr(x, type = c("node", "edge"))
x |
The Node |
type |
Either "node" (the default) or "edge" (to get the number of the edge from |
an integer representing the node
Other ape phylo conversions:
as.Node.phylo()
,
as.phylo.Node()
library(ape) library(data.tree) data(acme) ap <- as.phylo(acme) #plot(ap) #nodelabels("IT Dep.", GetPhyloNr(Climb(acme, "IT"))) #edgelabels("Good!", GetPhyloNr(Climb(acme, "IT", "Switch to R"), "edge"))
library(ape) library(data.tree) data(acme) ap <- as.phylo(acme) #plot(ap) #nodelabels("IT Dep.", GetPhyloNr(Climb(acme, "IT"))) #edgelabels("Good!", GetPhyloNr(Climb(acme, "IT", "Switch to R"), "edge"))
Node
is a leafCheck if a Node
is a leaf
isLeaf(node)
isLeaf(node)
node |
The Node to test. |
TRUE if the Node is a leaf, FALSE otherwise
Node
is not a leafCheck if a Node
is not a leaf
isNotLeaf(node)
isNotLeaf(node)
node |
The Node to test. |
FALSE if the Node is a leaf, TRUE otherwise
Node
is not a rootCheck if a Node
is not a root
isNotRoot(node)
isNotRoot(node)
node |
The Node to test. |
FALSE if the Node is the root, TRUE otherwise
Node
is the rootCheck if a Node
is the root
isRoot(node)
isRoot(node)
node |
The Node to test. |
TRUE if the Node is the root, FALSE otherwise
mushroom contains attributes of mushrooms. We can use this data to predict a mushroom's toxicity based on its attributes. The attributes available in the data set are:
data(mushroom)
data(mushroom)
data.frame
color the color of a mushroom
size whether a mushroom is small or large
points whether a mushroom has points
edibility whether a mushroom is edible or toxic
data.tree
Structure With Nodes
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")
# 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)
)
name
Gets or sets the name of a Node
. For example Node$name <- "Acme"
.
printFormatters
gets 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 = " ")
parent
Gets 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!
children
Gets 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!
isLeaf
Returns TRUE
if the Node
is a leaf, FALSE
otherwise
isRoot
Returns TRUE
if the Node
is the root, FALSE
otherwise
count
Returns the number of children of a Node
totalCount
Returns the total number of Node
s in the tree
path
Returns a vector of mode character
containing the names of the Node
s in the path from the root to this Node
pathString
Returns a string representing the path to this Node
, separated by backslash
position
The position of a Node
within its siblings
fields
Will be deprecated, use attributes
instead
fieldsAll
Will be deprecated, use attributesAll
instead
attributes
The attributes defined on this specific node
attributesAll
The distinct union of attributes defined on all the nodes in the tree spanned by this Node
levelName
Returns the name of the Node
, preceded by level times '*'. Useful for printing and not typically called by package users.
leaves
Returns a list containing all the leaf Node
s
leafCount
Returns the number of leaves are below a Node
level
Returns an integer representing the level of a Node
. For example, the root has level 1.
height
Returns max(level) of any of the Nodes
of the tree
isBinary
Returns TRUE
if all Node
s in the tree (except the leaves) have count = 2
root
Returns the root of a Node
in a tree.
siblings
Returns a list
containing all the siblings of this Node
averageBranchingFactor
Returns 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.
Node$new(name, check = c("check", "no-warn", "no-check"), ...)
name
the name of the node to be created
check
Either
"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
A new 'Node' object
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"), ...)
name
the name of the node to be created
check
Either
"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
The new Node
(invisibly)
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")
AddChildNode()
Adds a Node
as a child to this node.
Node$AddChildNode(child)
child
The child "Node"
to add.
the child node added (this lets you chain calls)
root <- Node$new("myroot") child <- Node$new("mychild") root$AddChildNode(child)
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"), ...)
name
the name of the node to be created
check
Either
"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
the sibling node (this lets you chain calls)
#' root <- Node$new("myroot") child <- root$AddChild("child1") sibling <- child$AddSibling("sibling1")
AddSiblingNode()
Adds a Node
after this Node
, as a sibling.
Node$AddSiblingNode(sibling)
sibling
The "Node"
to add as a sibling.
the added sibling node (this lets you chain calls, as in the examples)
root <- Node$new("myroot") child <- Node$new("mychild") sibling <- Node$new("sibling") root$AddChildNode(child)$AddSiblingNode(sibling)
RemoveChild()
Remove the child Node
called name
from a Node
and returns it.
Node$RemoveChild(name)
name
the name of the node to be created
the subtree spanned by the removed child.
node <- Node$new("myroot")$AddChild("mychild")$root node$RemoveChild("mychild")
RemoveAttribute()
Removes attribute called name
from this Node
.
Node$RemoveAttribute(name, stopIfNotAvailable = TRUE)
name
the name of the node to be created
stopIfNotAvailable
Gives 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
Node$Sort(attribute, ..., decreasing = FALSE, recursive = TRUE)
attribute
determines 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)
decreasing
sort order
recursive
if 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.
Returns the node on which Sort is called, invisibly. This can be useful to chain Node methods.
data(acme) acme$Do(function(x) x$totalCost <- Aggregate(x, "cost", sum), traversal = "post-order") Sort(acme, "totalCost", decreasing = FALSE) print(acme, "totalCost")
Revert()
Reverts the sort order of a Node
's children.
See also Revert
for the equivalent function.
Node$Revert(recursive = TRUE)
recursive
if TRUE
, the method will be called recursively on the Node
's children. This allows sorting an entire tree.
returns the Node invisibly (for chaining)
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.
Node$Prune(pruneFun)
pruneFun
allows providing a 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.
the number of nodes removed
data(acme) acme$Do(function(x) x$cost <- Aggregate(x, "cost", sum)) Prune(acme, function(x) x$cost > 700000) print(acme, "cost")
Climb()
Climb a tree from parent to children, by provided criteria.
Node$Climb(...)
...
an attribute-value pairlist to be searched. For brevity, you can also provide a character vector to search for names.
node
The 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, ...)
the Node
having path ...
, or NULL
if such a path does not exist
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.
Node$Navigate(path)
path
A string or a character vector describing the path to navigate
node
The starting Node
to navigate
The path
is always relative to the Node
. Navigation
to the parent is defined by ..
, whereas navigation to a child
is defined via the child's name.
If path is provided as a string, then the navigation steps are separated
by '/'.
data(acme) Navigate(acme$Research, "../IT/Outsource") Navigate(acme$Research, c("..", "IT", "Outsource"))
Get()
Traverse a Tree and Collect Values
Node$Get( attribute, ..., traversal = c("pre-order", "post-order", "in-order", "level", "ancestor"), pruneFun = NULL, filterFun = NULL, format = FALSE, inheritFromAncestors = FALSE, simplify = c(TRUE, FALSE, "array", "regular") )
attribute
determines 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.
traversal
defines 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.
pruneFun
allows 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.
filterFun
allows 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).
format
if 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.
inheritFromAncestors
if TRUE
, then the path above a Node
is searched to get the attribute
in case it is NULL.
simplify
same 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
.
See also Get
, Node
, Set
, Do
, Traverse
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 )
fun
the 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
traversal
defines 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.
pruneFun
allows 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.
filterFun
allows 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).
See also Node
, Get
, Set
, Traverse
data(acme) acme$Do(function(node) node$expectedCost <- node$p * node$cost) print(acme, "expectedCost")
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.
traversal
defines 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.
pruneFun
allows 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.
filterFun
allows 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).
The method takes one or more vectors as an argument. It traverses the tree, whereby the values are picked
from the vector. Also available as OO-style method on Node
.
See also Node
, Get
, Do
, Traverse
invisibly returns the nodes (useful for chaining)
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 ) print(acme, "departmentId", "head")
clone()
The objects of this class are cloneable with this method.
Node$clone(deep = FALSE)
deep
Whether to make a deep clone.
For more details see the data.tree
documentations, or the data.tree
vignette: vignette("data.tree")
library(data.tree) acme <- Node$new("Acme Inc.") accounting <- acme$AddChild("Accounting")$ AddSibling("Research")$ AddChild("New Labs")$ parent$ AddSibling("IT")$ AddChild("Outsource") print(acme) ## ------------------------------------------------ ## Method `Node$new` ## ------------------------------------------------ node <- Node$new("mynode", x = 2, y = "value of y") node$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") ## ------------------------------------------------ ## 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") ## ------------------------------------------------ ## Method `Node$RemoveAttribute` ## ------------------------------------------------ node <- Node$new("mynode") node$RemoveAttribute("age", stopIfNotAvailable = FALSE) node$age <- 27 node$RemoveAttribute("age") node ## ------------------------------------------------ ## 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") ## ------------------------------------------------ ## Method `Node$Prune` ## ------------------------------------------------ data(acme) acme$Do(function(x) x$cost <- Aggregate(x, "cost", sum)) Prune(acme, function(x) x$cost > 700000) print(acme, "cost") ## ------------------------------------------------ ## Method `Node$Climb` ## ------------------------------------------------ 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 ## ------------------------------------------------ ## Method `Node$Navigate` ## ------------------------------------------------ data(acme) Navigate(acme$Research, "../IT/Outsource") Navigate(acme$Research, c("..", "IT", "Outsource")) ## ------------------------------------------------ ## Method `Node$Get` ## ------------------------------------------------ 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") ## ------------------------------------------------ ## Method `Node$Do` ## ------------------------------------------------ data(acme) acme$Do(function(node) node$expectedCost <- node$p * node$cost) print(acme, "expectedCost") ## ------------------------------------------------ ## 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 ) print(acme, "departmentId", "head")
library(data.tree) acme <- Node$new("Acme Inc.") accounting <- acme$AddChild("Accounting")$ AddSibling("Research")$ AddChild("New Labs")$ parent$ AddSibling("IT")$ AddChild("Outsource") print(acme) ## ------------------------------------------------ ## Method `Node$new` ## ------------------------------------------------ node <- Node$new("mynode", x = 2, y = "value of y") node$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") ## ------------------------------------------------ ## 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") ## ------------------------------------------------ ## Method `Node$RemoveAttribute` ## ------------------------------------------------ node <- Node$new("mynode") node$RemoveAttribute("age", stopIfNotAvailable = FALSE) node$age <- 27 node$RemoveAttribute("age") node ## ------------------------------------------------ ## 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") ## ------------------------------------------------ ## Method `Node$Prune` ## ------------------------------------------------ data(acme) acme$Do(function(x) x$cost <- Aggregate(x, "cost", sum)) Prune(acme, function(x) x$cost > 700000) print(acme, "cost") ## ------------------------------------------------ ## Method `Node$Climb` ## ------------------------------------------------ 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 ## ------------------------------------------------ ## Method `Node$Navigate` ## ------------------------------------------------ data(acme) Navigate(acme$Research, "../IT/Outsource") Navigate(acme$Research, c("..", "IT", "Outsource")) ## ------------------------------------------------ ## Method `Node$Get` ## ------------------------------------------------ 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") ## ------------------------------------------------ ## Method `Node$Do` ## ------------------------------------------------ data(acme) acme$Do(function(node) node$expectedCost <- node$p * node$cost) print(acme, "expectedCost") ## ------------------------------------------------ ## 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 ) print(acme, "departmentId", "head")
These are reserved by the Node class, you cannot use these as attribute names. Note also that all attributes starting with a . are reserved.
NODE_RESERVED_NAMES_CONST
NODE_RESERVED_NAMES_CONST
An object of class character
of length 43.
Use these methods to style your graph, and to plot it. The functionality is built around the DiagrammeR package, so for anything that goes beyond simple plotting, it is recommended to read its documentation at https://rich-iannone.github.io/DiagrammeR/docs.html. Note that DiagrammeR is only suggested by data.tree, so 'plot' only works if you have installed it on your system.
## S3 method for class 'Node' plot( x, ..., direction = c("climb", "descend"), pruneFun = NULL, output = "graph" ) ToDiagrammeRGraph(root, direction = c("climb", "descend"), pruneFun = NULL) SetNodeStyle(node, inherit = TRUE, keepExisting = FALSE, ...) SetEdgeStyle(node, inherit = TRUE, keepExisting = FALSE, ...) SetGraphStyle(root, keepExisting = FALSE, ...) GetDefaultTooltip(node)
## S3 method for class 'Node' plot( x, ..., direction = c("climb", "descend"), pruneFun = NULL, output = "graph" ) ToDiagrammeRGraph(root, direction = c("climb", "descend"), pruneFun = NULL) SetNodeStyle(node, inherit = TRUE, keepExisting = FALSE, ...) SetEdgeStyle(node, inherit = TRUE, keepExisting = FALSE, ...) SetGraphStyle(root, keepExisting = FALSE, ...) GetDefaultTooltip(node)
x |
The root node of the data.tree structure to plot |
... |
For the SetStyle methods, this can be any stlyeName / value pair. See https://graphviz.org/Documentation.php for details. For the plot.Node generic method, this is not used. |
direction |
when converting to a network, should the edges point from root to children ("climb") or from child to parent ("descend")? |
pruneFun |
allows providing a prune criteria, i.e. a function taking a |
output |
A string specifying the output type; |
root |
The root |
node |
The |
inherit |
If TRUE, then children will inherit this node's style. Otherwise they inherit from this node's parent. Note that the inherit always applies to the node, i.e. all style attributes of a node and not to a single style attribute. |
keepExisting |
If TRUE, then style attributes are added to possibly existing style attributes on the node. |
Use SetNodeStyle
and SetEdgeStyle
to define the style of your plot. Use plot
to display a
graphical representation of your tree.
The most common styles that can be set on the nodes are:
color
fillcolor
fixedsize
true or false
fontcolor
fontname
fontsize
height
penwidth
shape
box, ellipse, polygon, circle, box, etc.
style
tooltip
width
The most common styles that can be set on the edges are:
arrowhead
e.g. normal, dot, vee
arrowsize
arrowtail
color
dir
forward, back, both, none
fontcolor
fontname
fontsize
headport
label
minlen
penwidth
tailport
tooltip
A good source to understand the attributes is https://graphviz.org/Documentation.php. Another good source is the DiagrammeR package documentation, or more specifically: https://rich-iannone.github.io/DiagrammeR/docs.html
In addition to the standard GraphViz functionality, the data.tree
plotting infrastructure takes advantage
of the fact that data.tree structure are always hierarchic. Thus, style attributes are inherited from parents
to children on an individual basis. For example, you can set the fontcolor to red on a parent, and then all children
will also have red font, except if you specifically disallow inheritance. Labels and tooltips are never inherited.
Another feature concerns functions: Instead of setting a fixed value (e.g. SetNodeStyle(acme, label = "Acme. Inc"
),
you can set a function (e.g. SetNodeStyle(acme, label = function(x) x$name)
). The function must take a Node
as its single argument. Together with inheritance, this becomes a very powerful tool.
The GetDefaultTooltip
method is a utility method that can be used to print all attributes of a Node
.
There are some more examples in the 'applications' vignette, see vignette('applications', package = "data.tree")
data(acme) SetGraphStyle(acme, rankdir = "TB") SetEdgeStyle(acme, arrowhead = "vee", color = "blue", penwidth = 2) #per default, Node style attributes will be inherited: SetNodeStyle(acme, style = "filled,rounded", shape = "box", fillcolor = "GreenYellow", fontname = "helvetica", tooltip = GetDefaultTooltip) SetNodeStyle(acme$IT, fillcolor = "LightBlue", penwidth = "5px") #inheritance can be avoided: SetNodeStyle(acme$Accounting, inherit = FALSE, fillcolor = "Thistle", fontcolor = "Firebrick", tooltip = "This is the accounting department") SetEdgeStyle(acme$Research$`New Labs`, color = "red", label = "Focus!", penwidth = 3, fontcolor = "red") #use Do to set style on specific nodes: Do(acme$leaves, function(node) SetNodeStyle(node, shape = "egg")) plot(acme) #print p as label, where available: SetNodeStyle(acme, label = function(node) node$p) plot(acme)
data(acme) SetGraphStyle(acme, rankdir = "TB") SetEdgeStyle(acme, arrowhead = "vee", color = "blue", penwidth = 2) #per default, Node style attributes will be inherited: SetNodeStyle(acme, style = "filled,rounded", shape = "box", fillcolor = "GreenYellow", fontname = "helvetica", tooltip = GetDefaultTooltip) SetNodeStyle(acme$IT, fillcolor = "LightBlue", penwidth = "5px") #inheritance can be avoided: SetNodeStyle(acme$Accounting, inherit = FALSE, fillcolor = "Thistle", fontcolor = "Firebrick", tooltip = "This is the accounting department") SetEdgeStyle(acme$Research$`New Labs`, color = "red", label = "Focus!", penwidth = 3, fontcolor = "red") #use Do to set style on specific nodes: Do(acme$leaves, function(node) SetNodeStyle(node, shape = "egg")) plot(acme) #print p as label, where available: SetNodeStyle(acme, label = function(node) node$p) plot(acme)
Node
in a human-readable fashion.Print a Node
in a human-readable fashion.
## S3 method for class 'Node' print( x, ..., pruneMethod = c("simple", "dist", NULL), limit = 100, pruneFun = NULL, row.names = T )
## S3 method for class 'Node' print( x, ..., pruneMethod = c("simple", "dist", NULL), limit = 100, pruneFun = NULL, row.names = T )
x |
The Node |
... |
Node attributes to be printed. Can be either a character (i.e. the name of a Node field),
a Node method, or a function taking a Node as a single argument. See |
pruneMethod |
The method can be used to prune for printing in a simple way. If NULL, the entire tree is displayed. If
"simple", then only the first |
limit |
The maximum number of nodes to print. Can be |
pruneFun |
allows providing a prune criteria, i.e. a function taking a |
row.names |
If |
data(acme) print(acme, "cost", "p") print(acme, "cost", probability = "p") print(acme, expectedCost = function(x) x$cost * x$p) do.call(print, c(acme, acme$attributesAll)) tree <- CreateRegularTree(4, 5) # print entire tree: print(tree, pruneMethod = NULL) # print first 20 nodes: print(tree, pruneMethod = "simple", limit = 20) # print 20 nodes, removing leafs first: print(tree, pruneMethod = "dist", limit = 20) # provide your own pruning function: print(tree, pruneFun = function(node) node$position != 2)
data(acme) print(acme, "cost", "p") print(acme, "cost", probability = "p") print(acme, expectedCost = function(x) x$cost * x$p) do.call(print, c(acme, acme$attributesAll)) tree <- CreateRegularTree(4, 5) # print entire tree: print(tree, pruneMethod = NULL) # print first 20 nodes: print(tree, pruneMethod = "simple", limit = 20) # print 20 nodes, removing leafs first: print(tree, pruneMethod = "dist", limit = 20) # provide your own pruning function: print(tree, pruneFun = function(node) node$position != 2)
Pruning refers to removing entire subtrees. This function has side-effects, it modifies your data.tree structure!
Prune(node, pruneFun)
Prune(node, pruneFun)
node |
The root of the sub-tree to be pruned |
pruneFun |
allows providing a prune criteria, i.e. a function taking a |
the number of nodes removed
data(acme) acme$Do(function(x) x$cost <- Aggregate(x, "cost", sum)) Prune(acme, function(x) x$cost > 700000) print(acme, "cost")
data(acme) acme$Do(function(x) x$cost <- Aggregate(x, "cost", sum)) Prune(acme, function(x) x$cost > 700000) print(acme, "cost")
Node
's children.Reverts the sort order of a Node
's children.
Revert(node, recursive = TRUE)
Revert(node, recursive = TRUE)
node |
the Node whose childrens' sort order is to be reverted |
recursive |
If |
returns the Node invisibly (for chaining)
The method takes one or more vectors as an argument. It traverses the tree, whereby the values are picked
from the vector. Also available as OO-style method on Node
.
#OO-style: # node$Set(..., # traversal = c("pre-order", "post-order", "in-order", "level", "ancestor"), # pruneFun = NULL, # filterFun = NULL) #traditional: Set(nodes, ...)
#OO-style: # node$Set(..., # traversal = c("pre-order", "post-order", "in-order", "level", "ancestor"), # pruneFun = NULL, # filterFun = NULL) #traditional: Set(nodes, ...)
nodes |
The nodes on which to perform the Get (typically obtained via |
... |
each argument can be a vector of values to be assigned. Recycled. |
invisibly returns the nodes (useful for chaining)
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 ) print(acme, "departmentId", "head")
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 ) print(acme, "departmentId", "head")
Formatter functions set on a Node act as a default formatter when printing and using
the Get
method. The formatter is inherited, meaning that whenever
Get
fetches an attribute from a Node
, it checks on the Node
or
on any of its ancestors whether a formatter is set.
SetFormat(node, name, formatFun)
SetFormat(node, name, formatFun)
node |
The node on which to set the formatter |
name |
The attribute name for which to set the formatter |
formatFun |
The formatter, i.e. a function taking a value as an input, and formatting returning the formatted value |
Get
print.Node
data(acme) acme$Set(id = 1:(acme$totalCount)) SetFormat(acme, "id", function(x) FormatPercent(x, digits = 0)) SetFormat(Climb(acme, "IT"), "id", FormatFixedDecimal) print(acme, "id") # Calling Get with an explicit formatter will overwrite the default set on the Node: print(acme, id = acme$Get("id", format = function(x) paste0("id:", x))) # Or, to avoid formatters, even though you set them on a Node: print(acme, id = acme$Get("id", format = identity))
data(acme) acme$Set(id = 1:(acme$totalCount)) SetFormat(acme, "id", function(x) FormatPercent(x, digits = 0)) SetFormat(Climb(acme, "IT"), "id", FormatFixedDecimal) print(acme, "id") # Calling Get with an explicit formatter will overwrite the default set on the Node: print(acme, id = acme$Get("id", format = function(x) paste0("id:", x))) # Or, to avoid formatters, even though you set them on a Node: print(acme, id = acme$Get("id", format = identity))
Node
or an entire data.tree
structureYou 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.
Sort(node, attribute, ..., decreasing = FALSE, recursive = TRUE)
Sort(node, attribute, ..., decreasing = FALSE, recursive = TRUE)
node |
The node whose children are to be sorted |
attribute |
determines what is collected. The
|
... |
any parameters to be passed on the the attribute (in case it's a method or a function) |
decreasing |
sort order |
recursive |
if |
Returns the node on which Sort is called, invisibly. This can be useful to chain Node methods.
data(acme) acme$Do(function(x) x$totalCost <- Aggregate(x, "cost", sum), traversal = "post-order") Sort(acme, "totalCost", decreasing = FALSE) print(acme, "totalCost")
data(acme) acme$Do(function(x) x$totalCost <- Aggregate(x, "cost", sum), traversal = "post-order") Sort(acme, "totalCost", decreasing = FALSE) print(acme, "totalCost")
data.tree
structure to Newick notationTo read from Newick, you can use the ape
package, and convert the resulting phylo
object to a data.tree
structure.
ToNewick(node, heightAttribute = DefaultPlotHeight, ...)
ToNewick(node, heightAttribute = DefaultPlotHeight, ...)
node |
The root |
heightAttribute |
The attribute (field name, method, or function) storing or calculating the height for each |
... |
parameters that will be passed on the the heightAttributeName, in case it is a function |
Other Conversions from Node:
as.dendrogram.Node()
data(acme) ToNewick(acme) ToNewick(acme, heightAttribute = NULL) ToNewick(acme, heightAttribute = function(x) DefaultPlotHeight(x, 200)) ToNewick(acme, rootHeight = 200)
data(acme) ToNewick(acme) ToNewick(acme, heightAttribute = NULL) ToNewick(acme, heightAttribute = function(x) DefaultPlotHeight(x, 200)) ToNewick(acme, rootHeight = 200)
Traverse takes the root of a tree or a sub-tree, and "walks" the tree in a specific order. It returns a list of
Node
objects, filtered and pruned by filterFun
and pruneFun
.
Traverse( node, traversal = c("pre-order", "post-order", "in-order", "level", "ancestor"), pruneFun = NULL, filterFun = NULL )
Traverse( node, traversal = c("pre-order", "post-order", "in-order", "level", "ancestor"), pruneFun = NULL, filterFun = NULL )
node |
the root of a tree or a sub-tree that should be traversed |
traversal |
any of 'pre-order' (the default), 'post-order', 'in-order', 'level', 'ancestor', or a custom function (see details) |
pruneFun |
allows providing a prune criteria, i.e. a function taking a |
filterFun |
allows providing a a filter, i.e. a function taking a |
The traversal order is as follows. (Note that these descriptions are not precise and complete. They are meant for quick reference only. See the data.tree vignette for a more detailed description).
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.
a list of Node
s