Search code examples
phpalgorithmphp-gdaxis-labels

displaying axis from min to max value - calculating scale and labels


Writing a routine to display data on a horizontal axis (using PHP gd2, but that's not the point here).

The axis starts at $min to $max and displays a diamond at $result, such an image will be around 300px wide and 30px high, like this:

example
(source: testwolke.de)

In the example above, $min=0, $max=3, $result=0.6. Now, I need to calculate a scale and labels that make sense, in the above example e.g. dotted lines at 0 .25 .50 .75 1 1.25 ... up to 3, with number-labels at 0 1 2 3.

If $min=-200 and $max=600, dotted lines should be at -200 -150 -100 -50 0 50 100 ... up to 600, with number-labels at -200 -100 0 100 ... up to 600.

With $min=.02and $max=5.80, dotted lines at .02 .5 1 1.5 2 2.5 ... 5.5 5.8 and numbers at .02 1 2 3 4 5 5.8.

I tried explicitly telling the function where to put dotted lines and numbers by arrays, but hey, it's the computer who's supposed to work, not me, right?!

So, how to calculate???


Solution

  • An algorithm (example values $min=-186 and $max=+153 as limits):

    1. Take these two limits $min, $max and mark them if you wish

    2. Calculate the difference between $max and $min: $diff = $max - $min
      153 - (-186) = 339

    3. Calculate 10th logarithm of the difference $base10 = log($diff,10) = 2,5302

    4. Round down: $power = round($base10) = 2.
      This is your tenth power as base unit

    5. To calculate $step calculate this:
      $base_unit = 10^$power = 100;
      $step = $base_unit / 2; (if you want 2 ticks per one $base_unit).

    6. Calculate if $min is divisible by $step, if not take the nearest (round up) one
      (in the case of $step = 50 it is $loop_start = -150)

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

    8. end

    I tested it in Excel and it gives quite nice results, you may want to increase its functionality,

    for example (in point 5) by calculating $step first from $diff,
    say $step = $diff / 4 and round $step in such way that $base_unit is divisible by $step;

    this will avoid such situations that you have between (101;201) four ticks with $step=25 and you have 39 steps $step=25 between 0 and 999.