显示从最小值到最大值的轴 - 计算比例和标签

mic*_*chi 6 php algorithm php-gd axis-labels

编写例程以在水平轴上显示数据(使用PHP gd2,但这不是重点).

轴开始于$min$max并显示在金刚石$result,这样的图像将围绕300像素宽和高30像素,如下:

例如http://www.testwolke.de/profile.png

另外,在上述的例子中,$min=0,$max=3,$result=0.6.现在,我需要计算一个有意义的比例和标签,在上面的例子中,例如虚线0 .25 .50 .75 1 1.25 ... up to 3,数字标签位于0 1 2 3.

如果$min=-200$max=600,虚线应该在-200 -150 -100 -50 0 50 100 ... up to 600,数字标签位于-200 -100 0 100 ... up to 600.

$min=.02$max=5.80,虚线.02 .5 1 1.5 2 2.5 ... 5.5 5.8和数字.02 1 2 3 4 5 5.8.

我试着明确告诉函数将数据放在虚线和数字的位置,但是,嘿,这是应该工作的计算机,而不是我,对吧?!

那么,如何计算???

Voi*_*cus 7

算法(示例值$min=-186$max=+153限制):

  1. 接受这两个限制$min$max如果您愿意,可以标记它们

  2. 计算之间的区别$max$min$diff = $max - $min
    153 - (-186) = 339

  3. 计算差值的第 10 对数$base10 = log($diff,10) = 2,5302

  4. 向下取整:$power = round($base10)= 2。
    这是您作为基本单位的第十次幂

  5. 要计算$step这个:
    $base_unit = 10^$power= 100;
    $step = $base_unit / 2; (如果你想要每一个 2 个滴答声$base_unit)。

  6. 计算是否可以$min被 整除$step,如果不能被 整除,则取最近的(向上取整)一个
    $step = 50如果是$loop_start = -150

  7. for ($i=$loop_start; $i<=$max; $i++=$step){ // $i's are your ticks

  8. 结尾

我在 Excel 中对其进行了测试,结果非常好,您可能希望增加其功能,

例如(在第 5 点)通过$step首先计算from $diff
say$step = $diff / 4$step以可$base_unit被 整除的方式取整$step

这将避免出现 (101;201) 四个刻度之间的情况,$step=25并且您$step=25在 0 和 999 之间有 39 个步骤。


Sim*_*mon 6

ACM 算法 463提供了三个简单的函数来生成良好的轴刻度,输出 xminp、xmaxp 和 dist,用于刻度上的最小值和最大值以及刻度上刻度线之间的距离,给定对n包括数据点xmin和 的间隔的请求xmax

  1. Scale1()给出一个具有近似n间隔的线性标度,并且dist是 1、2 或 5 的 10 的整数幂。
  2. Scale2()给出具有精确n间隔的线性标度(xminp 和 xmaxp 之间的差距往往大于由 产生的差距Scale1())。
  3. Scale3() 给出对数标度。

1973 年的原始论文在这里在线,它提供了比上面链接的代码更多的解释。

代码在 Fortran 中,但它只是一组算术计算,因此解释和转换为其他语言非常简单。我自己没有写过任何 PHP,但它看起来很像 C,所以你可能想从通过f2c运行代码开始它应该给你一些接近于可在 PHP 中运行的东西。

有更复杂的函数可以提供更漂亮的比例(例如 中的那些gnuplot),但Scale1()可能会用最少的代码为您完成这项工作。

(这个答案建立在我对上一个问题Graph axiscalibration in C++ 的回答之上)

(编辑——我找到了Scale1()我在 Perl 中所做的实现):

use strict;

sub scale1 ($$$) {
  # from TOMS 463
  # returns a suitable scale ($xMinp, $xMaxp, $dist), when called with 
  # the minimum and maximum x values, and an approximate number of intervals
  # to divide into. $dist is the size of each interval that results.
  # @vInt is an array of acceptable values for $dist.
  # @sqr is an array of geometric means of adjacent values of @vInt, which
  # is used as break points to determine which @vInt value to use.
  #
  my ($xMin, $xMax, $n) = @_;
  @vInt = {1, 2, 5, 10};
  @sqr = {1.414214, 3.162278, 7.071068 }
  if ($xMin > $xMax) {
    my ($tmp) = $xMin;
    $xMin = $xMax;
    $xMax = $tmp;
    }
  my ($del) = 0.0002;   # accounts for computer round-off
  my ($fn) = $n;
  # find approximate interval size $a
  my ($a) = ($xMax - $xMin) / $fn;
  my ($al) = log10($a);
  my ($nal) = int($al);
  if ($a < 1) {
    $nal = $nal - 1;
    }
  # $a is scaled into a variable named $b, between 1 and 10
  my ($b) = $a / 10^$nal;
  # the closest permissable value for $b is found)
  my ($i);
  for ($i = 0; $i < $_sqr; $i++) {
    if ($b < $sqr[$i]) last;
  }
  # the interval size is computed
  $dist = $vInt[$i] * 10^$nal;
  $fm1 = $xMin / $dist;
  $m1 = int($fm1);
  if ($fm1 < 0) $m1--;
  if (abs(($m1 + 1.0) - $fm1) < $del) $m1++;
  # the new minimum and maximum limits are found
  $xMinp = $dist * $m1;
  $fm2 = $xMax / $dist;
  $m2 = $fm2 + 1;
  if ($fm2 < -1) $m2--;
  if (abs ($fm2 + 1 - $m2) < $del) $m2--;
  $xMaxp = $dist * $m2;
  # adjust limits to account for round-off if necessary
  if ($xMinp > $xMin) $xMinp = $xMin;
  if ($xMaxp < $xMax) $xMaxp = $xMax;
  return ($xMinp, $xMaxp, $dist);
  }

sub scale1_Test {
  $par = (-3.1, 11.1, 5,
      5.2, 10.1, 5,
      -12000, -100, 9);
  print "xMin\txMax\tn\txMinp\txMaxp,dist\n";
  for ($i = 0; $i < $_par/3; $i++) {
    ($xMinp, $xMaxp, $dist) = scale1($par[3*$i+0], 
    $par[3*$i+1], $par[3*$i+2]);
    print "$par[3*$i+0]\t$par[3*$i+1]\t$par[3*$i+2]\t$xMinp\t$xMaxp,$dist\n";
    }
  }
Run Code Online (Sandbox Code Playgroud)