Chart-Strip
view release on metacpan or search on metacpan
=head1 DESCRIPTION
The Chart::Strip package plots data values versus time graphs, such as
used for seismographs, EKGs, or network usage reports.
It can plot multiple data sets on one graph. It offers several
styles of plots. It automatically determines the proper ranges
and labels for both axii.
=head1 USAGE
=head2 Create the Chart
$chart = Chart::Strip->new();
$chart = Chart::Strip->new(
option1 => value,
option2 => value,
);
If no options are specified, sensible default values will be used.
The following options are recognized:
=over 4
=item C<width>
The width of the image
=item C<height>
The height of the image.
=item C<title>
The title of the graph. Will be placed centered at the top.
=item C<x_label>
The label for the x axis. Will be placed centered at the bottom.
=item C<y_label>
The label for the y axis. Will be placed vertically along the left side.
=item C<draw_grid>
Should a grid be drawn on the graph?
=item C<draw_border>
Should a border be drawn around the edge of the image?
=item C<draw_tic_labels>
Should value labels be shown?
=item C<draw_data_labels>
Should each data set be labeled?
=item C<transparent>
Should the background be transparent?
=item C<grid_on_top>
Should the grid be drawn over the data (1) or below the data (0)?
=item C<binary>
Use powers of 2 instead of powers of 10 for the y axis labels.
=item C<data_label_style>
Style for drawing the graph labels. C<text> or C<box>
=item C<thickness>
Thickness of lines in pixels. (Requires GD newer than $VERSION).
=item C<skip_undefined>
Don\'t draw a line into or out of a datapoint whose value is undefined.
If false, undefined values are treated as though they were 0.
=item C<boxwidth>
Width of boxes for box style graphs. The width may also be specified as C<width>
in the data options or per point. If no width is specified a reasonable default is used.
=back
=head2 Adding Data
$chart->add_data( $data, $options );
The data should be an array ref of data points. Each data point
should be a hash ref containing:
{
time => $time_t, # must be a unix time_t
value => $value, # the data value
color => $color, # optional, used for this one point
}
or, range style graphs should contain:
{
time => $time_t, # must be a unix time_t
min => $low, # the minimum data value
max => $high, # the maximum data value
color => $color, # optional, used for this one point
}
and the options may contain:
{
style => 'line', # graph style: line, filled, range, points, box
color => 'FF00FF', # color used for the graph
label => 'New England', # name of the data set
}
points style graphs may specify the point diameter, as C<diam>
line, points, box, and filled graphs may specify a drop shadow,
consisting of a hashref containing C<dx>, C<dy>, C<dw>, and optionally, C<color>
shadow => { dx => 3, dy => 3, dw => 3, color => 'CCCCCC' }
=head2 Outputing The Image
=over 4
=item $chart->png()
Will return the PNG image
=item $chart->jpeg()
Will return the jpeg image
=item $chart->gd()
Will return the underlying GD object.
=back
=cut
;
package Chart::Strip;
use GD;
use Carp;
use POSIX;
use strict;
my $LT_HM = 1; # time
my $LT_HR = 2; # time/day
my $LT_DW = 3; # day/date
my $LT_DM = 4; # date/yr
my $LT_YR = 5; # year
my $MT_NO = 0; # none
my $MT_HR = 1; # hrs
my $MT_MN = 2; # midnight
my $MT_SU = 3; # sunday
my $MT_M1 = 4; # 1st
my $MT_Y1 = 5; # new years
sub new {
my $class = shift;
my %param = @_;
my $me = bless {
width => 640,
height => 192,
margin_left => 8,
margin_bottom => 8,
margin_right => 8,
margin_top => 8,
n_y_tics => 4, # aprox.
transparent => 1,
grid_on_top => 1,
draw_grid => 1,
draw_border => 1,
draw_tic_labels => 1,
draw_data_labels => 1,
limit_factor => 0,
data_label_style => 'text', # or 'box'
thickness => 1,
tm_time => \&POSIX::localtime, # or gmtime, or...
shadow_color => '#CCCCCC',
# GD can only antialias on a truecolor image, and only if thickness==1
# yes, I know what the GD documentation says. I also know what the src says...
antialias => 0,
truecolor => 0,
# title
# x_label
# y_label
# user specified params override defaults
%param,
}, $class;
$me->adjust();
my $im = GD::Image->new( $me->{width}, $me->{height}, $me->{truecolor} );
$me->{img} = $im;
# Nor long the sun his daily course withheld,
# But added colors to the world reveal'd:
# When early Turnus, wak'ning with the light,
# -- Virgil, Aeneid
# allocate some useful colors, 1st is used for bkg
my $bkg = $me->color({ color => $me->{background_color} }) if $me->{background_color};
$me->{color}{white} = $im->colorAllocate(255,255,255);
$me->{color}{black} = $im->colorAllocate(0,0,0);
$me->{color}{blue} = $im->colorAllocate(0, 0, 255);
$me->{color}{red} = $im->colorAllocate(255, 0, 0);
$me->{color}{green} = $im->colorAllocate(0, 255, 0);
$me->{color}{gray} = $im->colorAllocate(128, 128, 128);
# style for grid lines
$im->setStyle(gdTransparent, $me->{color}{gray}, gdTransparent, gdTransparent);
$im->interlaced('true');
$im->transparent($me->{color}{white})
if $me->{transparent};
$im->filledRectangle( 0, 0, $me->{width}-1, $me->{height}-1, ($bkg || $me->{color}{white}));
my $bc = $me->{border_color} ? $me->img_color($me->{border_color}) : $me->{color}{black};
$im->rectangle(0, 0, $me->{width}-1, $me->{height}-1, $bc )
if $me->{draw_border};
$me;
}
sub add_data {
my $me = shift;
my $data = shift;
my $opts = shift;
$me->analyze( $data, $opts );
unless( $opts->{style} ){
$opts->{style} = defined $data->[0]{min} ? 'range' : 'line';
}
push @{$me->{data}}, {data => $data, opts => $opts};
$me->{has_shadow} = 1 if $opts->{shadow};
$me;
}
# A plot shall show us all a merry day.
# -- Shakespeare, King Richard II
sub plot {
my $me = shift;
return unless $me->{data};
return if $me->{all_done};
$me->adjust();
$me->clabels();
$me->xlabel();
$me->ylabel();
$me->title();
if( $me->{draw_tic_labels} ){
# move margin for xtics before we do ytics
$me->{margin_bottom} += 12;
$me->adjust();
}
$me->ytics();
$me->xtics();
# draw shadows
foreach my $d ( @{$me->{data}} ){
next unless $d->{opts}{shadow};
$me->plot_data( $d->{data}, $d->{opts}, $d->{opts}{shadow} );
}
$me->axii();
$me->drawgrid() unless $me->{grid_on_top};
( run in 1.368 second using v1.01-cache-2.11-cpan-39bf76dae61 )