Treemap
portfolio cost
Nested size. Good for cost, storage, lines of code.
- Format.d3
- Length108 lines
- Includesnone
The source
108 lines of D3 JavaScript, and uses only the bundled D3 build. Copy it, or open the template inside Gnomon and render it as it is.
// Treemap — the default answer to "what do we spend IT on".
// `tile(d3.treemapSquarify)` keeps rectangles close to square, which is what
// makes areas comparable by eye.
const data = {
name: 'Portfolio',
children: [
{ name: 'Customer', children: [
{ name: 'Quote Engine', value: 1240 },
{ name: 'Broker Portal', value: 890 },
{ name: 'Customer Portal', value: 1120 },
{ name: 'Contact Centre', value: 1680 },
{ name: 'Campaign Manager', value: 260 },
]},
{ name: 'Policy', children: [
{ name: 'Policy Admin Core', value: 4820 },
{ name: 'Legacy Ledger', value: 1360 },
{ name: 'Underwriting', value: 1140 },
{ name: 'Risk Scoring', value: 520 },
]},
{ name: 'Claims', children: [
{ name: 'Claims Handling', value: 2140 },
{ name: 'Fraud Detection', value: 680 },
{ name: 'Supplier Network', value: 410 },
]},
{ name: 'Enterprise', children: [
{ name: 'Data Lakehouse', value: 1840 },
{ name: 'BI & Reporting', value: 720 },
{ name: 'Cloud Platform', value: 2960 },
{ name: 'Network Core', value: 1340 },
]},
],
};
const root = d3.treemap()
.tile(d3.treemapSquarify)
.size([width, height - 24])
.paddingTop(19)
.paddingInner(2)
.round(true)(
d3.hierarchy(data)
.sum(d => d.value || 0)
.sort((a, b) => b.value - a.value),
);
const color = d3.scaleOrdinal(data.children.map(c => c.name), theme.palette);
const topOf = d => d.ancestors().find(a => a.depth === 1)?.data.name ?? '';
const fmt = d3.format(',');
const svg = d3.select(container).append('svg')
.attr('viewBox', [0, 0, width, height])
.attr('width', width)
.attr('height', height)
.attr('font-family', 'system-ui, sans-serif')
.attr('font-size', 11);
const group = svg.selectAll('g.group')
.data(root.descendants().filter(d => d.depth === 1))
.join('g')
.attr('class', 'group')
.attr('transform', d => `translate(${d.x0},${d.y0})`);
group.append('rect')
.attr('width', d => d.x1 - d.x0)
.attr('height', d => d.y1 - d.y0)
.attr('rx', 3)
.attr('fill', d => color(d.data.name))
.attr('fill-opacity', 0.18);
group.append('text')
.attr('x', 5)
.attr('y', 13)
.attr('fill', d => color(d.data.name))
.attr('font-weight', 600)
.text(d => `${d.data.name} · £${fmt(d.value)}k`);
const leaf = svg.selectAll('g.leaf')
.data(root.leaves())
.join('g')
.attr('class', 'leaf')
.attr('transform', d => `translate(${d.x0},${d.y0})`);
leaf.append('rect')
.attr('width', d => Math.max(0, d.x1 - d.x0))
.attr('height', d => Math.max(0, d.y1 - d.y0))
.attr('rx', 2)
.attr('fill', d => color(topOf(d)))
.attr('fill-opacity', 0.85);
leaf.append('text')
.attr('x', 5)
.attr('y', 14)
.attr('fill', theme.mode === 'dark' ? '#ffffff' : '#1a1a1a')
.attr('display', d => (d.x1 - d.x0) > 70 && (d.y1 - d.y0) > 24 ? null : 'none')
.text(d => d.data.name);
leaf.append('text')
.attr('x', 5)
.attr('y', 28)
.attr('fill', theme.mode === 'dark' ? '#ffffffbb' : '#1a1a1abb')
.attr('display', d => (d.x1 - d.x0) > 70 && (d.y1 - d.y0) > 40 ? null : 'none')
.text(d => `£${fmt(d.value)}k`);
svg.append('text')
.attr('x', 0)
.attr('y', height - 6)
.attr('fill', theme.muted)
.text(`Total £${fmt(root.value)}k · area = annual run cost`);Render this offline
This template ships in Gnomon and renders on your machine, with no account and nothing sent to a server. The browser editor is free and needs no install.
Others in D3 visualisations
- Sankey — request flowFlow with volume. The best chart here for "where does it all go".
- Chord — service interactionWho talks to whom, when the traffic is bidirectional.
- Arc diagram — dependenciesNodes on one axis, arcs above. Readable where a force graph is not, provided the ordering means something.
- Adjacency matrix — couplingAdjacency matrix. Unfashionable, and better than a force graph for dense dependencies.
- Edge bundling — module importsHierarchical edge bundling. For import graphs big enough that straight edges become a hairball.
- Sunburst — nested spendNested hierarchy, radially. Prettier than an icicle, harder to compare.
- Icicle — nested spend (linear)A sunburst unrolled flat. Harder to love, much easier to compare siblings.
- Circle packing — nested sizeCircle packing. Nested size when the nesting matters more than reading exact areas.
- Tidy tree — structureA tidy tree. The default for anything with one parent per node.
- Radial tree — structure (radial)The same tree bent into a circle. Fits more depth on a slide, costs you easy comparison.
- Dendrogram — clusteringClustering, with join height carrying the distance. Not merely a tree with curves.
- Indented tree — file/spec outlineA file or spec outline. The chart that looks like the thing it describes.
- Force graph — service mapService map. Use for clusters, not for reading individual edges.
- Force graph — disjoint clustersForce graph that keeps unconnected clusters apart rather than flinging them off screen.
- Force graph — radial tiersForce layout pinned to rings, so tier is a position instead of a colour legend.
- Directed graph — call directionDirected edges with arrowheads. For when direction is the question, not just adjacency.
- Force tree — blast radiusBlast radius from one node: what breaks if this goes.
- Calendar heatmap — daily activityDaily activity over a year: deploys, incidents, commits.
- Streamgraph — shifting mixShifting composition over time. Good for the mix, poor for reading any single value.
- Gantt — delivery roadmapDelivery roadmap, rendered from data.
- Radar — capability scoringCapability scoring across axes. Fine for one subject, misleading with four overlaid.
- Bullet chart — target vs actualTarget against actual, in one line. The chart a gauge wishes it were.
- Beeswarm — distribution by groupEvery point, grouped, without the overplotting a strip plot suffers.
- Horizon chart — many series, little spaceMany series in little space. Takes a moment to learn, then very dense.
- Slope chart — before and afterBefore and after, two points, one line each. Devastatingly clear.
- Parallel coordinates — multi-criteriaMulti-criteria comparison: for option analysis.
- Box plot — latency distributionLatency distribution. The chart that shows the tail a mean hides.
- Grouped bar — category comparisonCategory comparison. Unglamorous, and usually the right answer.
- Multi-line — metrics over timeMetrics over time. Keep it under about five series, or switch to horizon.