How to Make a Piechart Using React and d3

DZone's Guide to

How to Make a Piechart Using React and d3

Piecharts might be the single most mocked chart in the world, but they’re easy and fun to make. They’re perfect for showing overwhelming proportions, and there’s nothing like a piechart to make an enterprise presentation more enterprisey. So, let's learn how to make one.

Piecharts might be the single most mocked chart in the world, but they’re great. Is there a better way to show proportions?

Of course, it all breaks down when you have more than a couple data points. And yes, it’s impossible to gauge the difference between 24% and 26% on a piechart... not to mention the accessibility issues when the charts rely on colors to distinguish slices.

If you Google "never use a piechart", 597,000 results show up. That’s a bunch of hate for the poor piechart.

But, they’re easy and fun to make. They’re perfect for showing overwhelming proportions, and there’s nothing like a piechart to make an enterprise presentation more enterprisey.

Especially, if you make it 3D.

When I say that a piechart is easy to make, I mean that with 86 lines of very beautiful and readable code, you can make one that looks great. 86 lines might sound like a lot for a piechart, but 33 of those are empty lines or closing braces. That’s 38%.

Let me show you that with a piechart:

See, piecharts work. To build this, we’re going to:

use a d3 layout to calculate a piechart

use React stuff to render the piechart

build a generic Piechart component

At the end of this tutorial, you’ll have piechart component that you can use like this:

We start by importing react and the LabeledArc component, which we’ll use for the arcs. The constructor is going to initialize d3’s pie layout, the arcGenerator is a helper function that makes our code easier to read, and render takes care of rendering.

Yes, this is a simple component. As such, it doesn’t really need to be a class. It could be a functional stateless component, but the code looks messier to me.

I’ll show you the functional version later, and you can decide for yourself.

We use super() to call the parent constructor, then initialize a pie layout with a basic value accessor. That tells it how to get values from our data.

Of course, we could avoid this step and re-initialize a new pie layout on every render, but that seems wasteful.

The layout is what turns the data into a piechart, by the way. It takes an array of values and returns an array of data in exactly the format that d3’s arc generator expects.

It’s great. You’ll see.

We also initialize a color scale. We’ll use it to give different colors to piechart slices.

The next function we need is arcGenerator. This function returns a LabeledArc component with some props filled in. We could put this code in the iterator inside render(), but doing it that way gets messy and makes our code harder to read.

We use the data to generate a piechart with this.pie, set up a translation to move our piechart into the desired position, then return a grouping element with a bunch of arcs.

That’s it. Our piechart shows up on the screen.

Or, well, an error shows up because LabeledArc doesn’t exist yet. But once we make that, a piechart is going to show up on screen.

Here’s the same code as a functional stateless component. This snippet is 12 lines shorter, but I’m not sure it’s better, per se. It reinitializes both the pie layout and the colors scale on each render, and it awkwardly embeds LabeledArc in the iterator.

Use the approach you prefer. In this case, they both work essentially the same way.

Arc

Ok, we’ve got the basic Piechart. It tries to draw arcs, but the component for them doesn’t exist yet.

When you think about it, a LabeledArc is a type of Arc. It’s a component that draws a pie slice and a label. So it makes sense to build an Arc component first, then subclass it with LabeledArc and add some features.

With ES6 classes, we can do that without funky JavaScript magic. Sure, Babel compiles it to weird funky magic, but we don’t have to worry about it.

We start by importing React and d3. Then, we define an Arc class which extends Component. In this case, we can’t use functional stateless components for two reasons:

We need component lifecycle functions to update the internal state of our arc generator. I’ll show you that in a bit.

You can’t extend a function. We could play with functional composition, but in my experience, that sort of code, in JavaScript at least, is hard to read 2 months later. And it causes interesting issues when debugging.

The Arc component has four methods: the constructor, the lifecycle hooks to call updateD3, the method that updates d3 internals’ state, and the render method.

All the constructor has to do is instantiate a new d3.svg.arc generator. That looks like this:

We now have an instance of the arc generator, and we’re going to update its internals in updateD3. If we wanted to set up some arc defaults or constants, this would be a good place.

If you aren’t familiar with arc generators, they’re these funny d3.js things that create SVG path definitions. For instance, the "Empty lines" path definition in that screenshot you saw earlier looks like this:

We calculate labelX and labelY with this.arc.centroid(data). This gives us the center point of an arc. I don’t know how the math works. All I know is that it works and that I’m happy somebody made it for me.

Notice how we can use this.arc as if it was defined inside LabeledArc. Subclassing is great like that. Don’t go overboard and become an architecture astronaut.

Next, we put these coordinates into the usual SVG translate transformation and render a grouping element with an arc and a label. We get the arc itself with super.render(), which calls the parent render function, and the label as a text element.

I know using this.props.data.data.label to get the text looks weird, but that’s how it works. this.props.data is a single datapoint in the entire piechart, its .data property is where d3’s pie layout puts original data and .label is how our base data defined labels. It works.

Our piechart’s code profile piechart looks like this:

Wonderful.

Voilà

You now have a generic piechart component that you can copy-paste around your codebase whenever you want.

Need a piechart? Use <Piechart> and give it some props. The component has you covered.

To recap, here’s what we learned:

Piecharts are okay, but not great, dataviz

A Piechart takes 53 lines of real code to make

41 lines with some boilerplate reduction

A Piechart is made up of 3 components: Piechart, Arc, LabeledArc

D3 makes the hard maths trivial

ES6 classes and subclassing are great

You can learn more about using React and d3js together in my new book, React+d3js ES6, here.