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/[email protected]"></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> |