File Coverage

blib/lib/App/RecordStream/Operation/togdgraph.pm
Criterion Covered Total %
statement 18 119 15.1
branch 0 26 0.0
condition n/a
subroutine 6 14 42.8
pod n/a
total 24 159 15.0


line stmt bran cond sub pod time code
1             package App::RecordStream::Operation::togdgraph;
2              
3             our $VERSION = "4.0.25";
4              
5 1     1   756 use strict;
  1         2  
  1         21  
6 1     1   4 use warnings;
  1         2  
  1         19  
7              
8 1     1   5 use App::RecordStream::OptionalRequire qw(GD::Graph::lines);
  1         2  
  1         4  
9 1     1   4 use App::RecordStream::OptionalRequire qw(GD::Graph::bars);
  1         1  
  1         3  
10 1     1   4 use App::RecordStream::OptionalRequire qw(GD::Graph::points);
  1         2  
  1         4  
11             App::RecordStream::OptionalRequire::require_done();
12              
13 1     1   5 use base qw(App::RecordStream::Operation);
  1         2  
  1         874  
14              
15             my $GD_TYPES = {
16             'line' => 'lines',
17             'scatter' => 'points',
18             'bar' => 'bars'
19             };
20              
21             sub init {
22 0     0     my $this = shift;
23 0           my $args = shift;
24              
25 0           my $png_file = 'togdgraph.png';
26 0           my $title;
27             my $label_x;
28 0           my $label_y;
29 0           my @additional_options;
30 0           my $graph_type = 'scatter';
31 0           my $width = 600;
32 0           my $height = 300;
33              
34 0           my $dump_use_spec;
35              
36 0           my $key_groups = App::RecordStream::KeyGroups->new();
37              
38             my $cmdspec = {
39 0     0     'key|k|fields|f=s' => sub { $key_groups->add_groups($_[1]); },
40 0     0     'option|o=s' => sub { push @additional_options, [split(/=/, $_[1])]; },
41 0           'label-x=s' => \$label_x,
42             'label-y=s' => \$label_y,
43             'graph-title=s' => \$title,
44             'png-file=s' => \$png_file,
45             'type=s' => \$graph_type,
46             'width=i' => \$width,
47             'height=i' => \$height,
48             'dump-use-spec' => \$dump_use_spec
49             };
50 0           $this->parse_options($args, $cmdspec);
51              
52 0 0         if ( ! $GD_TYPES->{$graph_type} ) {
53 0           die "Unsupported graph type: $graph_type\n";
54             }
55              
56 0           $this->{'DUMP_USE_SPEC'} = $dump_use_spec;
57              
58 0           $this->{'LABEL_X'} = $label_x;
59 0           $this->{'LABEL_Y'} = $label_y;
60 0 0         $this->{'TITLE'} = $title unless !$this->{'TITLE'};
61              
62 0           $this->{'GDGRAPH_OPTIONS'} = \@additional_options;
63 0           $this->{'KEYGROUPS'} = $key_groups;
64 0           $this->{'FIRST_RECORD'} = 1;
65              
66 0           $this->{'GRAPH_TYPE'} = $graph_type;
67 0           $this->{'WIDTH'} = $width;
68 0           $this->{'HEIGHT'} = $height;
69 0           $this->{'PNG_FILE'} = $png_file;
70              
71 0 0         if ( $dump_use_spec ) {
72 0 0         $this->push_line('x label: '.$title) unless !$this->{'LABEL_X'};
73 0 0         $this->push_line('y label: '.$title) unless !$this->{'LABEL_Y'};
74 0 0         $this->push_line('title: '.$title) unless !$this->{'TITLE'};
75 0           $this->push_line('type: '.$graph_type);
76 0           $this->push_line('width: '.$width);
77 0           $this->push_line('height: '.$height);
78 0           $this->push_line('output file: '.$png_file);
79             }
80             }
81              
82             sub init_fields {
83 0     0     my ($this, $record) = @_;
84              
85 0           my $specs = $this->{'KEYGROUPS'}->get_keyspecs($record);
86 0 0         if ( $this->{'DUMP_USE_SPEC'} ) {
87 0           foreach my $sfield (@{$specs}) {
  0            
88 0           $this->push_line('field: '.$sfield);
89             }
90             }
91 0           $this->{'FIELDS'} = $specs;
92              
93 0           $this->{'PLOTDATA'} = ();
94 0           foreach my $fkey (@{$this->{'FIELDS'}}) {
  0            
95 0           $this->{'PLOTDATA'}->{$fkey} = [];
96             }
97             }
98              
99             sub accept_record {
100 0     0     my $this = shift;
101 0           my $record = shift;
102              
103 0 0         if ( $this->{'FIRST_RECORD'} ) {
104 0           $this->{'FIRST_RECORD'} = 0;
105 0           $this->init_fields($record);
106             }
107              
108 0           my @record_spec;
109 0           foreach my $key (@{$this->{'FIELDS'}}) {
  0            
110 0           push @{$this->{'PLOTDATA'}->{$key}}, $record->{$key};
  0            
111 0           push @record_spec, $record->{$key};
112             }
113 0 0         if ( $this->{'DUMP_USE_SPEC'} ) {
114 0           $this->push_line(join(' ',@record_spec));
115             }
116              
117 0           return 1;
118             }
119              
120             sub stream_done {
121 0     0     my $this = shift;
122              
123 0           my $gdhnd;
124 0           my $w = $this->{'WIDTH'};
125 0           my $h = $this->{'HEIGHT'};
126              
127 0           my $gtype = 'GD::Graph::'.$GD_TYPES->{$this->{'GRAPH_TYPE'}};
128 0           $gdhnd = $gtype->new($w,$h);
129              
130             $gdhnd->set(
131             x_label => $this->{'LABEL_X'},
132 0           y_label => $this->{'LABEL_Y'}
133             );
134              
135 0 0         if ( $this->{'TITLE'} ) {
136 0           $gdhnd->set( title => $this->{'TITLE'} );
137             }
138              
139 0           foreach my $kv (@{$this->{'GDGRAPH_OPTIONS'}}) {
  0            
140 0           $gdhnd->set( $kv->[0] => $kv->[1] );
141             }
142              
143 0           my @data;
144              
145 0 0         if ( scalar(keys %{$this->{'PLOTDATA'}}) == 1 ) {
  0            
146 0           my @hkey = keys(%{$this->{'PLOTDATA'}});
  0            
147 0           my $arrsize = scalar @{$this->{'PLOTDATA'}->{$hkey[0]}};
  0            
148 0           push @data, [ 1 .. $arrsize ];
149 0           push @data, $this->{'PLOTDATA'}->{$hkey[0]};
150             } else {
151 0           for my $field (@{$this->{'FIELDS'}}) {
  0            
152 0           push @data, $this->{'PLOTDATA'}->{$field};
153             }
154             }
155 0           my $gd = $gdhnd->plot(\@data);
156 0 0         if ( !$gd ) {
157 0           print "could not plot data\n";
158 0           exit;
159             }
160 0 0         open(IMG, '>', $this->{'PNG_FILE'}) or die "Could not open file for writing $this->{PNG_FILE}: $!";
161 0           binmode IMG;
162 0           print IMG $gd->png;
163 0           close IMG;
164              
165             }
166              
167             sub add_help_types {
168 0     0     my $this = shift;
169 0           $this->use_help_type('keyspecs');
170 0           $this->use_help_type('keygroups');
171 0           $this->use_help_type('keys');
172             }
173              
174             sub usage {
175 0     0     my $this = shift;
176              
177 0           my $options = [
178             ['key|-k|--key ', 'Specify keys that correlate to keys in JSON data'],
179             ['option|-o option=val', 'Specify custom command for GD::Graph'],
180             ['label-x ', 'Specify X-axis label'],
181             ['label-y ', 'Specify Y-axis label'],
182             ['width ', 'Specify width'],
183             ['height ', 'Specify height'],
184             ['graph-title ', 'Specify graph title'],
185             ['type ', 'Specify different graph type other than scatter (supported: line, bar)'],
186             ['png-file ', 'Specify output PNG filename'],
187             ['dump-use-spec ', 'Dump GD usage (used mainly for testing)']
188             ];
189              
190 0           my $args_string = $this->options_string($options);
191              
192 0           return <
193             Usage: recs-togdgraph []
194             __FORMAT_TEXT__
195             Create a bar, scatter, or line graph using GD::Graph.
196             __FORMAT_TEXT__
197              
198             Args:
199             $args_string
200              
201             Examples:
202             for a plain point graph:
203              
204             recs-togdgraph --keys uid,ct --png-file login-graph.png --graph-title '# of logins' --label-x user --label-y logins
205              
206             togdgraph also accepts any GD::Graph options with the --option command...
207             for a pink background with yellow label text if that really is your thing:
208              
209             recs-togdgraph --keys uid,ct --option boxclr=pink --label-y 'logins' --label-x 'user' --option labelclr=yellow
210              
211             however, for a different graph type such as line or bar, specify with --type:
212              
213             recs-togdgraph --keys uid,ct --type line
214             USAGE
215             }
216              
217             1;