On Tue, Apr 18, 2006 at 09:58:20PM +0200, Bill Allombert wrote:
> There are some ticks above the graph now:
Oh dear. See below.
> > The default for max_y_ticks is the same in both cases, 100. The
> > 'integer_ticks_only' code aims for a tick interval of 1, but if that goes
> > over max_y_ticks, it starts compensating. Without 'integer_ticks_only',
> > the 'max_y_ticks' kicks in only with non-integer tick intervals.
>
> Ah, so this is the intended behaviour ? Weird.
The original upstream behaviour with 'integer_ticks_only' is to always
use a tick interval of 1 (or whatever is in 'skip_int_ticks'), and not
to care about eg. 'max_y_ticks' at all. This is handled with separate
logic from the non-integer case. I have been patching this separate
logic to take 'max_y_ticks' etc. into account.
But you're right, this is not the optimal solution. The attached patch
is a new approach: it uses the same code in both integer and non-integer
cases. The biggest special case left is now when a fixed tick interval
is explicitly given via 'skip_int_ticks'.
I think this is more robust than the previous solutions. I have tried to
test it more carefully this time, as my track record on buggy patches on
this issue is getting embarrassing. Sorry about that, and thanks for your
patience. I would appreciate once again if you could test this one too.
Cheers,
--
Niko Tyni [EMAIL PROTECTED]
--- Chart/Base.pm.orig 2006-04-09 14:47:02.000000000 +0300
+++ Chart/Base.pm 2006-04-19 14:20:27.136041124 +0300
@@ -41,6 +41,7 @@
use strict;
use Carp;
use FileHandle;
+use POSIX qw(floor ceil);
$Chart::Base::VERSION = '2.4.1';
@@ -651,9 +652,6 @@
# default value for skip_y_ticks for the labels
$self->{skip_y_ticks} = 1;
- # default value for skip_int_ticks only for integer_ticks_only
- $self->{skip_int_ticks} = 1;
-
# default value for precision
$self->{precision} = 3;
@@ -1845,6 +1843,7 @@
my @tickLabels; # List of labels for each tick.
my $maxtickLabelLen = 0; # The length of the longest tick label.
my $prec_test=0; # Boolean which indicate if precision < |rangeExponent|
+ my $precision = $self->{precision};
my $temp_rangeExponent;
# Find the datatset minimum and maximum.
@@ -1866,7 +1865,24 @@
}
}
}
-
+ # Allow the dataset range to be overidden by the user.
+ # f_min/max are booleans which indicate that the min & max should not be modified.
+ my $f_min = defined $self->{'min_val'};
+ $d_min = $self->{'min_val'} if $f_min;
+
+ my $f_max = defined $self->{'max_val'};
+ $d_max = $self->{'max_val'} if $f_max;
+
+ # Assert against the min is larger than the max.
+ if( $d_min > $d_max )
+ {
+ croak "The the specified 'min_val' & 'max_val' values are reversed (min > max: $d_min>$d_max)";
+ }
+ # Calculate the width of the dataset. (possibly modified by the user)
+ my $d_width = $d_max - $d_min;
+
+ my $f_interval = 0; # Forced tick interval from 'skip_int_ticks'
+
if ( $self->{'integer_ticks_only'} =~ /^\d$/ )
{
if ( $self->{'integer_ticks_only'} == 1 )
@@ -1880,87 +1896,53 @@
}
if( $self->{'integer_ticks_only'} =~ m!^true$!i )
{
- # Allow the dataset range to be overidden by the user.
- # f_min/max are booleans which indicate that the min & max should not be modified.
- my $f_min = defined $self->{'min_val'};
- $d_min = $self->{'min_val'} if $f_min;
-
- my $f_max = defined $self->{'max_val'};
- $d_max = $self->{'max_val'} if $f_max;
-
- # Assert against the min is larger than the max.
- if( $d_min > $d_max )
- {
- croak "The the specified 'min_val' & 'max_val' values are reversed (min > max: $d_min>$d_max)";
+ $precision = 0;
+ $f_interval = $self->{'skip_int_ticks'};
+ if ($f_interval && $f_interval =~ /\D/) {
+ croak "The specified 'skip_int_ticks' ($f_interval) must be a positive integer";
}
- # The user asked for integer ticks, force the limits to integers.
- # & work out the range directly.
- #$p_min = $self->_round2Tick($d_min, 1, -1);
- #$p_max = $self->_round2Tick($d_max, 1, 1);
-
- $skip = $self->{skip_int_ticks};
- $skip = 1 if $skip < 1;
-
- $p_min = $self->_round2Tick($d_min, 1, -1);
- $p_max = $self->_round2Tick($d_max, 1, 1);
- if ( ($p_max - $p_min ) == 0 )
- {
- $p_max++, $p_min--;
+
+ # Round the bounds regardless of 'f_min' or 'f_max'
+ $d_min = floor($d_min);
+ $d_max = ceil($d_max);
+
+ $d_width = $d_max - $d_min;
+
+ my $interval = 1;
+ if ($f_interval) {
+ $interval = $f_interval;
}
- $tickInterval = $skip;
- $tickCount = ($p_max - $p_min ) / $skip + 1;
-
+ # See if there's enough room for 'min_y_ticks'
+ # If not, expand the range
+ if ($d_width < ($self->{'min_y_ticks'} - 1) * $interval) {
+ if (!$f_max || $f_min) {
+ $d_max = $d_min + ($self->{'min_y_ticks'} - 1) * $interval;
+ $f_max = 0 if $f_min;
+ } else {
+ $d_min = $d_max - ($self->{'min_y_ticks'} - 1) * $interval;
+ }
+ $d_width = $d_max - $d_min;
+ }
- # Now sort out an array of tick labels.
-
- for( my $labelNum = $p_min; $labelNum<$p_max+$tickInterval/3; $labelNum+=$tickInterval )
- {
- my $labelText;
-
- if ( defined $self->{f_y_tick} )
- {
- # Is _default_f_tick function used?
- if ( $self->{f_y_tick} == \&_default_f_tick)
- {
- $labelText = sprintf("%d", $labelNum);
- }
- else
- {
- $labelText = $self->{f_y_tick}->($labelNum);
- }
- }
- else
- {
- $labelText = sprintf("%d", $labelNum);
- }
-
- push @tickLabels, $labelText;
- $maxtickLabelLen = length $labelText if $maxtickLabelLen < length $labelText;
+ # See if a forced tick interval would mean too many ticks
+ if ($f_interval && $d_width > ($self->{'max_y_ticks'} - 1) * $f_interval) {
+ $f_interval = 0;
}
}
- else
- {
- # Allow the dataset range to be overidden by the user.
- # f_min/max are booleans which indicate that the min & max should not be modified.
- my $f_min = defined $self->{'min_val'};
- $d_min = $self->{'min_val'} if $f_min;
-
- my $f_max = defined $self->{'max_val'};
- $d_max = $self->{'max_val'} if $f_max;
-
- # print "fmin $f_min fmax $f_max\n";
- # print "dmin $d_min dmax $d_max\n";
-
- # Assert against the min is larger than the max.
- if( $d_min > $d_max )
- {
- croak "The the specified 'min_val' & 'max_val' values are reversed (min > max: $d_min>$d_max)";
+
+ if ($f_interval) {
+ # Special case for tick calculation: the tick interval is forced
+ $tickInterval = $f_interval;
+ $p_min = $d_min;
+ $p_max = $d_max;
+ if (!$f_min) {
+ $p_min -= ($p_min % $f_interval);
}
+ $tickCount = ($p_max - $p_min) / $f_interval + 1;
+ } else {
+ # Normal case: calculate the tick interval from the range
- # Calculate the width of the dataset. (possibly modified by the user)
- my $d_width = $d_max - $d_min;
-
# If the width of the range is zero, forcibly widen it
# (to avoid division by zero errors elsewhere in the code).
if ( $d_width == 0 )
@@ -2002,13 +1984,12 @@
# print "pmin $p_min pmax $p_max\n";
# print "range exponent $rangeExponent\n";
- #get the precision for the labels
- my $precision = $self->{'precision'};
-
if ( $temp_rangeExponent != 0 && $rangeExponent < 0 && $temp_rangeExponent > $precision)
{
$prec_test = 1;
}
+
+ } # !$f_interval
# Now sort out an array of tick labels.
for( my $labelNum = $p_min; $labelNum<$p_max+$tickInterval/2; $labelNum+=$tickInterval )
@@ -2043,7 +2024,6 @@
push @tickLabels, $labelText;
$maxtickLabelLen = length $labelText if $maxtickLabelLen < length $labelText;
} # end for
- }
# Store the calculated data.
#### begin debugging output
--- Chart/HorizontalBars.pm.orig 2006-02-16 17:54:20.000000000 +0200
+++ Chart/HorizontalBars.pm 2006-04-19 12:02:20.172207627 +0300
@@ -377,7 +377,7 @@
$p_min = $self->_round2Tick($d_min, 1, -1);
$p_max = $self->_round2Tick($d_max, 1, 1);
- my $skip = $self->{skip_int_ticks};
+ my $skip = $self->{skip_int_ticks} || 1;
$tickInterval = $skip;
$tickCount = ($p_max - $p_min ) /$skip +1;