The task is to append a swarm of small circles around the nodes of a tree (where I have placed bigger circles). The depth of the tree is tiny -- just two, However, there is a slight degree of complexity when considering I'm appending several trees iteratively.
To keep it simple, I didn't even try to append swarms to all trees. Instead, I set myself with a more modest goal of appending the swarm to just one node of one tree. Comments and snippet below:
var margins = {top:100, bottom:300, left:100, right:100};
var height = 600;
var width = 900;
var totalWidth = width+margins.left+margins.right;
var totalHeight = height+margins.top+margins.bottom;
var svg = d3.select('body')
.append('svg')
.attr('width', totalWidth)
.attr('height', totalHeight);
var graphGroup = svg.append('g')
.attr('transform', "translate("+margins.left+","+margins.top+")");
var data = [
{name:"China", tree: {
"name": "Actors",
"children": [
{
"name": "Jackie Chan",
"movies":d3.range(50).map(function(v) {return v.toString()+'_movie'})
},
{
"name": "Jet Li",
"movies":d3.range(38).map(function(v) {return v.toString()+'_movie'})
},
{
"name": "Chow Yun Fat",
"movies":d3.range(46).map(function(v) {return v.toString()+'_movie'})
}
]
}},
{name:"USA", tree: {
"name": "Actors",
"children": [
{
"name": "Tom Cruise",
"movies":d3.range(7).map(function(v) {return v.toString()+'_movie'})
},
{
"name": "Johnny Depp",
"movies":d3.range(4).map(function(v) {return v.toString()+'_movie'})
},
{
"name": "Harrison Ford",
"movies":d3.range(20).map(function(v) {return v.toString()+'_movie'})
},
{
"name": "Ryan Gosling",
"movies":d3.range(4).map(function(v) {return v.toString()+'_movie'})
}
]
}},
{name:"UK", tree: {
"name": "Actors",
"children": [
{
"name": "Daniel Day-Lewis",
"movies":d3.range(36).map(function(v) {return v.toString()+'_movie'})
},
{
"name": "Christoper Lee",
"movies":d3.range(50).map(function(v) {return v.toString()+'_movie'})
},
]
}}
];
//var formatComma = d3.format(",");
var columns = 3;
var spacing = 200;
var vSpacing = 180;
var regionG = graphGroup.selectAll('.region')
.data(data)
.enter()
.append('g')
.attr('class', 'region')
.attr('id', (d, i) => 'region' + i)
.attr('transform', (d, k) => {
var horSpace = (k % columns) * spacing;
var vertSpace = ~~((k / columns)) * vSpacing;
return "translate(" + horSpace + "," + vertSpace + ")";
});
var miniTree = d3.tree()
.size([150, 75]);
regionG.append('rect')
.attr('x',0)
.attr('y',0)
.attr('width',100)
.attr('height',25)
.style('fill',"#003366");
regionG.append('text')
.attr('x',50)
.attr('y',-10)
.attr('text-anchor','middle')
.text(function(d) {return d.name});
regionG.selectAll(null)
.data( function(d) {
return miniTree(d3.hierarchy(d.tree)).descendants().slice(1)
})
.enter().append("path")
.attr("transform", "translate(-25,20)") // extra positioning.
.attr("class", "link")
.attr("d", function(d) {
return "M" + d.x + "," + d.y
+ "C" + d.x + "," + (d.y + d.parent.y) / 2
+ " " + d.parent.x + "," + (d.y + d.parent.y) / 2
+ " " + d.parent.x + "," + d.parent.y;
});
regionG.selectAll(null)
.data( function(d) {return miniTree(d3.hierarchy(d.tree)).descendants() })
.enter().append("g")
.attr("class", function(d) {
return "node" +
(d.children ? " node--internal" : " node--leaf"); })
.attr("transform", function(d) {
return "translate(" + (d.x - 25) + "," + (d.y+20) + ")"; }) // with extra positioning.
.append("circle")
.attr('r',10)
.attr('cx',0)
.attr('cy',0)
.style('fill',"#003366");
//start simulation for one node
var simulation = d3.forceSimulation(data[0].tree.children[0].movies)
.force("x", d3.forceX(function(d) {
return 0;
}).strength(0.03))
.force("y", d3.forceY(function(d) {
return 95;
}).strength(0.1))
.force("collide", d3.forceCollide(04).iterations(1))
.stop();
simulation.tick(75);
//append circles at (0,95) -- the center coorinates of the bottom left tree node
var circles = graphGroup.selectAll(null)
.data(data[0].tree.children[0].movies)
.enter()
.append("circle")
.attr("r", 3)
.attr("cx", function(d) { return d.x;})
.attr("cy", function(d) { return d.y;})
.style('fill', function(d) {return "#4f81b9"; });
<script src="https://d3js.org/d3.v5.min.js"></script>
This has given a huge swath of errors that I'm having trouble debugging:
Cannot create property 'vx' on string "0_movie" ... Cannot create property 'vx' on string "1_movie" ...
The desired result should be circles appended around the node. The idea is that:
- The top shows the region: China
- The big circles on the tree nodes show the actors: Jackie Chan
- The smaller swarm circles are to show the number of movies he/she acted in
The end result will have swarm circles around each node, but for the purposes of this question, we can just focus on the bottom-left node.
Question
How can I append swarm clusters at each node at the bottom-most depth of my tree?
from D3.js v5 - Swarm Tree - How to iteratively center swarms around tree nodes
No comments:
Post a Comment