AdeelK93 / collapsibleTree

Create Interactive Collapsible Tree Diagrams in R using D3.js
https://adeelk93.github.io/collapsibleTree/
158 stars 41 forks source link

Feature(s) request: Long form dataframe, multiple roots, variable branches? #7

Closed NovasTaylor closed 7 years ago

NovasTaylor commented 7 years ago

Data is often not in the convenient wide-form with columns parent,child,child.. , instead being in the more inconvenient long form:
Parent Relation Child A hasChild B A hasChild C A hasChild D B hasChild E B hasChild F C hasChild G E hasChild H E hasChild I F hasChild J K hasChild L K hasChild M M hasChild N M hasChild O

Representing the tree:

A-
  |---B-
  |     |---E-
  |     |    |---H
  |     |    |---I
  |     |
  |     |---F
  |          |---J
  |  
  |---C-
  |     |---G
  |
  |---D

K-
  |---L 
  |
  |---M-
         |---N
         |---O

Such trees often have a variable number of branches and multiple root nodes.

Do you see this package evolving to accommodate this type of long form dataframe with variable branches and multiple root nodes? Or perhaps you can suggest how to pre-process this data for use in the package? Right now I transform to hierarchical JSON for display in a D3 webpage. Containing this all within R would be a great efficiency and broaden the utility of the package.

Thanks for your great work!

AdeelK93 commented 7 years ago

Is your data more of a flat data frame looking like:

Parent Child
A B
A C
A D
B E
B F
C G
E H
E I
F J
K L
K M
M N
M O

or is it more of a nested list/JSON structure?

As for multiple root nodes, have you considered making those root nodes children of the main root node?

NovasTaylor commented 7 years ago

It is a flat data frame, exactly as you show here.

Adding a main root is a viable solution for the multi-root question. consider that question resolved. : )

AdeelK93 commented 7 years ago

If your data is formatted in a flat data frame, it should just work out the box! If your data frame is called df and has the same column names as above, then you should be able to use:

collapsibleTree(df, c("Parent", "Child"))

This is exactly what collapsibleTree was designed to do!

Edit: Reread your comment, that's totally not what you wanted. With some help from this answer, how about:

# Need to add some "."s to get data.tree to work right
Relationships <- data.frame(
  Parent=c(".",".","A", "A", "A", "B", "B", "C", "E", "E", "F", "K", "K", "M", 
    "M"),
  Child=c("A","K","B", "C", "D", "E", "F", "G", "H", "I", "J", "L", "M", "N", 
    "O")
)
library(data.tree)
tree <- FromDataFrameNetwork(Relationships)
df <- ToDataFrameTypeCol(tree)

# need to now remove those unnecessary "."s
collapsibleTree(df, colnames(df)[2:5])

Working on getting native data.tree support in #6 for this reason!

NovasTaylor commented 7 years ago

Out of the box, the flat data frame gives me a tree, but not the structure I am trying to represent. By only looking at the flat data frame, it at first seems reasonable that nodes A,B,C,E,F,K,M are all direct descendants of the root Relationship node. However, in my sketch, B is a Child of A. B is also a parent (of E,F) so it appears back in the Parent column of the data frame. This means that out of the box, the resulting tree shows B at two points in the graph:

  1. As a child of A and B where it terminates with no children
  2. As a child of the root node, Relationship, with children E,F. E,F should in fact be grandchildren of A via B.

For the multiple roots, you are exactly right - I was compromising. : ) The kludge of adding '.' works as you suggest.

For me, the example code: collapsibleTree(df, colnames(df)[2:5])

Results in error: Error in collapsibleTree(df, colnames(df)[2:5]) : NAs in data frame

I hope that helps explain what I am trying to do. I am using Pkg version 0.1.4

Cheers

AdeelK93 commented 7 years ago

Right sorry, varying levels of depths in trees is supported in the dev version, but will be on CRAN soon! You can get the github version with:

devtools::install_github("AdeelK93/collapsibleTree")
NovasTaylor commented 7 years ago

Just confirming from my end that this dev version works perfectly as you described. Well done! This will be extremely useful on one of my projects.

