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

One platform to build and deploy the best data apps

Experiment and prototype by building visualizations in live JavaScript notebooks. Collaborate with your team and decide which concepts to build out.
Use Observable Framework to build data apps locally. Use data loaders to build in any language or library, including Python, SQL, and R.
Seamlessly deploy to Observable. Test before you ship, use automatic deploy-on-commit, and ensure your projects are always up-to-date.
Learn more