BrowserUk has asked for the wisdom of the Perl Monks concerning the following question:

Problem: given the start and end (min & max) of a range values to be graphed, determine the 'best' tick mark interval.

Simple solution: (end - start + 1) / noOfTicks = interval.

For: 0 .. 9 by 10 := ( 9 - 0 + 1 ) / 10 = 1; gives ticks at 0,1,2,3,4,5,6,7,8,9.

But: 0.123 .. 8.672 by 10 := ( 8.672 - 0.123 +1 ) / 10 = 0.9549; gives ticks at: 0.123, 1.0779, 2.0328, 2.9877, 3.9426, 4.8975, 5.8524, 6.8073, 7.7622, 8.7171. Not so nice!

Okay. So do a little rounding. But to what boundaries?

Eg. rounding to the nearest integer works above, but how about if the inputs are: 0.022 .. 0.086 by 10?

0.022, 0.0294, 0.0368, 0.0442, 0.0516, 0.059, 0.0664, 0.0738, 0.0812, 0.0886

Here, by inspection, we can conclude that the 'best' tick marks would probably be 0.02, 0.03, 0.04, 0.05, 0.06, 0.07, 0.08, 0.09.

But that's only 8 ticks, and we had to change the calculation from +1 to +0.01. So the formula needs to be: r = ( end - start ); r += r/n; interval = r / n; some rounding formula?

Or 1,123,345,456 .. 1,124,246,357.5 by 11?

1123345456, 1123427356.13636, 1123509256.27273, 1123591156.40909, 1123673056.54546, 1123754956.68182, 1123836856.81818, 1123918756.95455, 1124000657.09091, 1124082557.22727, 1124164457.36364

Erm?

I know; its simple stuff that's been solved many times; but I've failed to see a fully generic pattern; nor find reference to one.

Thoughts; pointers; admonishments?


With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
"Science is about questioning the status quo. Questioning authority". I'm with torvalds on this
In the absence of evidence, opinion is indistinguishable from prejudice. Agile (and TDD) debunked

