GDGraph

 view release on metacpan or  search on metacpan

Graph/axestype.pm  view on Meta::CPAN

    $self->{y_max}[2] = $self->{y_max_value}  if defined $self->{y_max_value};

    $self->{y_min}[1] = $self->{y1_min_value} if defined $self->{y1_min_value};
    $self->{y_max}[1] = $self->{y1_max_value} if defined $self->{y1_max_value};

    $self->{y_min}[2] = $self->{y2_min_value} if defined $self->{y2_min_value};
    $self->{y_max}[2] = $self->{y2_max_value} if defined $self->{y2_max_value};

    $self->{x_min}    = $self->{x_min_value}  if defined $self->{x_min_value};
    $self->{x_max}    = $self->{x_max_value}  if defined $self->{x_max_value};

    if (
        $self->{two_axes} && !defined $self->{y1_min_value} && !defined $self->{y2_min_value}
        && !defined $self->{y1_max_value} && !defined $self->{y2_max_value}
    )
    {
        # If we have two axes, we need to make sure that the zero is at
        # the same spot.
        # And we need to change the number of ticks on the axes

        my $l_range = $self->{y_max}[1] - $self->{y_min}[1];
        my $r_range = $self->{y_max}[2] - $self->{y_min}[2];

        my $l_top = $self->{y_max}[1]/$l_range;
        my $r_top = $self->{y_max}[2]/$r_range;
        my $l_bot = $self->{y_min}[1]/$l_range;
        my $r_bot = $self->{y_min}[2]/$r_range;

        if ($l_top > $r_top)
        {
            $self->{y_max}[2] = $l_top * $r_range;
            $self->{y_min}[1] = $r_bot * $l_range;
            $self->{y_tick_number} *= 1 + abs $r_bot - $l_bot;
        }
        else
        {
            $self->{y_max}[1] = $r_top * $l_range;
            $self->{y_min}[2] = $l_bot * $r_range;
            $self->{y_tick_number} *= 1 + abs $r_top - $l_top;
        }
    }

    # Check to see if we have sensible values
    if ($self->{two_axes}) 
    {
        for my $i (1 .. $self->{_data}->num_sets)
        {
            my ($min, $max) = $self->{_data}->get_min_max_y($i);
            return $self->_set_error("Minimum for y" . $i . " too large")
                if $self->{y_min}[$self->{use_axis}[$i-1]] > $min;
            return $self->_set_error("Maximum for y" . $i . " too small")
                if $self->{y_max}[$self->{use_axis}[$i-1]] < $max;
        }
    } 

    return $self;
}

# CONTRIB Scott Prahl
#
# Calculate best endpoints and number of intervals for an axis and
# returns ($nice_min, $nice_max, $n), where $n is the number of
# intervals and
#
#    $nice_min <= $min < $max <= $nice_max
#
# Usage:
#       ($nmin,$nmax,$nint) = _best_ends(247, 508);
#       ($nmin,$nmax) = _best_ends(247, 508, 5); 
#           use 5 intervals
#       ($nmin,$nmax,$nint) = _best_ends(247, 508, [4..7]);   
#           best of 4,5,6,7 intervals
#       ($nmin,$nmax,$nint) = _best_ends(247, 508, 'auto');
#           best of 3,4,5,6 intervals
#       ($nmin,$nmax,$nint) = _best_ends(247, 508, [2..5]);
#           best of 2,3,4,5 intervals
sub _best_ends 
{
    my ($min, $max, $n_ref, $min_range) = @_;

    # Adjust for the min range if need be
    ($min, $max) = _fit_vals_range($min, $max, $min_range);

    my ($best_min, $best_max, $best_num) = ($min, $max, 1);

    # Check that min and max are not the same, and not 0
    ($min, $max) = ($min) ? ($min * 0.5, $min * 1.5) : (-1,1)
        if ($max == $min);
    
    # mgjv - Sometimes, for odd values, and only one data set, this will be
    # necessary _after_ the previous step, not before. Data sets of one
    # long with negative values were causing infinite loops later on.
    ($min, $max) = ($max, $min) if ($min > $max);

    my @n = ref($n_ref) ? @$n_ref : $n_ref;

    if (@n <= 0)
    {
        @n = (3..6);
    }
    else
    {
        @n = map { ref($_) ? @$_ : /(\d+)/i ? $1 : (3..6) } @n;
    }

    my $best_fit = 1e30;
    my $range = $max - $min;

    # create array of interval sizes
    my $s = 1;
    while ($s < $range) { $s *= 10 }
    while ($s > $range) { $s /= 10 }
    my @step = map {$_ * $s} (0.2, 0.5, 1, 2, 5);

    for my $n (@n) 
    {                               
        # Try all numbers of intervals
        next if ($n < 1);

        for my $step (@step) 
        {
            next if ($n != 1) and ($step < $range/$n) || ($step <= 0); 
            # $step too small

            my ($nice_min, $nice_max, $fit)
                    = _fit_interval($min, $max, $n, $step);

            next if $best_fit <= $fit;

            $best_min = $nice_min;
            $best_max = $nice_max;
            $best_fit = $fit;
            $best_num = $n;
        }
    }
    return ($best_min, $best_max, $best_num)
}

