Bubble chart
Bubble charts are non-hierarchical packed circles. The area of each circle is proportional its value (here, file size). The organic appearance of these diagrams can be intriguing, but also consider a treemap or a humble bar chart.
const width = 932;
const height = width;
const format = d3.format(",d");
const color = d3.scaleOrdinal(data.map((d) => d.group), d3.schemeObservable10);
const root = d3.pack()
.size([width - 2, height - 2])
.padding(3)
(d3.hierarchy({children: data})
.sum((d) => d.size));
const svg = d3.create("svg")
.attr("viewBox", [0, 0, width, height])
.attr("font-size", 10)
.attr("font-family", "var(--sans-serif)")
.attr("text-anchor", "middle");
const leaf = svg.selectAll("g")
.data(root.leaves())
.join("g")
.attr("transform", (d) => `translate(${d.x + 1},${d.y + 1})`);
leaf.append("circle")
.attr("id", (d) => (d.leafUid = DOM.uid("leaf")).id)
.attr("r", (d) => d.r)
.attr("fill-opacity", 0.7)
.attr("fill", (d) => color(d.data.group));
leaf.append("clipPath")
.attr("id", (d) => (d.clipUid = DOM.uid("clip")).id)
.append("use")
.attr("xlink:href", (d) => d.leafUid.href);
leaf.append("text")
.attr("clip-path", (d) => d.clipUid)
.selectAll("tspan")
.data((d) => d.data.name.split(/(?=[A-Z][a-z])|\s+/g))
.join("tspan")
.attr("x", 0)
.attr("y", (d, i, nodes) => `${i - nodes.length / 2 + 0.8}em`)
.text((d) => d);
leaf.append("title")
.text((d) => `${d.data.title === undefined ? "" : `${d.data.title}
`}${format(d.value)}`);
display(svg.node());
const data = FileAttachment("data/flare.csv").csv()
.then((data) => data.filter(({size}) => size !== ""))
.then((data) => data.map(({name, size}) => ({name: name.split(".").pop(), title: name.replace(/\./g, "/"), group: name.split(".")[1], size: +size})))
.then(display);