1
0
mirror of https://github.com/d3/d3.git synced 2025-12-08 19:46:24 +00:00
d3/examples/treemap.md
2024-09-24 17:09:14 +02:00

3.1 KiB
Raw Blame History

Treemap

Introduced by Ben Shneiderman, treemaps recursively partition space into rectangles according to each nodes associated value. D3 supports several treemap tiling methods. See also nested, zoomable and animated treemaps, and the bubble chart.

const tile = view(Inputs.select(
  new Map([
    ["binary", d3.treemapBinary],
    ["squarify", d3.treemapSquarify],
    ["slice-dice", d3.treemapSliceDice],
    ["slice", d3.treemapSlice],
    ["dice", d3.treemapDice]
  ]),
  {label: "Tiling method", value: d3.treemapBinary}
));
Plot.legend({color: {domain: color.domain(), range: color.range()}})
// Set the height to the (default) width.
const height = width;

// Specify the color scale.
const color = d3.scaleOrdinal()
    .domain(data.children.map((d) => d.name))
    .range(d3.schemeObservable10);

// Compute the layout.
const root = d3.treemap()
    .tile(tile) // e.g., d3.treemapBinary
    .size([width, height])
    .padding(1)
    .round(true)
  (d3.hierarchy(data)
      .sum((d) => d.value)
      .sort((a, b) => b.value - a.value));

// Create the SVG container.
const svg = d3.create("svg")
    .attr("viewBox", [0, 0, width, height])
    .attr("width", width)
    .attr("height", height)
    .attr("fill", "currentColor")
    .attr("style", "max-width: 100%; height: auto; font: 10px sans-serif;");

// Add a cell for each leaf of the hierarchy.
const leaf = svg.selectAll("g")
  .data(root.leaves())
  .join("g")
    .attr("transform", (d) => `translate(${d.x0},${d.y0})`);

const format = d3.format(",d");

// Append a tooltip.
leaf.append("title")
    .text((d) => `${d.ancestors().reverse().map((d) => d.data.name).join(".")}\n${format(d.value)}`);

// Append a color rectangle.
leaf.append("rect")
    .attr("id", (d, i) => `leaf-${i}`)
    .attr("fill", (d) => { while (d.depth > 1) d = d.parent; return color(d.data.name); })
    .attr("fill-opacity", 0.6)
    .attr("width", (d) => d.x1 - d.x0)
    .attr("height", (d) => d.y1 - d.y0);

// Append a clipPath to ensure text does not overflow.
leaf.append("clipPath")
    .attr("id", (d, i) => `leaf-clip-${i}`)
  .append("use")
   .attr("xlink:href", (d, i) => `#leaf-${i}`);

// Append multiline text. The last line shows the value and has a specific formatting.
leaf
  .filter((d) => d.x1 - d.x0 > 7)
    .append("text")
    .attr("clip-path", (d, i) => `url(#leaf-clip-${i})`)
  .selectAll("tspan")
  .data((d) => d.data.name.split(/(?=[A-Z][a-z])|\s+/g).concat(format(d.value)))
  .join("tspan")
    .attr("x", 3)
    .attr("y", (d, i, nodes) => `${(i === nodes.length - 1) * 0.3 + 1.1 + i * 0.9}em`)
    .attr("fill-opacity", (d, i, nodes) => i === nodes.length - 1 ? 0.7 : null)
    .text((d) => d);

display(svg.node());

The data here is provided as a JSON file.

const data = FileAttachment("/data/flare.json").json();
data