adeelk93 / collapsibletree Goto Github PK
View Code? Open in Web Editor NEWCreate Interactive Collapsible Tree Diagrams in R using D3.js
Home Page: https://adeelk93.github.io/collapsibleTree/
Create Interactive Collapsible Tree Diagrams in R using D3.js
Home Page: https://adeelk93.github.io/collapsibleTree/
Since xml itself is already represented as a nice tree, can collapsible tree display an xml file as it is?
It will be nice to allow XML as an input directly without transform it into a tabular form suppose someone already have the XML file and just would like to display it as it is (or allow certain level of modifications)
Great package.
Just one question, if I'd like to present a 'paths' structure using this package, which leaves may not have the same depth.
For example, Root(100) have 3 children, A(50), B(20), C(30), then there is no child for node A, node B and C may continue to grow, in such case, how to arrange the data.tree structure?
Sometimes I have tree with only one root without children. I would like display the unique node without the errors "This is not a Tree".
My workaround is to build a 2nd node with parent id, the id of root, and its id "nothing", when there is only one root line in the tree.
Great tool!
I was wondering if the tooltip functionality can (or does) allow for tooltips.style.pointerEvents =True/False. I am trying to have a tooltip which renders html but allows the the html to be a clickable link. Using the current methods I am able to insert html but not click it to open a link.
Thank you
I've upgraded R and RStudio to the latest versions, and I end up getting the same error on both systems I have RStudio installed on:
library(collapsibleTree)
Error: package or namespace load failed for ‘collapsibleTree’:
object ‘cividis’ is not exported by 'namespace:viridisLite'
I'm trying to render a heavily nested tree with ~100 total nodes. Specifically, I'm also building a shiny app to show a variable color annotation on each node.
The package is awesome for doing exactly this, but my one annoying user experience so far is that I don't see an option to keep which nodes are "open" when re-rendering the tree. Alternatively, it'd be great to have some parameter that displays the full tree initially, and then users can collapse nodes back down as needed.
Any thoughts on this?
Hi Adeel,
I'm getting errors when I try to make tree diagrams wit varying depth My repo. Is there a work around? I could not vind it in the manual.
Kind regards,
Sharon
Hi there, great package! I was wondering if it's possible to add line breaks to the text shown in each node - is this possible and perhaps I can help create documentation on this if it already exists? This was also asked by somebody else here but no solution was available.
Thanks!
Are we able to search the tree without reloading?
(1) search against the whole tree, then a sub-tree is returned;
(2) search against a selected set of nodes, then a sub tree is returned;
(3) for (1) and (2) the result can be either a sub-tree or unfolding and highlighting the matched node.
hi is there a way to put text on the link?
Hello,
Thank you for your package and for the very good examples. I have seen tooltipHtml which is useful for additional informations. But I have not found or understood information to display a non technical label information.
For example I have many nodes with technical reference id used to build the tree(parent id, child id), but I would like to display simple name in place of technical id.
general examples :
my issue: Many different items but with node too much not human readable and category name more readable.
I know that tooltipHtml can make the job, but we have to click on it to see it.
Is it a normal R feature or a collapsibleTree bug ?
This works, eachs values are corrects in all leaves:
df_dep$tooltip <- paste0(
ifelse(!any(is.null(df_dep$my_var ) || is.na(df_dep$my_var ) ||is.nan(df_dep$my_var ) || (df_dep$my_var =="")) ,
paste0("<br>my_var :", df_dep$my_var ),
""
)
)
This doesn't work, the same value is dispatched in all leaves:
estvide <- function(x) { any(is.null(x) || is.na(x) ||is.nan(x) || (x=="")) }
df_dep$tooltip <- paste0(
ifelse(!estvide (df_dep$my_var) ,
paste0("<br>my_var:", df_dep$my_var),
""
)
)
My understanding is that colors can be applied to nodes within a level of the tree as either a gradient or solid, single color at that level.
I often have nodes of different types within the same level in of the tree. It would be ideal if colors could be defined for individual nodes based on a 'type' assignment determined by another column in the dataframe or regex'ing their name within the collapsibleTree call.
Any thoughts on if this is possible now, or could be part of a future version? In attached example using D3js, the node stroke for the namespace "custom" is orange, the others green. Having the ability to color node stroke and fill individually would open up a lot of functionality. May be difficult to implement?
Great work so far!
Above all: Excellent work. I thank you for sharing your hard work.
(1) Links / Shiny Input
Is it already possible to trigger a shiny input variable given clicks on a terminal node's text? I'd like for users to be able to search through a tree and then, after finding the entry that interests them, to have the ability to trigger events/content associated with that node.
(2) Pan & Zoom
I want to second the other request for http://bl.ocks.org/robschmuecker/7880033 style panning and zooming. I think this will be a game changer.
I've enjoyed working my way through and learning about building trees via this package. I have my attribute set to a sum/count, and it's showing up fine as a tooltip. Is there any way to get this value to display not as a tooltip, but as a number inside of the node? It would make comparing nodes a bit easier without having to move the mouse over each one.
Hi!! thanks for this great package, I wonder if would be possible to define a symbol for each node based on a attribute, for example like this:
code:
library(collapsibleTree)
df <- read.csv(file="test_data.csv", header=TRUE,sep=",", na.strings = c("", NA))
len <- nrow(df)
colfunc <- colorRampPalette(c("red", "paleturquoise1"))
color_col <- colfunc(len)
df$Color <- color_col
p <- collapsibleTreeNetwork(
df,
fill = "Color",
attribute = "value",
collapsed = TRUE,
height = 800,
width = 2000,
zoomable = TRUE,
aggFun = identity,
tooltip = TRUE,
nodeSize = "value"
)
In the plot, the size of node B is not proportional to its value 184 as screenshot below.
It seems like parent node size is sum aggregation of its all children size. However, what I expect is that each node size is independent based on its specified column variable.
Can you please make more clarification about this?
Thank you!
Hi ,
Thank you for this excellent package , I am currently using it to visualise some categorical data . Apologies , if I have missed this , but is it possible to add legends for the different groupings for each hierarchies in the network?
Thank you again
I've tried multiple approach to install the package with no successful. Appreciate any help to get this amazing visualization package to work.
Approach 1:
library('devtools')
devtools::install_github("AdeelK93/collapsibleTree")
Error : object 'Sort' is not exported by 'namespace:data.tree'
ERROR: lazy loading failed for package 'collapsibleTree'
Approach 2
install.packages('collapsibleTree')
package ‘collapsibleTree’ is available as a source package but not as a binary
Warning in install.packages :
package ‘collapsibleTree’ is not available (for R version 3.1.2)
Approach 3
install.packages('collapsibleTree', dependencies=TRUE, type="source")
Warning in install.packages :
installation of package ‘collapsibleTree’ had non-zero exit status
@AdeelK93, thanks for creating this wonderful r package.
I was wondering if you could add a function that creates collapsibleTree
diagrams directly from a data.tree
object.
A use case -
I am creating data.tree object from separate links and nodes dataset and it needs some preprocessing before it's ready for visualization -
d_edge = data.frame(from = c(-1, 0, 0, 1, 2), to = c(0, 1, 2, 3, 4)) # edge data.frame
d_node = data.frame(node = c(0, 1, 2, 3, 4), # node data.frame
type1 = c("country", "state", "state", "city", "city"),
stringsAsFactors = FALSE) # attributes
d_comb = d_edge %>% left_join(d_node, by = c("to" = "node"))
node_a = FromDataFrameNetwork(d_comb)
node_b = Clone(node_a$children[[1]]) # removed redundant -1 node
node_b
now is ready for visualization. If we make some minor changes to collapsibleTree
function we can visualize this data.tree -
Something like -
collapsibleTree1 <- function(node, hierarchy ,root = deparse(substitute(df)),
inputId = NULL, width = NULL, height = NULL,
attribute = "leafCount", aggFun = sum,
fill = "lightsteelblue", fillByLevel = TRUE,
linkLength = NULL, fontSize = 10, tooltip = FALSE) {
# preserve this name before evaluating node
root <- root
# reject bad inputs
if(!(is(node) %in% "Node")) stop("node must be a data tree")
if(!is.character(fill)) stop("fill must be a character vector")
if(length(hierarchy) <= 1) stop("hierarchy vector must be greater than length 1")
# if(!all(hierarchy %in% colnames(df))) stop("hierarchy column names are incorrect")
if(!(attribute %in% c(names(node), "leafCount"))) stop("attribute column name is incorrect")
# if(sum(complete.cases(df[hierarchy])) != nrow(df)) stop("NAs in data frame")
# calculate the right and left margins in pixels
leftMargin <- nchar(root)
# rightLabelVector <- as.character(df[[hierarchy[length(hierarchy)]]])
rightMargin <- 1#max(sapply(rightLabelVector, nchar))
# create a list that contains the options
options <- list(
hierarchy = hierarchy,
input = inputId,
attribute = attribute,
linkLength = linkLength,
fontSize = fontSize,
tooltip = tooltip,
margin = list(
top = 20,
bottom = 20,
left = (leftMargin * fontSize/2) + 25,
right = (rightMargin * fontSize/2) + 25
)
)
# fill in the node colors, traversing down the tree
if(length(fill)>1) {
if(length(fill) != node$totalCount) {
stop(paste("Expected fill vector of length", node$totalCount, "but got", length(fill)))
}
node$Set(fill = fill, traversal = ifelse(fillByLevel, "level", "pre-order"))
} else {
options$fill <- fill
}
# only necessary to perform these calculations if there is a tooltip
if(tooltip & !is.null(aggFun)) {
# traverse down the tree and compute the weights of each node for the tooltip
t <- data.tree::Traverse(node, "pre-order")
data.tree::Do(t, function(x) {
x$WeightOfNode <- data.tree::Aggregate(x, attribute, aggFun)
# make the tooltips look nice
x$WeightOfNode <- prettyNum(
x$WeightOfNode, big.mark = ",", digits = 3, scientific = FALSE
)
})
jsonFields <- c("fill", "WeightOfNode")
} else if(tooltip & is.null(aggFun)){
node$Do(function(self) self$WeightOfNode = self[[attribute]])
jsonFields <- c("fill", "WeightOfNode")
} else
jsonFields <- c("fill")
# keep only the fill attribute in the final JSON
data <- data.tree::ToListExplicit(node, unname = TRUE, keepOnly = jsonFields)
# pass the data and options using 'x'
x <- list(
data = data,
options = options
)
# create the widget
htmlwidgets::createWidget(
"collapsibleTree", x, width = width, height = height,
htmlwidgets::sizingPolicy(viewer.padding = 0)
)
}
collapsibleTree1(node = b,
hierarchy = c("country", "city", "state"),
attribute = "type1",
tooltip = TRUE,
aggFun = NULL)
Hi Adeel,
First of all, this is a great package so thanks a lot for developing it.
The collapsibleTree function seemingly can't cope with dataframes that are too long, 8000 rows and 1000 steps in the hierarchy in my case. The following error is thrown:
Error: evaluation nested too deeply: infinite recursion / options(expressions=)? Error during wrapup: evaluation nested too deeply: infinite recursion / options(expressions=)?
Digging into this a little deeper, I suspect that the issue can be solved by setting the max ppsize in the command line to allow for larger dataframe processing. This isn't very seemless especially as the aim is to push my Shiny App to production.
Is there a way around this within your package? And if not, are you aware of a work-around within R rather than the command line?
Any help is much appreciated.
Thanks,
Nima
Hi @AdeelK93. Thanks for the great R package. One question: is it possible to supply a vector to the linkLength argument such that distances between nodes are informed by these values? As I understand it currently, we can only supply a single value, and all linkLength distances are rendered using this value. It would be great if those distances were variable according to the data provided. Thanks.
I'm trying to figure out if it is possible to add additional attributes to the tooltip, pulling from additional columns in the data. Any advice on how to do this?
Just adding to this - wondering if it is possible to implement pan and zoom functionality as well, similar to that shown here or here (easier version). I can't seem to get either working unfortunately.
Thanks Adeel,
This is a really useful package - one of my current favorites. I am wondering whether its possible to add a feature that would allow labels between nodes on the connecting lines. This would be particularly useful if the output could use latex math symbols. In the case of collapseTreeNetwork, perhaps this is just another column for the raw label data, though not sure what is required for latex conversion, if that is possible.
Best regards,
Mike
My apologies if this request just reflects my lack of familiarity with data.tree.
The data.tree objects that I usually generate are made by using as.Node() and these objects lack any information at the df$fields, rendering the fill
argument useless on the method collapsibleTree/R/collapsibleTree.data.tree.R
. Being able to choose between df$fields
or df$fieldsAll
can guarantee that different data.tree objects can be plotted.
I confirm that by changing df$fields
to df@fieldsAll
the nodes are properly colored.
Hi! This looks like a great tool, so thank you!
But is there a way I could load the data dynamically instead of using a file? I'm trying to avoid the CORS issue when running the solution locally without a server.
Is this possible?
Thanks!
I'm in the position where I have a hierarchical dataframe, but I want to take advantage of the greater functionality of a parent-child format. Is it possible to implement a function to do this conversion?
i have code that works in terminal.
however if i want to put it in a shiny, the plots doesn't show.
ui.R file:
library(collapsibleTree)
iibrary(shiny)
ui <- fluidPage(
# Application title
titlePanel("Tree"),
sidebarLayout(
sidebarPanel(
width = 2,
textInput("tr", "tr (comma seperated): ", value = "xxxx", width = NULL, placeholder = NULL),
actionButton(
"tr_update",
"Draw Tree",
icon = NULL,
width = NULL
)
),
mainPanel(
collapsibleTreeOutput("d3", height = "700px")
)
)
)
server.r file
library(shiny)
library(inbioseR)
library(collapsibleTree)
require(data.tree)
# Define server logic required to draw a histogram
server <- function(input, output, session) {
p <- eventReactive(input$tr_update, {
... code to create correct dataframe (which seems in order)
t #final dataframe to return with a column, compare_str to be used as attribute
})
output$d3 <- renderCollapsibleTree({
t <- p()
collapsibleTreeNetwork(t, collapsed = FALSE, linkLength=100, tooltipHtml = 'compare_str')
})
}
why doesn't this show up?
For example, to generate a tree with
collapsibleTree(warpbreaks, c("wool", "tension", "breaks"))
can we have some specific node opened while other closed?
Would be great to have a legend based on the coloring of nodes, especially for gradient coloring. I would be happy to test such a feature, I just don't know how to get started since I don't know java script. Thanks!
Is it possible to change the background colour to something other than white?
Hi,
We're using your fantastic package to visualise some data, and using both node colour and size to represent frequency and a 'value' attribute. Unfortunately this has created an issue with node spacing as small nodes are appearing 'within' large nodes, presumably because the spacing is being measured from the node centres.
It would be really good if the package could account for node size variability by incorporating radius into the spacing calculations as well.
I am really grateful for the package as I am using it to represent a path data set. I was wondering if there is a way/workaround to change the size of the nodes based on the attribute. I have included a simple reproducible example as follows.
V1 <- structure(c(5L, 5L, 5L, 5L, 5L, 5L), .Label = c("Display", "Email",
"SEM", "SEO", "Social"), class = "factor")
V2 <- structure(c(6L, 6L, 6L, 6L, 6L, 6L), .Label = c("", "Display",
"Email", "SEM", "SEO", "Social"), class = "factor")
V3 <- structure(c(4L, 4L, 4L, 4L, 4L, 3L), .Label = c("", "Email",
"SEO", "Social"), class = "factor")
Paths <- c(30L, 40L, 71L, 156L, 273L, 40L)
data_paths <- data.frame(V1,V2,V3,Paths)
collapsibleTree(data_paths,hierarchy = c('V1','V2','V3'),attribute = "Paths",tooltip = T)
Hi,
I have a requirement to create tree in the BI tool called Yellowfin BI.
As I am new to JS, I couldnt able to understand how to embed the code in the tool.
Can you please help me in executing the same.
Thanks in advance.
I've looked around a bit online for how one might do this for htmlwidgets
in general, but I haven't had any luck. Is there a straightforward way to export the current plot to a static image (ideally a PDF or SVG) ? I'm using collapsibleTree
in a Shiny app where users may heavily customize a tree (colors, nodes appearing, etc.) but then I want to afford them the ability to export the image to a static format.
Thanks!
Thank you for your effort on this. I see these errors when trying the shiny apps.
shiny::runApp(system.file("examples/02shiny", package = "collapsibleTree"))
Listening on http://127.0.0.1:5097
Warning: Error in data.tree::ToListExplicit: unused argument (keepOnly = jsonFields)
Stack trace (innermost first):
Firstly, I want to say this is a fantastic package! Thanks for releasing this!
Is it possible to use a character field in tooltips?
If this is not possible, is there a way to make multi-line labels on nodes?
The reason I ask is I'm testing out having an organization chart with this. It's helpful to have both employee name and job title visible.
Hi Adeel,
Can we parametrize/configure node level expand/collapse the tree on load?
The current "collapsed=TRUE/FALSE" does expand/collapse all.
Hi AdeelK93!
First, this is a great package and very useful to visualize hierarchical data.
I have run into an issue when trying to generate a collapsible tree using the method collapsibleTreeNetwork, with strings (some quite long) as the attribute for each node. The error is:
Error in unclass(x) : cannot unclass an environment
If no attribute is assigned, then the tree will render with no error.
Google tells me this could be a layout issue, but I am not exactly sure what it means. Would it be possible to provide some insights how to fix this?
The network data frame has 634 unique nodes.
Here is my script:
library(shiny)
library(collapsibleTree)
library(data.tree)
aft_tree<-read.delim("aftv212_child_parent_class_tree_fixes.tsv", stringsAsFactors = F)
#convert a data.frame in network structure to a data.tree structure
aft_tree_network<-FromDataFrameNetwork(aft_tree)
#see if all node names are unique
print(AreNamesUnique(aft_tree_network))
#convert data.tree structure back to the data.frame in network structure with column names "from" and "to"
#order of the nodes are preserved using this method
aft_tree_df<-ToDataFrameNetwork(aft_tree_network)
aft_tree_df_for_d3<-rbind(data.frame(from=NA, to="entity", stringsAsFactors = F),aft_tree_df)
aft_tree<-rbind(data.frame(parentLabel=NA, childLabel="entity", parentURI="", childURI="<http://purl.obolibrary.org/obo/BFO_0000001>", description="An entity is anything that exists or has existed or will exist. (axiom label in BFO2 Reference: [001-001])", root="<http://purl.obolibrary.org/obo/BFO_0000001>", depth=0, stringsAsFactors = F), aft_tree)
colnames(aft_tree)<-c("from", "to", "fromIRI", "toIRI", "description", "root", "depth")
aft_tree_for_d3_wDes<-cbind(aft_tree_df_for_d3, data.frame(aft_tree$description, stringsAsFactors = F))
colnames(aft_tree_for_d3_wDes)<-c("from", "to", "description")
collapsibleTreeNetwork(aft_tree_for_d3_wDes, attribute="description", zoomable = F, linkLength = 300)
Thanks!
Violet
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!
Hi AdeelK93,
This is an excellent package which will give lots of insights.
Can we show the images dynamically each image for each bubble.
Is it possible.
Thanks
Mohan V
Hi - does this support crosstalk ?
Hi AdeelK93,
How to colour the tree nodes based on only levels of the first hierarchy ?
Thanks.
Hello,
It is possible to use the attributes option in the form below:
df %>%
summarise(`sum of IPs` = n(), `% of IPs` = n()) %>%
collapsibleTreeSummary(
...
attribute = c("sum of IPs", "% de IPs"),
percentOfParent = TRUE,
zoomable = TRUE
)
This is such a great package!
Is this possible to define another method in attribute instead of "leafCount" in collapsibleTreeSummary?
I need a mean function that for each node sums up the numeric values defined in attribute and divides them by the number of leaves.
An instance of collapsibleTreeSummary()
becomes distorted as it's rendered more than once in the same modelDialog()
within a Shiny app. The tree is compressed after the modal and tree are rendered more than once, making it difficult to comprehend.
For example, this code displays a horizontal tree, representing an artificial company's headcount by division.
library(shiny)
library(collapsibleTree)
df = data.frame(
V1 = c(rep("Corporate",3),"Sales"),
V2 = c("Finance","Marketing","HR","Sales"),
V3 = c(110,43,12,243)
)
ui <- fluidPage(
mainPanel(
br(),
actionButton("mainButton","Click me")
)
)
server <- function(input,output,session){
observeEvent(input$mainButton,{
output$tree = renderCollapsibleTree({
collapsibleTreeSummary(
df,
root="Fake Corporation",
hierarchy=c("V1","V2"),
zoomable=T,
attribute="V3",
nodeSize="V3",
tooltip=T,
linkLength=250,
fontSize=12
)
})
showModal(
session=session,
modalDialog(
size="l",
easyClose=T,
# Display the tree
collapsibleTreeOutput("tree")
)
)
})
}
shinyApp(ui,server)
It would be nice to have option to flip the tree into top-to-bottom format.
One thing:
(1) Running a collapsibleTree seems to interfere with networkD3's simpleNetwork but not vice versa. Specifically the simple network nodes become white.
Thank you for your efforts!
PS: The issue is my data. Essentially, I have a data.tree object whose root I cannot rename. I tested with your data before posting but I must have mistyped something because it works now. Sorry.
Thanks for this awesome library!
It would be awesome to propose a radial layout as well. Like https://bl.ocks.org/mbostock/4063550.
Thanks again,
Yan
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.