Replies are listed 'Best First'.
Re: Simple calculation. (A solution; can it be improved/broken?)
by BrowserUk (Patriarch) on May 09, 2015 at 12:56 UTC

    Here's what I got so far. The code's not great, can it be improved?

    Can you think of a set of inputs that will exercise it better? (Note: I haven't got around to log() scales yet.)

    #! perl -slw use strict; sub log10{ log( $_[0] ) / log( 10 ) } sub ticks { my( $start, $end, $n ) = @_; $n ||= 10; my $range = $end - $start; $range += $range / $n; my $interval = $range / $n; $interval = 10**int( log10( $interval ) ); $interval *= 10 while ( $range / $interval ) > ( $n * 2 ); $interval /= 2 while ( $range / $interval ) < ( $n / 2 ); $start = int( $start / $interval ) * $interval; my @ticks; while( $start < ( $end + $interval ) ) { push @ticks, $start; $start += $interval; } return @ticks; } for my $range ( [0,9], [0.123,8.673], [0.022, 0.086], [1_123_345_456, 1_124_246_357.5], [1_123_345_456, 1_123_346_357.5] +, [ 0.00011, 0.00041], ) { for my $n ( 0, 4, 5, 8 , 10, 15, 16, 20, 21 ) { my @ticks = ticks( @$range, $n ); printf "from:%12.12g to %12.12g by:%2u -> [%2u][ %s ]\n", @$range, $n, scalar( @ticks ), join ' ', map{ my $s = sprintf( "%.8g", $_ ); $s =~ s[e([+-])0*([1-9] ++)]['e' . ($1 eq '-' ? '-' : '') . $2]e; $s; } @ticks; } }

    Output:

    C:\test>calcTicks.pl from: 0 to 9 by: 0 -> [10][ 0 1 2 3 4 5 6 7 8 9 ] from: 0 to 9 by: 4 -> [ 3][ 0 5 10 ] from: 0 to 9 by: 5 -> [ 5][ 0 2.5 5 7.5 10 ] from: 0 to 9 by: 8 -> [10][ 0 1 2 3 4 5 6 7 8 9 ] from: 0 to 9 by:10 -> [10][ 0 1 2 3 4 5 6 7 8 9 ] from: 0 to 9 by:15 -> [10][ 0 1 2 3 4 5 6 7 8 9 ] from: 0 to 9 by:16 -> [10][ 0 1 2 3 4 5 6 7 8 9 ] from: 0 to 9 by:20 -> [19][ 0 0.5 1 1.5 2 2.5 3 3 +.5 4 4.5 5 5.5 6 6.5 7 7.5 8 8.5 9 ] from: 0 to 9 by:21 -> [19][ 0 0.5 1 1.5 2 2.5 3 3 +.5 4 4.5 5 5.5 6 6.5 7 7.5 8 8.5 9 ] from: 0.123 to 8.673 by: 0 -> [10][ 0 1 2 3 4 5 6 7 8 9 ] from: 0.123 to 8.673 by: 4 -> [ 3][ 0 5 10 ] from: 0.123 to 8.673 by: 5 -> [ 5][ 0 2.5 5 7.5 10 ] from: 0.123 to 8.673 by: 8 -> [10][ 0 1 2 3 4 5 6 7 8 9 ] from: 0.123 to 8.673 by:10 -> [10][ 0 1 2 3 4 5 6 7 8 9 ] from: 0.123 to 8.673 by:15 -> [10][ 0 1 2 3 4 5 6 7 8 9 ] from: 0.123 to 8.673 by:16 -> [10][ 0 1 2 3 4 5 6 7 8 9 ] from: 0.123 to 8.673 by:20 -> [19][ 0 0.5 1 1.5 2 2.5 3 3 +.5 4 4.5 5 5.5 6 6.5 7 7.5 8 8.5 9 ] from: 0.123 to 8.673 by:21 -> [19][ 0 0.5 1 1.5 2 2.5 3 3 +.5 4 4.5 5 5.5 6 6.5 7 7.5 8 8.5 9 ] from: 0.022 to 0.086 by: 0 -> [ 8][ 0.02 0.03 0.04 0.05 0 +.06 0.07 0.08 0.09 ] from: 0.022 to 0.086 by: 4 -> [ 5][ 0 0.025 0.05 0.075 0. +1 ] from: 0.022 to 0.086 by: 5 -> [ 5][ 0 0.025 0.05 0.075 0. +1 ] from: 0.022 to 0.086 by: 8 -> [ 8][ 0.02 0.03 0.04 0.05 0 +.06 0.07 0.08 0.09 ] from: 0.022 to 0.086 by:10 -> [ 8][ 0.02 0.03 0.04 0.05 0 +.06 0.07 0.08 0.09 ] from: 0.022 to 0.086 by:15 -> [15][ 0.02 0.025 0.03 0.035 + 0.04 0.045 0.05 0.055 0.06 0.065 0.07 0.075 0.08 0.085 0.09 ] from: 0.022 to 0.086 by:16 -> [15][ 0.02 0.025 0.03 0.035 + 0.04 0.045 0.05 0.055 0.06 0.065 0.07 0.075 0.08 0.085 0.09 ] from: 0.022 to 0.086 by:20 -> [15][ 0.02 0.025 0.03 0.035 + 0.04 0.045 0.05 0.055 0.06 0.065 0.07 0.075 0.08 0.085 0.09 ] from: 0.022 to 0.086 by:21 -> [15][ 0.02 0.025 0.03 0.035 + 0.04 0.045 0.05 0.055 0.06 0.065 0.07 0.075 0.08 0.085 0.09 ] from: 1123345456 to 1124246357.5 by: 0 -> [11][ 1.1233e9 1.1234e9 1.1 +235e9 1.1236e9 1.1237e9 1.1238e9 1.1239e9 1.124e9 1.1241e9 1.1242e9 1 +.1243e9 ] from: 1123345456 to 1124246357.5 by: 4 -> [ 4][ 1.123e9 1.1235e9 1.12 +4e9 1.1245e9 ] from: 1123345456 to 1124246357.5 by: 5 -> [ 5][ 1.12325e9 1.1235e9 1. +12375e9 1.124e9 1.12425e9 ] from: 1123345456 to 1124246357.5 by: 8 -> [11][ 1.1233e9 1.1234e9 1.1 +235e9 1.1236e9 1.1237e9 1.1238e9 1.1239e9 1.124e9 1.1241e9 1.1242e9 1 +.1243e9 ] from: 1123345456 to 1124246357.5 by:10 -> [11][ 1.1233e9 1.1234e9 1.1 +235e9 1.1236e9 1.1237e9 1.1238e9 1.1239e9 1.124e9 1.1241e9 1.1242e9 1 +.1243e9 ] from: 1123345456 to 1124246357.5 by:15 -> [11][ 1.1233e9 1.1234e9 1.1 +235e9 1.1236e9 1.1237e9 1.1238e9 1.1239e9 1.124e9 1.1241e9 1.1242e9 1 +.1243e9 ] from: 1123345456 to 1124246357.5 by:16 -> [11][ 1.1233e9 1.1234e9 1.1 +235e9 1.1236e9 1.1237e9 1.1238e9 1.1239e9 1.124e9 1.1241e9 1.1242e9 1 +.1243e9 ] from: 1123345456 to 1124246357.5 by:20 -> [20][ 1.1233e9 1.12335e9 1. +1234e9 1.12345e9 1.1235e9 1.12355e9 1.1236e9 1.12365e9 1.1237e9 1.123 +75e9 1.1238e9 1.12385e9 1.1239e9 1.12395e9 1.124e9 1.12405e9 1.1241e9 + 1.12415e9 1.1242e9 1.12425e9 ] from: 1123345456 to 1124246357.5 by:21 -> [20][ 1.1233e9 1.12335e9 1. +1234e9 1.12345e9 1.1235e9 1.12355e9 1.1236e9 1.12365e9 1.1237e9 1.123 +75e9 1.1238e9 1.12385e9 1.1239e9 1.12395e9 1.124e9 1.12405e9 1.1241e9 + 1.12415e9 1.1242e9 1.12425e9 ] from: 1123345456 to 1123346357.5 by: 0 -> [11][ 1.1233454e9 1.1233455 +e9 1.1233456e9 1.1233457e9 1.1233458e9 1.1233459e9 1.123346e9 1.12334 +61e9 1.1233462e9 1.1233463e9 1.1233464e9 ] from: 1123345456 to 1123346357.5 by: 4 -> [ 4][ 1.123345e9 1.1233455e +9 1.123346e9 1.1233465e9 ] from: 1123345456 to 1123346357.5 by: 5 -> [ 6][ 1.1233453e9 1.1233455 +e9 1.1233458e9 1.123346e9 1.1233463e9 1.1233465e9 ] from: 1123345456 to 1123346357.5 by: 8 -> [11][ 1.1233454e9 1.1233455 +e9 1.1233456e9 1.1233457e9 1.1233458e9 1.1233459e9 1.123346e9 1.12334 +61e9 1.1233462e9 1.1233463e9 1.1233464e9 ] from: 1123345456 to 1123346357.5 by:10 -> [11][ 1.1233454e9 1.1233455 +e9 1.1233456e9 1.1233457e9 1.1233458e9 1.1233459e9 1.123346e9 1.12334 +61e9 1.1233462e9 1.1233463e9 1.1233464e9 ] from: 1123345456 to 1123346357.5 by:15 -> [11][ 1.1233454e9 1.1233455 +e9 1.1233456e9 1.1233457e9 1.1233458e9 1.1233459e9 1.123346e9 1.12334 +61e9 1.1233462e9 1.1233463e9 1.1233464e9 ] from: 1123345456 to 1123346357.5 by:16 -> [11][ 1.1233454e9 1.1233455 +e9 1.1233456e9 1.1233457e9 1.1233458e9 1.1233459e9 1.123346e9 1.12334 +61e9 1.1233462e9 1.1233463e9 1.1233464e9 ] from: 1123345456 to 1123346357.5 by:20 -> [20][ 1.1233455e9 1.1233455 +e9 1.1233456e9 1.1233456e9 1.1233457e9 1.1233457e9 1.1233458e9 1.1233 +458e9 1.1233459e9 1.1233459e9 1.123346e9 1.123346e9 1.1233461e9 1.123 +3461e9 1.1233462e9 1.1233462e9 1.1233463e9 1.1233463e9 1.1233464e9 1. +1233464e9 ] from: 1123345456 to 1123346357.5 by:21 -> [20][ 1.1233455e9 1.1233455 +e9 1.1233456e9 1.1233456e9 1.1233457e9 1.1233457e9 1.1233458e9 1.1233 +458e9 1.1233459e9 1.1233459e9 1.123346e9 1.123346e9 1.1233461e9 1.123 +3461e9 1.1233462e9 1.1233462e9 1.1233463e9 1.1233463e9 1.1233464e9 1. +1233464e9 ] from: 0.00011 to 0.00041 by: 0 -> [ 8][ 0.0001 0.00015 0.0002 + 0.00025 0.0003 0.00035 0.0004 0.00045 ] from: 0.00011 to 0.00041 by: 4 -> [ 5][ 0.0001 0.0002 0.0003 +0.0004 0.0005 ] from: 0.00011 to 0.00041 by: 5 -> [ 5][ 0.0001 0.0002 0.0003 +0.0004 0.0005 ] from: 0.00011 to 0.00041 by: 8 -> [ 8][ 0.0001 0.00015 0.0002 + 0.00025 0.0003 0.00035 0.0004 0.00045 ] from: 0.00011 to 0.00041 by:10 -> [ 8][ 0.0001 0.00015 0.0002 + 0.00025 0.0003 0.00035 0.0004 0.00045 ] from: 0.00011 to 0.00041 by:15 -> [14][ 0.0001 0.000125 0.000 +15 0.000175 0.0002 0.000225 0.00025 0.000275 0.0003 0.000325 0.00035 +0.000375 0.0004 0.000425 ] from: 0.00011 to 0.00041 by:16 -> [14][ 0.0001 0.000125 0.000 +15 0.000175 0.0002 0.000225 0.00025 0.000275 0.0003 0.000325 0.00035 +0.000375 0.0004 0.000425 ] from: 0.00011 to 0.00041 by:20 -> [14][ 0.0001 0.000125 0.000 +15 0.000175 0.0002 0.000225 0.00025 0.000275 0.0003 0.000325 0.00035 +0.000375 0.0004 0.000425 ] from: 0.00011 to 0.00041 by:21 -> [14][ 0.0001 0.000125 0.000 +15 0.000175 0.0002 0.000225 0.00025 0.000275 0.0003 0.000325 0.00035 +0.000375 0.0004 0.000425 ]

    With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    "Science is about questioning the status quo. Questioning authority". I'm with torvalds on this
    In the absence of evidence, opinion is indistinguishable from prejudice. Agile (and TDD) debunked
Re: Simple calculation.
by Anonymous Monk on May 09, 2015 at 07:26 UTC
    Mmmm, I think the formula is (end - start) / (number_of_parts - 1).
    use strict; use warnings; use feature 'say'; display_parts( 0, 9, 10 ); display_parts( 0.022, 0.086, 10 ); display_parts( 0.123, 8.672, 10 ); display_parts( 1_123_345_456, 1_124_246_357.5, 11 ); sub display_parts { my $result = get_ticks(@_); printf "start: %s, end: %s, parts: %s\n", map pretty($_), @_; for ( 0 .. $#$result ) { printf " %2d => %s\n", $_, pretty( $result->[$_] ); } print "\n"; } sub get_ticks { my ( $start, $end, $parts ) = @_; my $tick = ( $end - $start ) / ( $parts - 1 ); my @result; push @result, $start; push @result, $result[-1] + $tick for 1 .. ($parts - 1); return \@result; } sub pretty { return shift =~ s/\d \K (?= (?: \d{3} )+ \b )/_/xgr; }
    output:
    start: 0, end: 9, parts: 10 0 => 0 1 => 1 2 => 2 3 => 3 4 => 4 5 => 5 6 => 6 7 => 7 8 => 8 9 => 9 start: 0.022, end: 0.086, parts: 10 0 => 0.022 1 => 0.0_291_111_111_111_111 2 => 0.0_362_222_222_222_222 3 => 0.0_433_333_333_333_333 4 => 0.0_504_444_444_444_444 5 => 0.0_575_555_555_555_555 6 => 0.0_646_666_666_666_667 7 => 0.0_717_777_777_777_778 8 => 0.0_788_888_888_888_889 9 => 0.086 start: 0.123, end: 8.672, parts: 10 0 => 0.123 1 => 1.07_288_888_888_889 2 => 2.02_277_777_777_778 3 => 2.97_266_666_666_667 4 => 3.92_255_555_555_556 5 => 4.87_244_444_444_445 6 => 5.82_233_333_333_333 7 => 6.77_222_222_222_222 8 => 7.72_211_111_111_111 9 => 8.672 start: 1_123_345_456, end: 1_124_246_357.5, parts: 11 0 => 1_123_345_456 1 => 1_123_435_546.15 2 => 1_123_525_636.3 3 => 1_123_615_726.45 4 => 1_123_705_816.6 5 => 1_123_795_906.75 6 => 1_123_885_996.9 7 => 1_123_976_087.05 8 => 1_124_066_177.2 9 => 1_124_156_267.35 10 => 1_124_246_357.5

      Hint: Retaining .05 precision in tick marks distributed over a range of 900+ doesn't make much sense.

      The kind of output I'm looking for for that example is:

      1,123,345,400 1,123,346,500 1,123,345,600 1,123,345,600 1,123,345,700 +1,123,345,800 1,123,345,900 1,123,346,000 1,123,346,100 1,123,346,200 + 1,123,346,300 1,123,346,400

      With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
      Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
      "Science is about questioning the status quo. Questioning authority". I'm with torvalds on this
      In the absence of evidence, opinion is indistinguishable from prejudice. Agile (and TDD) debunked
        Hint: Retaining .05 precision in tick marks distributed over a range of 900+ doesn't make much sense.
        Makes perfect sense to me. I just thought that getting 8.721 as max is strange when the real max is 8.672. I actually thought your 'not so nice!' refers to that. I don't know how to produce "aethetically pleasing" numbers, sorry.
Re: calculate the best Interval between tick marks (dollars cents)
by Anonymous Monk on May 09, 2015 at 07:17 UTC
      http://stackoverflow.com/questions/14923812/displaying-axis-from-min-to-max-value-calculating-scale-and-labels

      Dog! I hate that site: So many jumped up little hitlers and so much dross.

      1. Eg. "(EDIT -- I've found an implementation of Scale1() that I did in Perl)" Liar. The code he posted contains (amongst others):
        • use strict;
        • @vInt = {1, 2, 5, 10};
        • if ($xMaxp < $xMax) $xMaxp = $xMax;
        • $par = (-3.1, 11.1, 5, 5.2, 10.1, 5, -12000, -100, 9);
      2. Another "perl" answer contains (amongst others):    $label_arr[] = array('label' => $label, 'x_pos' => $width_between * $i);.

      Not sure what's worse. Trying to decode Javascript kiddy "perl"; or the COBOLFortran?! they were trying to transcribe :)

      Damn! I'd forgotten just how horrible '70s languages were.


      With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
      Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
      "Science is about questioning the status quo. Questioning authority". I'm with torvalds on this
      In the absence of evidence, opinion is indistinguishable from prejudice. Agile (and TDD) debunked