Skip to content

d3.scaleRadial? #90

@mbostock

Description

@mbostock

To avoid introducing distortion with radial bars, you need a scale that smoothly varies from d3.scaleSqrt when the inner radius is zero to d3.scaleLinear when the inner and outer radius are equal. It’s the same principle as uniform annulus sampling.

Here’s a simplified implementation I came up with:

function scaleRadial() {
  var domain = [0, 1],
      range = [0, 1];

  function scale(x) {
    var r0 = range[0] * range[0], r1 = range[1] * range[1];
    return Math.sqrt((x - domain[0]) / (domain[1] - domain[0]) * (r1 - r0) + r0);
  }

  scale.domain = function(_) {
    return arguments.length ? (domain = [+_[0], +_[1]], scale) : domain.slice();
  };

  scale.range = function(_) {
    return arguments.length ? (range = [+_[0], +_[1]], scale) : range.slice();
  };

  scale.ticks = function(count) {
    return d3.scaleLinear().domain(domain).ticks(count);
  };

  scale.tickFormat = function(count, specifier) {
    return d3.scaleLinear().domain(domain).tickFormat(count, specifier);
  };

  return scale;
}

For comparison, here’s what a linear scale looks like:

linear

The area of the largest bar, California, is exaggerated because the bar gets wider as it extends away from the center of the circle: the circumference grows linearly with radius. But a sqrt scale over-fixes the problem, causing the small bars to appear too large:

sqrt

A sqrt scale only works when the inner radius is zero. Here is area-proportional result using the proposed “radial” scale:

radial

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions