Skip to content

Regular Numbers ​

The regular numbers up to 511, numbers of the form 2i3j5k, linked to the numbers they're multiplied from, on a log scale. After Regular numbers by Philippe Rivière.

js
const N = 511;
const x = ([i, j, k]) => 0.5 * i + 2 * j - 3.6 * k;
const value = ([i, j, k]) => 2 ** i * 3 ** j * 5 ** k;
const numbers = d3
  .cross(
    d3.range(1 + Math.log(N) / Math.log(2)),
    d3.range(1 + Math.log(N) / Math.log(3)),
    d3.range(1 + Math.log(N) / Math.log(5)),
  )
  .filter((d) => value(d) <= N);
const links = numbers
  .flatMap(([i, j, k]) => [
    [
      [i - 1, j, k],
      [i, j, k],
    ],
    [
      [i, j - 1, k],
      [i, j, k],
    ],
    [
      [i, j, k - 1],
      [i, j, k],
    ],
  ])
  .filter(([n]) => Math.min(...n) >= 0);

function applyScale(flow) {
  flow.transform(cm.mapPosition, {
    scaleY: cm.scaleLog,
    padding: 15,
    domainX: d3.extent(numbers, x),
    domainY: d3.extent(numbers, value),
    reverseY: true,
  });
}

const renderer = cm.canvas({width: 640, height: 480});
const root = cm.flow().renderer(renderer);

root
  .data(links)
  .append(cm.link, {
    x: ([n]) => x(n),
    y: ([n]) => value(n),
    x1: ([, n]) => x(n),
    y1: ([, n]) => value(n),
    stroke: "lightblue",
  })
  .call(applyScale);

root.data(numbers).append(cm.circle, {x, y: value, r: 12, fill: "white", stroke: "black"}).call(applyScale);

root
  .data(numbers)
  .append(cm.text, {
    x,
    y: value,
    text: value,
    fill: "black",
    fontSize: 10,
    fontFamily: "sans-serif",
    textAlign: "center",
    textBaseline: "middle",
  })
  .call(applyScale);

root.render();

document.body.append(renderer.node());