PDF-Reuse-OverlayChart
view release on metacpan or search on metacpan
OverlayChart.pm view on Meta::CPAN
if (ref($name))
{ $class = ref($name);
$self = $name;
}
else
{ $class = $name;
$self = {};
}
bless $self, $class;
return $self;
}
sub outlines
{ no warnings;
my $self = shift;
my %param = @_;
for (keys %param)
{ my $key = lc($_);
if ($possible{$key})
{ $self->{$key} = $param{$_};
}
else
{ warn "Unrecognized parameter: $_, ignored\n";
}
}
$self->{xsize} = 1 unless ($self->{xsize} != 0);
$self->{ysize} = 1 unless ($self->{ysize} != 0);
$self->{size} = 1 unless ($self->{size} != 0);
$self->{width} = 450 unless ($self->{width} != 0);
$self->{height} = 450 unless ($self->{height} != 0);
if (($self->{type} ne 'bars')
&& ($self->{type} ne 'totalbars')
&& ($self->{type} ne 'percentbars')
&& ($self->{type} ne 'lines')
&& ($self->{type} ne 'area'))
{ if (substr($self->{type}, 0, 1) eq 't')
{ $self->{type} = 'totalbars';
}
elsif (substr($self->{type}, 0, 1) eq 'p')
{ $self->{type} = 'percentbars';
}
elsif (substr($self->{type}, 0, 1) eq 'l')
{ $self->{type} = 'lines';
}
elsif (substr($self->{type}, 0, 1) eq 'a')
{ $self->{type} = 'area';
}
else
{ $self->{type} = 'bars';
}
}
if (! defined $self->{color})
{ $self->{color} = ['0 0 0.8', '0.8 0 0.3', '0.9 0.9 0', '0 1 0', '0.6 0.6 0.6',
'1 0.8 0.9', '0 1 1', '0.9 0 0.55', '0.2 0.2 0.2','0.55 0.9 0.9'];
}
return $self;
}
sub overlay
{ my $self = shift;
my %param = @_;
for (keys %param)
{ my $key = lc($_);
if ($possible{$key})
{ $self->{$key} = $param{$_};
}
else
{ warn "Unrecognized parameter: $_, ignored\n";
}
}
if (($self->{type} ne 'bars')
&& ($self->{type} ne 'totalbars')
&& ($self->{type} ne 'lines')
&& ($self->{type} ne 'area'))
{ if (substr($self->{type}, 0, 1) eq 't')
{ $self->{type} = 'totalbars';
}
elsif (substr($self->{type}, 0, 1) eq 'l')
{ $self->{type} = 'lines';
}
elsif (substr($self->{type}, 0, 1) eq 'a')
{ $self->{type} = 'area';
}
else
{ $self->{type} = 'bars';
}
}
$self->{xdensity} = 1 if (! exists $self->{xdensity});
$self->{ydensity} = 1 if (! exists $self->{ydensity});
$self->{level} = 'overlay';
return $self;
}
sub add
{ my $self = shift;
my @values = @_;
my $name = shift @values || ' ';
my $num = 0;
my $ready;
if (! defined $self->{col})
{ for (@values)
{ if (ref($_) eq 'ARRAY')
{ last;
}
if ((defined $_)
&& ($_ =~ m'[A-Za-z]+'o)
&& ($_ !~ m'undef'oi))
{ $ready = 1;
$self->{col} = \@values;
$self->{xunit} = $name;
last;
}
}
}
if (! defined $ready)
{ if (! exists $self->{series}->{$name})
{ push @{$self->{sequence}}, $name;
$self->{series}->{$name} = [];
}
my @array = @{$self->{series}->{$name}};
for (@values)
{ if (ref($_) eq 'ARRAY')
{ my @newArray;
for my $element (@{$_})
{ if ((defined $element) && (length($element)))
{ push @newArray, $element;
}
else
{ push @newArray, undef;
}
}
$array[$num] = [ @newArray ];
}
elsif ((defined $_) && ($_ =~ m'([\d\.\-]*)'o))
{ if (length($1))
{ $array[$num] += $1;
}
}
$num++;
}
$self->{series}->{$name} = \@array;
}
return $self;
}
sub columns
{ my $self = shift;
my $xunit = shift;
$self->{col} = \@_;
OverlayChart.pm view on Meta::CPAN
var x2 = vec[3] + x;
var y = y2 + vec[4];
var name = 'p' + page + 'x' + x + 'y' + y + 'x2' + x2 + 'y2' + y2;
var b = this.addField(name, "button", page, [x, y, x2, y2]);
b.setAction("MouseUp", vec[5]);
if (vec[6])
b.userName = vec[6];
}
EOF
prJs($code);
return $self;
}
sub draw
{ my $self = shift;
my %param = @_;
for (keys %param)
{ my $key = lc($_);
if ($possible{$key})
{ $self->{$key} = $param{$_};
}
else
{ warn "Unrecognized parameter: $_, ignored\n";
}
}
$self->outlines();
$self->{level} = 'top';
my ($str, $xsize, $ysize, $font, $x, $y, $y0, $ySteps, $xT, @array, $chartMax,
$chartMin, $rightScale, $topScale);
my ($max, $min, $maxSum, $minSum, $num,
$posPercent, $negPercent ) = $self->analysera();
if (($self->{type} eq 'totalbars') || ($self->{type} eq 'area'))
{ $chartMax = $maxSum;
$chartMin = $minSum;
}
else
{ $chartMax = $max;
$chartMin = $min;
}
if ((defined $self->{initialmaxy})
&& ($self->{initialmaxy} > $chartMax))
{ $chartMax = $self->{initialmaxy}
}
if ((defined $self->{initialminy})
&& ($self->{initialminy} < $chartMin))
{ $chartMin = $self->{initialminy}
}
if ((exists $param{'merge'}) && ($self->{type} ne 'percentbars'))
{ for (@{$param{'merge'}})
{ if ($_->{type} ne 'percentbars')
{ push @array, $_;
}
}
for my $overlay (@array)
{ my ($tmax, $tmin, $tmaxSum, $tminSum, $tnum) = $overlay->analysera();
if (($overlay->{type} eq 'totalbars') || ($overlay->{type} eq 'area'))
{ $tmaxSum = sprintf ("%.0f", ($tmaxSum / $overlay->{ydensity}));
$tminSum = sprintf ("%.0f", ($tminSum / $overlay->{ydensity}));
$chartMax = $tmaxSum if ($tmaxSum > $chartMax);
$chartMin = $tminSum if ($tminSum < $chartMin);
}
else
{ $tmax = sprintf ("%.0f", ($tmax / $overlay->{ydensity}));
$tmin = sprintf ("%.0f", ($tmin / $overlay->{ydensity}));
$chartMax = $tmax if ($tmax > $chartMax);
$chartMin = $tmin if ($tmin < $chartMin);
}
$tnum = sprintf ("%.0f", ($tnum / $overlay->{xdensity}));
$num = $tnum if ($tnum > $num);
$tnum = sprintf ("%.0f", ($self->{num} / $overlay->{xdensity}));
$num = $tnum if ($tnum > $num);
if ((defined $overlay->{rightscale})
&& (! defined $rightScale))
{ $rightScale = $overlay;
}
if ((defined $overlay->{topscale})
&& (! defined $topScale))
{ $topScale = $overlay;
}
$overlay->{x} = $self->{x};
$overlay->{xsize} = $self->{xsize};
$overlay->{size} = $self->{size};
$overlay->{y} = $self->{y};
$overlay->{ysize} = $self->{ysize};
}
}
my $xSteps = $#{$self->{col}} + 1;
$xSteps = $num if ($num > $xSteps);
my $groups = $#{$self->{sequence}} + 1;
if ($self->{type} ne 'percentbars')
{ if ($chartMin > 0)
{ $ySteps = $chartMax || 1;
}
elsif ($chartMax < 0)
{ $ySteps = ($chartMin * -1) || 1;
}
else
{ $ySteps = ($chartMax - $chartMin) || 1;
}
}
else
{ $max = $posPercent;
$min = $negPercent * -1;
$ySteps = sprintf("%.0f", ($max - $min));
$chartMax = $max;
$chartMin = $min;
}
####################
# N�gra kontroller
####################
if ($num < 1)
{ prText ($self->{x}, $self->{y},
'Values are missing - no graph can be shown');
return;
}
if ((! defined $max) || (! defined $min))
{ prText ($self->{x}, $self->{y},
'Values are missing - no graph can be shown');
return;
}
my $tal1 = sprintf("%.0f", $chartMax);
my $tal2 = sprintf("%.0f", $chartMin);
my $tal = (length($tal1) > length($tal2)) ? $tal1 : $tal2;
my $langd = length($tal);
my $xCor = ($langd * 7.5) || 25; # margin to the left
my $yCor = 20; # margin from the bottom
my $xEnd = $self->{width};
my $yEnd = $self->{height};
my $xArrow = $xEnd * 0.9;
my $yArrow = $yEnd * 0.97;
my $xAreaEnd = $xEnd * 0.85;
my $yAreaEnd = $yEnd * 0.92;
my $xAxis = $xAreaEnd - $xCor;
my $yAxis = $yAreaEnd - $yCor;
$xsize = $self->{xsize} * $self->{size};
$ysize = $self->{ysize} * $self->{size};
$str = "q\n"; # save graphic state
$str .= "3 M\n"; # miter limit
OverlayChart.pm view on Meta::CPAN
while ($skala <= $rightMax)
{ my $yPos = $rightFactor * $skala + $y0;
if (($yPos - $last) > 13)
{ if (! $self->{nounits})
{ $str .= "BT\n";
$str .= "/$font 12 Tf\n";
$str .= "$rx4 $yPos Td\n";
$str .= "($skala)Tj\n";
$str .= "ET\n";
}
$last = $yPos;
$str .= "$rx1 $yPos m\n";
$str .= "$rx3 $yPos l\n";
$str .= "b*\n";
}
$skala += $langd;
}
$last = $rightFactor * $langd + $y0;
$skala = 0;
while ($skala >= $rightMin)
{ my $yPos = $rightFactor * $skala + $y0;
if (($last - $yPos) > 13)
{ if (! $self->{nounits})
{ $str .= "BT\n";
$str .= "/$font 12 Tf\n";
$str .= "$rx4 $yPos Td\n";
$str .= "($skala)Tj\n";
$str .= "ET\n";
}
$last = $yPos;
$str .= "$rx1 $yPos m\n";
$str .= "$rx3 $yPos l\n";
$str .= "b*\n";
}
$skala -= $langd;
}
if ((defined $rightScale->{marginAction})
&& (defined $self->{iparam}))
{ $rightScale->insert( $xAreaEnd,
0,
35,
$yArrow,
$self->{iparam},
$rightScale->{marginAction},
$rightScale->{marginToolTip});
}
}
$str .= "0 0 0 RG\n";
my $col1 = 0.9;
my $col2 = 0.4;
my $col3 = 0.9;
srand(9);
my $tStart = $xStart + 20;
unshift @array, $self;
for my $overlay (@array)
{ if (defined $overlay->{groupstitle})
{ my $yTemp = $yStart;
if ($yTemp < ($y0 + 20))
{ $yTemp = $y0 - 20;
$yStart = $yTemp - 20;
}
$str .= "0 0 0 rg\n";
$str .= "BT\n";
$str .= "/$font 12 Tf\n";
$str .= "$xStart $yTemp Td\n";
$str .= '(' . $overlay->{groupstitle} . ') Tj' . "\n";
$str .= "ET\n";
$yStart -= $iStep;
}
if (defined $overlay->{groupstext})
{ my $yTemp = $yStart;
if ($yTemp < ($y0 + 20))
{ $yTemp = $y0 - 20;
$yStart = $yTemp - 20;
}
$str .= "0 0 0 rg\n";
$str .= "BT\n";
$str .= "/$font 12 Tf\n";
$str .= "$xStart $yTemp Td\n";
$str .= '(' . $overlay->{groupstext} . ') Tj' . "\n";
$str .= "ET\n";
$yStart -= $iStep;
}
my @color = (defined $overlay->{color}) ? @{$overlay->{color}} : ();
my $groups = $#{$overlay->{sequence}} + 1;
for (my $i = 0; $i < $groups; $i++)
{ if (! defined $color[$i])
{ $col1 = $col3;
my $alt1 = sprintf("%.2f", (rand(1)));
my $alt2 = sprintf("%.2f", (rand(1)));
$col2 = abs($col2 - $col3) > abs(1 - $col3) ? $col3 : (1 - $col3);
$col3 = abs($col3 - $alt1) > abs($col3 - $alt2) ? $alt1 : $alt2;
$color[$i] = "$col1 $col2 $col3";
}
if ((defined $overlay->{nogroups}) && ($overlay->{nogroups}))
{ next;
}
my $name = $overlay->{sequence}->[$i];
$str .= "$color[$i] rg\n";
if (($yStart < ($y0 + 13)) && ($yStart > ($y0 - 18)))
{ $yStart = $y0 - 20;
}
$str .= "$xStart $yStart 10 7 re\n";
$str .= "b*\n";
$str .= "0 0 0 rg\n";
$str .= "BT\n";
$str .= "/$font 12 Tf\n";
$str .= "$tStart $yStart Td\n";
if ($name)
{ $str .= '(' . $name . ') Tj' . "\n";
}
else
{ $str .= '(' . $i . ') Tj' . "\n";
}
$str .= "ET\n";
if ((defined $self->{iparam})
&& (defined $overlay->{boxAction}->{$name}))
{ $overlay->insert($xStart,
$yStart,
10,
7,
$self->{iparam},
$overlay->{boxAction}->{$name},
$overlay->{boxToolTip}->{$name});
}
$yStart -= $iStep;
}
@{$overlay->{color}} = @color;
}
for my $overlay ( reverse @array)
{ $str .= "0 0 0 RG\n0 j\n0 J\n";
if ($overlay->{type} eq 'bars')
{ $str .= $overlay->draw_bars($xSteps, $xCor, $y0, $labelStep, $prop);
}
elsif ($overlay->{type} eq 'totalbars')
{ $str .= $overlay->draw_totalbars($xSteps, $xCor, $y0, $labelStep, $prop);
}
elsif ($overlay->{type} eq 'lines')
{ $str .= $overlay->draw_lines($xSteps, $xCor, $yCor, $labelStep, $prop, $min);
}
elsif ($overlay->{type} eq 'percentbars')
{ $str .= $overlay->draw_percentbars($xSteps, $xCor, $y0, $labelStep, $prop);
}
elsif ($overlay->{type} eq 'area')
{ $str .= $overlay->draw_area($xSteps, $xCor, $y0, $labelStep, $prop);
}
}
$str .= "Q\n";
PDF::Reuse::prAdd($str);
return $self;
}
sub draw_bars
{ my $self = shift;
my ($xSteps, $xCor, $y0, $labelStep, $prop) = @_;
if ($self->{level} ne 'top')
{ if ($self->{ydensity} != 1)
{ $prop = sprintf("%.5f", ($prop / $self->{ydensity}));
}
if ($self->{xdensity} != 1)
{ $labelStep = sprintf("%.5f", ($labelStep / $self->{xdensity}));
}
}
my $string = '';
my @color = @{$self->{color}};
my $groups = $#{$self->{sequence}} + 1;
my $width = sprintf("%.5f", ($labelStep / $groups ));
for (my $j = 0; $j <= $xSteps; $j++)
{ my $height;
my $i = -1;
for my $namn (@{$self->{sequence}})
{ $i++;
if (defined $self->{series}->{$namn}->[$j])
{ if (ref($self->{series}->{$namn}->[$j]) eq 'ARRAY')
{ my $number = $#{$self->{series}->{$namn}->[$j]} + 1;
my $fraction = sprintf("%.4f", ($width / $number));
my @actions = (ref($self->{barAction}->{$namn}->[$j]) eq 'ARRAY') ?
@{$self->{barAction}->{$namn}->[$j]} : ();
my @toolTips = (ref($self->{barToolTip}->{$namn}->[$j]) eq 'ARRAY')
? @{$self->{barToolTip}->{$namn}->[$j]} : ();
my $k = 0;
for (@{$self->{series}->{$namn}->[$j]})
{ if (! defined $_)
{ $xCor += $fraction;
$k++;
next;
}
$height = sprintf("%.5f", ($_ * $prop));
$string .= "$color[$i] rg\n";
$string .= "$xCor $y0 $fraction $height re\n";
$string .= "b*\n";
if ((defined $self->{iparam})
&& (defined $actions[$i]))
{ $self->insert( $xCor,
$y0,
$fraction,
$height,
$self->{iparam},
$actions[$i],
$toolTips[$i]);
}
$xCor += $fraction;
OverlayChart.pm view on Meta::CPAN
=item size
A number to resize the graph, with lines, texts and everything
(If you change the size of a graph with the parameters width and height, the
font sizes, distances between lines etc. are untouched, but with 'size' they
also change.)
=item xsize
A number to resize the graph horizontally, with lines, texts and everything
=item ySize
A number to resize the graph vertically, with lines, texts and everything
=item type
By default: 'bars'. Can also be 'totalbars', percentbars', 'lines' and 'area',
(you could abbreviate to the first character if you want).
When you have 'lines' or 'area', you get vertical lines. They show where the
values of the graph are significant. The values between these points are possible,
but of course not necessarily true. It is an illustration.
=item yUnit
What to write above the y-axis
=item background
Three RGB numbers ex. '0.95 0.95 0.95'.
=item noUnits
If this parameter is equal to 1, no units are written.
=item title
Title above the chart
=item groupsTitle
Titel above the column to the right of the chart
=item groupsText
Text under groupsTitle
=item initialMaxY
To force the program start with a specific max (positive) value for the scale along the y-axis.
=item initialMinY
To force the program start with a specific min (negative) value for the scale along the y-axis.
=item merge
To merge different graph-objects into one chart. The graph-objects should be put
in an anonymous array. Each graph-object should use the "overlay" method.
Ex :
$val->draw(x => 20,
y => 460,
width => 400,
height => 300,
type => 'lines',
noMarker => 1,
groupstitle => 'Left Scale',
title => 'Amazon',
yUnit => 'USD',
merge => [ $sek->overlay ( type => 'lines',
yDensity => $sekDensity,
noMarker => 1),
$spIndex->overlay( type => 'lines',
yDensity => $spDensity,
noMarker => 1),
$vol->overlay ( type => 'area',
rightScale => 1,
yDensity => $volumeDensity,
groupstitle => 'Right Scale'),] );
In the example above 4 objects are combined into 1 chart. Each object can have its'
own density (but it is not necessary) and some other characteristics described under
"overlay". The objects are painted in reversed order: $vol, $spIndex, $sek and at
last $val, which automatically gets the left scale and also the normative density
of the chart. (Interactive functions for each object are also imported.)
The merge parameter is ignored, if the type of the main object is percentbars
=item noMarker
Only for lines. No markers will be painted.
=item noGroups
To suppress the names of the groups, so they will not be printed to the right of
the chart.
=back
=head2 color
$s->color( ('1 1 0', '0 1 1', '0 1 0', '1 0 0', '0 0 1'));
To define colors to be used. The parameter to this method is a list of RGB numbers.
You can also use some predefined color arrays: 'bright', 'dark', 'gray' or 'light',
but only one at a time. Then you get 10 predefined colors ex:
$s-color('dark');
If the module needs more colors than what has been given in the script,
it creates more, just from random numbers.
=head2 overlay
Defines how an imported graph-object should be painted. See the parameter merge
under draw for an example.
Parameters:
=over 4
=item type
Can be bars, totalbars, lines and area, but not percentbars.
=item rightScale
If many objects have this parameter, only the first object will have a right scale
painted, and the "yDensity" of the scale will be derived from that object.
=item topScale
If many objects have this parameter, only the first object will have a top scale
painted, and the "xDensity" of the scale will be derived from that object. If
that object has some column labels defined (with the columns method), they will
also be used here.
=item noMarker
Only for lines. No markers will be painted.
=item noGroups
To suppress the names of the groups, so they will not be printed to the right of
the chart.
=item xDensity
Density along the x-axis, a numeric value, possibly with decimals. If it is 10, it
denotes that 10 units along the x-axis in this sub chart corresponds to 1 unit in
the main chart. If it is 0.1, 1 unit in this chart corresponds to 10 units in the
main chart
=item yDensity
Density along the y-axis, a numeric value, possibly with decimals. If it is 10, it
denotes that 10 units along the y-axis in this sub chart corresponds to 1 unit in
the main chart.
=back
=head1 A simple example
An invented company with a few offices.
=for general.pl begin
use PDF::Reuse::OverlayChart;
use PDF::Reuse;
use strict;
prFile('myFile.pdf');
prCompress(1);
OverlayChart.pm view on Meta::CPAN
$costs->columns( qw(Month January February Mars April May June July));
$costs->add( qw(Riga -316 -290 -376 -823 -243 -320 -509));
$costs->add( qw(Helsinki -440 -830 -989 -671 -170 -394 -618));
$costs->add( qw(Stockholm -218 -345 -242 -467 -412 -299 -590));
$costs->add( qw(Oslo -369 -343 -567 -589 -390 -258 -459));
$costs->draw(x => 45,
y => 55,
yUnit => '1000 Euros',
type => 'bars',
title => 'Costs',
height => 300,
width => 460);
####################################
# The costs are added to 'money in'
####################################
$s->add( qw(Riga -316 -290 -376 -823 -243 -320 -509));
$s->add( qw(Helsinki -440 -830 -989 -671 -170 -394 -618));
$s->add( qw(Stockholm -218 -345 -242 -467 -412 -299 -590));
$s->add( qw(Oslo -369 -343 -567 -589 -390 -258 -459));
prPage();
$s->draw(x => 45,
y => 455,
yUnit => '1000 Euros',
type => 'bars',
title => 'Profit');
########
# Taxes
########
$s->add( qw(Riga -116 -90 -179 -230 -43 -20 -90));
$s->add( qw(Helsinki 40 -130 -190 -32 -70 -30 -18));
$s->add( qw(Stockholm 28 -45 -42 -107 -92 -99 -90));
$s->add( qw(Oslo -169 -43 -67 -189 -190 -58 -59));
$s->draw(x => 45,
y => 55,
yUnit => '1000 Euros',
type => 'bars',
title => 'After Tax');
prEnd();
=for end
=head1 An example how to mix different graph types in the same chart
In this example you let a program collect historical quotes for 'Amazon', approximately
1 year back, and also values for 'S&P 100' and then you get a chart with combined
data, an area graph for volumes, and lines for the other values. (You need to have the
environment variable TZ defined somewhere, see Date::Manip, which is a module needed by
Finance::QuoteHist. TZ, time zone, could e.g. be CET or GMT in Western Europe.)
=for overlay.pl begin
use PDF::Reuse::OverlayChart;
use Finance::QuoteHist;
use PDF::Reuse;
use strict;
#################
# Some variables
#################
my (%values, @values, %volumes, @volumes, %sp100, @sp100, $startValue,
$startSpValue);
my $maxVolume = 0;
my $maxValue = 0;
my $month = sprintf("%02d", ((localtime())[4]) + 1);
my $lastYear = sprintf("%04d", ((localtime())[5] + 1900 - 1));
my $aYearAgo = "$month/01/$lastYear";
prFile('myFile.pdf');
prCompress(1);
###########################################################
# Get historical quotes via the web for Amazon and S&P100
###########################################################
my $q = Finance::QuoteHist->new ( symbols => [qw(AMZN ^OEX)],
start_date => $aYearAgo,
end_date => 'today',);
##################################
# Accumulate the values in hashes
##################################
for my $row ($q->quotes())
{ my ($symbol, $date, $open, $high, $low, $close, $volume) = @$row;
if ($date =~ m'(\d+\/\d+)\/(\d+)'o)
{ my $yearMonth = $1;
my $day = $2;
if ($symbol ne '^OEX')
{ $volume = sprintf("%.0f", ($volume / 1000000));
$values{$yearMonth}->[$day] = $close if ($close);
$volumes{$yearMonth}->[$day] = $volume if ($volume);
$maxVolume = $volume if $volume > $maxVolume;
$maxValue = $close if $close > $maxValue;
$startValue = $close if (! defined $startValue);
}
else
{ $sp100{$yearMonth}->[$day] = $close if ($close);
$startSpValue = $close if (!defined $startSpValue);
}
}
}
my @keys = sort (keys %volumes);
my $i;
##########################################
# Make one array of arrays of the volumes
##########################################
for my $key (@keys)
OverlayChart.pm view on Meta::CPAN
}
push @values, [@array];
}
##########################################################
# Make one array of arrays of the closing values of SP100
##########################################################
for my $key (@keys)
{ my @array;
for (@{$sp100{$key}})
{ push @array, $_ if $_;
}
for ($i = $#array; $i < 18; $i++)
{ push @array, undef;
}
push @sp100, [@array];
}
#########################################################################
# Calculate a suitable density for the volumes so they fill up the chart
#########################################################################
my $volumeDensity = sprintf("%.6f", ($maxVolume / $maxValue));
################################################################
# Make the density for S&P 100 so it gets a good starting point
################################################################
my $spDensity = sprintf("%.1f", ($startSpValue / $startValue));
########################################
# Create and populate the chart-objects
########################################
my $vol = PDF::Reuse::OverlayChart->new();
$vol->add('Volume (1/1000000)', ( @volumes ));
$vol->color('dark');
my $val = PDF::Reuse::OverlayChart->new();
$val->columns('Month', ( @keys ) );
$val->add('Closing Value USD', ( @values ));
$val->color('bright');
my $spIndex = PDF::Reuse::OverlayChart->new();
$spIndex->add("S&P 100 (1/$spDensity)", ( @sp100 ));
$spIndex->color( ('0 0 0') );
#####################
# Now draw the chart
#####################
$val->draw(x => 20,
y => 460,
width => 400,
height => 300,
type => 'lines',
noMarker => 1,
groupstitle => 'Left Scale',
title => 'Amazon',
merge => [ $spIndex->overlay( type => 'lines',
yDensity => $spDensity,
noMarker => 1),
$vol->overlay ( type => 'area',
rightScale => 1,
yDensity => $volumeDensity,
groupstitle => 'Right Scale')] );
prEnd();
=for end
Comments about the example:
All the values are put in arrays of arrays like this:
[ [day1 ... dayN], # This is the first month
[day1 ... dayN], # Next month
...
[day1 ... dayN]] # Last month
In the chart there will be one column for each month. The column labels will be
taken from the main object.
The 3 different chart-objects have different density along the y-axis
(yDensity). The main chart-object, '$val', gets a value automatically calculated.
It cannot be directly influenced. The other objects can get a yDensity defined.
Then it is always related to the main object. To make the S&P 100 index start in
the same point as the first closing value for Amazon ($startValue), the yDensity for
the index-graph is calculated like this:
my $spDensity = sprintf("%.1f", ($startSpValue / $startValue));
To make the graph for volumes fill the chart, the maximum values are coordinated
in a similar way:
my $volumeDensity = sprintf("%.6f", ($maxVolume / $maxValue));
When the combined chart is drawn, the charts are painted in reversed order, so the
main cart is pained last. It also automatically gets the left scale.
=head1 SEE ALSO
PDF::Reuse
PDF::Reuse::Tutorial
=head1 MAILING LIST
http://groups.google.com/group/PDF-Reuse
=head1 AUTHOR
Lars Lundberg, larslund@cpan.org
=head1 COPYRIGHT AND LICENSE
Copyright (C) 2004 - 2005 by Lars Lundberg
This library is free software; you can redistribute it and/or modify
it under the same terms as Perl itself.
=head1 DISCLAIMER
( run in 2.312 seconds using v1.01-cache-2.11-cpan-39bf76dae61 )