Reputation: 235
I am motivated by this article regarding Collapsible Tree in R
http://bl.ocks.org/mbostock/4339083
I am trying to reproduce the same example using a toy dataset like this
ID Car Bus Train Feedback_Car Feedback_Bus Feedback_Train
23433 Yes Yes Yes Toyota GreyHound Amtrak
Which can be represented as a collapsible tree as follows
I am wondering if anybody can help me reproduce that concept (collapsible trees) using this toy dataset above, this example will then give me an idea how different components work, for example formatting the JSON data in R etc...and serve as a starting point. Thanks in advance.
Upvotes: 10
Views: 4380
Reputation: 8848
In the current dev version of networkD3
(v0.4.9000 @ 2017.08.30), there is a new treeNetwork()
function that has this (interactive, collapsible tree network plots) and many other new features built-in.
You can install the current dev version with...
devtools::install_github("christophergandrud/networkD3")
and plot a collapsible tree network plot with your data using...
library(networkD3)
df <- read.table(header = T, stringsAsFactors = F, text = "
ID Car Bus Train Feedback_Car Feedback_Bus Feedback_Train
23433 Yes Yes Yes Toyota GreyHound Amtrak
")
links <- data.frame(nodeId = c(df$ID, names(df)[2:4], as.character(df[5:7])),
parentId = c("", rep(df$ID, 3), sub("^Feedback_", "", names(df[5:7]))))
links$name <- links$nodeId
treeNetwork(links, type = "tidy")
There are still plenty of bugs to work out, so we'd appreciate testing, filling out issues/bug reports, and/or pull requests. https://github.com/christophergandrud/networkD3
Upvotes: 0
Reputation: 1244
You can use the data.tree package to get your data converted to JSON, or also to use the networkD3 package:
dat <- read.table(text="ID Car Bus Train Feedback_Car Feedback_Bus Feedback_Train
23433 Yes Yes Yes Toyota GreyHound Amtrak", header=TRUE)
## Make an edgelist from your data
edges <- rbind(cbind(dat$ID, names(dat)[2:4]),
cbind(names(dat)[2:4], as.vector(t(dat[5:7]))))
library(data.tree)
tree <- FromDataFrameNetwork(as.data.frame(edges))
tree
That will print like this:
levelName
1 23433
2 ¦--Car
3 ¦ °--Toyota
4 ¦--Bus
5 ¦ °--GreyHound
6 °--Train
7 °--Amtrak
Now, use the tree structure to plot with networkD3:
lol <- ToListExplicit(tree, unname = TRUE)
library(networkD3)
diagonalNetwork(lol)
Unfortunately, that doesn't support collapsible trees yet. But here is an example how to get what you want with Shiny. In order to convert your data to the correct JSON format, simply do this:
library(jsonlite)
json <- toJSON(lol)
Upvotes: 0
Reputation: 447
I apologize for being so late. I think that you are looking for a solution in R, and not a solution that forces you to use outside code. Take advantage of the k3d3 package. https://github.com/kaseyriver11/k3d3 Here is what want:
library(k3d3)
library(RJSONIO)
library(stringr)
type <- c("Car", "Car", "Truck", "Truck", "Bus", "Bus")
name <- c("Chevy", "Ford", "Chevy", "Ford", "Greyhound", "Holiday Express")
size <- c(rep(3840,6))
data <- data.frame(type, name, size)
makeList<-function(x){
if(ncol(x)>2){
listSplit<-split(x[-1],x[1],drop=T)
lapply(names(listSplit),function(y){list(name=y,children=makeList(listSplit[[y]]))})
}else{
lapply(seq(nrow(x[1])),function(y){list(name=x[,1][y],Percentage=x[,2][y])})
}
}
jsonOut<-toJSON(list(name="23433",children=makeList(data)))
jsonOut2 <- str_replace_all(jsonOut, "[\r\n]" , "")
CTR(jsonOut2)
Picture of Tree with Data Provided
Upvotes: 1
Reputation: 23879
For what it's worth I wanted to share my way of pushing data from R to D3:
<!--begin.rcode results="asis", echo=FALSE, warning=FALSE, message=FALSE
library(RJSONIO)
library(MASS)
set.seed(1234)
data <- data.frame("Sample"=rbeta(1000,10,15))
out <- paste("<script type='text/javascript'> var json ='", jsonlite::serializeJSON(data), "';</script>", sep="")
end.rcode-->
This code chunk sits right at the beginning of the body element in my RHTML file. After knitting it, the data will be written inside the output HTML file and can be accessed by D3 via the json
variable.
Here is a screenshot of the output HTML file:
At the bottom of the picture you can see that you just have to parse the json
object with JSON.parse()
and you have your data JS ready :)
Upvotes: 0
Reputation: 903
There is a detailed explanation on how to format your data here. They build on this answer on how to create Json with children.
Note: I think you will have to reshape your dataset to get the following columns: ID, Type of vehicle, Brand.
Once you have your Json ready, you grab the html file of your example and you replace 'flare.json' with the path of our data output.
Upvotes: 0
Reputation: 32426
This collapsible tree looks really cool. My approach here is to first, create a graph using igraph
. I was hoping there was already a function to convert an igraph to json, however, it looks like that is an issue on github that hasn't been implemented. So, here is a simple function to do that. Then, you can just plug the resulting data into the linked source and you have a collapsible tree.
## Read your data
dat <- read.table(text="ID Car Bus Train Feedback_Car Feedback_Bus Feedback_Train
23433 Yes Yes Yes Toyota GreyHound Amtrak", header=TRUE)
## Make an edgelist from your data
edges <- rbind(cbind(dat$ID, names(dat)[2:4]),
cbind(names(dat)[2:4], as.vector(t(dat[5:7]))))
## Convert to a graph data structure
library(igraph)
g <- graph_from_edgelist(edges)
## This is the non-interactive version
plot(g, layout=layout.reingold.tilford(g, root='23433'))
## Recursive function to make a list of nodes to be parsed by toJSON
## call it with 'node' as the root node (here '23433')
f <- function(g, node, size=1000) {
n <- neighbors(g, node, mode='out')
if (length(n) == 0) return( list(name=node, size=size) )
children <- lapply(n$name, function(x) f(g, x, size))
list(name=node, children=children)
}
## Convert to json
library(jsonlite)
json <- toJSON(f(g, '23433'), auto_unbox = TRUE)
## I made a directory collapsible to store the index.html from the linked
## site, as well as this data
## For completeness, you should be able to run this to see the interactive results,
## But, of course, this is creating files on your box
dir.create('collapsible')
writeLines(json, 'collapsible/data.json')
## Download the index.html
download.file("https://gist.githubusercontent.com/mbostock/4339083/raw/0d003e5ea1686dd6e79562b37f8c7afca287d9a2/index.html", "collapsible/index.html", method='curl')
## Replace with the correct data
txt <- readLines('collapsible/index.html')
txt[grepl("^d3.json", txt)] <- "d3.json('data.json', function(error, flare) {"
writeLines(txt, 'collapsible/index.html')
## Open in broweser
browseURL(paste0('file://', normalizePath('collapsible/index.html')))
The results can also be seen here.
Upvotes: 5
Reputation: 32327
I read the csv and make the node JSON structure like below:
d3.csv("my.csv", function(error, data) {
var map1 = []
data.reduce(function(map, node) {
map1.push(node)
return node;
}, {});
root = {};
root.name = map1[0].ID;
root.children = [];
var car = {
name: "Car",
children: [{
name: map1[0].Feedback_Car,
children: []
}]
};
root.children.push(car);
var bus = {
name: "Bus",
children: [{
name: map1[0].Feedback_Bus,
children: []
}]
};
root.children.push(bus);
var train = {
name: "Bus",
children: [{
name: map1[0].Feedback_Train,
children: []
}]
};
root.children.push(train);
});
Working code here
Hope this helps!
Upvotes: 2