A few days ago Kiran B sent me a challenge via Twitter DM: How can I make a drilldown piechart?
The annoyed emoji is a bit much but I'll allow it. The challenge was fun to solve. Got it roughly working in a 45min stream 👇
You can also try it out via CodeSandbox. I'm surprised how nice default D3 category colors work with a black border. It's gorgeous 😍
You can think of a drilldown piechart as a recursive data visualization. Take a tree structure of data and you render a piechart for each level. Click on a slice, drill down into that branch.
Easiest way to get started is to generate that dataset from scratch ✌️
Random number of datapoints,
N, create an array with
d3.range, loop through, generate a datapoint for each step. Random value, some identifier, save the level of recursing, the index, the parent index, a name, and then generate some children.
Generating children calls this same function thus creating a recursive data structure.
We'll use the level and index and previous index to help us pick slice colors later on.
I like to keep my
<App> component simple so using the data and rendering the piechart looks like this:
An svg element with a
Ok the colors aren't perfect, the drilling down is confusing without an animation, and you can't drill up just yet. But it's a great start!
Three components play together:
- A styled
<Path>component handles colors
<Arc>component renders arcs, deals with mouseovers, and registers clicks
<DrilldownPie>component holds it all together and deals with drilling
<Path> component is a styled SVG path that uses props to decide the color of each slice.
Level 4 is the top level 👉 use a color scheme from D3 and the slice index to pick a color.
With other levels the idea was to take the base color and make it progressively brighter based on the index. Works okay for the first level down, didn't quite work later on.
Might have to change how we approach this. Maybe colors as part of the dataset itself?
<Arc> component renders a single slice of the piechart and handles mouseover events using hooks to change size. Messing with the radius creates the effect of individual slices popping out.
That's the whole component. Let's break it down :)
First we've got the state management: A single
radiusAdd variable that tells us how much to add or take away from the default radius of our arc.
Second we've got the
d3.arc generator. Takes some configuration and produces path definitions using SVG's crazy path language.
Third we've got 2 functions calling the
setRadiusAdd setter to change the radius. That triggers a re-render, the arc generator sees the new value, creates a different path definition 👌
Fourth we render our styled
<Path> component making sure to pass in all the right props. The path definition, the level and index for color, and all the event listeners.
<DrilldownPie> component ties this all together.
Less code even than the Arc component god I love hooks 😱
First we've got state. We copy our data into it. That's so we can do the drilling down. Haven't tried how this plays with data changing from the outside ... trigger a re-render I assume 🤔
Second we've got a
d3.pie generator. Takes our data and creates an array of objects perfectly suited for the
d3.arc generator. Angles and values and all.
drilldown function uses our state setter to move data one level down. Take the children, set them as current data, trigger re-render, magic. 🧙♂️
Fourth render it all in a loop.
And that's how you build a drilldown piechart with React and D3 and hooks.
I'm going to continue this challenge either Friday night (today) or Sunday afternoon. Want to figure out how to make the drilldown transition animated and get drilling up to work.
Drilling up is easy in principle, but gets tricky if you want to support arbitrary levels. That's because we aren't using real recursion to drill down 😅
See you at the stream maybe?
About the Author
Hi, I’m Swizec Teller. I help coders become software engineers.
Story time 👇
React+D3 started as a bet in April 2015. A friend wanted to learn React and challenged me to publish a book. A month later React+D3 launched with 79 pages of hard earned knowledge.
In April 2016 it became React+D3 ES6. 117 pages and growing beyond a single big project it was a huge success. I kept going, started live streaming, and publishing videos on YouTube.
In 2017, after 10 months of work, React + D3v4 became the best book I'd ever written. At 249 pages, many examples, and code to play with it was designed like a step-by-step course. But I felt something was missing.
So in late 2018 I rebuilt the entire thing as React for Data Visualization — a proper video course. Designed for busy people with real lives like you. Over 8 hours of video material, split into chunks no longer than 5 minutes, a bunch of new chapters, and techniques I discovered along the way.
React for Data Visualization is the best way to learn how to build scalable dataviz components your whole team can understand.
Some of my work has been featured in 👇