Posted by & filed under Content - Highlights and Reviews, Programming & Development.

code A guest post by John Williams, a web developer who has worked for media, education, and government organizations for seventeen years. For the last seven, he has been working for NewCity in Blacksburg, VA, assisting with several data visualization projects in bioinformatics. He can be found on Twitter @thudfactor. If you are at the Fluent conference, be sure to listen to John’s D3 talk today, March 11th.

Overlapping labels in your D3 charts and diagrams are the worst. They’re not only useless as labels, they make your chart look like junk. To solve this you might be tempted to use D3’s force layout so the labels can find their own place. But before you dive into something quite so complex (and uncontrollable), perhaps you should consider using a strategy called “constraint relaxing.”

Since my name is “John Williams,” people ask me a lot about my work as a composer and director. Here’s a chart showing how many times people have made variations on a joke about my name:

fig01

That’s a typical donut chart. If you don’t follow how it’s made, the comments in the fiddle should help.

If you were using a spreadsheet, you’d probably make a “legend” block mapping the colors to the labels. But I like to put the labels a little closer to each wedge.

Rigid rule label placement

To do that, we’re going to use a pretty rigid rule for label placement. Labels will be placed at a radius of 175px from the center and at an angle that bisects the label’s wedge. The centroid() method of our arc function is handy here, since it returns the [x,y] coordinates of the centroid. With some trigonometry, we can use that to figure out the bisecting angle and place our label. Here’s the labeled chart:

fig02

As you can see, our rigid rule has crammed most of the labels together, which is unfortunate.

Implementing constraint relaxing

This is where constraint relaxing comes in: we use our rigid placement rules to start, then tweak the results a bit until the labels look better. Here, we adapt an approach from Kai Chang and get this:

fig03

Let’s walk through the changes to see how that works:

First, we decide how much we’re going to nudge each label (alpha) and the minimal distance between each anchor (spacing).

Then we use nested each() functions on our labels to compare each label to every other label. The outer loop selects the first item we use to compare:

again is used to tell us at the end of this function whether we have to do it again. Let’s assume not.

The function you pass to each function gets datum (d) and index (i) parameters, and is executed in the context of the DOM element. So this refers to the label element.

So we store a reference to this in a. We also make a D3 object out of the element and store that in da, then run a D3 method on da to get its y value.

In the nested each() we compare a to every other element.

As we did in the outer each(), we capture the reference to this as b. Then we start testing for collisions:

If a == b, it’s the same label. Labels can’t collide with themselves.

If the text anchor doesn’t match, then they are on opposite sides of the chart and don’t collide.

Now we check the vertical distance. If this is greater than spacing, we’re not colliding.

But if you haven’t bailed by now, a and b are colliding. Here’s what you’ll do about it:

We’re moving the top element up and the bottom element down, whichever one that happens to be. And since we found a collision, we need to set again to true.

That’s the end of our nested each() loops. If there is a collision, though, you need to do another pass:

Doing this in stages with setTimeout() means you’ll see a little animation as the labels adjust themselves. And it does look a lot like “relaxing.”

Adding chart lines

If you squint, you can tell which label belongs to which wedge. But some lines would be really nice. Here’s an unrelaxed version of the chart with lines:

fig04

The y2 value of each line should share the same value as the label’s anchor. So, we’ll update the if(again) block to copy those values over to each line:

The 0th item of every selection is the associated array of elements. Using that and the index inside the attr setter let’s us look up and copy the y value. That keeps the lines in sync. And now our chart is readable:

fig05

Before we say “done,” though, it’s worth pointing out that this is just one possible approach to constraint relaxing. It’s simple, but it’s really only appropriate for smaller data sets. As the data set grows, there are more labels to sift through, more chances for collisions and more iterations to find satisfactory placement for all of the labels.

So it’s worth looking into other collision detection and resolution strategies. D3 even provides some tools, like a quadtree implementation, that might help with that.

Conclusion

If you are at the Fluent conference, be sure to listen to John’s D3 talk today, March 11th.

Be sure to read his Creating a Right-Click Contextual Popup with D3 post.

Look below for some great D3.js books from Safari Books Online.

Not a subscriber? Sign up for a free trial.

Safari Books Online has the content you need

Interactive Data Visualization for the Web shows you how to create and publish your own interactive data visualization projects on the Web – even if you have little or no experience with data visualization or web development. It’s easy and fun with this practical, hands-on introduction. Author Scott Murray teaches you the fundamental concepts and methods of D3, a JavaScript library that lets you express data visually in a web browser.
Developing a D3.js Edge D3 is a powerful framework for producing interactive data visualizations. Many examples created in the real world with D3, however, can best be described as “spaghetti code.” So, if you are interested in using D3 in a reusable and modular way, which is of course in line with modern development practices, then this book is for you!
Data Visualization with d3.js walks you through 20 examples. You can finally stop struggling to piece together examples you’ve found online. With this book, you will learn enough of the core concepts to conceive of and build your own visualizations from scratch.
It begins with the basics of putting lines on the screen, and builds on this foundation all the way to creating interactive animated visualizations using d3.js layouts.
Visual Storytelling with D3: An Introduction to Data Visualization in JavaScript provides readers with a strong framework of principles for making well-conceived and well-crafted infographics, as well as detailed and practical instructions for how to really wield D3, the best tool for making web infographics available. An extended example is used in the book to explain how to put theory to practical use.

Tags: Constraint Relaxing, D3, D3.js, Label Placement,

Comments are closed.