Public
Edited
Jul 9, 2023
Insert cell
Insert cell
graph = {
const svg = d3
.select(DOM.svg(width, width))
.attr("viewBox", `${-width / 2} ${-width / 2} ${width} ${width}`)
.style("font-family", "'Helvetica Neue', Helvetica, Arial sans-serif");

let link = svg
.append("g")
.selectAll("link")
.data(connectivity)
.enter()
.append("path")
.each(function (d) {
(d.source = d[0]), (d.target = d[d.length - 1]);
})
.attr("d", line)
.attr("fill", "none")
//.attr("pointer-events", "none")
//.attr("mix-blend-mode", "multiply")
.attr("stroke", (d) => color(d.source.x));

let node = svg
.append("g")
.selectAll("text")
.data(root.leaves())
.enter()
.append("text")
.text((d) => d.data.Alias)
.attr("transform", (d) => tilt(d))
.attr("dy", "0.3em")
.attr("x", (d) => (d.x < Math.PI ? 5 : -5))
.attr("text-anchor", (d) => (d.x < Math.PI ? "start" : "end"))
.on("mouseover", mouseover)
.on("mouseout", reset);

let highlight = svg
.append("g")
.attr("text-anchor", "middle")
.attr("fill", "#333")
.attr("fill-opacity", 0.8)
.style("font-size", "10vw")
.style("font-weight", 700);

let alias = highlight.append("text").attr("dy", "-0.3em");

let points = highlight
.append("text")
.attr("dy", "0.3em")
.attr("fill-opacity", 0.6)
.style("font-size", "2.5vw")
.style("font-weight", 500);

let connections = highlight
.append("text")
.attr("dy", "0.8em")
.style("font-size", "3vw")
.style("font-weight", 600);

function mouseover(d) {
d3.select(this)
.attr("fill", (d) => color(d.x))
.style("font-weight", 700)
.style("font-size", "2vw");

node.each((n) => (n.linked = false));

link
.filter((l) => (l.target === d) | (l.source === d))
.each((l) =>
l.target === d ? (l.source.linked = true) : (l.target.linked = true)
)
.attr("stroke-width", 2)
.attr("stroke-opacity", 0.7);

node
.filter((n) => n.linked)
.style("font-weight", 500)
.style("font-size", "1.4vw");

alias.text(d.data.Alias).attr("fill", color(d.x));
points.text(d3.format(",")(d.data.Points) + " points");
connections.text(d.data.Count + " connections");
}

function reset() {
node
.attr("fill", "#999")
.style("font-weight", 300)
.style("font-size", "1.3vw");

link.attr("stroke-opacity", 0.3).attr("stroke-width", 0.5);

alias.text("");
points.text("");
connections.text("");
}

reset();
return svg.node();
}
Insert cell
Insert cell
// Per each node
// create an array with all targets for that node
connectivity = d3.merge(
root.leaves().map((n) => n.data.targets.map((i) => n.path(players.get(i))))
)
Insert cell
connectivity[0].map((n) => n)
Insert cell
Insert cell
players = new Map(root.leaves().map(d => [d.data.Key, d]))
Insert cell
Insert cell
hierarchyOutput = d3.hierarchy(cluster)
Insert cell
root = tree(hierarchyOutput)
Insert cell
Insert cell
Insert cell
firstLevel = cluster.children.map(({ name }) => name)
Insert cell
Insert cell
secondLevel = cluster.children[2].children.map(({ name }) => name)
Insert cell
leave = cluster.children[2].children[1].children
Insert cell
cluster = {
// An array,
let flags = new Map();
for (let node of data.nodes) {
let flag = flags.get(node.Flag);
if (!flag) flags.set(node.Flag, (flag = { name: node.Flag, children: [] }));
flag.children.push(node);
node.targets = [];
}
flags = [...flags.values()];

let regions = new Map();
for (let flag of flags) {
let r = flag.children[0].Region;
let region = regions.get(r);
if (!region) regions.set(r, (region = { name: r, children: [] }));
region.children.push(flag);
}
regions = [...regions.values()].sort((a, b) =>
a.name > b.name ? 1 : a.name < b.name ? -1 : 0
);

for (const link of data.links) {
link[0].targets.push(link[1].Key);
}

return { name: "DPC", children: regions };
}
Insert cell
Insert cell
tree = d3.cluster().size([2 * Math.PI, radius - 100])
Insert cell
Insert cell
Insert cell
line = d3.radialLine()
.curve(d3.curveBundle.beta(0.7))
.radius(d => d.y)
.angle(d => d.x)
Insert cell
Insert cell
tilt = n =>`rotate(${n.x * 180/Math.PI - 90}) translate(${n.y},0) ${n.x >= Math.PI ? "rotate(180)" : ""}`
Insert cell
color = d3.scaleSequential(d3.interpolateViridis).domain([0,7])
Insert cell
radius = width/2 - 50
Insert cell
Insert cell
data = {
let json = await d3.json("https://raw.githubusercontent.com/youmikoh/dpc-connectivity/master/data/dpc_connectivity_data.json")
// Add key field to nodes
Object.keys(json.nodes).forEach(d => json.nodes[d].Key = String(d));
// Rewrite the links so we have nodes on each entry instead of just the names
json.links = json.links.map(d => [ json.nodes[d[0]], json.nodes[d[1]] ]);
// Nodes is now an array of nodes - links is an array of array of two nodes.
return {nodes: Object.values(json.nodes), links: json.links};
}
Insert cell
data.nodes[0]
Insert cell
data.links[0][0]
Insert cell
data.links[0][1]
Insert cell
Insert cell
Insert cell
json.nodes[Object.keys(json.nodes)[0]]
Insert cell
Insert cell
json.links[0]
Insert cell
json = await d3.json("https://raw.githubusercontent.com/youmikoh/dpc-connectivity/master/data/dpc_connectivity_data.json")
Insert cell
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