Published
Edited
Dec 14, 2021
Fork of Sankey
5 forks
2 stars
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
import {titleCard, html} from "@trase/title-card"
Insert cell
import {loadFonts, traseCategory5} from "4be0b7b0578fccff@1102"
Insert cell
nodeLabelLength = 20
Insert cell
crop = (text, charLength = nodeLabelLength) => {
const textLength = text.length;
return charLength >= textLength
? text
: text.substr(0, charLength).trim() + "...";
}
Insert cell
height = width * 0.6
Insert cell
margin = ({top: 5, right: 0, bottom: 5, left: 0})
Insert cell
data = FileAttachment("civ_seipcs_simple@3.csv").csv({typed: true})
Insert cell
keys = Object.keys(data[0]).filter(d => d != "value")
Insert cell
format = d3.format(".02s")
Insert cell
colourColumn = 0
Insert cell
colour = link => {
const scale = d3.scaleOrdinal([...new Set(graph.links.map(d => d.names[colourColumn]))], [traseCategory1[1], traseCategory1[0], ...traseCategory1.slice(2, traseCategory1.length)]);
return scale(link.names[colourColumn])
}
Insert cell
fontSizeNodeNames = 13
Insert cell
fontSizeValues = 12
Insert cell
segregated = false
Insert cell
graph = {
let index = -1;
const nodes = [];
const nodeByKey = new Map;
const indexByKey = new Map;
const links = [];

for (const k of keys) {
for (const d of data) {
const key = JSON.stringify([k, d[k]]);
if (nodeByKey.has(key)) continue;
const node = {name: d[k]};
nodes.push(node);
nodeByKey.set(key, node);
indexByKey.set(key, ++index);
}
}

for (let i = 1; i < keys.length; ++i) {
const a = keys[i - 1];
const b = keys[i];
const linkByKey = new Map;
const prefix = segregated ? keys : keys.slice(0, i + 1);
for (const d of data) {
const names = prefix.map(k => d[k]);
const key = JSON.stringify(names);
const value = d.value || 1;
let link = linkByKey.get(key);
if (link) { link.value += value; continue; }
link = {
source: indexByKey.get(JSON.stringify([a, d[a]])),
target: indexByKey.get(JSON.stringify([b, d[b]])),
names,
value
};
links.push(link);
linkByKey.set(key, link);
}
}
return {nodes, links};
}
Insert cell
sankey = d3.sankey()
.nodeSort(sortNodes)
.linkSort(sortLinks)
.nodeWidth(3)
.nodePadding(20)
.extent([[margin.left, margin.top], [width - margin.right, height - margin.bottom]])
Insert cell
sortNodes = (a, b) => {
if (["DIRECT SOURCING", "INDIRECT SOURCING", "UNKNOWN SOURCING"].includes(a.name)) {
return a.name.localeCompare(b.name)
}
// if ((a.depth === 1 && a.layer === 1) || (b.depth === 1 && b.layer === 1)) {
// if (a.name === "OTHER EXPORTERS" || b.name === "OTHER EXPORTERS") { return 1 }
// return -1
// }
return b.value - a.value
}
Insert cell
Insert cell
annotate = g => {}
Insert cell
function hover(g, svg) {
const tooltip = new Tooltip();
g
.style("cursor", "pointer")
.on("touchstart", event => event.preventDefault())
.on("pointerenter", (event, d) => {
tooltip.position(...tooltipOffset(tooltip, d3.pointer(event), width, height));
const path = d.names.join(" → ");
tooltip.show(`${path}`, tooltipKeyValue(tooltipKey, formatTooltipValue(d.value), d));
})
.on("pointermove", function(event, d) {
// add content
const path = d.names.join(" → ");
tooltip.show(`${path}`, tooltipKeyValue(tooltipKey, formatTooltipValue(d.value), d));
// position tooltip
let [x, y] = tooltipOffset(tooltip, d3.pointer(event), width, height);
tooltip.position(x, y);
this.releasePointerCapture(event.pointerId);
// highlight flow
g.filter(d => d.names.join(" → ") === path)
.attr("stroke-opacity", 1);
})
.on("pointerout", () => {
tooltip.hide();
g.attr("stroke-opacity", 0.7);
});
svg.append(() => tooltip.node);
}
Insert cell
tooltipKey = "VALUE"
Insert cell
formatTooltipValue = d3.format(".02s")
Insert cell
import { getLabelLength } from "@trase/legends@376"
Insert cell
import {traseColours, traseCategory1, fonts, traseGreens, traseReds, trasePurples, traseOranges, traseOrPu } from "@trase/visual-id@1366"

Insert cell
import { Tooltip, tooltipKeyValue, tooltipOffset } from "@trase/tooltip@440"
Insert cell
d3 = require("d3@6", "d3-sankey@0.12")
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more