On Tue, Apr 04, 2006 at 11:58:32AM +0200, Bill Allombert wrote:

> Unfortunately there is a bug: 
> 
> The larger tick value is smaller than the max, or it is drawn outside
> the chart.

Thanks, so there is. I'm attaching a new try at a patch.  It also uses
m*10^n as the interval, where m is 1,2 or 5, to mimic the behaviour
without 'integer_ticks_only'.

The previous patch didn't apply because Chart/Base.pm uses DOS-style
newlines, and they had got lost somewhere on the way. This one should
apply cleanly against 2.4.1-3.

Please tell me if it works for you.

Cheers,
-- 
Niko Tyni       [EMAIL PROTECTED]
--- Chart/Base.pm.orig  2006-04-09 14:47:02.268171711 +0300
+++ Chart/Base.pm       2006-04-09 14:58:26.590677648 +0300
@@ -41,6 +41,7 @@
 use strict;
 use Carp;
 use FileHandle;
+use POSIX qw(ceil);
 
 $Chart::Base::VERSION = '2.4.1';
 
@@ -1815,6 +1816,40 @@
    return 1;
 }
 
+# calculate an integer tick interval, given a range and the number of ticks
+# round up- or downwards to 1,2 or 5 * 10^n
+
+sub _recalc_integer_tickinterval {
+       my $self = shift;
+
+       my ($range, $ticks, $round) = @_;
+       die("a range of 0 makes no sense") if ($range == 0);
+
+        my $tickInterval = $range / ($ticks - 1);
+       my ($exponent, $mantissa) = $self->_sepFP($tickInterval);
+       die("an interval 0 makes no sense") if ($mantissa == 0);
+
+       while ($mantissa < 1) {
+               $mantissa *= 10;
+               $exponent--;
+       }
+       if ($exponent < 0) { # minimum interval is 1
+               $exponent = 0;
+               $mantissa = 1;
+       } elsif ($round > 0) { # round upwards
+               for (2,5,10) {
+                   $mantissa = $_, last if $mantissa < $_;
+                }
+       } else { # round downwards
+               for (5,2,1) {
+                   $mantissa = $_, last if $mantissa > $_;
+                }
+       }
+        $tickInterval = $mantissa * 10 ** $exponent;
+
+        my $newTickCount = ceil($range / $tickInterval) + 1;
+       return ($tickInterval, $newTickCount);
+}
 
 ##  find good values for the minimum and maximum y-value on the chart
 # New version, re-written by David Pottage of Tao Group.
@@ -1911,6 +1946,44 @@
            $tickInterval = $skip;
             $tickCount = ($p_max - $p_min ) / $skip + 1;
                 
+            # Honor max_y_ticks, even if that means overriding skip_int_ticks.
+            if ($tickCount > $self->{'max_y_ticks'}) {
+               ($tickInterval, $tickCount) 
+                   = $self->_recalc_integer_tickinterval(
+                       $p_max - $p_min, $self->{'max_y_ticks'}, 1);
+            }
+
+            # Honor min_y_ticks if we can, first by reducing tick interval
+            # (even if that means overriding skip_int_ticks)
+            # and then by increasing the range if allowed.
+            if ($tickCount < $self->{'min_y_ticks'}) {
+               ($tickInterval, $tickCount) 
+                   = $self->_recalc_integer_tickinterval(
+                       $p_max - $p_min, $self->{'min_y_ticks'}, -1);
+
+                if ($tickCount < $self->{'min_y_ticks'} &&
+                        (!$f_max || !$f_min)) {
+                    # Reducing interval didn't work, we have to increase the 
range.
+                    # Just don't do it if both min_val and max_val were 
specified.
+                    
+                    my $minRange = $tickInterval * ($self->{'min_y_ticks'} - 
1);
+                    if (!$f_max) {
+                        $d_max = $d_min + $minRange;
+                        $p_max = $self->_round2Tick($d_max, 1, 1); 
+                    } elsif (!$f_min) {
+                        $d_min = $d_max - $minRange;
+                        $p_min = $self->_round2Tick($d_min, 1, -1);
+                    }
+
+                   # recalculate the tick interval once more
+                   ($tickInterval, $tickCount) 
+                       = $self->_recalc_integer_tickinterval(
+                           $p_max - $p_min, $self->{'min_y_ticks'}, -1);
+                }
+            }
+
+           # set $p_max to the real maximum value of the graph
+           $p_max = $p_min + $tickInterval * ($tickCount - 1);
 
             # Now sort out an array of tick labels.
                 

Reply via email to