Built with blockbuilder.org
xxxxxxxxxx
<!-- Based on Harry Stevens "Sankey from CSV"-->
<html>
<head>
<meta charset="utf-8">
<style>
body
{
background: silver;
margin: 0;
font-family: "Helvetica Neue", sans-serif;
}
.node rect
{
cursor: move;
fill-opacity: .9;
shape-rendering: crispEdges;
}
.node text
{
pointer-events: none;
text-shadow: 0px 0px 2px #fff;
font-size: .8em;
}
.link
{
fill: none;
stroke: #000;
stroke-opacity: .7;
}
.link:hover
{
stroke-opacity: 1;
}
</style>
</head>
<body>
<script src="https://d3js.org/d3.v4.min.js"></script>
<script src="https://unpkg.com/d3-sankey@0.4"></script>
<center><h3 class = "title">Who Dominates the Top and Bottom 20 Paying Occupations</h3></center>
<center><button type="button" onclick="top20()">Top 20</button>
<button type="button" onclick="all20()">All</button>
<button type="button" onclick="bottom20()">Bottom 20</button></center>
<div id="sank"></div>
<script>
var margin = {top: 20, right: 15, bottom: 20, left: 15},
width = 960 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
var color = d3.scaleOrdinal(d3.schemeCategory20);
// append the svg object to the body of the page
var svg = d3.select("#sank").append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform",
"translate(" + margin.left + "," + margin.top + ")");
// Set the sankey diagram properties
var sankey = d3.sankey()
.nodeWidth(10)
.nodePadding(10)
.size([width, height]);
var path = sankey.link();
// load the data
d3.queue()
.defer(d3.csv, "data.csv")
.await(ready);
function ready(error, csv)
{
var arr = [];
csv.forEach(function(d)
{
arr.push(d.source);
arr.push(d.target);
});
var nodes = arr.filter(onlyUnique).map(function(d,i)
{
return {
node: i,
name: d
}
});
var links = csv.map(function(csv_row)
{
return {
source: getNode("source"),
target: getNode("target"),
value: +csv_row.value
}
function getNode(type)
{
return nodes.filter(function(node_object)
{
return node_object.name == csv_row[type];
})
[0].node;
}
});
sankey
.nodes(nodes)
.links(links)
.layout(32);
// add in the links
var link = svg.append("g").selectAll(".link")
.data(links)
.enter().append("path")
.attr("class", "link")
.attr("d", path)
.style("stroke", function(d)
{
return color(d.source.name.replace(/ .*/, ""));
})
.style("stroke-width", function(d)
{
return Math.max(1, d.dy);
});
// add the link titles
link.append("title")
.text(function(d)
{
return d.source.name + " → "
+ d.target.name + "\n"
+ d.value*1000/1000000 + "m workers";
});
// add in the nodes
var node = svg.append("g").selectAll(".node")
.data(nodes)
.enter().append("g")
.attr("class", "node")
.attr("transform", function(d)
{
return "translate(" + d.x + "," + d.y + ")";
})
.call(d3.drag()
.subject(function(d)
{
return d;
})
.on("start", function()
{
this.parentNode.appendChild(this);
})
.on("drag", dragmove));
// add the rectangles for the nodes
node.append("rect")
.attr("height", function(d)
{
return d.dy < 0 ? .1 : d.dy;
})
.attr("width", sankey.nodeWidth())
.style("fill", function(d)
{
return d.color = color(d.name.replace(/ .*/, ""));
})
.style("stroke", function(d)
{
return d3.rgb(d.color).darker(2);
})
.append("title")
.text(function(d)
{
return d.name + " Workers \n" + d.value*1000/1000000 + "m";
});
// add in the title for the nodes
node.append("text")
.attr("x", -6)
.attr("y", function(d)
{
return d.dy / 2;
})
.attr("dy", ".35em")
.attr("text-anchor", "end")
.attr("transform", null)
.text(function(d)
{
if(d.name === "Top 20" || d.name === "Bottom 20")
{
return d.name + " Occupations";
}
else if(d.name === "Total")
{
return d.name + " Workers: " + d.value*1000/1000000+"m";
}
else
{
return d.name;
}
})
.filter(function(d)
{
return d.x < width / 2;
})
.attr("x", 6 + sankey.nodeWidth())
.attr("text-anchor", "start");
// the function for moving the nodes
function dragmove(d)
{
d3.select(this)
.attr("transform", "translate(" + d.x + ","
+ (d.y = Math.max(0, Math.min(height - d.dy, d3.event.y))) + ")");
sankey.relayout();
link.attr("d", path);
}
}
function top20()
{
d3.select('#sank').text('');
var svg = d3.select("#sank").append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
var sankey = d3.sankey()
.nodeWidth(10)
.nodePadding(10)
.size([width, height]);
var path = sankey.link();
d3.queue()
.defer(d3.csv, "data2.csv")
.await(ready);
function ready(error, csv)
{
var arr = [];
csv.forEach(function(d)
{
arr.push(d.source);
arr.push(d.target);
});
var nodes = arr.filter(onlyUnique).map(function(d,i)
{
return {
node: i,
name: d
}
});
var links = csv.map(function(csv_row)
{
return {
source: getNode("source"),
target: getNode("target"),
value: +csv_row.value
}
function getNode(type)
{
return nodes.filter(function(node_object)
{
return node_object.name == csv_row[type];
})
[0].node;
}
});
sankey
.nodes(nodes)
.links(links)
.layout(32);
var link = svg.append("g").selectAll(".link")
.data(links)
.enter().append("path")
.attr("class", "link")
.attr("d", path)
.style("stroke", function(d)
{
return color(d.source.name.replace(/ .*/, ""));
})
.style("stroke-width", function(d)
{
return Math.max(1, d.dy);
});
link.append("title")
.text(function(d)
{
return d.source.name + " → "
+ d.target.name + "\n"
+ d.value*1000/1000000 + "m workers";
});
var node = svg.append("g").selectAll(".node")
.data(nodes)
.enter().append("g")
.attr("class", "node")
.attr("transform", function(d)
{
return "translate(" + d.x + "," + d.y + ")";
})
.call(d3.drag()
.subject(function(d)
{
return d;
})
.on("start", function()
{
this.parentNode.appendChild(this);
})
.on("drag", dragmove));
node.append("rect")
.attr("height", function(d)
{
return d.dy < 0 ? .1 : d.dy;
})
.attr("width", sankey.nodeWidth())
.style("fill", function(d)
{
return d.color = color(d.name.replace(/ .*/, ""));
})
.style("stroke", function(d)
{
return d3.rgb(d.color).darker(2);
})
.append("title")
.text(function(d)
{
return d.name + " Workers \n" + d.value*1000/1000000 + "m";
});
node.append("text")
.attr("x", -6)
.attr("y", function(d)
{
return d.dy / 2;
})
.attr("dy", ".35em")
.attr("text-anchor", "end")
.attr("transform", null)
.text(function(d)
{
if(d.name === "Top 20" || d.name === "Bottom 20")
{
return d.name + " Occupations";
}
else if(d.name === "Total")
{
return d.name + " workers: " + d.value;
}
else
{
return d.name;
}
})
.filter(function(d)
{
return d.x < width / 2;
})
.attr("x", 6 + sankey.nodeWidth())
.attr("text-anchor", "start");
function dragmove(d)
{
d3.select(this)
.attr("transform", "translate("
+ d.x + ","
+ (d.y = Math.max(0, Math.min(height - d.dy, d3.event.y))) + ")");
sankey.relayout();
link.attr("d", path);
}
}
}
function bottom20()
{
d3.select('#sank').text('');
var svg = d3.select("#sank").append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
var sankey = d3.sankey()
.nodeWidth(10)
.nodePadding(10)
.size([width, height]);
var path = sankey.link();
d3.queue()
.defer(d3.csv, "data3.csv")
.await(ready);
function ready(error, csv)
{
var arr = [];
csv.forEach(function(d)
{
arr.push(d.source);
arr.push(d.target);
});
var nodes = arr.filter(onlyUnique).map(function(d,i)
{
return {
node: i,
name: d
}
});
var links = csv.map(function(csv_row)
{
return {
source: getNode("source"),
target: getNode("target"),
value: +csv_row.value
}
function getNode(type)
{
return nodes.filter(function(node_object)
{
return node_object.name == csv_row[type];
})
[0].node;
}
});
sankey
.nodes(nodes)
.links(links)
.layout(32);
var link = svg.append("g").selectAll(".link")
.data(links)
.enter().append("path")
.attr("class", "link")
.attr("d", path)
.style("stroke", function(d)
{
return color(d.source.name.replace(/ .*/, ""));
})
.style("stroke-width", function(d)
{
return Math.max(1, d.dy);
});
link.append("title")
.text(function(d)
{
return d.source.name + " → "
+ d.target.name + "\n"
+ d.value*1000/1000000 + "m workers";
});
var node = svg.append("g").selectAll(".node")
.data(nodes)
.enter().append("g")
.attr("class", "node")
.attr("transform", function(d)
{
return "translate(" + d.x + "," + d.y + ")";
})
.call(d3.drag()
.subject(function(d)
{
return d;
})
.on("start", function()
{
this.parentNode.appendChild(this);
})
.on("drag", dragmove));
node.append("rect")
.attr("height", function(d)
{
return d.dy < 0 ? .1 : d.dy;
})
.attr("width", sankey.nodeWidth())
.style("fill", function(d)
{
return d.color = color(d.name.replace(/ .*/, ""));
})
.style("stroke", function(d)
{
return d3.rgb(d.color).darker(2);
})
.append("title")
.text(function(d)
{
return d.name + " Workers \n" + d.value*1000/1000000 + "m";
});
node.append("text")
.attr("x", -6)
.attr("y", function(d)
{
return d.dy / 2;
})
.attr("dy", ".35em")
.attr("text-anchor", "end")
.attr("transform", null)
.text(function(d)
{
if(d.name === "Top 20" || d.name === "Bottom 20")
{
return d.name + " Occupations";
}
else if(d.name === "Total")
{
return d.name + " workers: " + d.value;
}
else
{
return d.name;
}
})
.filter(function(d)
{
return d.x < width / 2;
})
.attr("x", 6 + sankey.nodeWidth())
.attr("text-anchor", "start");
function dragmove(d)
{
d3.select(this)
.attr("transform", "translate("
+ d.x + ","
+ (d.y = Math.max(0, Math.min(height - d.dy, d3.event.y))) + ")");
sankey.relayout();
link.attr("d", path);
}
}
}
function all20()
{
d3.select('#sank').text('');
var svg = d3.select("#sank").append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
var sankey = d3.sankey()
.nodeWidth(10)
.nodePadding(10)
.size([width, height]);
var path = sankey.link();
d3.queue()
.defer(d3.csv, "data.csv")
.await(ready);
function ready(error, csv)
{
var arr = [];
csv.forEach(function(d)
{
arr.push(d.source);
arr.push(d.target);
});
var nodes = arr.filter(onlyUnique).map(function(d,i)
{
return {
node: i,
name: d
}
});
var links = csv.map(function(csv_row)
{
return {
source: getNode("source"),
target: getNode("target"),
value: +csv_row.value
}
function getNode(type)
{
return nodes.filter(function(node_object)
{
return node_object.name == csv_row[type];
})
[0].node;
}
});
sankey
.nodes(nodes)
.links(links)
.layout(32);
var link = svg.append("g").selectAll(".link")
.data(links)
.enter().append("path")
.attr("class", "link")
.attr("d", path)
.style("stroke", function(d)
{
return color(d.source.name.replace(/ .*/, ""));
})
.style("stroke-width", function(d)
{
return Math.max(1, d.dy);
});
link.append("title")
.text(function(d)
{
return d.source.name + " → "
+ d.target.name + "\n"
+ d.value*1000/1000000 + "m workers";
});
var node = svg.append("g").selectAll(".node")
.data(nodes)
.enter().append("g")
.attr("class", "node")
.attr("transform", function(d)
{
return "translate(" + d.x + "," + d.y + ")";
})
.call(d3.drag()
.subject(function(d)
{
return d;
})
.on("start", function()
{
this.parentNode.appendChild(this);
})
.on("drag", dragmove));
node.append("rect")
.attr("height", function(d)
{
return d.dy < 0 ? .1 : d.dy;
})
.attr("width", sankey.nodeWidth())
.style("fill", function(d)
{
return d.color = color(d.name.replace(/ .*/, ""));
})
.style("stroke", function(d)
{
return d3.rgb(d.color).darker(2);
})
.append("title")
.text(function(d)
{
return d.name + " Workers \n" + d.value*1000/1000000 + "m";
});
node.append("text")
.attr("x", -6)
.attr("y", function(d)
{
return d.dy / 2;
})
.attr("dy", ".35em")
.attr("text-anchor", "end")
.attr("transform", null)
.text(function(d)
{
if(d.name === "Top 20" || d.name === "Bottom 20")
{
return d.name + " Occupations";
}
else if(d.name === "Total")
{
return d.name + " workers: " + d.value;
}
else
{
return d.name;
}
})
.filter(function(d)
{
return d.x < width / 2;
})
.attr("x", 6 + sankey.nodeWidth())
.attr("text-anchor", "start");
function dragmove(d)
{
d3.select(this)
.attr("transform", "translate("
+ d.x + ","
+ (d.y = Math.max(0, Math.min(height - d.dy, d3.event.y))) + ")");
sankey.relayout();
link.attr("d", path);
}
}
}
function onlyUnique(value, index, self)
{
return self.indexOf(value) === index;
}
</script>
</body>
</html>
https://d3js.org/d3.v4.min.js
https://unpkg.com/d3-sankey@0.4