Last active
September 8, 2020 19:16
-
-
Save mootari/8d3eeb938fafbdf43cda77fe23642d00 to your computer and use it in GitHub Desktop.
Ported from https://observablehq.com/@d3/sankey-diagram
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<script src="https://cdn.jsdelivr.net/npm/d3-require@1"></script> | |
<script> | |
(async()=>{ | |
/* | |
Ported from https://observablehq.com/@d3/sankey-diagram@278 | |
Copyright 2018–2020 Observable, Inc. | |
Permission to use, copy, modify, and/or distribute this software for any | |
purpose with or without fee is hereby granted, provided that the above | |
copyright notice and this permission notice appear in all copies. | |
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |
*/ | |
const d3 = await window.d3.require("d3@6", "[email protected]"); | |
const width = 954; | |
const height = 600; | |
const align = "justify"; | |
const edgeColor = "path"; | |
const color = (()=>{ | |
const color = d3.scaleOrdinal(d3.schemeCategory10); | |
return d => color(d.category === undefined ? d.name : d.category); | |
})(); | |
data = (()=>{ | |
const links = d3.csvParse(document.getElementById('data').textContent, d3.autoType); | |
const nodes = Array.from(new Set(links.flatMap(l => [l.source, l.target])), name => ({name, category: name.replace(/ .*/, "")})); | |
return {nodes, links, units: "TWh"}; | |
})(); | |
const format = (()=>{ | |
const format = d3.format(",.0f"); | |
return data.units ? d => `${format(d)} ${data.units}` : format; | |
})(); | |
const sankey = (()=>{ | |
const sankey = d3.sankey() | |
.nodeId(d => d.name) | |
.nodeAlign(d3[`sankey${align[0].toUpperCase()}${align.slice(1)}`]) | |
.nodeWidth(15) | |
.nodePadding(10) | |
.extent([[1, 5], [width - 1, height - 5]]); | |
return ({nodes, links}) => sankey({ | |
nodes: nodes.map(d => Object.assign({}, d)), | |
links: links.map(d => Object.assign({}, d)) | |
}); | |
})(); | |
const chart = (()=>{ | |
const svg = d3.create("svg") | |
.attr("viewBox", [0, 0, width, height]); | |
const {nodes, links} = sankey(data); | |
svg.append("g") | |
.attr("stroke", "#000") | |
.selectAll("rect") | |
.data(nodes) | |
.join("rect") | |
.attr("x", d => d.x0) | |
.attr("y", d => d.y0) | |
.attr("height", d => d.y1 - d.y0) | |
.attr("width", d => d.x1 - d.x0) | |
.attr("fill", color) | |
.append("title") | |
.text(d => `${d.name}\n${format(d.value)}`); | |
const link = svg.append("g") | |
.attr("fill", "none") | |
.attr("stroke-opacity", 0.5) | |
.selectAll("g") | |
.data(links) | |
.join("g") | |
.style("mix-blend-mode", "multiply"); | |
if (edgeColor === "path") { | |
const gradient = link.append("linearGradient") | |
.attr("id", (d, i) => (d.uid = `link-${i}`)) | |
.attr("gradientUnits", "userSpaceOnUse") | |
.attr("x1", d => d.source.x1) | |
.attr("x2", d => d.target.x0); | |
gradient.append("stop") | |
.attr("offset", "0%") | |
.attr("stop-color", d => color(d.source)); | |
gradient.append("stop") | |
.attr("offset", "100%") | |
.attr("stop-color", d => color(d.target)); | |
} | |
link.append("path") | |
.attr("d", d3.sankeyLinkHorizontal()) | |
.attr("stroke", d => edgeColor === "none" ? "#aaa" | |
: edgeColor === "path" ? `url(#${d.uid})` | |
: edgeColor === "input" ? color(d.source) | |
: color(d.target)) | |
.attr("stroke-width", d => Math.max(1, d.width)); | |
link.append("title") | |
.text(d => `${d.source.name} → ${d.target.name}\n${format(d.value)}`); | |
svg.append("g") | |
.attr("font-family", "sans-serif") | |
.attr("font-size", 10) | |
.selectAll("text") | |
.data(nodes) | |
.join("text") | |
.attr("x", d => d.x0 < width / 2 ? d.x1 + 6 : d.x0 - 6) | |
.attr("y", d => (d.y1 + d.y0) / 2) | |
.attr("dy", "0.35em") | |
.attr("text-anchor", d => d.x0 < width / 2 ? "start" : "end") | |
.text(d => d.name); | |
return svg.node(); | |
})(); | |
document.body.appendChild(chart); | |
})() | |
</script> | |
<!-- Data: Department of Energy & Climate Change via Tom Counsell --> | |
<script id=data type="text/csv">source,target,value | |
Agricultural 'waste',Bio-conversion,124.729 | |
Bio-conversion,Liquid,0.597 | |
Bio-conversion,Losses,26.862 | |
Bio-conversion,Solid,280.322 | |
Bio-conversion,Gas,81.144 | |
Biofuel imports,Liquid,35 | |
Biomass imports,Solid,35 | |
Coal imports,Coal,11.606 | |
Coal reserves,Coal,63.965 | |
Coal,Solid,75.571 | |
District heating,Industry,10.639 | |
District heating,Heating and cooling - commercial,22.505 | |
District heating,Heating and cooling - homes,46.184 | |
Electricity grid,Over generation / exports,104.453 | |
Electricity grid,Heating and cooling - homes,113.726 | |
Electricity grid,H2 conversion,27.14 | |
Electricity grid,Industry,342.165 | |
Electricity grid,Road transport,37.797 | |
Electricity grid,Agriculture,4.412 | |
Electricity grid,Heating and cooling - commercial,40.858 | |
Electricity grid,Losses,56.691 | |
Electricity grid,Rail transport,7.863 | |
Electricity grid,Lighting & appliances - commercial,90.008 | |
Electricity grid,Lighting & appliances - homes,93.494 | |
Gas imports,Ngas,40.719 | |
Gas reserves,Ngas,82.233 | |
Gas,Heating and cooling - commercial,0.129 | |
Gas,Losses,1.401 | |
Gas,Thermal generation,151.891 | |
Gas,Agriculture,2.096 | |
Gas,Industry,48.58 | |
Geothermal,Electricity grid,7.013 | |
H2 conversion,H2,20.897 | |
H2 conversion,Losses,6.242 | |
H2,Road transport,20.897 | |
Hydro,Electricity grid,6.995 | |
Liquid,Industry,121.066 | |
Liquid,International shipping,128.69 | |
Liquid,Road transport,135.835 | |
Liquid,Domestic aviation,14.458 | |
Liquid,International aviation,206.267 | |
Liquid,Agriculture,3.64 | |
Liquid,National navigation,33.218 | |
Liquid,Rail transport,4.413 | |
Marine algae,Bio-conversion,4.375 | |
Ngas,Gas,122.952 | |
Nuclear,Thermal generation,839.978 | |
Oil imports,Oil,504.287 | |
Oil reserves,Oil,107.703 | |
Oil,Liquid,611.99 | |
Other waste,Solid,56.587 | |
Other waste,Bio-conversion,77.81 | |
Pumped heat,Heating and cooling - homes,193.026 | |
Pumped heat,Heating and cooling - commercial,70.672 | |
Solar PV,Electricity grid,59.901 | |
Solar Thermal,Heating and cooling - homes,19.263 | |
Solar,Solar Thermal,19.263 | |
Solar,Solar PV,59.901 | |
Solid,Agriculture,0.882 | |
Solid,Thermal generation,400.12 | |
Solid,Industry,46.477 | |
Thermal generation,Electricity grid,525.531 | |
Thermal generation,Losses,787.129 | |
Thermal generation,District heating,79.329 | |
Tidal,Electricity grid,9.452 | |
UK land based bioenergy,Bio-conversion,182.01 | |
Wave,Electricity grid,19.013 | |
Wind,Electricity grid,289.366 | |
</script> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment