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 )