embed json file within d3.js (d3.layout.partition) - javascript

I am using this:
http://mbostock.github.io/d3/talk/20111018/partition.html
instead of d3.json("flare.json", function(root) {
how do i make it use the json file within the html, like say i have
var json = [{
"name": "flare",
"children": [
{"name": "analytics",
"children": [
{"name": "cluster","children": [{"name": "AgglomerativeCluster", "size": 3938},
{"name": "CommunityStructure", "size": 3812},
{"name": "HierarchicalCluster", "size": 6714},
{"name": "MergeEdge", "size": 743}
]
},
and i want to use this instead of an external json file, how do i achieve this?
Link to json file: http://mbostock.github.io/d3/talk/20111018/flare.json
Any JSFiddle example please?
Thank you.

You will achieve this by two method:
1.you can assign the JSON data to variable name then You can build any layout
2.use one function to get the JSON data
Fiddle for 1 solution
var root = json;
Fiddle for 2 solution
var root = getData();
var g = vis.selectAll("g")
.data(partition.nodes(root))
.enter().append("svg:g")
.attr("transform", function(d) { return "translate(" + x(d.y) + "," + y(d.x) + ")"; })
.on("click", click);

Related

D3 Force Layout Graph load data from file

I took this code off the web and it works correctly. I need to load the data from a json instead of the data being coded into the page. Being new to this, I decide to first simply take the original data and put it in a json file and call the file. I can't seem to get it to work. I get a blank section where the graph would go and all I get from debugger is "mutating the prototype of an object will cause you code to run slowly", which I get with the original code so that's not it.
Here is the section of the original code
function loadImage(){
if(LoadData){
root = {
"name": "Daniel Vinod", "imageURL":"images/root.png","id":"1",
"children": [
{"name": "Abraham Aaron", "imageURL":"images/user1.png","id":"2",
"children":[{"name": "Joseph Titus", "imageURL":"images/user3.png","id":"3"},
{"name": "Herold Enoch", "imageURL":"images/user4.png","id":"4"}]},
{"name": "Samuel Goliatf", "imageURL":"images/user7.png","id":"5",
"children":[{"name": "Enoch Titus", "imageURL":"images/user2.png","id":"6"},
{"name": "Quintus Titus", "imageURL":"images/user5.png","id":"7"}]},
{"name": "Absalom Dauid", "imageURL":"images/user2.png","id":"8" ,
"children":[{"name": "Abraham Shalom", "imageURL":"images/user4.png","id":"9"},
{"name": "Elisha Titus", "imageURL":"images/user6.png","id":"10"}]},
{"name": "Daniel Goliatf", "imageURL":"images/user3.png","id":"12",
"children":[{"name": "Quintus Titus", "imageURL":"images/user5.png","id":"13"},
{"name": "Enoch Titus", "imageURL":"images/user1.png","id":"14"},
{"name": "Elisha Titus", "imageURL":"images/user6.png","id":"15",
"children":[ {"name": "Enoch Absalom", "imageURL":"images/user1.png","id":"11"}]}]},
{"name": "Enoch Shalom", "imageURL":"images/user5.png","id":"16",
"children":[{"name": "Absalom Joseph", "imageURL":"images/user7.png","id":"17"},
{"name": "Shalom Joseph", "imageURL":"images/user4.png","id":"18"},
{"name": "Quintus Titus", "imageURL":"images/user5.png","id":"7"}]}
]
};
force = d3.layout.force()
.on("tick", tick)
.size([w, h]);
vis = d3.select("#chart").append("svg:svg")
.attr("width", w)
.attr("height", h);
update();
LoadData = false;
}
}
I swapped the data for this
function loadImage(){
if(LoadData){
root = d3.json("data2.json", function(error, graph) {
if (error) throw error;
force = d3.layout.force()
.on("tick", tick)
.size([w, h]);
vis = d3.select("#chart").append("svg:svg")
.attr("width", w)
.attr("height", h);
update();
LoadData = false;
});
}
}
And created a data2.json file:
{
"name": "Daniel Vinod", "imageURL":"images/root.png","id":"1",
"children": [
{"name": "Abraham Aaron", "imageURL":"images/user1.png","id":"2",
"children":[{"name": "Joseph Titus", "imageURL":"images/user3.png","id":"3"},
{"name": "Herold Enoch", "imageURL":"images/user4.png","id":"4"}]},
{"name": "Samuel Goliatf", "imageURL":"images/user7.png","id":"5",
"children":[{"name": "Enoch Titus", "imageURL":"images/user2.png","id":"6"},
{"name": "Quintus Titus", "imageURL":"images/user5.png","id":"7"}]},
{"name": "Absalom Dauid", "imageURL":"images/user2.png","id":"8" ,
"children":[{"name": "Abraham Shalom", "imageURL":"images/user4.png","id":"9"},
{"name": "Elisha Titus", "imageURL":"images/user6.png","id":"10"}]},
{"name": "Daniel Goliatf", "imageURL":"images/user3.png","id":"12",
"children":[{"name": "Quintus Titus", "imageURL":"images/user5.png","id":"13"},
{"name": "Enoch Titus", "imageURL":"images/user1.png","id":"14"},
{"name": "Elisha Titus", "imageURL":"images/user6.png","id":"15",
"children":[ {"name": "Enoch Absalom", "imageURL":"images/user1.png","id":"11"}]}]},
{"name": "Enoch Shalom", "imageURL":"images/user5.png","id":"16",
"children":[{"name": "Absalom Joseph", "imageURL":"images/user7.png","id":"17"},
{"name": "Shalom Joseph", "imageURL":"images/user4.png","id":"18"},
{"name": "Quintus Titus", "imageURL":"images/user5.png","id":"7"}]}
]
}
Note, no brackets, so it's not a true json but it doesn't work with the brackets either. Again, no error, just a white space where the graph should be. Thanks for the help in advance.
root is a variable in the original which points to the json object, which I suspect gets picked up and used in the update() function. In your 2nd example, you've defined root so it points to the json loading function, whereas graph is the pointer to the loaded json object. Rename root as jsonFunc and set root = graph; within the json loading function in your 2nd example, see if that works. If not, it's make a jsfiddle time.

D3.js JSON parse error

While parsing inline JSON object with d3.json(obj, function(error, root), its working properly when I'm running it locally, but when I run on tomcat server I'm getting an XMLHttpparse error. I searched over the Internet. Answer that I found was CORS. But there was no clarity how to achieve this. Could you please help me?
var obj = {
"name": "vis",
"children": [
{
"name": "Votes",
"children": [
{"name": "200", "size": 200,"url":"1"},
{"name": "500", "size": 500,"url":"2"},
{"name": "300", "size": 300,"url":"3"},
{"name": "400", "size": 400,"url":"4"}
]
},
{
"name": "Reputation",
"children": [
{"name": "200", "size": 200},
{"name": "500", "size": 500},
{"name": "300", "size": 300},
{"name": "400", "size": 400}
]
},
{
"name": "Accepted Answer",
"children": [
{
"name": "encoder",
"children": [
{"name": "Accepted Answer", "size": 500}
]
}
]
}
]
};
d3.json(obj, function(error, root) {
alert('error '+error);
alert('root: '+root);
if (error) return console.log(error);
}
First, make sure you are passing in a URL as the first argument to d3.json().
Second, you need to configure Tomcat to support CORS. In version 7.0.41+, Tomcat includes a CORS filter. Add the filter to your web.xml file.
Here's the minimum configuration you need:
<filter>
<filter-name>CorsFilter</filter-name>
<filter-class>org.apache.catalina.filters.CorsFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>CorsFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
See the documentation for more information and additional configuration options: http://tomcat.apache.org/tomcat-7.0-doc/config/filter.html#CORS_Filter
And here's a flowchart of request processing for this filter that may help you with setting up any additional parameters:
You are misunderstanding what d3.json is used for. d3.json makes an actual AJAX request (hence why in the documentation names the chapter as Requests) so it is literally trying to fetch that obj but can't because it doesn't need to. If you really want to use d3.json, you can move that JSON object into its own file and then reference it by doing d3.json(data.json, function(err, root)).
The result d3.json would return is literally the object you have declared. You can simply assign it to the variable name root.
Related question: d3 js - loading json without a http get

Creating a d3 horizontal bar chart with a multidimensional array/nested json file

I'm trying to create a simple d3 bar chart (http://bost.ocks.org/mike/bar/2/) using the following nested json file.
{
"clustername": "cluster1",
"children": [
{
"neighborhoodname": "Shaw",
"children": [
{
"totpop2000": "1005",
"children": [
{
"name": "demographic",
"children": [
{"name": "Black", "size2000":0.18},
{"name": "White", "size2000":0.6},
{"name": "Hispanic", "size2000":0.40},
{"name": "Asian", "size2000":0.10}
]
},
{
"name": "wellbeing",
"children": [
{"name": "Unemployment", "size2000":0.40},
{"name": "Poverty", "size2000":0.1},
{"name": "Without HS Education", "size2000":0.31}
]
},
{
"name": "crime",
"children": [
{"name": "Violent Crime", "size2000":0.09},
{"name": "Property Crime", "size2000":0.08}
]
},
{
"name": "housing",
"children": [
{"name": "Home Ownership", "size2000":0.34},
{"name": "Houses for Rent", "size2000":0.50}
]
}
]
}
]
}
]
}
So far, my javascript includes the following for adding the amounts labeled as size2000 to the svg but when I run the code I can't seem to append the appropriate array of data (i.e. I get the first array/"clustername": "cluster1") in my json file.
var data = d3.json("data/test.json", function(json) {
console.log(json);
var bar = chart2000.selectAll("g")
.data(data)
.enter().append("g")
.attr("transform", function(d, i) { return "translate(0," + i * height + ")"; });
bar.append("rect")
.attr("width", function(d) { return x((d.size2000)*100); })
.attr("height", height - 1);
bar.append("text")
.attr("x", function(d) { return x((d.size2000)*100) - 3; })
.attr("y", height / 2)
.attr("dy", ".35em")
.text(function(d) { return (d.size2000)*100); });
});
Is there a way to keep the json data structure and append the size2000 values to a svg? If so, how?
One of the basic tenets of visualizations made using D3 is the correspondence between data and elements in the DOM. The mapping should also respect hierarchy of the data and DOM nodes, though it is not a strict requirement. Hence, if the data is nested, the visualization should be nested in some way as well (e.g. multiple bar charts divided by the hierarchy). Walking this analogy in the other direction, if you want a flat bar chart, then the data should also be a flat list of values.
It doesn't have to flat, but it would make the implementation and the DOM mapping easier. I would map the json data that you have manually for the bar chart into a flat list:
d3.json("data/test.json", function(json) {
var barChartData = [];
function addLeaves(node) {
if (typeof node.children !== "undefined") {
node.children.forEach(addLeaves);
} else {
barChartData.push(node);
}
}
addLeaves(json);
var bar = chart2000.selectAll("g")
.data(barChartData)
// ...
}

Generate layout histogram with specified parent values

I am new to D3, so my project of D3 is a rough problem to me and I really do need some help, I have been search solutions for days.
The problem is, I want to draw a Hierarchical Bar Chart, every time one clicks a bar, the sub layout of that bar is shown, just like this one http://bl.ocks.org/mbostock/1283663, however, the value of parent node is the sum value of its children node. I want to set the parent value by myself and keep the layout. The json file is:
{
"name": "flare",
"children": [
{
"name": "analytics",
"children": [
{
"name": "cluster",
"children": [
{"name": "AgglomerativeCluster", "size": 3938},
{"name": "CommunityStructure", "size": 3812},
{"name": "HierarchicalCluster", "size": 6714},
{"name": "MergeEdge", "size": 743}
]
},
I want to edit the parent value, so I edit the file as :
{
"name": "flare",
"children": [
{
"name": "analytics",size:555555 //I want to set value by myself rather than the sum of children value
"children": [
{
"name": "cluster",
"children": [
{"name": "AgglomerativeCluster", "size": 3938},
{"name": "CommunityStructure", "size": 3812},
{"name": "HierarchicalCluster", "size": 6714},
{"name": "MergeEdge", "size": 743}
]
},
However, it does not work. Does anyone knows how to set parent's value? I searched for days and got nothing, hope you can help me, and I am appreciate your help!
Is your issue with using the parent element sizes to draw the bars? If so, you should scale everything (to say 0 to 100) and then multiply this by a constant to get the appropriate parent value. After all, if you edit each parent value, they won't necessarily be proportional.
Here's an example of a scale:
edit: (fixed the domain)
var myscale = d3.scale.linear()
.domain([0, maxParentWidth])
.range([0,y]); // .range([0,1]) is the default range
This will scale all the "parents" on the domain 0 to the largest parent value to a range of [0,y], where y is whatever you want (i.e., 100). Let's say you want the largest parent bar to be 300px. Now, all you have to do is multiply this scaled value by a constant, in this case, 3.

D3 javascript color from JSON attribute

Using D3 Javascript and JSON, I need to create something very similar to:
http://bl.ocks.org/mbostock/4063550
The JSON file (copied from website) looks something like:
{
"name": "flare",
"children": [
{
"name": "analytics",
"children": [
{
"name": "cluster",
"children": [
{"name": "AgglomerativeCluster", "size": 3938},
{"name": "CommunityStructure", "size": 3812},
{"name": "HierarchicalCluster", "size": 6714},
{"name": "MergeEdge", "size": 743}
]
},
Now instead of the "size" in the code above, I have "score" (i.e. "score": 3).
What I want to achieve is the diagram similar to the website, but the difference is that is the score is over a certain threshold (e.g >5), I want the small blue circle to be of a certain color (i.e. red).
I know this needs to be updated in the index.html file, but I just don't know how to get around to doing that. Any pointers would be appreciated!
Thanks!
All you need to do this is to slightly modify the code that appends the circles. You need to change the snippet
node.append("circle")
.attr("r", 4.5);
to
node.append("circle")
.style("stroke", function(d) { return d.score > 5 ? "red" : "steelblue"; })
.attr("r", 4.5);
You can obviously apply something like this to e.g. the fill colour in the same way. If you have a larger number of different colours and thresholds, it might be worth investigating using a scale instead of a conditional statement.
Change your JSON like so:
{
"name": "flare",
"children": [
{
"name": "analytics",
"children": [
{
"name": "cluster",
"children": [
{"name": "AgglomerativeCluster", "score": 3938},
{"name": "CommunityStructure", "score": 3812},
{"name": "HierarchicalCluster", "score": 6714},
{"name": "MergeEdge", "score": 743}
]
},
Now use a function to check for the condition in the data and set the style for the circle:
node.append("circle")
.attr("r", 4.5)
.style("fill",function(d){
return ((d.score > 5)?"red":"blue");
});

Categories