Skip to content

Instantly share code, notes, and snippets.

@chule
Created November 23, 2018 12:31
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 chule/551e55765903aa0fc1e3ff07f37f8b9a to your computer and use it in GitHub Desktop.
Save chule/551e55765903aa0fc1e3ff07f37f8b9a to your computer and use it in GitHub Desktop.
interactive visualizations using D3
license: mit
<!DOCTYPE html>
<head>
<meta charset="utf-8">
<script src="https://d3js.org/d3.v3.min.js"></script>
<style>
body { margin:0;position:fixed;top:0;right:0;bottom:0;left:0; }
.link {
stroke: gray;
stroke-width: .8px;
}
.node {
fill: white;
stroke: #000;
stroke-width: .9px;
}
.node:hover {
fill: black;
}
</style>
</head>
<body>
<form>
Layout:
<label><input type="radio" name="layout" value="force" checked> Force</label>
<label><input type="radio" name="layout" value="random" > Random</label>
<label><input type="radio" name="layout" value="circular"> Circular</label>
<label><input type="radio" name="layout" value="line"> Line</label>
<label><input type="radio" name="layout" value="line_cat"> Line by Category</label>
</form>
<form>
Color:
<label><input type="radio" name="color" value="nocolor" checked> None</label>
<label><input type="radio" name="color" value="color_cat" > Category</label>
</form>
<form>
Size:
<label><input type="radio" name="size" value="nosize" checked> None</label>
<label><input type="radio" name="size" value="size_cat" > Category</label>
</form>
<script>
var margin = {top: 0, bottom: 10, left: 50, right: 40};
var width = 800 - margin.left - margin.right;
var height = 480 - margin.top - margin.bottom;
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height);
var fill = d3.scale.category10();
var graph = {nodes: [], links: []};
var nb_nodes = 120, nb_cat = 10;
var node_scale = d3.scale.linear().domain([0, nb_cat]).range([5, 50])
graph.nodes = d3.range(nb_nodes).map(function() {
return {
cat: Math.floor(nb_cat*Math.random())
};
})
graph.nodes.forEach(function(d, i) {
graph.nodes.forEach(function(e, j) {
if(Math.random()>.99 && i!=j)
graph.links.push({"source": i, "target": j})
})
})
// Generate the force layout
var force = d3.layout.force()
.size([width, height])
.charge(-50)
.linkDistance(10)
.on("tick", tick)
.on("start", function(d) {})
.on("end", function(d) {})
function tick(d) {
graph_update(0);
}
function random_layout() {
force.stop();
graph.nodes.forEach(function(d, i) {
d.x = width/4 + 2*width*Math.random()/4;
d.y = height/4 + 2*height*Math.random()/4;
})
graph_update(500);
}
function force_layout() {
force.nodes(graph.nodes)
.links(graph.links)
.start();
}
function line_layout() {
force.stop();
graph.nodes.forEach(function(d, i) {
d.y = height/2;
})
graph_update(500);
}
function line_cat_layout() {
force.stop();
graph.nodes.forEach(function(d, i) {
d.y = height/2 + d.cat*20;
})
graph_update(500);
}
function circular_layout() {
force.stop();
var r = Math.min(height, width)/2;
var arc = d3.svg.arc()
.outerRadius(r);
var pie = d3.layout.pie()
.sort(function(a, b) { return a.cat - b.cat;}) // Sorting by categories
.value(function(d, i) {
return 1; // We want an equal pie share/slice for each point
});
graph.nodes = pie(graph.nodes).map(function(d, i) {
// Needed to caclulate the centroid
d.innerRadius = 0;
d.outerRadius = r;
// Building the data object we are going to return
d.data.x = arc.centroid(d)[0]+width/2;
d.data.y = arc.centroid(d)[1]+height/2;
return d.data;
})
graph_update(500);
}
function category_color() {
d3.selectAll("circle").transition().duration(500)
.style("fill", function(d) {
return fill(d.cat);
});
}
function category_size() {
d3.selectAll("circle").transition().duration(500)
.attr("r", function(d) {
return Math.sqrt(node_scale(d.cat));
});
}
function graph_update(duration) {
link.transition().duration(duration)
.attr("x1", function(d) { return d.target.x; })
.attr("y1", function(d) { return d.target.y; })
.attr("x2", function(d) { return d.source.x; })
.attr("y2", function(d) { return d.source.y; });
node.transition().duration(duration)
.attr("transform", function(d) {
return "translate("+d.x+","+d.y+")";
});
}
d3.select("input[value=\"force\"]").on("click", force_layout);
d3.select("input[value=\"random\"]").on("click", random_layout);
d3.select("input[value=\"line\"]").on("click", line_layout);
d3.select("input[value=\"line_cat\"]").on("click", line_cat_layout);
d3.select("input[value=\"circular\"]").on("click", circular_layout);
d3.select("input[value=\"nocolor\"]").on("click", function() {
d3.selectAll("circle").transition().duration(500).style("fill", "#66CC66");
})
d3.select("input[value=\"color_cat\"]").on("click", category_color);
d3.select("input[value=\"nosize\"]").on("click", function() {
d3.selectAll("circle").transition().duration(500).attr("r", 5);
})
d3.select("input[value=\"size_cat\"]").on("click", category_size);
var link = svg.selectAll(".link")
.data(graph.links);
link.enter().append("line")
.attr("class", "link")
var node = svg.selectAll(".node")
.data(graph.nodes)
.enter()
.append("g").attr("class", "node");
node.append("circle")
.attr("r", 5)
force_layout();
</script>
</body>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment