This example created for development purposes using the d3-sankey plugin for D3 4.0.
forked from syntagmatic's block: Sankey Transitions
border: no |
This example created for development purposes using the d3-sankey plugin for D3 4.0.
forked from syntagmatic's block: Sankey Transitions
{ | |
"nodes": [{ | |
"name": "Agricultural 'waste'" | |
}, { | |
"name": "Bio-conversion" | |
}, { | |
"name": "Liquid" | |
}, { | |
"name": "Losses" | |
}, { | |
"name": "Solid" | |
}, { | |
"name": "Gas" | |
}, { | |
"name": "Biofuel imports" | |
}, { | |
"name": "Biomass imports" | |
}, { | |
"name": "Coal imports" | |
}, { | |
"name": "Coal" | |
}, { | |
"name": "Coal reserves" | |
}, { | |
"name": "District heating" | |
}, { | |
"name": "Industry" | |
}, { | |
"name": "Heating and cooling - commercial" | |
}, { | |
"name": "Heating and cooling - homes" | |
}, { | |
"name": "Electricity grid" | |
}, { | |
"name": "Over generation / exports" | |
}, { | |
"name": "H2 conversion" | |
}, { | |
"name": "Road transport" | |
}, { | |
"name": "Agriculture" | |
}, { | |
"name": "Rail transport" | |
}, { | |
"name": "Lighting & appliances - commercial" | |
}, { | |
"name": "Lighting & appliances - homes" | |
}, { | |
"name": "Gas imports" | |
}, { | |
"name": "Ngas" | |
}, { | |
"name": "Gas reserves" | |
}, { | |
"name": "Thermal generation" | |
}, { | |
"name": "Geothermal" | |
}, { | |
"name": "H2" | |
}, { | |
"name": "Hydro" | |
}, { | |
"name": "International shipping" | |
}, { | |
"name": "Domestic aviation" | |
}, { | |
"name": "International aviation" | |
}, { | |
"name": "National navigation" | |
}, { | |
"name": "Marine algae" | |
}, { | |
"name": "Nuclear" | |
}, { | |
"name": "Oil imports" | |
}, { | |
"name": "Oil" | |
}, { | |
"name": "Oil reserves" | |
}, { | |
"name": "Other waste" | |
}, { | |
"name": "Pumped heat" | |
}, { | |
"name": "Solar PV" | |
}, { | |
"name": "Solar Thermal" | |
}, { | |
"name": "Solar" | |
}, { | |
"name": "Tidal" | |
}, { | |
"name": "UK land based bioenergy" | |
}, { | |
"name": "Wave" | |
}, { | |
"name": "Wind" | |
}], | |
"links": [{ | |
"source": 0, | |
"target": 1, | |
"value": 124.729 | |
}, { | |
"source": 1, | |
"target": 2, | |
"value": 0.597 | |
}, { | |
"source": 1, | |
"target": 3, | |
"value": 26.862 | |
}, { | |
"source": 1, | |
"target": 4, | |
"value": 280.322 | |
}, { | |
"source": 1, | |
"target": 5, | |
"value": 81.144 | |
}, { | |
"source": 6, | |
"target": 2, | |
"value": 35 | |
}, { | |
"source": 7, | |
"target": 4, | |
"value": 35 | |
}, { | |
"source": 8, | |
"target": 9, | |
"value": 11.606 | |
}, { | |
"source": 10, | |
"target": 9, | |
"value": 63.965 | |
}, { | |
"source": 9, | |
"target": 4, | |
"value": 75.571 | |
}, { | |
"source": 11, | |
"target": 12, | |
"value": 10.639 | |
}, { | |
"source": 11, | |
"target": 13, | |
"value": 22.505 | |
}, { | |
"source": 11, | |
"target": 14, | |
"value": 46.184 | |
}, { | |
"source": 15, | |
"target": 16, | |
"value": 104.453 | |
}, { | |
"source": 15, | |
"target": 14, | |
"value": 113.726 | |
}, { | |
"source": 15, | |
"target": 17, | |
"value": 27.14 | |
}, { | |
"source": 15, | |
"target": 12, | |
"value": 342.165 | |
}, { | |
"source": 15, | |
"target": 18, | |
"value": 37.797 | |
}, { | |
"source": 15, | |
"target": 19, | |
"value": 4.412 | |
}, { | |
"source": 15, | |
"target": 13, | |
"value": 40.858 | |
}, { | |
"source": 15, | |
"target": 3, | |
"value": 56.691 | |
}, { | |
"source": 15, | |
"target": 20, | |
"value": 7.863 | |
}, { | |
"source": 15, | |
"target": 21, | |
"value": 90.008 | |
}, { | |
"source": 15, | |
"target": 22, | |
"value": 93.494 | |
}, { | |
"source": 23, | |
"target": 24, | |
"value": 40.719 | |
}, { | |
"source": 25, | |
"target": 24, | |
"value": 82.233 | |
}, { | |
"source": 5, | |
"target": 13, | |
"value": 0.129 | |
}, { | |
"source": 5, | |
"target": 3, | |
"value": 1.401 | |
}, { | |
"source": 5, | |
"target": 26, | |
"value": 151.891 | |
}, { | |
"source": 5, | |
"target": 19, | |
"value": 2.096 | |
}, { | |
"source": 5, | |
"target": 12, | |
"value": 48.58 | |
}, { | |
"source": 27, | |
"target": 15, | |
"value": 7.013 | |
}, { | |
"source": 17, | |
"target": 28, | |
"value": 20.897 | |
}, { | |
"source": 17, | |
"target": 3, | |
"value": 6.242 | |
}, { | |
"source": 28, | |
"target": 18, | |
"value": 20.897 | |
}, { | |
"source": 29, | |
"target": 15, | |
"value": 6.995 | |
}, { | |
"source": 2, | |
"target": 12, | |
"value": 121.066 | |
}, { | |
"source": 2, | |
"target": 30, | |
"value": 128.69 | |
}, { | |
"source": 2, | |
"target": 18, | |
"value": 135.835 | |
}, { | |
"source": 2, | |
"target": 31, | |
"value": 14.458 | |
}, { | |
"source": 2, | |
"target": 32, | |
"value": 206.267 | |
}, { | |
"source": 2, | |
"target": 19, | |
"value": 3.64 | |
}, { | |
"source": 2, | |
"target": 33, | |
"value": 33.218 | |
}, { | |
"source": 2, | |
"target": 20, | |
"value": 4.413 | |
}, { | |
"source": 34, | |
"target": 1, | |
"value": 4.375 | |
}, { | |
"source": 24, | |
"target": 5, | |
"value": 122.952 | |
}, { | |
"source": 35, | |
"target": 26, | |
"value": 839.978 | |
}, { | |
"source": 36, | |
"target": 37, | |
"value": 504.287 | |
}, { | |
"source": 38, | |
"target": 37, | |
"value": 107.703 | |
}, { | |
"source": 37, | |
"target": 2, | |
"value": 611.99 | |
}, { | |
"source": 39, | |
"target": 4, | |
"value": 56.587 | |
}, { | |
"source": 39, | |
"target": 1, | |
"value": 77.81 | |
}, { | |
"source": 40, | |
"target": 14, | |
"value": 193.026 | |
}, { | |
"source": 40, | |
"target": 13, | |
"value": 70.672 | |
}, { | |
"source": 41, | |
"target": 15, | |
"value": 59.901 | |
}, { | |
"source": 42, | |
"target": 14, | |
"value": 19.263 | |
}, { | |
"source": 43, | |
"target": 42, | |
"value": 19.263 | |
}, { | |
"source": 43, | |
"target": 41, | |
"value": 59.901 | |
}, { | |
"source": 4, | |
"target": 19, | |
"value": 0.882 | |
}, { | |
"source": 4, | |
"target": 26, | |
"value": 400.12 | |
}, { | |
"source": 4, | |
"target": 12, | |
"value": 46.477 | |
}, { | |
"source": 26, | |
"target": 15, | |
"value": 525.531 | |
}, { | |
"source": 26, | |
"target": 3, | |
"value": 787.129 | |
}, { | |
"source": 26, | |
"target": 11, | |
"value": 79.329 | |
}, { | |
"source": 44, | |
"target": 15, | |
"value": 9.452 | |
}, { | |
"source": 45, | |
"target": 1, | |
"value": 182.01 | |
}, { | |
"source": 46, | |
"target": 15, | |
"value": 19.013 | |
}, { | |
"source": 47, | |
"target": 15, | |
"value": 289.366 | |
}] | |
} |
<!DOCTYPE html> | |
<html> | |
<meta charset="utf-8"> | |
<title>Sankey Diagram</title> | |
<style> | |
body { | |
font-family: sans-serif; | |
} | |
#chart { | |
height: 500px; | |
} | |
.node rect { | |
cursor: move; | |
fill-opacity: .9; | |
shape-rendering: crispEdges; | |
} | |
.node text { | |
pointer-events: none; | |
font-size: 12px; | |
} | |
.link { | |
fill: none; | |
stroke: #000; | |
stroke-opacity: .16; | |
} | |
.link:hover { | |
stroke-opacity: .5; | |
} | |
</style> | |
<body> | |
<div id="chart"></div> | |
<script src="https://d3js.org/d3.v4.min.js"></script> | |
<script src="https://unpkg.com/d3-sankey@0.4.1"></script> | |
<script> | |
var margin = { | |
top: 1, | |
right: 1, | |
bottom: 6, | |
left: 1 | |
}, | |
width = 960 - margin.left - margin.right, | |
height = 500 - margin.top - margin.bottom; | |
var fontScale = d3.scaleLinear() | |
.range([8, 30]); | |
var formatNumber = d3.format(",.0f"), | |
format = function(d) { | |
return formatNumber(d) + " TWh"; | |
}, | |
color = d3.scaleOrdinal(d3.schemeCategory20); | |
var svg = d3.select("#chart").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 weightText = svg.append("text") | |
.text("Links weighted equally") | |
.attr("x", width/2-170) | |
.attr("y", height) | |
.style("font-size", "24px"); | |
var sankey = d3.sankey() | |
.nodeWidth(15) | |
.nodePadding(10) | |
.size([width, height]); | |
var path = sankey.link(); | |
d3.json("energy.json", function(energy) { | |
var empty_links = energy.links.map(function(d) { | |
d.id = d.source + " -> " + d.target; | |
return { | |
source: d.source, | |
target: d.target, | |
id: d.id, | |
value: 1 | |
} | |
}); | |
sankey | |
.nodes(energy.nodes) | |
.links(empty_links) | |
.layout(32); | |
fontScale.domain(d3.extent(energy.nodes, function(d) { return d.value })); | |
var link = svg.append("g").selectAll(".link") | |
.data(empty_links, function(d) { return d.id; }) | |
.enter().append("path") | |
.attr("class", "link") | |
.attr("d", path) | |
.style("stroke-width", function(d) { | |
return Math.max(1, d.dy) + "px"; | |
}) | |
.sort(function(a, b) { | |
return b.dy - a.dy; | |
}); | |
link.append("title") | |
.text(function(d) { | |
return d.source.name + " → " + d.target.name + "\n" + format(d.value); | |
}); | |
var node = svg.append("g").selectAll(".node") | |
.data(energy.nodes, function(d) { return d.name; }) | |
.enter().append("g") | |
.attr("class", "node") | |
.attr("transform", function(d) { | |
return "translate(" + d.x + "," + d.y + ")"; | |
}); | |
node.append("rect") | |
.attr("height", function(d) { | |
return 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(1.8); | |
}) | |
.append("title") | |
.text(function(d) { | |
return d.name + "\n" + format(d.value); | |
}); | |
node.append("text") | |
.attr("x", -6) | |
.attr("y", function(d) { | |
return d.dy / 2; | |
}) | |
.attr("dy", ".35em") | |
.attr("text-anchor", "end") | |
.attr("transform", null) | |
.style("fill", function(d) { | |
return d3.rgb(d.color).darker(2.4); | |
}) | |
.text(function(d) { | |
return d.name; | |
}) | |
.style("font-size", function(d) { | |
return Math.floor(fontScale(d.value)) + "px"; | |
}) | |
.filter(function(d) { | |
return d.x < width / 2; | |
}) | |
.attr("x", 6 + sankey.nodeWidth()) | |
.attr("text-anchor", "start"); | |
function update(nodeData, linkData) { | |
sankey | |
.nodes(nodeData) | |
.links(linkData) | |
.layout(32); | |
sankey.relayout(); | |
fontScale.domain(d3.extent(nodeData, function(d) { return d.value })); | |
svg.selectAll(".link") | |
.data(linkData, function(d) { return d.id; }) | |
.sort(function(a, b) { | |
return b.dy - a.dy; | |
}) | |
.transition() | |
.duration(1300) | |
.attr("d", path) | |
.style("stroke-width", function(d) { | |
return Math.max(1, d.dy) + "px"; | |
}); | |
svg.selectAll(".node") | |
.data(nodeData, function(d) { return d.name; }) | |
.transition() | |
.duration(1300) | |
.attr("transform", function(d) { | |
return "translate(" + d.x + "," + d.y + ")"; | |
}); | |
svg.selectAll(".node rect") | |
.transition() | |
.duration(1300) | |
.attr("height", function(d) { | |
return d.dy; | |
}); | |
svg.selectAll(".node text") | |
.transition() | |
.duration(1300) | |
.attr("y", function(d) { | |
return d.dy / 2; | |
}) | |
.style("font-size", function(d) { | |
return Math.floor(fontScale(d.value)) + "px"; | |
}); | |
}; | |
var counter = 0; | |
function toggleTransition() { | |
counter++; | |
var activeLinks = counter % 2 ? energy.links : empty_links; | |
weightText.text(counter % 2 ? "Links weighted by value" : "Links weighted equally"); | |
update(energy.nodes, activeLinks); | |
setTimeout(toggleTransition, 2400); | |
}; | |
setTimeout(toggleTransition, 2400); | |
}); | |
</script> |