# CONTRIB Ben Tilly
#
# Calculate best endpoints and number of intervals for a pair of axes
# where it is trying to line up the scale of the two intervals.  It
# returns ($nice_min_1, $nice_max_1, $nice_min_2, $nice_max_2, $n),
# where $n is the number of intervals and
#
#    $nice_min_1 <= $min_1 < $max_1 <= $nice_max_1
#    $nice_min_2 <= $min_2 < $max_2 <= $nice_max_2
#
# and 0 will appear at the same point on both axes.
#
# Usage:
#       ($nmin_1,$nmax_1,$nmin_2,$nmax_2,$nint) = _best_dual_ends(247, 508, undef, -1, 5, undef, [2..5]);
# etc.  (The usage of the last arguments just parallels _best_ends.)
#
sub _best_dual_ends
{
    my ($min_1, $max_1) = _fit_vals_range(splice @_, 0, 3);
    my ($min_2, $max_2) = _fit_vals_range(splice @_, 0, 3);
    my @rem_args = @_;

    # Fix the situation where both min_1 and max_1 are 0, which makes it
    # loop forever
    ($min_1, $max_1) = (0, 1) unless $min_1 or $max_1;

    my $scale_1 = _max(abs($min_1), abs($max_1));
    my $scale_2 = _max(abs($min_2), abs($max_2));

    $scale_1 = defined($scale_2) ? $scale_2 : 1 unless defined($scale_1);
    $scale_2 = $scale_1 unless defined($scale_2);

    my $ratio = $scale_1 / ($scale_2 || 1);
    my $fact_1 = my $fact_2 = 1;

    while ($ratio < sqrt(0.1))
    {
        $ratio *= 10;
        $fact_2 *= 10;
    }
    while ($ratio > sqrt(10))
    {
        $ratio /= 10;
        $fact_1 *= 10;
    }

    my ($best_min_1, $best_max_1, $best_min_2, $best_max_2, $best_n, $best_fit)
            = ($min_1, $max_1, $min_2, $max_2, 1, 1e10);

    # Now try all of the ratios of "simple numbers" in the right size-range
    foreach my $frac
    (
        [1,1], [1,2], [1,3], [2,1], [2,3], [2,5],
        [3,1], [3,2], [3,4], [3,5], [3,8], [3,10],
        [4,3], [4,5], [5,2], [5,3], [5,4], [5,6],
        [5,8], [6,5], [8,3], [8,5], [10,3]
    )
    {
        my $bfact_1 = $frac->[0] * $fact_1;
        my $bfact_2 = $frac->[1] * $fact_2;

        my $min = _min( $min_1/$bfact_1, $min_2/$bfact_2 );
        my $max = _max( $max_1/$bfact_1, $max_2/$bfact_2 );



( run in 0.894 second using v1.01-cache-2.11-cpan-e1769b4cff6 )