Chart
view release on metacpan or search on metacpan
lib/Chart/Pareto.pm view on Meta::CPAN
use GD;
use Carp;
#>>>>>>>>>>>>>>>>>>>>>>>>>>#
# public methods go here #
#<<<<<<<<<<<<<<<<<<<<<<<<<<#
#>>>>>>>>>>>>>>>>>>>>>>>>>>>#
# private methods go here #
#<<<<<<<<<<<<<<<<<<<<<<<<<<<#
## @fn private _find_y_scale
#calculate the range with the sum dataset1. all datas has to be positiv
sub _find_y_range
{
my $self = shift;
my $data = $self->{'dataref'};
my $sum = 0;
for ( my $i = 0 ; $i < $self->{'num_datapoints'} ; $i++ )
{
if ( $data->[1][$i] >= 0 )
{
$sum += $data->[1][$i];
}
else
{
carp "We need positiv data, if we want to draw a pareto graph!!";
return 0;
}
}
#store the sum
$self->{'sum'} = $sum;
#return the range
( 0, $sum );
}
## @fn private _sort_data
# sort the data
sub _sort_data
{
my $self = shift;
my $data = $self->{'dataref'};
my @labels = @{ $data->[0] };
my @values = @{ $data->[1] };
# sort the values and their labels
@labels = @labels[ sort { $values[$b] <=> $values[$a] } 0 .. $#labels ];
@values = sort { $b <=> $a } @values;
#save the sorted values and their labels
@{ $data->[0] } = @labels;
@{ $data->[1] } = @values;
#finally return
return 1;
}
## @fn private _draw_legend
# let them know what all the pretty colors mean
sub _draw_legend
{
my $self = shift;
my ($length);
my $num_dataset;
# check to see if legend type is none..
if ( $self->{'legend'} =~ /^none$/ )
{
return 1;
}
# check to see if they have as many labels as datasets,
# warn them if not
if ( ( $#{ $self->{'legend_labels'} } >= 0 )
&& ( ( scalar( @{ $self->{'legend_labels'} } ) ) != 2 ) )
{
carp "I need two legend labels. One for the data and one for the sum.";
}
# init a field to store the length of the longest legend label
unless ( $self->{'max_legend_label'} )
{
$self->{'max_legend_label'} = 0;
}
# fill in the legend labels, find the longest one
unless ( $self->{'legend_labels'}[0] )
{
$self->{'legend_labels'}[0] = "Dataset";
}
unless ( $self->{'legend_labels'}[1] )
{
$self->{'legend_labels'}[1] = "Running sum";
}
if ( length( $self->{'legend_labels'}[0] ) > length( $self->{'legend_labels'}[1] ) )
{
$self->{'max_legend_label'} = length( $self->{'legend_labels'}[0] );
}
else
{
$self->{'max_legend_label'} = length( $self->{'legend_labels'}[1] );
}
#set the number of datasets to 2, and store it
$num_dataset = $self->{'num_datasets'};
$self->{'num_datasets'} = 2;
# different legend types
if ( $self->{'legend'} eq 'bottom' )
{
$self->_draw_bottom_legend;
}
elsif ( $self->{'legend'} eq 'right' )
{
$self->_draw_right_legend;
}
elsif ( $self->{'legend'} eq 'left' )
{
$self->_draw_left_legend;
}
elsif ( $self->{'legend'} eq 'top' )
{
$self->_draw_top_legend;
}
else
{
carp "I can't put a legend there (at " . $self->{'legend'} . ")\n";
}
#reload the number of datasets
$self->{'num_datasets'} = $num_dataset;
# and return
return 1;
}
## @fn private _draw_data
# finally get around to plotting the data
sub _draw_data
{
my $self = shift;
my $data = $self->{'dataref'};
my $misccolor = $self->_color_role_to_index('misc');
my ( $x1, $x2, $x3, $y1, $y2, $y3, $y1_line, $y2_line, $x1_line, $x2_line, $h, $w );
my ( $width, $height, $delta1, $delta2, $map, $mod, $cut );
my ( $i, $j, $color, $line_color, $percent, $per_label, $per_label_len );
my $sum = $self->{'sum'};
my $curr_sum = 0;
my $font = $self->{'legend_font'};
my $pink = $self->{'gd_obj'}->colorAllocate( 255, 0, 255 );
my $diff;
# make sure we're using a real font
unless ( ( ref($font) ) eq 'GD::Font' )
{
croak "The subtitle font you specified isn\'t a GD Font object";
}
# get the size of the font
( $h, $w ) = ( $font->height, $font->width );
# init the imagemap data field if they wanted it
if ( $self->true( $self->{'imagemap'} ) )
{
$self->{'imagemap_data'} = [];
}
# find both delta values ($delta1 for stepping between different
# datapoint names, $delta2 for setpping between datasets for that
# point) and the mapping constant
$width = $self->{'curr_x_max'} - $self->{'curr_x_min'};
$height = $self->{'curr_y_max'} - $self->{'curr_y_min'};
$delta1 = $width / ( $self->{'num_datapoints'} > 0 ? $self->{'num_datapoints'} : 1 );
$diff = ( $self->{'max_val'} - $self->{'min_val'} );
$diff = 1 if $diff == 0;
$map = $height / $diff;
if ( $self->true( $self->{'spaced_bars'} ) )
{
$delta2 = $delta1 / 3;
}
else
{
$delta2 = $delta1;
}
# get the base x-y values
$x1 = $self->{'curr_x_min'};
$y1 = $self->{'curr_y_max'};
$y1_line = $y1;
$mod = $self->{'min_val'};
$x1_line = $self->{'curr_x_min'};
# draw the bars and the lines
$color = $self->_color_role_to_index('dataset0');
$line_color = $self->_color_role_to_index('dataset1');
# draw every bar for this dataset
for $j ( 0 .. $self->{'num_datapoints'} )
{
# don't try to draw anything if there's no data
if ( defined( $data->[1][$j] ) )
{
#calculate the percent value for this data and the actual sum;
$curr_sum += $data->[1][$j];
$percent = int( $curr_sum / ( $sum || 1 ) * 100 );
# find the bounds of the rectangle
( run in 1.408 second using v1.01-cache-2.11-cpan-5837b0d9d2c )