Root element is not showing its children in sunburst - d3.js

I am trying to make a sunburst by following the 3-part tutorial on https://bl.ocks.org/denjn5/3b74baf5edc4ac93d5e487136481c601 My json contains sell information based on country and product division. I am trying to show in the first layer sell based on country and in the 2nd layer sell based on product division. My Json file looks like this:
{
"country": "All",
"shares":[
{
"country": "at",
"shares":[
{
"productdivision": "accessorie",
"label": 53222
},
{
"productdivision": "apparel",
"label": 365712
},
{
"productdivision": "footwear",
"label": 523684
}
]
},
{
"country": "be",
"shares":[
{
"productdivision": "accessorie",
"label": 57522
},
{
"productdivision": "apparel",
"label": 598712
},
{
"productdivision": "footwear",
"label": 52284
}
]
},
{
"country": "DE",
"shares":[
{
"productdivision": "accessorie",
"label": 56982
},
{
"productdivision": "apparel",
"label": 55312
},
{
"productdivision": "footwear",
"label": 67284
}
]
},
{
"country": "Fr",
"shares":[
{
"productdivision": "accessorie",
"label": 5862
},
{
"productdivision": "apparel",
"label": 45312
},
{
"productdivision": "footwear",
"label": 26284
}
]
}
]
}
This json file's name is kpiDrillDown2.json and I call it in my code with d3.json(). I have made slight changes to the code to work for my data. The code is as follows:
<html>
<head>
<style>
#import url('https://fonts.googleapis.com/css?family=Raleway');
body {
font-family: "Raleway", "Helvetica Neue", Helvetica, Arial, sans-serif;
}
</style>
<script src="https://d3js.org/d3.v4.min.js"></script>
</head>
<body>
<svg></svg>
<script>
//initialize variables
var width = 500;
var height = 500;
var radius = Math.min(width, height) / 2;
var color = d3.scaleOrdinal(d3.schemeCategory20b);
//setting up svg workspace
var g = d3.select('svg')
.attr('width', width)
.attr('height', height)
.append('g')
.attr('transform', 'translate(' + width / 2 + ',' + height / 2 + ')');
//formatting the data
var partition = d3.partition()
.size([2 * Math.PI, radius]);
function draw(nodeData){
debugger;
//finding the root node
var root = d3.hierarchy(nodeData)
.sum(function (d) { return d.label});
//calculating each arc
partition(root);
var arc = d3.arc()
.startAngle(function (d) { return d.x0; })
.endAngle(function (d) { return d.x1; })
.innerRadius(function (d) { return d.y0; })
.outerRadius(function (d) { return d.y1; });
g.selectAll('g')
.data(root.descendants())
.enter()
.append('g')
.attr("class", "node")
.append('path')
.attr("display", function (d) { return d.depth ? null : "none"; })
.attr("d", arc)
.style('stroke', '#fff')
.style("fill", function (d) { return color((d.parent ? d : d.parent).data.productdivision); })
g.selectAll(".node")
.append("text")
.attr("transform", function(d) {
return "translate(" + arc.centroid(d) + ")rotate(" + computeTextRotation(d) + ")"; })
.attr("dx", "-20")
.attr("dy", ".5em")
.text(function(d) { return d.parent ? d.data.productdivision : "" });
function computeTextRotation(d) {
var angle = (d.x0 + d.x1) / Math.PI * 90;
// Avoid upside-down labels
return (angle < 90 || angle > 270) ? angle : angle + 180;
}
}
d3.json('kpiDrillDown3.json', draw);
</script>
</body>
</html>
I put a debbuger in the draw functin to inspect root element. Root doesn't have any children. This is what I see in the console:
When I continue it gives me the error:"Cannot read property 'data' of null". As shown in console, root doesn't have children. My question is, do I need to change my json data format to make root recogninze the chilren, or am I doing something wrong. I am new to d3js and basically by getting the source code and modifying it, I am making my way through. This is the error in console:
I appreciate your help and thank you very much.

