📄 axestype.pm
字号:
#
sub draw_y_ticks($$) # GD::Image, \@data
{
my $s = shift;
my $g = shift;
my $d = shift;
#
# Ticks and values for y axes
#
my $t;
foreach $t (0 .. $s->{y_tick_number})
{
my $a;
foreach $a (1 .. ($s->{two_axes} + 1))
{
my $value = $s->{y_values}[$a][$t];
my $label = $s->{y_labels}[$a][$t];
my ($x, $y) = $s->val_to_pixel(0, $value, $a);
#my ($x, $y) = $s->val_to_pixel(
# ($a-1) * ($s->{numpoints} + 2),
# $value,
# $a
#);
$x = ($a == 1) ? $s->{left} : $s->{right};
if ($s->{long_ticks})
{
$g->line(
$x, $y,
$x + $s->{right} - $s->{left}, $y,
$s->{fgci}
) unless ($a-1);
}
else
{
$g->line(
$x, $y,
$x + (3 - 2 * $a) * $s->{tick_length}, $y,
$s->{fgci}
);
}
next
if ( $t % ($s->{y_label_skip}) || ! $s->{y_plot_values} );
$x -=
(2-$a) * length($label) * $s->{yafw} +
(3 - 2 * $a) * $s->{axis_space};
$y -= $s->{yafh}/2;
$g->string($s->{yaf}, $x, $y, $label, $s->{alci});
}
}
}
#
# Ticks and values for x axes
#
sub draw_x_ticks($$) # GD::Image, \@data
{
my $s = shift;
my $g = shift;
my $d = shift;
#
# Ticks and values for X axis
#
my $i;
for $i (0 .. $s->{numpoints})
{
my ($x, $y) = $s->val_to_pixel($i + 1, 0, 1);
$y = $s->{bottom} unless $s->{zero_axis_only};
next
if ( !$s->{x_all_ticks} and
$i%($s->{x_label_skip}) and $i != $s->{numpoints} );
if ($s->{x_ticks})
{
if ($s->{long_ticks})
{
$g->line(
$x, $s->{bottom}, $x,
$s->{top},
$s->{fgci}
);
}
else
{
$g->line( $x, $y, $x, $y - $s->{tick_length},
$s->{fgci} );
}
}
next
if ( $i%($s->{x_label_skip}) and $i != $s->{numpoints} );
if ($s->{x_labels_vertical})
{
$x -= $s->{xafw};
my $yt =
$y + $s->{text_space}/2 + $s->{xafw} * length($d->[0][$i]);
$g->stringUp($s->{xaf}, $x, $yt, $d->[0][$i], $s->{alci});
}
else
{
$x -= $s->{xafw} * length($d->[0][$i])/2;
my $yt = $y + $s->{text_space}/2;
$g->string($s->{xaf}, $x, $yt, $d->[0][$i], $s->{alci});
}
}
}
# CONTRIB Scott Prahl
# Assume x array contains equally spaced x-values
# and generate an appropriate axis
#
sub draw_x_ticks_number($$) # GD::Image, \@data
{
my $s = shift;
my $g = shift;
my $d = shift;
my $i;
for $i (0 .. $s->{x_tick_number})
{
my $value = $s->{numpoints}
* ($s->{x_values}[$i] - $s->{true_x_min})
/ ($s->{true_x_max} - $s->{true_x_min});
my $label = $s->{x_values}[$i];
my ($x, $y) = $s->val_to_pixel($value + 1, 0, 1);
$y = $s->{bottom} unless $s->{zero_axis_only};
if ($s->{x_ticks})
{
if ($s->{long_ticks})
{
$g->line($x, $s->{bottom}, $x, $s->{top},$s->{fgci});
}
else
{
$g->line( $x, $y, $x, $y - $s->{tick_length}, $s->{fgci} );
}
}
next
if ( $i%($s->{x_label_skip}) and $i != $s->{x_tick_number} );
if ($s->{x_labels_vertical})
{
$x -= $s->{xafw};
my $yt =
$y + $s->{text_space}/2 + $s->{xafw} * length($d->[0][$i]);
$g->stringUp($s->{xaf}, $x, $yt, $label, $s->{alci});
}
else
{
# $x -= $s->{xafw} * length($$d[0][$i])/2;
$x -= length($d->[0][$i])/2;
my $yt = $y + $s->{text_space}/2;
$g->string($s->{xaf}, $x, $yt, $label, $s->{alci});
}
}
}
sub draw_ticks($$) # GD::Image, \@data
{
my $s = shift;
my $g = shift;
my $d = shift;
$s->draw_y_ticks($g, $d);
return unless ( $s->{x_plot_values} );
if (defined $s->{x_tick_number})
{
$s->draw_x_ticks_number($g, $d);
}
else
{
$s->draw_x_ticks($g, $d);
}
}
sub draw_data($$) # GD::Image, \@data
{
my $s = shift;
my $g = shift;
my $d = shift;
my $ds;
foreach $ds (1 .. $s->{numsets})
{
$s->draw_data_set($g, $d->[$ds], $ds);
}
}
# draw_data_set is in sub classes
sub draw_data_set()
{
# ABSTRACT
my $s = shift;
$s->die_abstract( "sub draw_data missing, ")
}
# Figure out the maximum values for the vertical exes, and calculate
# a more or less sensible number for the tops.
sub set_max_min($)
{
my $s = shift;
my $d = shift;
my @max_min;
# First, calculate some decent values
if ( $s->{two_axes} )
{
my $i;
for $i (1 .. 2)
{
my $true_y_min = get_min_y(@{$$d[$i]});
my $true_y_max = get_max_y(@{$$d[$i]});
($s->{y_min}[$i], $s->{y_max}[$i], $s->{y_tick_number}) =
_best_ends($true_y_min, $true_y_max, $s->{y_tick_number});
}
}
else
{
my ($true_y_min, $true_y_max) = $s->get_max_min_y_all($d);
($s->{y_min}[1], $s->{y_max}[1], $s->{y_tick_number}) =
_best_ends($true_y_min, $true_y_max, $s->{y_tick_number});
}
if (defined( $s->{x_tick_number} ))
{
$s->{true_x_min} = get_min_y(@{$d->[0]});
$s->{true_x_max} = get_max_y(@{$d->[0]});
($s->{x_min}, $s->{x_max}, $s->{x_tick_number}) =
_best_ends( $s->{true_x_min}, $s->{true_x_max},
$s->{x_tick_number});
}
# Make sure bars and area always have a zero offset
if (ref($s) eq 'GIFgraph::bars' or ref($s) eq 'GIFgraph::area')
{
$s->{y_min}[1] = 0 if $s->{y_min}[1] > 0;
$s->{y_min}[2] = 0 if $s->{y_min}[2] && $s->{y_min}[2] > 0;
}
# Overwrite these with any user supplied ones
$s->{y_min}[1] = $s->{y_min_value} if defined $s->{y_min_value};
$s->{y_min}[2] = $s->{y_min_value} if defined $s->{y_min_value};
$s->{y_max}[1] = $s->{y_max_value} if defined $s->{y_max_value};
$s->{y_max}[2] = $s->{y_max_value} if defined $s->{y_max_value};
$s->{y_min}[1] = $s->{y1_min_value} if defined $s->{y1_min_value};
$s->{y_max}[1] = $s->{y1_max_value} if defined $s->{y1_max_value};
$s->{y_min}[2] = $s->{y2_min_value} if defined $s->{y2_min_value};
$s->{y_max}[2] = $s->{y2_max_value} if defined $s->{y2_max_value};
$s->{x_min} = $s->{x_min_value} if defined $s->{x_min_value};
$s->{x_max} = $s->{x_max_value} if defined $s->{x_max_value};
# Check to see if we have sensible values
if ( $s->{two_axes} )
{
my $i;
for $i (1 .. 2)
{
die "Minimum for y" . $i . " too large\n"
if ( $s->{y_min}[$i] > get_min_y(@{$d->[$i]}) );
die "Maximum for y" . $i . " too small\n"
if ( $s->{y_max}[$i] < get_max_y(@{$d->[$i]}) );
}
}
# else
# {
# die "Minimum for y too large\n"
# if ( $s->{y_min}[1] > $max_min[1] );
# die "Maximum for y too small\n"
# if ( $s->{y_max}[1] < $max_min[0] );
# }
}
# return maximum value from an array
sub get_max_y(@) # array
{
my $max = undef;
my $i;
foreach $i (@_)
{
next unless defined $i;
$max = (defined($max) && $max >= $i) ? $max : $i;
}
return $max
}
sub get_min_y(@) # array
{
my $min = undef;
my $i;
foreach $i (@_)
{
next unless defined $i;
$min = ( defined($min) and $min <= $i) ? $min : $i;
}
return $min
}
# get maximum y value from the whole data set
sub get_max_min_y_all($) # \@data
{
my $s = shift;
my $d = shift;
my $max = undef;
my $min = undef;
if ($s->{overwrite} == 2)
{
my $i;
for $i (0 .. $s->{numpoints})
{
my $sum = 0;
my $j;
for $j (1 .. $s->{numsets})
{
$sum += $d->[$j][$i];
}
$max = _max( $max, $sum );
$min = _min( $min, $sum );
}
}
else
{
my $i;
for $i ( 1 .. $s->{numsets} )
{
$max = _max( $max, get_max_y(@{$d->[$i]}) );
$min = _min( $min, get_min_y(@{$d->[$i]}) );
}
}
return ($max, $min)
}
# 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
sub _best_ends {
my ($min, $max, @n) = @_;
my ($best_min, $best_max, $best_num) = ($min, $max, 1);
# fix endpoints, fix intervals, set defaults
($min, $max) = ($max, $min) if ($min > $max);
($min, $max) = ($min) ? ($min * 0.5, $min * 1.5) : (-1,1)
if ($max == $min);
@n = (3..6) if (@n <= 0 || $n[0] =~ /auto/i);
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 (@n)
{
# Try all numbers of intervals
my $n = $_;
next if ($n < 1);
for (@step)
{
next if ($n != 1) && ($_ < $range/$n); # $step too small
my $nice_min = $_ * int($min/$_);
$nice_min -= $_ if ($nice_min > $min);
my $nice_max = ($n == 1)
? $_ * int($max/$_ + 1)
: $nice_min + $n * $_;
my $nice_range = $nice_max - $nice_min;
next if ($nice_max < $max); # $nice_min too small
next if ($best_fit <= $nice_range - $range); # not closer fit
$best_min = $nice_min;
$best_max = $nice_max;
$best_fit = $nice_range - $range;
$best_num = $n;
}
}
return ($best_min, $best_max, $best_num)
}
# Convert value coordinates to pixel coordinates on the canvas.
sub val_to_pixel($$$) # ($x, $y, $i) in real coords ($Dataspace),
{ # return [x, y] in pixel coords
my $s = shift;
my ($x, $y, $i) = @_;
my $y_min =
($s->{two_axes} && $i == 2) ? $s->{y_min}[2] : $s->{y_min}[1];
my $y_max =
($s->{two_axes} && $i == 2) ? $s->{y_max}[2] : $s->{y_max}[1];
my $y_step = abs(($s->{bottom} - $s->{top})/($y_max - $y_min));
return (
_round( ($s->{x_tick_number} ? $s->{x_offset} : $s->{left})
+ $x * $s->{x_step} ),
_round( $s->{bottom} - ($y - $y_min) * $y_step )
)
}
} # End of package GIFgraph::axestype
1;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -