一尘不染

为图形的Y轴选择有吸引力的线性比例

algorithm

我正在写一些代码来在我们的软件中显示条形图。一切都很好。让我感到困扰的是标记Y轴。

呼叫者可以告诉我他们想要对Y比例尺进行标记的精确程度,但是我似乎始终坚持以“有吸引力”的方式对它们进行标注。我无法形容“吸引人”,也许您也无法形容,但是当我们看到它时我们就知道了,对吗?

因此,如果数据点是:

   15, 234, 140, 65, 90

用户要求在Y轴上贴上10个标签,然后用纸和铅笔稍微摆弄一下:

  0, 25, 50, 75, 100, 125, 150, 175, 200, 225, 250

因此,那里有10个(不包括0),最后一个超出了最大值(234
<250),并且每个增加了“不错”,为25。如果他们要求提供8个标签,则增加30个标签看起来不错:

  0, 30, 60, 90, 120, 150, 180, 210, 240

九个人会很棘手。也许只使用8或10,然后将其称为足够接近就可以了。当某些观点是负面的时该怎么办?

我可以看到Excel很好地解决了这个问题。

有谁知道解决该问题的通用算法(即使有些蛮力也可以)?我不必很快做,但是看起来应该不错。


阅读 197

收藏
2020-07-28

共1个答案

一尘不染

很久以前,我写了一个图形模块很好地涵盖了这一点。挖掘灰色块得到以下结果:

  • 确定数据的上下限。(请注意下界=上限的特殊情况!
  • 将范围划分为所需的刻度数。
  • 将刻度范围四舍五入成不错的数量。
  • 相应地调整上下限。

让我们举个例子:

15, 234, 140, 65, 90 with 10 ticks
  1. 下界= 15
  2. 上限= 234
  3. 范围= 234-15 = 219
  4. 刻度范围= 21.9。这应该是25.0
  5. 新的下界= 25 *圆(15/25)= 0
  6. 新上限= 25 *舍入(1 + 235/25)= 250

所以范围= 0,25,50,…,225,250

您可以通过以下步骤获得合适的刻度范围:

  1. 除以10 ^ x,使结果介于0.1和1.0之间(包括0.1排除1)。
  2. 相应地翻译:
    • 0.1-> 0.1
    • <= 0.2-> 0.2
    • <= 0.25-> 0.25
    • <= 0.3-> 0.3
    • <= 0.4-> 0.4
    • <= 0.5-> 0.5
    • <= 0.6-> 0.6
    • <= 0.7-> 0.7
    • <= 0.75-> 0.75
    • <= 0.8-> 0.8
    • <= 0.9-> 0.9
    • <= 1.0-> 1.0
  3. 乘以10 ^ x。

在这种情况下,将21.9除以10 ^ 2得到0.219。这是<= 0.25,所以我们现在有0.25。乘以10 ^ 2得到25。

让我们看一下具有8个滴答声的相同示例:

15, 234, 140, 65, 90 with 8 ticks
  1. 下界= 15
  2. 上限= 234
  3. 范围= 234-15 = 219
  4. 刻度范围= 27.375
    1. 用10 ^ 2除以0.27375,转换为0.3,得出(乘以10 ^ 2)30。
  5. 新的下界= 30 *圆(15/30)= 0
  6. 新上限= 30 *舍入(1 + 235/30)= 240

给出您要求的结果;-)。

------ KD添加了------

这是无需使用查找表等即可实现此算法的代码:

double range = ...;
int tickCount = ...;
double unroundedTickSize = range/(tickCount-1);
double x = Math.ceil(Math.log10(unroundedTickSize)-1);
double pow10x = Math.pow(10, x);
double roundedTickRange = Math.ceil(unroundedTickSize / pow10x) * pow10x;
return roundedTickRange;

一般而言,刻度数包括底部刻度,因此实际的y轴分段比刻度数少一个。

2020-07-28