All examples By author By category About

schnerd

D3 Cluster Scale

D3 Cluster Scale is a scale that supports clustering values around natural breaks in the input domain. The scale is similar to d3.scaleQuantile and d3.scaleQuantize in that it maps a continuous domain to a discrete range, however quantile and quantize often produce sub-optimal results when the distribution of data is skewed or when there are extreme outliers.

This block demonstrates how these three scale types would perform for a given input domain. Notice how quantile splits 1, 2, 4, and 5 across three different quantiles, despite their differences being very small. quantize, on the other hand, does a decent job of accurately representing the magnitude of the values, but does not end up using the full color spectrum. Our cluster scale uses the full spectrum and each cluster contains values of a similar magnitude.

While this new clustering scale does produce nice results, it should be noted that it can be an order of magnitude slower than quantile and quantize. For a sample size of 1000, the algorithm takes roughly 30ms on Chrome 53 for a 2013 Macbook Pro 3.1GHz Intel Core i7. The underlying clustering algorithm is Ckmeans from the simple-statistics library (the original algorithm described by Haizhou Wang and Mingzhou Song). Accordingly, it should currently only be used in places where the input domain has less than 1000 values, or performance is not mission critical. I'll be investigating faster clustering algorithms to use in this scaleā€“if you have any suggestions I'd love to hear them.

d3-cluster-scale is available as an npm module and as a d3 plugin included via <script> tag.

###Usage

This scale largely has the same API as d3.scaleQuantile (however we use clusters() instead of quantiles())

var scale = d3.scaleCluster()
    .domain([1, 2, 4, 5, 12, 43, 52, 123, 234, 1244])
    .range(['#E5D6EA', '#C798D3', '#9E58AF', '#7F3391', '#581F66', '#30003A']);

var clusters = scale.clusters(); // [12, 43, 123, 234, 1244]
var color = scale(52); // '#9E58AF'
var extent = scale.invertExtent('#9E58AF'); // [43, 123]

Enjoy!