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;

Reply via email to