According to the API:
The specified children accessor function is invoked for each datum, starting with the root data, and must return an array of data representing the children, or null if the current datum has no children. If children is not specified, it defaults to:
function children(d) {
return d.children;
}
However, in your data structure, you don't have children, but shares instead.
So, the hierarchy should be:
var root = d3.hierarchy(data, function(d) {
return d.shares;
})
Pay attention to the fact that in the JSON of that tutorial you linked (just like in the API's example) the children's array is named children.
Here is a demo, look at the console (your browser's console, not the snippet one):
var data = {
"country": "All",
"shares": [{
"country": "at",
"shares": [{
"productdivision": "accessorie",
"label": 53222
},
{
"productdivision": "apparel",
"label": 365712
},
{
"productdivision": "footwear",
"label": 523684
}
]
},
{
"country": "be",
"shares": [{
"productdivision": "accessorie",
"label": 57522
},
{
"productdivision": "apparel",
"label": 598712
},
{
"productdivision": "footwear",
"label": 52284
}
]
},
{
"country": "DE",
"shares": [{
"productdivision": "accessorie",
"label": 56982
},
{
"productdivision": "apparel",
"label": 55312
},
{
"productdivision": "footwear",
"label": 67284
}
]
},
{
"country": "Fr",
"shares": [{
"productdivision": "accessorie",
"label": 5862
},
{
"productdivision": "apparel",
"label": 45312
},
{
"productdivision": "footwear",
"label": 26284
}
]
}
]
};
var root = d3.hierarchy(data, function(d) {
return d.shares;
})
.sum(function(d) {
return d.label
});
console.log(root)
<script src="https://d3js.org/d3.v4.min.js"></script>

Related

Zooming d3js graph corresponding to nodes count

I am trying to display my full tree within fixed height and width.
Since I dont know the exact nodes count , tree nodes went out of focus.
I have tried to adjust the zoom scale (manually) to display within the boundaries.
I just want to adjust the zoom scale automatically depends on the nodes count
Can anyone help me to sortout this issue.
var treeData = {
"name": "Share point Server 2019",
"id": "a093F0000078Id5QAE",
"children": [{
"name": "is extended by",
"level": "sub node",
"children": [{
"name": "Share point Server 2019",
"id": "a093F0000078Id5QAE"
}]
},
{
"name": "manages",
"level": "sub node",
"children": [{
"name": "HPE ProLiant ML350 Tower",
"id": "a093F0000078IcHQAU"
},
{
"name": "HPE ProLiant ML350 Tower",
"id": "a093F0000078IcHQAU"
},
{
"name": "HPE ProLiant ML350 Tower",
"id": "a093F0000078IcHQAU"
},
{
"name": "HPE ProLiant ML350 Tower",
"id": "a093F0000078IcHQAU"
},
{
"name": "HPE ProLiant ML350 Tower",
"id": "a093F0000078IcHQAU"
},
{
"name": "HPE ProLiant ML350 Tower",
"id": "a093F0000078IcHQAU"
},
{
"name": "HPE ProLiant ML350 Tower",
"id": "a093F0000078IcHQAU"
},
{
"name": "HPE ProLiant ML350 Tower",
"id": "a093F0000078IcHQAU"
},
{
"name": "HPE ProLiant ML350 Tower",
"id": "a093F0000078IcHQAU"
},
{
"name": "HPE ProLiant ML350 Tower",
"id": "a093F0000078IcHQAU"
},
{
"name": "HPE ProLiant ML350 Tower",
"id": "a093F0000078IcHQAU"
}
]
},
{
"name": "is operated by",
"level": "sub node",
"children": [{
"name": "Power point SH-20",
"id": "a093F00000794ZWQAY"
},
{
"name": "Power point SH-20",
"id": "a093F00000794ZWQAY"
},
{
"name": "Power point SH-20",
"id": "a093F00000794ZWQAY"
},
{
"name": "Power point SH-20",
"id": "a093F00000794ZWQAY"
},
{
"name": "Power point SH-20",
"id": "a093F00000794ZWQAY"
},
{
"name": "Power point SH-20",
"id": "a093F00000794ZWQAY"
},
{
"name": "Power point SH-20",
"id": "a093F00000794ZWQAY"
},
{
"name": "Power point SH-20",
"id": "a093F00000794ZWQAY"
},
{
"name": "Power point SH-20",
"id": "a093F00000794ZWQAY"
},
{
"name": "Power point SH-20",
"id": "a093F00000794ZWQAY"
},
{
"name": "Power point SH-20",
"id": "a093F00000794ZWQAY"
},
{
"name": "Power point SH-20",
"id": "a093F00000794ZWQAY"
},
{
"name": "Power point SH-20",
"id": "a093F00000794ZWQAY"
},
{
"name": "Power point SH-20",
"id": "a093F00000794ZWQAY"
},
{
"name": "Power point SH-20",
"id": "a093F00000794ZWQAY"
},
{
"name": "Power point SH-20",
"id": "a093F00000794ZWQAY"
},
{
"name": "Power point SH-20",
"id": "a093F00000794ZWQAY"
},
{
"name": "Power point SH-20",
"id": "a093F00000794ZWQAY"
},
{
"name": "Power point SH-20",
"id": "a093F00000794ZWQAY"
},
{
"name": "Power point SH-20",
"id": "a093F00000794ZWQAY"
},
{
"name": "Power point SH-20",
"id": "a093F00000794ZWQAY"
},
{
"name": "Power point SH-20",
"id": "a093F00000794ZWQAY"
},
{
"name": "Power point SH-20",
"id": "a093F00000794ZWQAY"
}
]
}
]
};
var nodeCount = 53;
var scale = 1,
svgHeight = 200,
nodeCount = 13;;
var margin = {
top: 20,
right: 90,
bottom: 30,
left: 90
},
width = window.outerWidth,
height = window.outerHeight;
var focused = false;
console.log('scale', scale)
var svg = d3.select("body").append("svg")
.call(d3.zoom().on("zoom", function() {
svg.attr("transform", d3.event.transform);
})).on("dblclick.zoom", null)
.attr("width", "1000")
.attr("height", 800)
.append("g")
svg.attr("transform", function(d) {
return "translate(" +
(450) + "," + (svgHeight) + ")scale(" + scale + ")";
});
var nodeCount = 15;
var i = 0,
duration = 750,
root;
// declares a tree layout and assigns the size
var treemap = d3.tree().size([height, width]);
// Assigns parent, children, height, depth
root = d3.hierarchy(treeData, function(d) {
return d.children;
});
root.x0 = height;
root.y0 = 0;
// Collapse after the second level
if (typeof collapse === 'undefined')
root.children.forEach(collapse);
update(root);
// Collapse the node and all it's children
function collapse(d) {
if (d.children) {
d._children = d.children
d._children.forEach(collapse)
d.children = null
}
}
function update(source) {
// Assigns the x and y position for the nodes
var treeData = treemap(root);
// Compute the new tree layout.
var nodes = treeData.descendants(),
links = treeData.descendants().slice(1);
let left = root;
let right = root;
var dx = ((nodeCount * 18) / 1000);
// Normalize for fixed-depth.
nodes.forEach(function(d, index) {
d.y = d.depth * 180;
d.x = d.x * ((nodeCount * 18) / 1000);
});
// ****************** Nodes section ***************************
// Update the nodes...
var node = svg.selectAll('g.node')
.data(nodes, function(d) {
return d.id || (d.id = ++i);
});
// Enter any new modes at the parent's previous position.
var nodeEnter = node.enter().append('g')
.attr('class', 'node')
.attr("transform", function(d) {
return "translate(" + (source.y0) + "," + (source.x0) + ")";
})
.on('click', d => {
// d3.event.preventDefault();
component.set("v.nodeName", d.data.name);
})
.on("dblclick", click);
// Add Circle for the nodes
nodeEnter.append('circle')
.attr('class', 'node')
.attr('r', 1e-6)
.style('stroke', 'steelblue')
.style('stroke-width', '3px');
// Add labels for the nodes
nodeEnter.append('text')
.attr("dy", ".35em")
.attr("x", function(d) {
return d.children || d._children ? -13 : 13;
})
.attr("text-anchor", function(d) {
return d.children || d._children ? "end" : "start";
})
.text(function(d) {
return d.data.name;
});
// UPDATE
var nodeUpdate = nodeEnter.merge(node);
// Transition to the proper position for the node
nodeUpdate.transition()
.duration(duration)
.attr("transform", function(d) {
return "translate(" + (d.y) + "," + (d.x) + ")";
});
// Update the node attributes and style
nodeUpdate.select('circle.node')
.attr('r', 3)
.style("fill", function(d) {
return d._children ? "lightsteelblue" : "#fff";
})
.attr('cursor', 'pointer');
// Remove any exiting nodes
var nodeExit = node.exit().transition()
.duration(duration)
.attr("transform", function(d) {
return "translate(" + (source.y) + "," + source.x + ")";
})
.remove();
// On exit reduce the node circles size to 0
nodeExit.select('circle')
.attr('r', 1e-6);
// On exit reduce the opacity of text labels
nodeExit.select('text')
.style('fill-opacity', 1e-6);
// ****************** links section ***************************
// Update the links...
var link = svg.selectAll('path.link')
.data(links, function(d) {
return d.id;
});
// Enter any new links at the parent's previous position.
var linkEnter = link.enter().insert('path', "g")
.attr("class", "link")
.style('fill', "none")
.style('stroke', "#ccc")
.style('stroke-width', "2px")
.attr('d', function(d) {
var o = {
x: source.x0,
y: source.y0
}
return diagonal(o, o)
});
// UPDATE
var linkUpdate = linkEnter.merge(link);
// Transition back to the parent element position
linkUpdate.transition()
.duration(duration)
.attr('d', function(d) {
return diagonal(d, d.parent)
});
// Remove any exiting links
var linkExit = link.exit().transition()
.duration(duration)
.attr('d', function(d) {
var o = {
x: source.x,
y: source.y
}
return diagonal(o, o)
})
.remove();
// Store the old positions for transition.
nodes.forEach(function(d) {
d.x0 = d.x;
d.y0 = d.y;
});
// Creates a curved (diagonal) path from parent to the child nodes
function diagonal(s, d) {
var path = "M" + d.y + "," + d.x +
"C" + (d.y + s.y) / 2 + "," + d.x +
" " + (d.y + s.y) / 2 + "," + s.x +
" " + s.y + "," + s.x;
return path;
}
// Toggle children on click.
function click(d) {
}
}
body {
font: 10px sans-serif;
margin: 50px;
}
.grid .tick {
stroke: lightgrey;
opacity: 0.7;
shape-rendering: crispEdges;
}
.grid path {
stroke-width: 0;
}
.axis path {
fill: none;
stroke: #bbb;
shape-rendering: crispEdges;
}
.axis text {
fill: #555;
}
.axis line {
stroke: #e7e7e7;
shape-rendering: crispEdges;
}
.axis .axis-label {
font-size: 14px;
}
.line {
fill: none;
stroke-width: 1.5px;
}
.dot {
/* consider the stroke-with the mouse detect radius? */
stroke: transparent;
stroke-width: 10px;
cursor: pointer;
}
.dot:hover {
stroke: rgba(68, 127, 255, 0.3);
}
<script src="https://d3js.org/d3.v4.min.js"></script>
<div style="background:white" id="body"></div>

D3 JS - How to set maximum length of links in force graph?

I am trying to create a simple force graph. Graph contains nodes and links and not any labels. I came across this weird issue in which length of links is increasing automatically when I group some nodes at one position. Nodes are sticky. When I drag and place nodes at upper left side then other non sticky nodes goes down right side and length of links also increases.
Is there any way I can set maximum length of links? Code is given below.
Or is there any force to control this kind of behavior?
//create somewhere to put the force directed graph
var svg = d3.select("svg"),
width = +svg.attr("width"),
height = +svg.attr("height");
//d3 code goes here
//Characters
var nodes_data = [{
"name": "Lillian",
"sex": "F"
}, {
"name": "Gordon",
"sex": "M"
}, {
"name": "Sylvester",
"sex": "M"
}, {
"name": "Mary",
"sex": "F"
}, {
"name": "Helen",
"sex": "F"
}, {
"name": "Jamie",
"sex": "M"
}, {
"name": "Jessie",
"sex": "F"
}, {
"name": "Ashton",
"sex": "M"
}, {
"name": "Duncan",
"sex": "M"
}, {
"name": "Evette",
"sex": "F"
}, {
"name": "Mauer",
"sex": "M"
}, {
"name": "Fray",
"sex": "F"
}, {
"name": "Duke",
"sex": "M"
}, {
"name": "Baron",
"sex": "M"
}, {
"name": "Infante",
"sex": "M"
}, {
"name": "Percy",
"sex": "M"
}, {
"name": "Cynthia",
"sex": "F"
}]
//Relationships
//type: A for Ally, E for Enemy
var links_data = [{
"source": "Sylvester",
"target": "Gordon",
"type": "A"
}, {
"source": "Sylvester",
"target": "Lillian",
"type": "A"
}, {
"source": "Sylvester",
"target": "Mary",
"type": "A"
}, {
"source": "Sylvester",
"target": "Jamie",
"type": "A"
}, {
"source": "Sylvester",
"target": "Jessie",
"type": "A"
}, {
"source": "Sylvester",
"target": "Helen",
"type": "A"
}, {
"source": "Helen",
"target": "Gordon",
"type": "A"
}, {
"source": "Mary",
"target": "Lillian",
"type": "A"
}, {
"source": "Ashton",
"target": "Mary",
"type": "A"
}, {
"source": "Duncan",
"target": "Jamie",
"type": "A"
}, {
"source": "Gordon",
"target": "Jessie",
"type": "A"
}, {
"source": "Sylvester",
"target": "Fray",
"type": "E"
}, {
"source": "Fray",
"target": "Mauer",
"type": "A"
}, {
"source": "Fray",
"target": "Cynthia",
"type": "A"
}, {
"source": "Fray",
"target": "Percy",
"type": "A"
}, {
"source": "Percy",
"target": "Cynthia",
"type": "A"
}, {
"source": "Infante",
"target": "Duke",
"type": "A"
}, {
"source": "Duke",
"target": "Gordon",
"type": "A"
}, {
"source": "Duke",
"target": "Sylvester",
"type": "A"
}, {
"source": "Baron",
"target": "Duke",
"type": "A"
}, {
"source": "Baron",
"target": "Sylvester",
"type": "E"
}, {
"source": "Evette",
"target": "Sylvester",
"type": "E"
}, {
"source": "Cynthia",
"target": "Sylvester",
"type": "E"
}, {
"source": "Cynthia",
"target": "Jamie",
"type": "E"
}, {
"source": "Mauer",
"target": "Jessie",
"type": "E"
}]
//set up the simulation
//nodes only for now
var simulation = d3.forceSimulation()
.nodes(nodes_data);
//add forces
//we're going to add a charge to each node
//also going to add a centering force
simulation
.force("charge_force", d3.forceManyBody().strength([-400]))
.force("center_force", d3.forceCenter(width / 2, height / 2))
.on("tick", tickActions);
//draw lines for the links
var link = svg.append("g")
.attr("class", "links")
.selectAll("line")
.data(links_data)
.enter().append("line")
.attr("stroke-width", 3)
.attr("stroke", linkColour);
function linkColour(d) {
if (d.type == "A") {
return "green";
} else {
return "red";
}
}
//draw circles for the nodes
var node = svg.append("g")
.attr("class", "nodes")
.selectAll("circle")
.data(nodes_data)
.enter()
.append("circle")
.attr("r", 15)
.attr("fill", circleColour);
function circleColour(d) {
if (d.sex == "M") {
return "blue";
} else {
return "pink";
}
}
//Create the link force
//We need the id accessor to use named sources and targets
var link_force = d3.forceLink(links_data)
.id(function(d) {
return d.name;
});
//Add a links force to the simulation
//Specify links in d3.forceLink argument
simulation.force("links", link_force);
// setup drag handler
var drag_handler = d3.drag()
.on("start", drag_start)
.on("drag", drag_drag)
.on("end", drag_end);
//same as using .call on the node variable as in https://bl.ocks.org/mbostock/4062045
drag_handler(node)
//drag handler
//d is the node
function drag_start(d) {
if (!d3.event.active) simulation.alphaTarget(0.3).restart();
d.fx = d.x;
d.fy = d.y;
}
function drag_drag(d) {
d.fx = d3.event.x;
d.fy = d3.event.y;
}
// // for non sticky behaviour
// function drag_end(d) {
// if (!d3.event.active) simulation.alphaTarget(0);
// d.fx = null;
// d.fy = null;
// }
// // for sticky behaviour
function drag_end(d) {
if (!d3.event.active) simulation.alphaTarget(0);
d.fx = d.x;
d.fy = d.y;
}
// // Sticky nodes on x axis
// function drag_end(d) {
// if (!d3.event.active) simulation.alphaTarget(0);
// d.fx = d.x;
// d.fy = null;
// }
// // Sticky nodes on y axis
// function drag_end(d) {
// if (!d3.event.active) simulation.alphaTarget(0);
// d.fx = null;
// d.fy = d.y;
// }
// // Fixed node position on dragged
// function drag_end(d) {
// if (!d3.event.active) simulation.alphaTarget(0);
// d.fx = 300;
// d.fy = 200;
// }
// Invert node position on dragged
// function drag_end(d) {
// if (!d3.event.active) simulation.alphaTarget(0);
// d.fx = d.y;
// d.fy = d.x;
// }
function tickActions() {
//update circle positions to reflect node updates on each tick of the simulation
node
.attr("cx", function(d) {
return d.x;
})
.attr("cy", function(d) {
return d.y;
});
//update link positions
//simply tells one end of the line to follow one node around
//and the other end of the line to follow the other node around
link
.attr("x1", function(d) {
return d.source.x;
})
.attr("y1", function(d) {
return d.source.y;
})
.attr("x2", function(d) {
return d.target.x;
})
.attr("y2", function(d) {
return d.target.y;
});
}
.links line {
/* stroke: #999; */
stroke-opacity: 0.6;
}
.nodes circle {
stroke: #fff;
stroke-width: 1.5px;
}
<!DOCTYPE html>
<meta charset="utf-8">
<script src="https://d3js.org/d3.v4.min.js"></script>
<h2>Draggable force graph with sticky nodes and other behaviours of node positioning</h2>
<svg width="960" height="600"></svg>

Arrows are not touching to nodes in d3.js in tree layout

I am using d3 tree with more than 500 nodes(one root and 500/1000 child nodes to it in 2nd level). Arrows looks perfect up-to 50 child nodes but more than that on left and right side nodes, arrows shown at top of node and path are intersects node edge diagonally.
how to resolve this issue in such way that arrow should touch node where path intersect node?Nodes used are rectangular as given in this question Arrows are not touching to nodes in d3.js
All right, all right here's your solution. This is what I call the "back-off" approach. It's the same approach I used in this question. It works by fitting the path and then subtracting off of it the "radius" of your square plus marker head.
Couple things first, you only need to append the "marker" def once, it can be used on all the lines. Second, I switched the paths to draw top down, you had them drawing what I would all backwards - from child to parent. This requires additional rotation of the head.
Here's the code:
var width = 500;
var height = 500;
var nodeWidth = 40;
var nodeHeight = 40;
var circleRadius = 5;
var diagramLayout;
var graphData = {
"nodes": [{
"uid": "Term20",
"name": "Term20",
"image": "images/Term.png"
}, {
"uid": "glossforArrow",
"name": "glossforArrow",
"image": "images/Glossary.png"
}, {
"uid": "Term43",
"name": "Term43",
"image": "images/Term.png"
}, {
"uid": "Term1",
"name": "Term43",
"image": "images/Term.png"
}, {
"uid": "Term2",
"name": "Term43",
"image": "images/Term.png"
}],
"links": [{
"source": "glossforArrow",
"target": "Term20",
"direction": "output",
"label": "Owned Terms"
}, {
"source": "glossforArrow",
"target": "Term43",
"direction": "output",
"label": "Owned Terms"
}, {
"source": "glossforArrow",
"target": "Term1",
"direction": "output",
"label": "Owned Terms"
}, {
"source": "glossforArrow",
"target": "Term3",
"direction": "output",
"label": "Owned Terms"
}, {
"source": "glossforArrow",
"target": "Term4",
"direction": "output",
"label": "Owned Terms"
}, {
"source": "glossforArrow",
"target": "Term5",
"direction": "output",
"label": "Owned Terms"
}, {
"source": "glossforArrow",
"target": "Term6",
"direction": "output",
"label": "Owned Terms"
}, {
"source": "glossforArrow",
"target": "Term7",
"direction": "output",
"label": "Owned Terms"
}, {
"source": "glossforArrow",
"target": "Term8",
"direction": "output",
"label": "Owned Terms"
}, {
"source": "glossforArrow",
"target": "Term9",
"direction": "output",
"label": "Owned Terms"
}, {
"source": "glossforArrow",
"target": "Term2",
"direction": "output",
"label": "Owned Terms"
}]
};
treeInitialize(graphData)
function treeInitialize(graphData) {
diagramLayout = d3.select("#diagramLayout")
.attr("id", "diagramLayout") //set id
.attr("width", width) //set width
.attr("height", height) //set height
.append("g")
.attr("transform", "translate(" + 20 + "," + 20 + ")")
markerRefx = 40;
var data2 = graphData.links.filter(function(l) {
if (l.target == undefined && l.source == undefined) {
return false;
} else {
return true;
}
});
data2.push(JSON.parse('{"target":"glossforArrow","source":""}'))
var treeData = d3.stratify().id(function(d) {
return d.target;
}).parentId(function(d) {
return d.source;
})(data2)
nodes = d3.hierarchy(treeData, function(d) {
return d.children;
});
var levelWidth = [1];
var childCount = function(level, n) {
if (n.children && n.children.length > 0) {
if (levelWidth.length <= level + 1) levelWidth.push(0);
levelWidth[level + 1] += n.children.length;
n.children.forEach(function(d) {
childCount(level + 1, d);
});
}
};
childCount(0, nodes);
newHeight = d3.max(levelWidth) * 100;
var tree = d3.tree().size([height, width])
tree.size([newHeight, height / 2]);
tree.separation(function(a, b) {
return a.parent == b.parent ? 50 : 100;
});
nodes = tree(nodes);
treeLayout(nodes);
function treeLayout(nodes) {
var node = diagramLayout.selectAll(".node");
node = node.data(nodes.descendants());
var link = diagramLayout.selectAll(".link")
.data(nodes.descendants().slice(1))
.enter().append("path")
.attr("class", "link")
.attr("fill", "none")
.attr("stroke", "#000")
.attr("stroke-width", "1px")
.attr("stroke-opacity", "0.3")
.attr("d", function(d) {
return connector(d.parent, d);
})
//nodes.descendants().slice(1).forEach(function(d) {
var mark = diagramLayout.append("svg:defs").selectAll("marker") //
.data(["start"]) // Different link/path types can be defined here
.enter().append("svg:marker") // This section adds in the arrows
.attr("id", String)
.attr("viewBox", "0 -5 10 10")
.attr("refX", 0)
.attr("refY", 0)
.attr("markerWidth", 5)
.attr("markerHeight", 5)
.attr("orient", "auto")
.attr("stroke", "#000")
.attr("fill", "#000")
.append("svg:path")
.attr("d", "M0,-5L10,0L0,5")
.style("stroke-width", "0.3px")
//.attr("transform","rotate(180,5, 0)");
// });
link.attr("marker-end", "url(#start)")
.each(function(d, i, j) {
var self = d3.select(this),
t = this.getTotalLength(),
p = this.getPointAtLength(t - 25);
self.attr("d", connector(d.parent, p));
})
var nodeEnter = node.enter().append("g")
.attr("class", "node")
.attr("height", nodeHeight)
.attr("width", nodeWidth)
nodeEnter.attr("transform", function(d) {
return "translate(" + project(d.x, d.y) + ")";
})
var nodeIcon = nodeEnter.append("rect")
.attr("class", "rect")
.attr("x", -20)
.attr("y", -20)
.attr("rx", 10)
.attr("width", 40)
.attr("height", 40)
.attr("stroke-width", function(d) {
return Math.sqrt(2);
})
.attr("stroke-opacity", "0.3")
.attr("stroke", "#000")
.attr("fill", "none")
//wrap(nodeText, 8)
}
}
function connector(from, to) {
return "M" + project(from.x, from.y) + "C" + project(from.x, (from.y + to.y) / 2) + " " + project(to.x, (from.y + to.y) / 2) + " " + project(to.x, to.y);
}
function project(x, y) {
return [x, y];
}
.node {
stroke: #fff;
stroke-width: 1.5px;
}
.link {
stroke: #000;
stroke-opacity: .6;
}
<script src="https://d3js.org/d3.v4.min.js"></script>
<div id="mainScreen" style="height:100%;width:100%;position:absolute;">
<svg id="diagramLayout" style="height:100%;width:100%;position:absolute;">
</svg>
</div>

JSON instead of CSV for bubble chart

I'm using bubble chart which takes input from csv file, is there a way to use JSON instead?
Here is the Problem url:
http://ec2-54-198-148-171.compute-1.amazonaws.com/webapp/provider-view
Problem Code:
d3.csv(flare.csv, function(d) {
//console.log(d);
d.value = +d.value;
d.seq = +d.seq;
if (d.value) return d;
}, function(error, classes) {
if (error) throw error;
var root = d3.hierarchy({children: classes})
.sum(function(d) { return d.value; })
.each(function(d) {
if (id = d.data.id) {
var id,seq, i = id.lastIndexOf(".");
d.id = id;//console.log(i + " " + id);
d.package = id.slice(0, i);//console.log(d.package);
d.class = id.slice(i + 1);
d.seq = d.data.seq;
}
});
var node = svg.selectAll(".node")
.data(pack(root).leaves())
.enter().append("g")
.attr("class", "node")
.attr("transform", function(d) {
if(d.seq==1){
d.x = d.x - 100;
d.y = d.y + 20;
return "translate(" + d.x + "," + d.y + ")";
}else{
d.x = d.x + 500;
d.y = d.y + 20;
return "translate(" + d.x + "," + d.y + ")";
} });
node.append("circle")
.attr("id", function(d) { return d.id; })
.attr("r", function(d) { d.r = parseInt(d.r)-5; return d.r; })
.attr("onclick",function(d) { return "demo('" +d.id + "',"+ d.seq+","+ (d.x+d.r+111)+","+ (d.y+100-30)+");"; })
.style("fill", function(d) { //console.log(d.seq);
if(d.seq==1){
return "url(#gradient1)";
}else{
return "#773F9B";
}
});
node.append("clipPath")
.attr("id", function(d) { return "clip-" + d.id; })
.append("use")
.attr("xlink:href", function(d) { return "#" + d.id; });
node.append("div")
.attr("id","tooltip")
.attr("style","width:100px;height:10px;background-color:gray;z-index:1000");
});
Sample csv :
id,value,seq
demo11,100,1
demo12,200,1
demo13,300,1
demo14,400,1
demo15,500,1
demo16,600,1
demo17,600,1
demo21,50,2
demo22,100,2
demo23,150,2
demo24,200,2
demo25,250,2
demo26,300,2
demo27,350,2
The short answer is: yes.
The long answer: to change the data from a csv file to a json file, it's not simply a matter of changing d3.csv for d3.json. That's necessary, of course, as #RobertLongson said in the comments. But, besides that, you'll have to understand how d3.csv creates an array of objects with your CSV, since you need to create your JSON mimicking that array.
So, given your CSV, this is how d3.csv creates an array of objects:
var data = d3.csvParse(d3.select("#csv").text());
console.log(JSON.stringify(data))
pre {
display: none;
}
<script src="https://d3js.org/d3.v4.min.js"></script>
<pre id="csv">id,value,seq
demo11,100,1
demo12,200,1
demo13,300,1
demo14,400,1
demo15,500,1
demo16,600,1
demo17,600,1
demo21,50,2
demo22,100,2
demo23,150,2
demo24,200,2
demo25,250,2
demo26,300,2
demo27,350,2</pre>
That being said, to change your data from CSV to JSON (without doing any further change in the code), your JSON need to have exactly this structure:
[{
"id": "demo11",
"value": "100",
"seq": "1"
}, {
"id": "demo12",
"value": "200",
"seq": "1"
}, {
"id": "demo13",
"value": "300",
"seq": "1"
}, {
"id": "demo14",
"value": "400",
"seq": "1"
}, {
"id": "demo15",
"value": "500",
"seq": "1"
}, {
"id": "demo16",
"value": "600",
"seq": "1"
}, {
"id": "demo17",
"value": "600",
"seq": "1"
}, {
"id": "demo21",
"value": "50",
"seq": "2"
}, {
"id": "demo22",
"value": "100",
"seq": "2"
}, {
"id": "demo23",
"value": "150",
"seq": "2"
}, {
"id": "demo24",
"value": "200",
"seq": "2"
}, {
"id": "demo25",
"value": "250",
"seq": "2"
}, {
"id": "demo26",
"value": "300",
"seq": "2"
}, {
"id": "demo27",
"value": "350",
"seq": "2"
}]

Json d3 access each object

{
"name": "Max",
"value": 107,
"children": [
{
"name": "Don",
"value": 60,
"children" [
{"name": "CC", "value": 25},
{"name": "Jim", "value": 35}
]
},
{
"name": "David",
"value": 47,
"children": [
{"name": "Jeff", "value": 32},
{"name": "Buffy", "value": 15}
]
}
]
}
How can I access the inner most child name with d3?
I tried doing :
.text(function (d) { return d.children ? null : d.name; });
But it didn't work....
When I do
.text(function (d) { return d.name });
it only shows the name of the outer loop --> Don, David.
d3.json('flare.json', function (data) {
var canvas = d3.select('p1')
.append('svg')
.attr('width', 800)
.attr('height', 800)
var color = d3.scale.category20c();
var data1 = data.children;
canvas.selectAll('text')
.data(data1)
.enter()
.append('text')
.attr('x', function (d) { return 2; })
.attr('y', function (d, i) { return i * 15; })
.attr('fill', 'black')
.style('font-size', '12px')
.text(function (d) { return d.children ? null: d.name; })
Data I had before ↓ ↓
{
"name": "Don",
"value": 75,
"children" [
{"name": "CC", "value": 25},
{"name": "Jim", "value": 35}
]
}
When the data was in this single nested format, my code worked perfectly, but when I did double nest on it, it no longer works
You need a recursive function for this --
function getNames(d) {
return d.children ? d.children.map(getNames) : d.name;
}
This will return a nested list with the names of the elements that have no children.

Resources