Published
Edited
Dec 16, 2020
Insert cell
Insert cell
chart = {
const root = partition(data);
let focus = root;

const topfolds = root.descendants()
.sort((a, b) => b.value - a.value)
.filter(d => d.depth == 3)
.slice(0, 10)

const topfoldIds = topfolds.map(d => d.data.cath_id)

const topsfams = root.descendants()
.sort((a, b) => b.value - a.value)
.filter(d => d.depth == 4 && topfoldIds.indexOf(d.parent.data.cath_id) != -1)
.slice(0, 10)

const topsfamIds = topsfams.map(d => d.data.cath_id)
const dataset = root.descendants()
dataset.map(d => {
let visible = false
const cath_id = d.data.cath_id
switch (d.depth) {
case 1:
case 2:
visible = true
break
case 3:
visible = topfoldIds.indexOf(cath_id) == -1 ? false : true
break
case 4:
visible = topsfamIds.indexOf(cath_id) == -1 ? false : true
break
}
d.visible = visible
})
const svg = d3.create("svg")
.attr("viewBox", [0, 0, width, height])
.style("font", "12px sans-serif");

const cell = svg
.selectAll("g")
.data(dataset)
.join("g")
.attr("transform", d => `translate(${d.y0},${d.x0})`);

const rect = cell.append("rect")
.attr("width", d => d.y1 - d.y0 - 1)
.attr("height", d => rectHeight(d))
.attr("fill-opacity", 0.6)
.attr("visibility", d => d.visible ? "visible" : "hidden")
.attr("fill", d => {
if (!d.depth) return "#ccc";
while (d.depth > 1) d = d.parent;
return color(d.data.name);
})
.style("cursor", "pointer")
.on("click", clicked);

const text = cell.append("text")
.attr("visibility", d => d.visible ? "visible" : "hidden")
.style("user-select", "none")
.attr("pointer-events", "none")
.attr("x", 4)
.attr("y", 13)
.attr("fill-opacity", d => +labelVisible(d));

text.append("tspan")
.text(d => d.data.name);

const tspan = text.append("tspan")
.attr("fill-opacity", d => labelVisible(d) * 0.7)
.text(d => ` (${d.data.cath_id})`);

cell.append("title")
.text(d => `${d.ancestors().map(d => d.data.name).reverse().join(" / ")}\n${format(d.data.cath_id)}`);

function clicked(event, p) {
focus = focus === p ? p = p.parent : p;

root.each(d => d.target = {
x0: (d.x0 - p.x0) / (p.x1 - p.x0) * height,
x1: (d.x1 - p.x0) / (p.x1 - p.x0) * height,
y0: d.y0 - p.y0,
y1: d.y1 - p.y0
});

const t = cell.transition().duration(750)
.attr("transform", d => `translate(${d.target.y0},${d.target.x0})`);

rect.transition(t).attr("height", d => rectHeight(d.target));
text.transition(t).attr("fill-opacity", d => +labelVisible(d.target));
tspan.transition(t).attr("fill-opacity", d => labelVisible(d.target) * 0.7);
}
function rectHeight(d) {
return d.x1 - d.x0 - Math.min(1, (d.x1 - d.x0) / 2);
}

function labelVisible(d) {
return d.y1 <= width && d.y0 >= 0 && d.x1 - d.x0 > 16;
}
return svg.node();
}
Insert cell
data = FileAttachment("cathtree_v4_3_0.json").json()
Insert cell
partition = data => {
const root = d3.hierarchy(data)
.sum(d => {
return d.cath_id_depth == 4 ? d.descendants_count[8] : 0
})
return d3.partition()
.size([height, (root.height + 1) * width / 5])
(root);
}
Insert cell
color = d3.scaleOrdinal(["#d62728", "#2ca02c", "#1f77b4", "#bcbd22", "#17becf", "#e377c2"])
Insert cell
format = d3.format(",d")
Insert cell
width = 975
Insert cell
height = 900
Insert cell
d3 = require("d3@6")
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