Apache-Wyrd
view release on metacpan or search on metacpan
Wyrd/Chart.pm view on Meta::CPAN
<BASENAME::Chart img="chart.png" type="bars" height="200" width="300">
<BASENAME::Query>
select month, price
from monthly_prices
order by month
</BASENAME::Query>
</BASENAME::Chart>
=head1 DESCRIPTION
Chart-graphic Wyrd wrapping the C<GD::Graph> Module. Creates a graphic file
(PNG) and a meta-data file based on data handed it to by an
C<Apache::Wyrd::Query> Wyrd.
=head2 HTML ATTRIBUTES
The Chart Wyrd accepts nearly all the attributes of the GD::Graph module and the
E<lt>imgE<gt> tag, producing an E<lt>imgE<gt> tag which points to the
graphic file produced by GD::Graph, having most attributes (such as onClick,
border, but not src) given to the Chart Wyrd.
=over
=item Wyrd attributes:
=over
=item data_col
Which column of the query to plot. Default: 2.
=item labels
A comma or whitespace-separated list of label names. If not enough labels
are given, the remainder will be labeled "unknown"
=item label_col
Which column of the query to use for labels. Default: 1.
=item other_limit
Items with values under this number will be lumped together under the item
name "Other".
=item label_filters, value_filters
A whitespace or comma delineated list of builtin filters to apply to the
labels or values respectively. Current filters:
=over
=item zero
Replace undefined values with 0.
=item dollar_sign
Put a dollar sign to the left
=item percent_sign
Put a percent sign to the right
=item commify
Put numbers into (north american style) comma splits, i.e. 3,000,000 for 3E6
=back
=item Flags
=over
=item nochache
Always generate the graphic, instead of checking to see if it has changed
=item percent
Convert values to percentages of total
=item rotate
Pivot the table returned by the query to make X Y and vice-versa
=item value_labels
Add the value to the label, as in "Foobars (2), Widgets (23)"
=back
=back
=over
=item IMG-style attributes:
=over
=item height, width, vspace, border, hspace
In pixels, as per IMG tag
=item src
Required - Where (document-root-relative) the graphic is to appear.
Currently must end with .png.
=back
=item GD::Graph-style attributes
See GD::Graph documentation for more details. Files are always
document-root-relative. Colors may be in GD::Graph name format or in in
HTML "#XXXXXX" format. Edge-positions are in the GD::Graph standard of UL
for Upper-Left, LL for Lower-Left, etc. 1 is the usual value for "yes" in
boolean attributes. Lists are in a whitespace-separated or comma-separated
list of items (using Apache::Wyrd::Services::SAK::token_parse). Angles are
in degrees.
=over
=item type
What type of graph, per the GD::Graph subclasses. Valid types are: lines,
hbars, bars, points, linespoints, area, or pie
=item b_margin t_margin l_margin r_margin
edge-to-graphic margins
=item transparent interlaced
PNG options
=item bgclr fgclr boxclr textclr labelclr axislabelclr legendclr valuesclr
accentclr shadowclr
Colors for the respective chart elements
Wyrd/Chart.pm view on Meta::CPAN
$data[1] = $data[$self->{'data_col'} - 1];
$truncate ||= 1;
}
if ($self->_flags->by_value) {
my @labels = ();
my @values = ();
my $count = 0;
foreach my $datum (
sort {lc($a->[1]) cmp lc($b->[1]) || $a->[1] <=> $b->[1]}
map {[$data[0]->[$_], $data[1]->[$_]]}
map {$count++}
@{$data[0]}
) {
#warn Dumper($datum);
push @labels, $datum->[0];
push @values, $datum->[1];
}
@data = (\@labels, \@values);
#warn Dumper(\@data);
$truncate ||= 1;
} elsif ($self->_flags->by_label) {
my @labels = ();
my @values = ();
my $count = 0;
foreach my $datum (
sort {lc($a->[0]) cmp lc($b->[0]) || $_->[0] <=> $_->[0]}
map {[$data[0]->[$_], $data[1]->[$_]]}
map {$count++}
@{$data[0]}
) {
#warn Dumper($datum);
push @labels, $datum->[0];
push @values, $datum->[1];
}
@data = (\@labels, \@values);
$truncate ||= 1;
}
if ($self->{'other_limit'}) {
my $other = 0;
my $limit_reached = 0;
my @labels = ();
my @values = ();
foreach my $value (@{$data[1]}) {
my $label = shift @{$data[0]};
if ($value < $self->{'other_limit'}) {
$limit_reached = 1;
$other += $value;
#warn "name: $label, value: $value, total: $other";
} else {
push @labels, $label;
push @values, $value
}
}
if ($limit_reached) {
$truncate = 1;
push @labels, "Other";
push @values, $other;
@data = (\@labels, \@values);
}
}
if ($self->_flags->percent) {
foreach my $line (1 .. $#data) {
my $sum = 0;
map {$sum += $_} @{$data[$line]};
my $count = 0;
my $total = 0;
foreach my $item (@{$data[0]}) {
$data[$line][$count] = int((($data[1][$count]/$sum) * 100) + .5);
$count++;
}
}
}
if ($self->_flags->value_labels) {
$truncate ||= 1;
my $count = 0;
my $percent = '';
$percent = '%' if ($self->_flags->percent);
map {$data[0][$count] = $data[0][$count] . " ($_$percent)"; $count++} @{$data[1]};
}
} else {
if ($self->_flags->rotate) {
my @new = ();
my $size = scalar(@{$data[0]});
for (my $i = 0; $i < $size; $i++) {
my @outline = ();
foreach my $datum (@data) {
push @outline, $datum->[$i];
}
push @new, [@outline];
}
@data = @new;
}
if ($self->{'labels'}) {
my @label = ();
my @given_label = token_parse($self->{'labels'});
my $count = scalar(@{$data[0]});
for (my $item = 0; $item < $count; $item++) {
$label[$item] = ($given_label[$item] || 'unknown');
}
unshift @data, \@label;
}
}
if ($truncate) {
$self->_error("This chart cannot be represented as a series due to other parameters you have chosen.")
if ($self->_flags->series);
if ($truncate > 1) {
$data[0] = [splice(@{$data[0]}, 0, $truncate + 1)];
$data[1] = [splice(@{$data[1]}, 0, $truncate + 1)];
}
@data = ($data[0],$data[1]);
}
$self->{'_graph_data'} = \@data;
$self->_filter_labels if ($self->{'label_filters'});
$self->_filter_values if ($self->{'value_filters'});
}
sub _filter_labels {
my ($self) = @_;
my @labels = ();
my @filters = token_parse($self->{'label_filters'});
foreach my $filter (@filters) {
my @filtered = ();
my @labels = @{$self->{'_graph_data'}->[0]};
foreach my $label (@labels) {
push @filtered, $self->_filter($filter, $label);
}
$self->{'_graph_data'}->[0] = \@filtered;
}
}
sub _filter_values {
my ($self) = @_;
my @values = ();
my @filters = token_parse($self->{'value_filters'});
for (my $line = scalar(@{$self->{'_graph_data'}}); $line > 1; $line--) {
foreach my $filter (@filters) {
my @filtered = ();
my @values = @{$self->{'_graph_data'}->[$line - 1]};
foreach my $value (@values) {
push @filtered, $self->_filter($filter, $value);
}
$self->{'_graph_data'}->[$line - 1] = \@filtered;
}
}
}
sub _filter {
my ($self, $filter, $value) = @_;
if ($filter eq 'zero') {
return '0' unless $value;
} elsif ($filter eq 'dollar_sign') {
return '$' . $value;
} elsif ($filter eq 'percent_sign') {
return "$value%";
} elsif ($filter eq 'commify') {
1 while ($value =~ s/^([-+]?\d+)(\d{3})/$1,$2/);
return $value;
}else {
return $self->_special_filter($filter, $value);
}
}
=pod
=item (scalar) C<_special_filter> (scalar, scalar)
"Hook" for filtering data/labels. Should accept a value for the filter and
the data to perform filters upon.
=cut
sub _special_filter {
my ($self, $filter, $value) = @_;
return $value;
}
=pod
=back
=head1 BUGS/CAVEATS/RESERVED METHODS
Reserves the register_filter, _setup and _format_output methods. Also
reserves the methods _set_default_attributes, _get_data, _process_data,
_filter_labels, _filter_values, _filter. Also reserves the standard
register_query method.
Produces, by default, a second file (E<lt>graphic_nameE<gt>.tdf) in the same
directory as the graphic which has the HTML fingerprint and the data stored
in tab-delineated-text format.
=cut
sub _setup {
my ($self) = @_;
$self->{'_valid_attributes'} = {
'img' => [qw(align alt border height hspace ismap longdesc usemap vspace width src)],
'all' => [qw(b_margin t_margin l_margin r_margin transparent interlaced bgclr fgclr boxclr textclr labelclr axislabelclr legendclr valuesclr accentclr shadowclr dclrs show_values values_vertical values_space values_format logo logo_position logo_...
'axes' => [qw(x_label y_label box_axis two_axes zero_axis zero_axis_only x_plot_values y_plot_values y_max_value y_min_value x_tick_number x_min_value x_tick_number x_min_value x_max_value y_number_format x_label_skip y_label_skip x_tick_offset x...
'bars' => [qw(overwrite bar_width bar_spacing shadow_depth borderclrs cycle_clrs cumulate)],
'lines' => [qw(line_types line_type_scale line_width skip_undef)],
'points' => [qw(markers marker_size)],
'pie' => [qw(3d pie_height start_angle suppress_angle)],
'builtin_fonts' => [qw(gdTinyFont gdSmallFont gdMediumBoldFont gdLargeFont gdGiantFont)],
'font_attr' => [qw(legend_font title_font x_label_font y_label_font x_axis_font y_axis_font)],
'font_attr_pie' => [qw(legend_font title_font label_font value_font)],
'color_attr' => [qw(bgclr fgclr boxclr textclr labelclr axislabelclr legendclr valuesclr accentclr shadowclr dclrs)],
'array_attr' => [qw(dclrs markers)],
'boolean_attr' => [qw(transparent interlaced show_values values_vertical box_axis two_axes zero_axis zero_axis_only x_plot_values y_plot_values x_all_ticks x_labels_vertical long_ticks x_ticks correct_width cycle_clrs cumulate skip_undef 3d)]
};
$self->{'_chart_attributes'} = [];
$self->_set_default_attributes;
}
( run in 0.674 second using v1.01-cache-2.11-cpan-364913b4093 )