Voronoi Treemap

This tutorial is an introduction to creating a Voronoi treemap with React and D3.js. A Voronoi treemap is a space-filling visualization that recursively partitions a plane into regions based on a set of points, where each region contains all points closer to one of the generating points than to any other.
This example will show you how to create a basic Voronoi treemap that displays hierarchical data in a visually appealing way, with each cell's size proportional to its value.
Plot and code
Here's what we're going to create:
A Voronoi treemap is a powerful visualization that combines the space-filling properties of a treemap with the geometric elegance of a Voronoi diagram. It's particularly useful for displaying hierarchical data where the size of each cell represents a quantitative value.
A Voronoi treemap showing hierarchical data with cell sizes proportional to their values.
The Data
The dataset used for this example is a hierarchical structure where each node has:
- A
name
property for identification - A
value
property determining the cell size - Optional
children
for nested data
const data = {
name: "root",
value: 100,
children: [
{
name: "Category A",
value: 40,
children: [
{ name: "A1", value: 20 },
{ name: "A2", value: 20 }
]
},
{
name: "Category B",
value: 60,
children: [
{ name: "B1", value: 30 },
{ name: "B2", value: 30 }
]
}
]
};
Implementation
The implementation involves several key steps:
- Creating a Voronoi diagram using D3's
d3-delaunay
- Recursively partitioning the space based on the data hierarchy
- Rendering the cells with appropriate colors and labels
import { useMemo } from 'react';
import * as d3 from 'd3';
const VoronoiTreemap = ({ data, width, height }) => {
// Compute the Voronoi diagram
const voronoi = useMemo(() => {
const points = generatePoints(data, width, height);
return d3.Delaunay.from(points).voronoi([0, 0, width, height]);
}, [data, width, height]);
return (
<svg width={width} height={height}>
{voronoi.cellPolygons().map((polygon, i) => (
<path
key={i}
d={`M${polygon.join("L")}Z`}
fill={d3.interpolateRainbow(i / data.children.length)}
stroke="white"
/>
))}
</svg>
);
};
Contact
👋 Hey, I'm Yan and I'm currently working on this project!
Feedback is welcome ❤️. You can fill an issue on Github, drop me a message on Twitter, or even send me an email pasting yan.holtz.data
with gmail.com
. You can also subscribe to the newsletter to know when I publish more content!