Skip to content

Instantly share code, notes, and snippets.

@stereocat
Last active June 3, 2017 15:28
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save stereocat/8e5c9927a11441f71228471d5340b406 to your computer and use it in GitHub Desktop.
Save stereocat/8e5c9927a11441f71228471d5340b406 to your computer and use it in GitHub Desktop.
d3.js(v4) cluster layout basics
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<style type="text/css">
circle {
opacity: 0.8;
stroke-width: 2;
stroke : black;
fill : grey;
}
path {
opacity: 0.8;
stroke-width: 2;
stroke : blue;
fill : none;
}
</style>
</head>
<body>
<script src="https://d3js.org/d3.v4.min.js"></script>
<script src="https://d3js.org/d3-selection-multi.v1.min.js"></script>
<script src="https://d3js.org/d3-collection.v1.min.js"></script>
<script src="https://d3js.org/d3-hierarchy.v1.js"></script>
<script src="./d3-cluster-layout.js"></script>
</body>
</html>
"use strict";
function draw_cluster() {
var width = 500;
var height = 250;
var svg = d3.select("body")
.append("svg")
.attrs({"width" : width,
"height" : height})
.append("g")
.attr("transform", "scale(0.8, 0.8)translate(20, 20)");
var data = {
"name": "Eve",
"children": [
{ "name": "Cain" },
{
"name": "Seth",
"children": [
{ "name": "Enos" },
{ "name": "Noam" }
]
},
{ "name": "Abel" },
{
"name": "Awan",
"children": [
{ "name": "Enoch" }
]
},
{ "name": "Azura" }
]
};
// see also:
// d3/d3-hierarchy: 2D layout algorithms for visualizing hierarchical data.
// https://github.com/d3/d3-hierarchy
var root_node = d3.hierarchy(data);
console.log("root_node");
console.log(root_node);
var node_size = 20;
var cluster = d3.cluster()
.size([width, height]);
var nodes = cluster(root_node);
var links = nodes.links();
console.log("clustered nodes");
console.log(nodes);
console.log("clustered nodes (leaves)");
console.log(nodes.leaves());
console.log("clustered nodes (ancestors)"); // from root
console.log(nodes.ancestors());
console.log("clustered nodes (descendants)"); // from root
console.log(nodes.descendants());
console.log("clustered links");
console.log(links);
// path
// see also:
// d3/d3-shape: Graphical primitives for visualization, such as lines and areas.
// https://github.com/d3/d3-shape
var line = d3.line()
.curve(d3.curveBundle.beta(0.85))
.x(function(d) { return d.x; })
.y(function(d) { return d.y; });
svg.selectAll("path")
.data(links)
.enter()
.append("path")
.attr("d", function(d) {
return line([
d.source,
{"x" : d.source.x, "y" : (d.source.y + d.target.y)/2 },
{"x" : d.target.x, "y" : (d.source.y + d.target.y)/2 },
d.target
]);
});
// circle (overwrite path)
svg.selectAll("circle")
.data(nodes.descendants())
.enter()
.append("circle")
.attrs({
"cx" : function(d) { return d.x; },
"cy" : function(d) { return d.y; },
"r" : node_size/2
})
.append("title")
.text(function(d) { return d.data.name; });
// text
svg.selectAll("text")
.data(nodes.descendants())
.enter()
.append("text")
.attrs({
"dy" : node_size * 1.1,
"text-anchor" : "middle",
"x" : function(d) { return d.x; },
"y" : function(d) { return d.y; }
})
.text(function(d) { return d.data.name; } );
}
// run
draw_cluster();
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<style type="text/css">
circle {
opacity: 0.8;
stroke-width: 2;
stroke : black;
fill : grey;
}
path.parent2child {
opacity: 0.8;
stroke-width: 1;
stroke : blue;
fill : none;
}
path.interleaf {
opacity: 0.3;
stroke-width: 8;
stroke: green;
fill : none;
}
</style>
</head>
<body>
<script src="https://d3js.org/d3.v4.min.js"></script>
<script src="https://d3js.org/d3-selection-multi.v1.min.js"></script>
<script src="https://d3js.org/d3-collection.v1.min.js"></script>
<script src="https://d3js.org/d3-hierarchy.v1.js"></script>
<script src="./d3-hierarchical-edge-bundling.js"></script>
</body>
</html>
"use strict";
function draw_cluster() {
var width = 500;
var height = 500;
var radius = Math.min(width/2, height/2);
var svg = d3.select("body")
.append("svg")
.attrs({"width" : width,
"height" : height})
.append("g")
.attr("transform", "translate(" + width/2 + "," + height/2 + ")scale(0.8,0.8)");
var data = {
"name": "Eve",
"children": [
{ "name": "Cain" },
{
"name": "Seth",
"children": [
{ "name": "Enos" },
{ "name": "Noam" }
]
},
{ "name": "Abel" },
{
"name": "Awan",
"children": [
{ "name": "Enoch" }
]
},
{ "name": "Azura" }
]
};
var link_data = [
{"source" : "Azura", "target" : "Enoch"},
{"source" : "Enoch", "target" : "Abel"},
{"source" : "Enoch", "target" : "Noam"},
{"source" : "Azura", "target" : "Noam"},
{"source" : "Abel", "target" : "Enos"},
{"source" : "Abel", "target" : "Noam"},
{"source" : "Noam", "target" : "Enos"},
{"source" : "Enos", "target" : "Cain"}
];
// see also:
// d3/d3-hierarchy: 2D layout algorithms for visualizing hierarchical data.
// https://github.com/d3/d3-hierarchy
var root_node = d3.hierarchy(data);
var node_size = 20;
var cluster = d3.cluster().size([360, radius]);
var nodes = cluster(root_node);
var parent2child_links = nodes.links();
console.log("parent2child_links");
console.log(parent2child_links);
var nodes_name_map = d3.map(nodes.leaves(), function(d) { return d.data.name; });
var interleaf_links = link_data.map(function(d) {
return {
"source" : nodes_name_map.get(d.source),
"target" : nodes_name_map.get(d.target)
};
});
console.log("interleaf_links");
console.log(interleaf_links);
// path
// see also:
// d3/d3-shape: Graphical primitives for visualization, such as lines and areas.
// https://github.com/d3/d3-shape
var line = d3.radialLine()
.curve(d3.curveBundle.beta(0.85))
.radius(function(d) { return d.y; })
.angle(function(d) { return path_angle(d.x); });
svg.selectAll("path.parent2child")
.data(parent2child_links)
.enter()
.append("path")
.attr("class", "parent2child")
.attr("d", function(d) {
return line([
d.source,
{ "x" : d.source.x, "y" : (d.source.y + d.target.y)/2 },
{ "x" : d.target.x, "y" : (d.source.y + d.target.y)/2 },
d.target
]);
});
// path
svg.selectAll("path.interleaf")
.data(interleaf_links)
.enter()
.append("path")
.attr("class", "interleaf")
.attr("d", function(d) {
return line(d.source.path(d.target));
});
// circle (overwrite path)
svg.selectAll("circle")
.data(nodes.descendants())
.enter()
.append("circle")
.attrs({
"cx" : node_x,
"cy" : node_y,
"r" : node_size/2
})
.append("title")
.text(function(d) { return d.data.name; });
// text
svg.selectAll("text")
.data(nodes.descendants())
.enter()
.append("text")
.attrs({
"dy" : node_size * 1.1,
"text-anchor" : "middle",
"x" : node_x,
"y" : node_y,
})
.text(function(d) { return d.data.name; } );
}
function path_angle(x) {
return rad(x);
}
function node_angle(x) {
return rad(x) - Math.PI/2;
}
function node_x(d) {
return d.y * Math.cos(node_angle(d.x));
}
function node_y(d) {
return d.y * Math.sin(node_angle(d.x));
}
function rad(deg) {
return deg/360 * 2 * Math.PI;
}
// run
draw_cluster();
"use strict";
function draw_cluster() {
var width = 500;
var height = 500;
var radius = Math.min(width/2, height/2);
var svg = d3.select("body")
.append("svg")
.attrs({"width" : width,
"height" : height})
.append("g")
.attr("transform", "translate(" + width/2 + "," + height/2 + ")scale(0.8,0.8)");
var data = {
"name": "Eve",
"children": [
{ "name": "Cain" },
{
"name": "Seth",
"children": [
{ "name": "Enos" },
{ "name": "Noam" }
]
},
{ "name": "Abel" },
{
"name": "Awan",
"children": [
{ "name": "Enoch" }
]
},
{ "name": "Azura" }
]
};
var link_data = [
{"source" : "Azura", "target" : "Enoch"},
{"source" : "Enoch", "target" : "Abel"},
{"source" : "Enoch", "target" : "Noam"},
{"source" : "Azura", "target" : "Noam"},
{"source" : "Abel", "target" : "Enos"},
{"source" : "Abel", "target" : "Noam"},
{"source" : "Noam", "target" : "Enos"},
{"source" : "Enos", "target" : "Cain"}
];
// see also:
// d3/d3-hierarchy: 2D layout algorithms for visualizing hierarchical data.
// https://github.com/d3/d3-hierarchy
var root_node = d3.hierarchy(data);
var node_size = 20;
var cluster = d3.cluster().size([360, radius]);
var nodes = cluster(root_node);
var nodes_name_map = d3.map(nodes.leaves(), function(d) { return d.data.name; });
var interleaf_links = link_data.map(function(d) {
return {
"source" : nodes_name_map.get(d.source),
"target" : nodes_name_map.get(d.target)
};
});
console.log("interleaf_links");
console.log(interleaf_links);
// path
// see also:
// d3/d3-shape: Graphical primitives for visualization, such as lines and areas.
// https://github.com/d3/d3-shape
var line = d3.radialLine()
.curve(d3.curveBundle.beta(0.85))
.radius(function(d) { return d.y; })
.angle(function(d) { return path_angle(d.x); });
// path
svg.selectAll("path.interleaf")
.data(interleaf_links)
.enter()
.append("path")
.attr("class", "interleaf")
.attr("d", function(d) {
return line(d.source.path(d.target));
});
// circle (overwrite path)
svg.selectAll("circle")
.data(nodes.leaves())
.enter()
.append("circle")
.attrs({
"cx" : node_x,
"cy" : node_y,
"r" : node_size/2
})
.append("title")
.text(function(d) { return d.data.name; });
// text
svg.selectAll("text")
.data(nodes.leaves())
.enter()
.append("text")
.attrs({
"dy" : node_size * 1.1,
"text-anchor" : "middle",
"x" : node_x,
"y" : node_y,
})
.text(function(d) { return d.data.name; } );
}
function path_angle(x) {
return rad(x);
}
function node_angle(x) {
return rad(x) - Math.PI/2;
}
function node_x(d) {
return d.y * Math.cos(node_angle(d.x));
}
function node_y(d) {
return d.y * Math.sin(node_angle(d.x));
}
function rad(deg) {
return deg/360 * 2 * Math.PI;
}
// run
draw_cluster();
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<style type="text/css">
circle {
opacity: 0.8;
stroke-width: 2;
stroke : black;
fill : grey;
}
path {
opacity: 0.8;
stroke-width: 2;
stroke : blue;
fill : none;
}
</style>
</head>
<body>
<script src="https://d3js.org/d3.v4.min.js"></script>
<script src="https://d3js.org/d3-selection-multi.v1.min.js"></script>
<script src="https://d3js.org/d3-collection.v1.min.js"></script>
<script src="https://d3js.org/d3-hierarchy.v1.js"></script>
<script src="./d3-radial-cluster-layout.js"></script>
</body>
</html>
"use strict";
function draw_cluster() {
var width = 500;
var height = 500;
var radius = Math.min(width/2, height/2);
var svg = d3.select("body")
.append("svg")
.attrs({"width" : width,
"height" : height})
.append("g")
.attr("transform", "translate(" + width/2 + "," + height/2 + ")scale(0.8,0.8)");
var data = {
"name": "Eve",
"children": [
{ "name": "Cain" },
{
"name": "Seth",
"children": [
{ "name": "Enos" },
{ "name": "Noam" }
]
},
{ "name": "Abel" },
{
"name": "Awan",
"children": [
{ "name": "Enoch" }
]
},
{ "name": "Azura" }
]
};
// see also:
// d3/d3-hierarchy: 2D layout algorithms for visualizing hierarchical data.
// https://github.com/d3/d3-hierarchy
var root_node = d3.hierarchy(data);
var node_size = 20;
var cluster = d3.cluster().size([360, radius]);
var nodes = cluster(root_node);
var links = nodes.links();
console.log(links);
// path
// see also:
// d3/d3-shape: Graphical primitives for visualization, such as lines and areas.
// https://github.com/d3/d3-shape
var line = d3.radialLine()
.curve(d3.curveBundle.beta(0.85))
.radius(function(d) { return d.y; })
.angle(function(d) { return path_angle(d.x); });
svg.selectAll("path")
.data(links)
.enter()
.append("path")
.attr("d", function(d) {
return line([
d.source,
{ "x" : d.source.x, "y" : (d.source.y + d.target.y)/2 },
{ "x" : d.target.x, "y" : (d.source.y + d.target.y)/2 },
d.target
]);
});
// circle (overwrite path)
svg.selectAll("circle")
.data(nodes.descendants())
.enter()
.append("circle")
.attrs({
"cx" : node_x,
"cy" : node_y,
"r" : node_size/2
})
.append("title")
.text(function(d) { return d.data.name; });
// text
svg.selectAll("text")
.data(nodes.descendants())
.enter()
.append("text")
.attrs({
"dy" : node_size * 1.1,
"text-anchor" : "middle",
"x" : node_x,
"y" : node_y,
})
.text(function(d) { return d.data.name; } );
}
function path_angle(x) {
return rad(x);
}
function node_angle(x) {
return rad(x) - Math.PI/2;
}
function node_x(d) {
return d.y * Math.cos(node_angle(d.x));
}
function node_y(d) {
return d.y * Math.sin(node_angle(d.x));
}
function rad(deg) {
return deg/360 * 2 * Math.PI;
}
// run
draw_cluster();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment