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.