使用最小值、最大值和离散值创建对数刻度 "steps"

Creating a Logarithm Scale with Min, Max and Discrete "steps"

我正在构建一个比例尺来为地图生成颜色,其中不同范围的数字对应于颜色。在下面的比例尺中,abc 值(连同最小值和最大值)形成与颜色对应的“步长”或“桶”。在此示例中,-1min 之间的任何内容都将着色为 "#ffeda0,而 mina 之间的任何内容将以不同的方式着色:

  return [
    "#e7e9e9",
    -1,
    "#ffeda0",
    min,
    "#fed976",
    a
    "#feb24c",
    b
    "#fd8d3c",
    c
    "#fc4e2a",
    max
    "#e31a1c"
  ];

此比例始终以最小值 min 开始,以最大值 max 结束。我目前有一个像这样的简单线性比例尺:

  const min = Math.min(data);
  const range = Math.max(data) - min;
  const step = range / 4;

  return [
    "#e7e9e9",
    -1,
    "#ffeda0",
    min,
    "#fed976",
    min + step,
    "#feb24c",
    min + step * 2,
    "#fd8d3c",
    min + step * 3,
    "#fc4e2a",
    max,
    "#e31a1c"
  ];

如何编写一个函数,给定最小值、最大值和刻度中的步数(在本例中为三)输出 对数 的正确数字规模?

对数标度的对数是线性的。所以:

const min = Math.min(data);
const max = Math.max(data);

const logmin = Math.log(min);
const logmax = Math.log(max);

const logrange = logmax - logmin;
const logstep = logrange / 4;

现在线性刻度有

value = min + n * step;

对数刻度有:

value = Math.exp(logmin + n * logstep);

这仅在 minmax 均为正数时有效,因为您不能取零或负数的对数,并且在对数标度中,每个值都有一个常数正因子到上一个。您可以通过调整符号使负 minmax 起作用。

您可以在其他基数中进行计算,例如 10:

const logmin = Math.log10(min);
const logmax = Math.log10(max);

value = Math.pow(10, logmin + n * logstep);

或者,您可以通过取最小值和最大值的商的第 n 次根来求出一步到下一步的公因数:

const min = Math.min(data);
const max = Math.max(data);

const fact = Math.pow(max / min, 1.0 / 4.0);

然后通过重复乘法找到值:

value = prev_value * fact

value = xmin * Math.pow(fact, n);

这两种方法都可能产生“不整洁”的数字,即使比例应该有很好的整数,因为对数和 n-th 根可能会产生不准确的 floating-point 结果.如果您选择一个舍入因子并调整您的 min/max 值,您可能会得到更好的结果。