fengqifang commented 7 years ago

Thank you very much, AdeelK93, it is exact example I am looking for.

Only one more question, as your example shows above Is your data more of a flat data frame looking like:

Parent Child
A B
A C
A D
B E
B F
C G
E H
E I
F J
K L
K M
M N
M O

For each nodes in this tree, I have some attributes which are numerical values I want to present when I am hovering over the nodes. How can I pass these values to the 'attributes' option, assuming it is the right option I should use.

Thanks again.

AdeelK93 commented 7 years ago

On the latest dev version, this should be possible with:

Relationships <- data.frame(
  Parent=c(".",".","A", "A", "A", "B", "B", "C", "E", "E", "F", "K", "K", "M", 
           "M"),
  Child=c("A","K","B", "C", "D", "E", "F", "G", "H", "I", "J", "L", "M", "N", 
          "O"),
  Value=1:15
)
library(data.tree)
tree <- FromDataFrameNetwork(Relationships, "Value")
# Define root node value as 0
tree$Value <- 0

# Create tree diagram with the aggregation function of identity
collapsibleTree(tree, tooltip=T, attribute="Value", aggFun=identity)

How does this work?

Note that "Value" is not a reserved word and can be anything, though "Parent" and "Child" are reserved words.

fengqifang commented 7 years ago

Thanks, Adeel,

It seems the code example does not work on my machine, could you confirm it?

it says "Error in collapsibleTree(tree, tooltip = T, attribute = "Value", aggFun = identity) : df must be a data frame"

AdeelK93 commented 7 years ago

As I mentioned, you need to be on the latest dev version

fengqifang commented 7 years ago

Appreciate it, now it works, if you do not mind, could I use the "Gradients Colors" in the nodes based on the "Value", thanks again.

AdeelK93 commented 7 years ago

Great suggestion, I'll look into that over the next few days, unless you were interested in submitting a PR yourself

fengqifang commented 7 years ago

Adeel, I am happy to contribute it, though I have never officially worked on a R package before. Besides using Gradients colors based on given column 'Value', it will be also great that users can defined customerized 'hover over' pop-up information, like leaflet Popups, so that users can present multiple dimensional information for each node.

AdeelK93 commented 7 years ago

I decided to create a convenience function for this sort of data structure, and implemented better tooltip support for it. It's in the github version, hopefully this is a bit easier of an implementation!

# devtools::install_github("AdeelK93/collapsibleTree")

# Create a simple org chart
org <- data.frame(
  Manager = c(
    NA, "Ana", "Ana", "Bill", "Bill", "Bill", "Claudette", "Claudette", "Danny",
    "Fred", "Fred", "Grace", "Larry", "Larry", "Nicholas", "Nicholas"
  ),
  Employee = c(
    "Ana", "Bill", "Larry", "Claudette", "Danny", "Erika", "Fred", "Grace",
    "Henri", "Ida", "Joaquin", "Kate", "Mindy", "Nicholas", "Odette", "Peter"
  ),
  Title = c(
    "President", "VP Operations", "VP Finance", "Director", "Director", "Scientist",
    "Manager", "Manager", "Jr Scientist", "Operator", "Operator", "Associate",
     "Analyst", "Director", "Accountant", "Accountant"
  )
)
collapsibleTreeNetwork(org, attribute = "Title")

# Add in colors and sizes
org$Color <- org$Title
levels(org$Color) <- colorspace::rainbow_hcl(11)
collapsibleTreeNetwork(
  org,
  attribute = "Title",
  fill = "Color",
  nodeSize = "leafCount",
  collapsed = FALSE
)

# Use unsplash api to add in random photos to tooltip
org$tooltip <- paste0(
  org$Employee,
  "<br>Title: ",
  org$Title,
  "<br><img src='https://source.unsplash.com/collection/385548/150x100'>"
)

collapsibleTreeNetwork(
  org,
  attribute = "Title",
  fill = "Color",
  nodeSize = "leafCount",
  tooltipHtml = "tooltip",
  collapsed = FALSE
)