Treemap
A treemap displays a hierarchical dataset (a tree) as a set of rectangles. Rectangle sizes are proportional to their numeric value.
d3.js
has some handy functions to compute the rectangle positions. React
becomes useful to render those rectangles, animate transitions and more. This post explains how to make those 2 tools work together to build a Treemap
component.
The Data
The dataset describes a hierarchy using a recursive structure. Each item in this structure is called a node, the lowest nodes of the hierarchy being called leaves.
The dataset is an object that has at least 3 properties: name
, value
and children
.children
is an array of nodes that have this structure too.
Here is a minimal example of the data structure:
const data = {
type: 'node',
name: "boss",
value: 2300,
children: [
{type: 'leaf', name:"Mark", value: 90},
{type: 'leaf', name:"Robert", value: 12},
{type: 'leaf', name:"Emily", value: 34},
...
}
It's very likely that your dataset is not formatted as above yet. But don't fret, the next section will teach you how to convert it. ⬇️
Data wrangling
Three main input data formats are usually encountered when it comes to store hierarchical information. It's always a struggle to deal with those various formats:
→ list of connection (csv)
→ list of connection (js object)
→ json with hierarchy
I described in depth how to deal with those format in the dendrogram section of the gallery that shares the same kind of input format. Please take a look there!
Read moreThe hierarchy format or "root node"
A treemap is a hierarchical layout. D3.js has a lot of utility functions allowing to deal with this kind of hierarchical data. To use those functions we first need to create a "Root node" or "Hierarchy".
But what the heck is this? 🤔
A "root node" or "hierarchy" is a javascript object. It has almost the same shape as the input data described above. But with some additional properties and methods that will make our life easier.
→ how to build a root node
If your dealing with the format describe in the previous section, you just have to pass it to the d3 hierarchy
function:
const hierarchy = d3.hierarchy(data)
Note that this concept of root node is key for all the charts representing a hierarchy like dendrograms, circle packing, networks and more. Please check the dendrogram page where I explain it in detail.
Read moreCompute rectangle positions with d3.treemap()
From the hierarchy
object computed above we need to compute the position of every rectangles of the treemap.
This is possible thanks to the treemap()
function of d3.js that can be invoked like this:
const treeGenerator = d3.treemap()
.size([width, height])
.padding(4); // space between rectangles
// Use the generator on the hierarchy object built in previous section
const treeLayout = treeGenerator(hierarchy);
The result is an object that has almost the same shape as the initial hierarchy
object. But for each node, an additional x0
, x1
, y0
and y1
are available. Those are the coordinates of the rectangle in our SVG space! 🔥
Treemap with 1️⃣ level of hierarchy
With the coordinates of each rectangle being available, it is just a matter of looping through all of them and drawing them using SVG.
The leaves()
method is usefull to list all leaves, allowing to make the loop easily:
const rects = treeLayout.leaves().map((leaf) => {
return (
<g key={leaf.id}>
<rect
x={leaf.x0}
y={leaf.y0}
width={leaf.x1 - leaf.x0}
height={leaf.y1 - leaf.y0}
/>
</g>
)
}
This results in a first basic treemap 😋
The most basic treemap with 1 level of hierarchy made with react and d3.js.
Treemap with 2️⃣ levels of hierarchy
Treemaps are also handy to display nested data structure. For instance, let's consider a company with a CEO, several teams, and a few employees per team. This result in a structure with several levels of hierarchy.
Pretty much the same strategy is used to draw the treemap. But note that each leaf has a parent
property that is very handy to use a categorical color scale to the graph.
// Create a color scale
const firstLevelGroups = hierarchy?.children?.map((child) => child.data.name);
var colorScale = d3
.scaleOrdinal()
.domain(firstLevelGroups)
.range(['red', 'green', 'blue', ...]);
// Then In the loop through each leaves:
treeLayout.leaves().map((leaf) => {
const parentName = leaf.parent?.data.name;
const color = colorScale(parentName)
// ... render rect using this color
}
Treemap with 2 levels of hierarchy and a color scale, made with react and d3.js.
Hover effect
Adding a hover effect to your treemap is a nice polish detail. Here I suggest to highlight the slice that is hovered over by dimming all the other slices.
There are several strategies available to implement such an effect. One can rely on css pseudo classes only, or add a css class using javascript and the onMouseEnter
event. It's also possible to rely on an animation library like react-spring
.
I'm preparing a full section on the topic. You can subscribe to my dataviz-universe newsletter to know when it will be ready. Meanwhile, there is a code sandbox waiting for you below to reveal the code of this example.
SubscribeHover over a group on the treemap to see the other groups fading.
Part Of A Whole
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!