Bug#359943: libchart-perl: integer_ticks_only doesn't honor
max_y_ticks
Niko Tyni
ntyni at iki.fi
Sun Apr 9 12:20:05 UTC 2006
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 ntyni at iki.fi
-------------- next part --------------
--- 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.
More information about the pkg-perl-maintainers
mailing list