App-RecordStream
view release on metacpan or search on metacpan
lib/App/RecordStream/Operation/togdgraph.pm view on Meta::CPAN
package App::RecordStream::Operation::togdgraph;
our $VERSION = "4.0.25";
use strict;
use warnings;
use App::RecordStream::OptionalRequire qw(GD::Graph::lines);
use App::RecordStream::OptionalRequire qw(GD::Graph::bars);
use App::RecordStream::OptionalRequire qw(GD::Graph::points);
App::RecordStream::OptionalRequire::require_done();
use base qw(App::RecordStream::Operation);
my $GD_TYPES = {
'line' => 'lines',
'scatter' => 'points',
'bar' => 'bars'
};
sub init {
my $this = shift;
my $args = shift;
my $png_file = 'togdgraph.png';
my $title;
my $label_x;
my $label_y;
my @additional_options;
my $graph_type = 'scatter';
my $width = 600;
my $height = 300;
my $dump_use_spec;
my $key_groups = App::RecordStream::KeyGroups->new();
my $cmdspec = {
'key|k|fields|f=s' => sub { $key_groups->add_groups($_[1]); },
'option|o=s' => sub { push @additional_options, [split(/=/, $_[1])]; },
'label-x=s' => \$label_x,
'label-y=s' => \$label_y,
'graph-title=s' => \$title,
'png-file=s' => \$png_file,
'type=s' => \$graph_type,
'width=i' => \$width,
'height=i' => \$height,
'dump-use-spec' => \$dump_use_spec
};
$this->parse_options($args, $cmdspec);
if ( ! $GD_TYPES->{$graph_type} ) {
die "Unsupported graph type: $graph_type\n";
}
$this->{'DUMP_USE_SPEC'} = $dump_use_spec;
$this->{'LABEL_X'} = $label_x;
$this->{'LABEL_Y'} = $label_y;
$this->{'TITLE'} = $title unless !$this->{'TITLE'};
$this->{'GDGRAPH_OPTIONS'} = \@additional_options;
$this->{'KEYGROUPS'} = $key_groups;
$this->{'FIRST_RECORD'} = 1;
$this->{'GRAPH_TYPE'} = $graph_type;
$this->{'WIDTH'} = $width;
$this->{'HEIGHT'} = $height;
$this->{'PNG_FILE'} = $png_file;
if ( $dump_use_spec ) {
$this->push_line('x label: '.$title) unless !$this->{'LABEL_X'};
$this->push_line('y label: '.$title) unless !$this->{'LABEL_Y'};
$this->push_line('title: '.$title) unless !$this->{'TITLE'};
$this->push_line('type: '.$graph_type);
$this->push_line('width: '.$width);
$this->push_line('height: '.$height);
$this->push_line('output file: '.$png_file);
}
}
sub init_fields {
my ($this, $record) = @_;
my $specs = $this->{'KEYGROUPS'}->get_keyspecs($record);
if ( $this->{'DUMP_USE_SPEC'} ) {
foreach my $sfield (@{$specs}) {
$this->push_line('field: '.$sfield);
}
}
$this->{'FIELDS'} = $specs;
$this->{'PLOTDATA'} = ();
foreach my $fkey (@{$this->{'FIELDS'}}) {
$this->{'PLOTDATA'}->{$fkey} = [];
}
}
sub accept_record {
my $this = shift;
my $record = shift;
if ( $this->{'FIRST_RECORD'} ) {
$this->{'FIRST_RECORD'} = 0;
$this->init_fields($record);
}
my @record_spec;
foreach my $key (@{$this->{'FIELDS'}}) {
push @{$this->{'PLOTDATA'}->{$key}}, $record->{$key};
push @record_spec, $record->{$key};
}
if ( $this->{'DUMP_USE_SPEC'} ) {
$this->push_line(join(' ',@record_spec));
}
return 1;
}
sub stream_done {
my $this = shift;
my $gdhnd;
my $w = $this->{'WIDTH'};
my $h = $this->{'HEIGHT'};
my $gtype = 'GD::Graph::'.$GD_TYPES->{$this->{'GRAPH_TYPE'}};
$gdhnd = $gtype->new($w,$h);
$gdhnd->set(
x_label => $this->{'LABEL_X'},
y_label => $this->{'LABEL_Y'}
);
if ( $this->{'TITLE'} ) {
$gdhnd->set( title => $this->{'TITLE'} );
}
foreach my $kv (@{$this->{'GDGRAPH_OPTIONS'}}) {
$gdhnd->set( $kv->[0] => $kv->[1] );
}
my @data;
if ( scalar(keys %{$this->{'PLOTDATA'}}) == 1 ) {
my @hkey = keys(%{$this->{'PLOTDATA'}});
my $arrsize = scalar @{$this->{'PLOTDATA'}->{$hkey[0]}};
push @data, [ 1 .. $arrsize ];
push @data, $this->{'PLOTDATA'}->{$hkey[0]};
} else {
for my $field (@{$this->{'FIELDS'}}) {
push @data, $this->{'PLOTDATA'}->{$field};
}
}
my $gd = $gdhnd->plot(\@data);
if ( !$gd ) {
print "could not plot data\n";
exit;
}
open(IMG, '>', $this->{'PNG_FILE'}) or die "Could not open file for writing $this->{PNG_FILE}: $!";
binmode IMG;
print IMG $gd->png;
close IMG;
}
sub add_help_types {
my $this = shift;
$this->use_help_type('keyspecs');
$this->use_help_type('keygroups');
$this->use_help_type('keys');
}
sub usage {
my $this = shift;
my $options = [
['key|-k|--key <keyspec>', 'Specify keys that correlate to keys in JSON data'],
['option|-o option=val', 'Specify custom command for GD::Graph'],
['label-x <val>', 'Specify X-axis label'],
['label-y <val>', 'Specify Y-axis label'],
['width <val>', 'Specify width'],
['height <val>', 'Specify height'],
['graph-title <val>', 'Specify graph title'],
['type <val>', 'Specify different graph type other than scatter (supported: line, bar)'],
['png-file <val>', 'Specify output PNG filename'],
['dump-use-spec <val>', 'Dump GD usage (used mainly for testing)']
];
my $args_string = $this->options_string($options);
return <<USAGE;
Usage: recs-togdgraph <args> [<files>]
__FORMAT_TEXT__
Create a bar, scatter, or line graph using GD::Graph.
__FORMAT_TEXT__
Args:
$args_string
Examples:
for a plain point graph:
recs-togdgraph --keys uid,ct --png-file login-graph.png --graph-title '# of logins' --label-x user --label-y logins
togdgraph also accepts any GD::Graph options with the --option command...
for a pink background with yellow label text if that really is your thing:
recs-togdgraph --keys uid,ct --option boxclr=pink --label-y 'logins' --label-x 'user' --option labelclr=yellow
however, for a different graph type such as line or bar, specify with --type:
recs-togdgraph --keys uid,ct --type line
USAGE
}
1;
( run in 0.700 second using v1.01-cache-2.11-cpan-df04353d9ac )