Nicholas Felton’s 2013 Annual Report contained two distinct histogram variants. This post covers how I created the first variant, which looks like this:
A pretty typical histogram. However, the styling aspects are what I found most interesting:
- Truncated measure labels with a scale factor in the upper-right corner
- Slanted measure transition lines that join the entire series of measurements into a single line
I’ll cover how I achieved both of these below.
Truncated Measure Labels
This was pretty straightforward, as there’s a math function that can be used directly to determine how many significant digits you need to represent a number:
log10 function calculates the base 10 logarithm of a number, which can be used to calculate the number of digits within it. For example,
Math.log10(623) = 2.7944880466591697
The scale factor is calculated by using the whole part of the result (using
Math.floor) as the exponent in a call to
The minimum value was used to ensure that the labels weren’t unnecessarily “flattened” by a scale that was off by a factor of 10 (or more), and D3’s formatting functions were used to discard the fractional part of each measure.
Inside the SVG, the measure labels were added using
The title and scale indicator was added using additional text elements:
I implemented two separate line styles while building this visualization. The first used the built-in D3 line generation tools, and the second used a custom line generator.
First Attempt Using D3 Curves
At first I tried to use the
line function to generate a segmented line that represented the measures in the histogram. There is a
curve function that can be used to specify how points in a line should be joined, and in particular
curveStepAfter seemed like it might do the job.
💣 However, in order for this to work I needed to ensure that there was one extra entry in the data, or D3 wouldn’t create the final flat value segment. I simply copied the last point and set the date to one month in the future.
This resulted in the following:
This was actually a pretty good starting point, and was what I used until I had time to revisit the visualization.
Second Attempt Using Custom Line Generator
Once I had a little more time to revisit my first attempt, I decided to implement the slanted segment connectors that were used in the original.
I had to replace the use of the
y functions with a custom function that took the spacing between measured values into consideration. My goal was to allocate 5% of each measure line at the start and end to be used for the transition. As a result, each line segment was drawn by creating a horizontal line for the measure itself, and then creating a line from the end of that measure to the start of the next. This logic is contained in the following function:
Once that was done I could create the measure line as follows:
Resulting in a much-improved (in my opinion) final version of the visualization:
The code I used to write this post is available on GitHub.
Please feel free to contact me if you have any questions or comments.