1
votes

from a data.frame (or any other R object type), with 3 Columns: "Node, Parent and text", I'd like to plot a tree with rows from "Node" to "Parent" and "text" as label.

Can anyone suggest a good library to use and example code, if possible. I've been looking at the igraph library, but all examples I could find plot trees with sequential numbers or letters as nodes and its not simple to set the tree layout.

Any help would be greatly appreciated

Thanks

EDIT:

Thanks guys for all your help, I really appreciate it. Some extra comments, if you can help further

@md1630, I tried your suggestion but that's not what I'm looking for. The fist code plots the tree with the root on top and the arrows from root to leaf and the second corrects the arrows but inverts the tree. What I'd like is root on top and arrow from leafs to root (I understand that may not be a tree per say - but that's the requirement

enter image description here

@user20650 your solution looks correct but the image starts to get crowded as the number of nodes increase. Any idea on how to add more space between them?enter image description here

@math Am I using the function you provided correctly? I called plot(layout.binary(g)) and got the result on the left. The one on the right is the output of plot(g)

enter image description here

3
You can use igraph. Use graph.data.frame to create the graph, set edge labels in the plot call with edge.label=E(g)$text and get a tree layout with layout.reingold.tilforduser20650

3 Answers

3
votes

upgrade comment

library(igraph)

# some example data
dat <- data.frame(parent=rep(letters[1:3], each=2), 
                  node=letters[2:7], 
                  text=paste0("lab", 1:6))
# create graph
g <- graph.data.frame(dat)

# plot
# layout.reingold.tilford gives a tree structure
# edge and vertx labels can be defined in the plot command or alternatively
# you can add them to the graph via V(g)$name and E(g($label assignments

plot(g, layout = layout.reingold.tilford, 
             edge.label=E(g)$text, vertex.label=paste0("v_lab",1:7))

EDIT re comment

If you want the direction to go from the leaves towards the root; you can first, get the tree layout coordinates from the more standard tree structure, and then reverse the edges.

# get tree layout coords
g <- graph.data.frame(dat)
lay = layout.reingold.tilford(g)

# redraw graph with edges reversed
g2 <- graph.data.frame(dat[2:1], vertices = get.data.frame(g, what="vertices"))

par(mar=rep(0,4), mfrow=c(1,2))
plot(g, layout=lay)
plot(g2, layout=lay)

enter image description here

2
votes

You can use rgraphviz. Here's the code to plot the tree from a dataframe df with columns "Node, Parent and text". I didn't run this on my computer so there may be bugs. But roughly this is the idea:

source("http://bioconductor.org/biocLite.R")
biocLite("Rgraphviz")
library("Rgraphviz")
#first set up the graph with just the nodes
nodes<- unique(df['Node'])
gR <- new("graphNEL", nodes = nodes, edgemode = "directed")
#add edges for each row in df
    for (j in (1:nrow(df))) {
       gR <- addEdge(df[j,2], df[j,1], gR, 1)
    }
#add text labels
nAttrs <- list()
z <- df['text']
nAttrs$label <- z
#plot
plot(gR, nodeAttrs = nAttrs) #you can specify more attributes here 
0
votes

You can use igraph to get a network with your data (supposing your dataframe is dd):

g = graph(t(dd[,2:1]))
V(g)$label = as.character(dd$text)
plot(g, layout=layout.binary)

I supposed your root (with no parents) is not in the dataframe, otherwise use dd[-1,2:1] instead.

If you want to have a tree, you can easily produce a layout, it is simply a function that takes a graph and return a matrix. For a binary tree :

layout.binary = function(graph) {
    layout = c()
    r_vertex = length(V(graph))
    depth = ceiling(log2(r_vertex+1))
    for (ii in 0:(depth-1)) {
        for (jj in 1:min(2^ii, r_vertex)) {
            layout = rbind(layout, c(ii, (2*(jj-1)+1)/(2^(ii+1))))
        }
        r_vertex = r_vertex - 2^ii
    }
    return(layout)
}

It will plot an horizontal tree, use c((2*(jj-1)+1)/(2^(ii+1)), ii) if you want it to be vertical.