File Coverage

blib/lib/Chart/Graph/Gnuplot.pm
Criterion Covered Total %
statement 274 457 59.9
branch 186 322 57.7
condition 19 41 46.3
subroutine 17 19 89.4
pod 0 1 0.0
total 496 840 59.0


line stmt bran cond sub pod time code
1             ## Gnuplot.pm is a sub-module of Graph.pm. It has all the subroutines
2             ## needed for the gnuplot part of the package.
3             ##
4             ## $Id: Gnuplot.pm,v 1.48 2006/06/07 21:09:33 emile Exp $ $Name: $
5             ##
6             ## This software product is developed by Michael Young and David Moore,
7             ## and copyrighted(C) 1998 by the University of California, San Diego
8             ## (UCSD), with all rights reserved. UCSD administers the CAIDA grant,
9             ## NCR-9711092, under which part of this code was developed.
10             ##
11             ## There is no charge for this software. You can redistribute it and/or
12             ## modify it under the terms of the GNU General Public License, v. 2 dated
13             ## June 1991 which is incorporated by reference herein. This software is
14             ## distributed WITHOUT ANY WARRANTY, IMPLIED OR EXPRESS, OF MERCHANTABILITY
15             ## OR FITNESS FOR A PARTICULAR PURPOSE or that the use of it will not
16             ## infringe on any third party's intellectual property rights.
17             ##
18             ## You should have received a copy of the GNU GPL along with this program.
19             ##
20             ##
21             ## IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY
22             ## PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
23             ## DAMAGES, INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS
24             ## SOFTWARE, EVEN IF THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF
25             ## THE POSSIBILITY OF SUCH DAMAGE.
26             ##
27             ## THE SOFTWARE PROVIDED HEREIN IS ON AN "AS IS" BASIS, AND THE
28             ## UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE,
29             ## SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. THE UNIVERSITY
30             ## OF CALIFORNIA MAKES NO REPRESENTATIONS AND EXTENDS NO WARRANTIES
31             ## OF ANY KIND, EITHER IMPLIED OR EXPRESS, INCLUDING, BUT NOT LIMITED
32             ## TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A
33             ## PARTICULAR PURPOSE, OR THAT THE USE OF THE SOFTWARE WILL NOT INFRINGE
34             ## ANY PATENT, TRADEMARK OR OTHER RIGHTS.
35             ##
36             ##
37             ## Contact: graph-dev@caida.org
38             ##
39             ##
40             package Chart::Graph::Gnuplot;
41 4     4   22 use Exporter ();
  4         9  
  4         219  
42              
43             @ISA = qw(Exporter);
44             @EXPORT = qw();
45             @EXPORT_OK = qw(&gnuplot);
46              
47 4     4   26 use Carp; # for carp() and croak()
  4         4  
  4         540  
48 4     4   23 use Chart::Graph::Utils qw(:UTILS); # get global subs and variable
  4         6  
  4         3855  
49 4     4   4337 use POSIX 'strftime';
  4         49652  
  4         31  
50 4     4   10682 use FileHandle;
  4         70885  
  4         33  
51              
52             $cvs_Id = '$Id: Gnuplot.pm,v 1.48 2006/06/07 21:09:33 emile Exp $';
53             $cvs_Author = '$Author: emile $';
54             $cvs_Name = '$Name: $';
55             $cvs_Revision = '$Revision: 1.48 $';
56              
57             $VERSION = 3.2;
58              
59 4     4   8020 use strict;
  4         9  
  4         725  
60              
61 4     4   24 use vars qw($show_year $show_seconds);
  4         8  
  4         18512  
62              
63             # these variables hold default options for gnuplot
64             my %def_gnu_global_opts = (
65             "title" => "untitled",
66             "output type" => "png",
67             "output file" => "untitled-gnuplot.png",
68             "x-axis label" => "x-axis",
69             "y-axis label" => "y-axis",
70             "x2-axis label" => undef,
71             "y2-axis label" => undef,
72             "logscale x" => "0",
73             "logscale y" => "0",
74             "logscale x2" => "0",
75             "logscale y2" => "0",
76             "xtics" => undef,
77             "ytics" => undef,
78             "x2tics" => undef,
79             "y2tics" => undef,
80             "xdata" => undef,
81             "ydata" => undef,
82             "x2data" => undef,
83             "y2data" => undef,
84             "timefmt" => undef,
85             "format" => undef,
86             "xrange" => undef,
87             "yrange" => undef,
88             "extra_opts" => undef,
89             "uts" => undef,
90             "uts_normalize" => undef,
91             "size"=> undef,
92             );
93              
94              
95             my %def_gnu_data_opts = (
96             "title" => "untitled data",
97             "style" => "points", # points, lines...
98             "axes" => "x1y1",
99             "type" => undef,
100             "using" => "1:2",
101             );
102              
103              
104              
105             #
106             #
107             # Subroutine: gnuplot()
108             #
109             # Description: this is the main function you will be calling from
110             # our scripts. please see
111             # www.caida.org/Tools/Graph/ for a full description
112             # and how-to of this subroutine
113             #
114              
115             sub gnuplot {
116 48     48 0 25871 my ($user_global_opts_ref, @data_sets) = @_;
117 48         127 my (%data_opts, %global_opts,);
118 0         0 my ($plottype, $output_file, $plot_file, $output_type, $data_set_ref);
119             # create a new filehandle to be used throughout package
120 48         1268 my $handle = new FileHandle;
121              
122             # create tmpdir
123 48         7422 _make_tmpdir("_Gnuplot_");
124              
125             # set paths for external programs
126 48 100       778 if (not _set_gnupaths()) {
127 1         4 _cleanup_tmpdir();
128 1         12 return 0;
129             }
130            
131             # check first arg for hash
132 47 50       194 if (ref($user_global_opts_ref) ne "HASH") {
133 0         0 carp "Global options must be a hash";
134 0         0 _cleanup_tmpdir();
135 0         0 return 0;
136             }
137              
138             # check for data sets
139 47 50       220 if (not @data_sets) {
140 0         0 carp "no data sets";
141 0         0 $handle->close;
142 0         0 _cleanup_tmpdir();
143 0         0 return 0;
144             }
145            
146             # call to combine user options with default options
147 47         830 %global_opts = _mesh_opts($user_global_opts_ref, \%def_gnu_global_opts);
148            
149 47         582 my $command_file = _make_tmpfile("command");
150              
151             #remember to close the file if we return
152 47 50       680 if (not $handle->open(">$command_file")) {
153 0         0 carp "could not open file: $command_file";
154 0         0 _cleanup_tmpdir();
155 0         0 return 0;
156             }
157              
158             # check if uts option is chosen and process first
159 47 100       7913 if (my $value = $global_opts{uts}) {
160 2 50 33     58 if (defined($value) and ref($value) eq "ARRAY") {
161 2 50 33     8 if (@{$value} < 2 || @{$value} > 4) {
  2         27  
  2         17  
162 0         0 carp "out of range for 'uts': [start, end, , ]\n";
163 0         0 _cleanup_tmpdir();
164 0         0 return 0;
165             }
166             # set x tics to human readable time stamps
167 2         34 _gnuplot_date_utc($value->[0], $value->[1], $value->[2], $value->[3], \%global_opts);
168             } else {
169 0         0 carp "Invalid value for 'uts', give [start, end, , ]\n";
170             }
171             }
172              
173             # uts_normalize will be removed in a future version, so don't use it
174 47 50       200 if (my $value = $global_opts{uts_normalize}) {
175 0 0 0     0 if (defined($value) and ref($value) eq "ARRAY") {
176 0 0 0     0 if (@{$value} < 2 || @{$value} > 3) {
  0         0  
  0         0  
177 0         0 carp "out of range for 'uts_normalize': [start, end, ]\n";
178 0         0 _cleanup_tmpdir();
179 0         0 return 0;
180             }
181             # set x tics to human readable time stamps
182 0         0 _gnuplot_date_utc_normalize($value->[0], $value->[1], $value->[2], \%global_opts);
183             } else {
184 0         0 carp "Invalid value for 'uts_normalize', give [start, end]";
185             }
186             }
187              
188             # Check if we have options for reading data as date/time formats
189             # these must be in command file before any others.
190 47         547 foreach my $time_set ("xdata", "ydata", "x2data", "y2data") {
191 188 100       942 if (defined($global_opts{$time_set})) {
192 4         179 print $handle "set $time_set time\n";
193             }
194             }
195            
196             # Set the format for reading data/time data. Only one format for all axes.
197 47 100       263 if (my $value = $global_opts{timefmt}) {
198 2 50       14 if (defined($value)) {
199 2         82 print $handle "set timefmt \"$value\"\n";
200             }
201             }
202              
203             # Now write remain global options to command file
204 47         684 while (my ($key, $value) = each %global_opts) {
205            
206             ## Generic pass-thru, stuff random Gnuplot commands in this key
207 1269 100       3627 if ($key eq "extra_opts") {
208 47 100       155 if (defined $value) {
209 4 100       16 if (ref($value) eq 'ARRAY') {
210             # arrayref
211 1         25 print $handle join("\n", @$value);
212 1         7 print $handle "\n";
213             } else {
214             # assume it's a string and user provided \n's
215 3         12 print $handle "$value\n";
216             }
217             }
218             }
219              
220 1269 100       7500 if ($key eq "title") {
221 47         351 print $handle "set title \"$value\"\n";
222             }
223            
224 1269 100       3497 if ($key eq "x-axis label") {
225 47         342 print $handle "set xlabel \"$value\"\n";
226             }
227            
228 1269 100       5585 if ($key eq "y-axis label") {
229 47         775 print $handle "set ylabel \"$value\"\n";
230             }
231            
232 1269 100       2509 if ($key eq "x2-axis label") {
233 47 100       128 if (defined($value)) {
234 4         42 print $handle "set x2label \"$value\"\n";
235             }
236             }
237            
238 1269 100       3975 if ($key eq "y2-axis label") {
239 47 100       269 if (defined($value)) {
240 1         16 print $handle "set y2label \"$value\"\n";
241             }
242             }
243            
244 1269 100       4064 if ($key eq "logscale x") {
245 47 50       136 if ($value == 1) {
246 0         0 print $handle "set logscale x\n";
247             }
248             }
249            
250 1269 100       7679 if ($key eq "logscale y") {
251 47 100       200 if ($value == 1) {
252 3         21 print $handle "set logscale y\n";
253             }
254             }
255 1269 100       4838 if ($key eq "logscale x2") {
256 47 100       175 if ($value == 1) {
257 3         17 print $handle "set logscale x2\n";
258             }
259             }
260            
261 1269 100       3169 if ($key eq "logscale y2") {
262 47 100       171 if ($value == 1) {
263 1         25 print $handle "set logscale y2\n";
264             }
265             }
266            
267             # tics are not required so we can fall through if we want
268 1269 100       6180 if ($key eq "xtics") {
269 47 100 66     269 if (defined($value) and ref($value) eq "ARRAY") {
270 6         12 _print_tics($handle, $key, @{$value});
  6         38  
271             }
272             }
273              
274 1269 100       3140 if ($key eq "ytics") {
275 47 100 66     186 if (defined($value) and ref($value) eq "ARRAY") {
276 5         8 _print_tics($handle, $key, @{$value});
  5         24  
277             }
278             }
279            
280 1269 100       3172 if ($key eq "x2tics") {
281 47 100       160 if (defined($value)) {
282 2 50       92 if (ref($value) eq "ARRAY") {
283 2         13 _print_tics($handle, $key, @{$value});
  2         22  
284             }
285 2 50       22 if ($value eq "on") {
286 0         0 print $handle "set $key\n";
287             }
288             }
289             }
290 1269 100       4712 if ($key eq "y2tics") {
291 47 100       126 if (defined($value)) {
292 2 50       35 if (ref($value) eq "ARRAY") {
293 2         12 _print_tics($handle, $key, @{$value});
  2         15  
294             }
295 2 50       231 if ($value eq "on") {
296 0         0 print $handle "set $key\n";
297             }
298             }
299             }
300 1269 100 100     7643 if ($key eq 'xrange' || $key eq 'yrange' ) {
301 94 100       227 if (defined($value)) {
302 7 100       36 if (ref($value) eq 'ARRAY') {
303             # arrayref
304 2         555 print $handle "set $key [$value->[0] : $value->[1]]\n";
305             } else {
306             # assume string
307 5         363 print $handle "set $key $value\n";
308             }
309             }
310             }
311             # The only time related Gnuplot code that doesn't need to be
312             # output first.
313 1269 100       3853 if ($key eq "format") {
314 47 100       120 if (defined($value)) {
315 2 50       20 if(ref($value) eq "ARRAY") {
316             # Print value supplying quotes for time format.
317 2         15 print $handle "set $key ", $$value[0]," \"",
318             $$value[1], "\" \n";
319             } else {
320 0         0 carp "Invalid setting for format option";
321             }
322             }
323             }
324             # Date/Time and UTS keys which are processed first.
325 1269 100       3143 if ($key eq "timefmt") {
326             # already processed
327             }
328 1269 100       2716 if ($key eq "xdata") {
329             # already processed
330             }
331 1269 100       2809 if ($key eq "ydata") {
332             # already processed
333             }
334 1269 100       2565 if ($key eq "x2data") {
335             # already processed
336             }
337 1269 100       3334 if ($key eq "y2data") {
338             # already processed
339             }
340 1269 100       3226 if ($key eq "uts") {
341             # already been processed
342             }
343 1269 100       3054 if ($key eq "uts_normalize") {
344             # already been processed
345             }
346 1269 100 100     4277 if ($key eq "size" && defined $value) {
347 1 50 33     21 if (ref($value) eq 'ARRAY' && @{$value} == 2) {
  1         9  
348 1         4 print $handle "set $key ". @{$value}[0] . "," . @{$value}[1] . "\n";
  1         4  
  1         7  
349             }
350             else {
351            
352 0         0 print STDERR "option `size' must be given a two element array\n";
353             }
354             }
355            
356 1269 100       3144 if ($key eq "output file") {
357 47         79 $output_file = $value;
358             }
359            
360 1269 100       6419 if ($key eq "output type") {
361 47 50       736 if (!($value =~ /^(pbm|gif|tgif|png|svg|eps(:? .*)?)$/)) {
362 0         0 carp "invalid output type: $value";
363 0         0 $handle->close();
364 0         0 _cleanup_tmpdir();
365 0         0 return 0;
366             }
367 47         247 $output_type = $value;
368             }
369             }
370              
371             # create the data file
372 47 100       1328 if ($output_type =~ /^eps( .*)?$/) {
    100          
    100          
    100          
    50          
    0          
373 2   100     41 my $options = $1 || "";
374 2 50       7 if (defined $output_file) {
375 0         0 $plot_file = _make_tmpfile("plot", "eps");
376 0         0 print $handle "set output \"$plot_file\"\n";
377             }
378             #print $handle "set terminal postscript eps color \"Arial\" 18\n";
379 2         9 print $handle "set terminal postscript eps $options\n";
380             } elsif ($output_type eq "pbm" ) {
381 1 50       9 if (defined $output_file) {
382 0         0 $plot_file = _make_tmpfile("plot", "pbm");
383 0         0 print $handle "set output \"$plot_file\"\n";
384             }
385 1         6 print $handle "set terminal pbm small color\n";
386             } elsif ($output_type eq "gif") {
387             # always needs the tempfile because of conversion later on
388 5         42 $plot_file = _make_tmpfile("plot", "pbm");
389 5         21 print $handle "set output \"$plot_file\"\n";
390 5         10 print $handle "set terminal pbm small color\n";
391             } elsif ($output_type eq "png") {
392 38 100       381 if (defined $output_file) {
393 1         10 $plot_file = _make_tmpfile("plot", "png");
394 1         6 print $handle "set output \"$plot_file\"\n";
395             }
396 38         273 print $handle "set terminal png small\n";
397             } elsif ($output_type eq "tgif") {
398 1 50       13 if (defined $output_file) {
399 0         0 $plot_file = _make_tmpfile("plot", "obj");
400 0         0 print $handle "set output \"$plot_file\"\n";
401             }
402 1         2 print $handle "set terminal tgif\n";
403             } elsif ($output_type eq 'svg') {
404 0 0       0 if (defined $output_file) {
405 0         0 $plot_file = _make_tmpfile("plot", "svg");
406 0         0 print $handle "set output \"$plot_file\"\n";
407             }
408 0         0 print $handle "set terminal svg\n";
409             }
410              
411             # process data sets
412 47         115 print $handle "plot ";
413 47         141 while (@data_sets) {
414            
415 59         137 $data_set_ref = shift @data_sets;
416            
417 59 50       544 if (ref($data_set_ref) ne "ARRAY") {
418 0         0 carp "Data set must be an array";
419 0         0 $handle->close();
420 0         0 _cleanup_tmpdir();
421 0         0 return 0;
422             }
423            
424 59 50       82 if (not _gnuplot_data_set($handle, @{$data_set_ref})) {
  59         347  
425             ## already printed error message
426 0         0 $handle->close();
427 0         0 _cleanup_tmpdir();
428 0         0 return 0;
429             }
430            
431 59 100       365 if (@data_sets) {
432 12         39 print $handle ", ";
433             }
434             }
435            
436 47         1168 $handle->close();
437            
438             # gnuplot and convert pbm file to gif
439 47 50       4107 if (not _exec_gnuplot($command_file)) {
440 47         277 _cleanup_tmpdir();
441 47         6156 return 0;
442             }
443            
444 0 0 0     0 if ($output_type eq "gif") {
    0          
445 0 0       0 if(not _exec_pbmtogif($plot_file, $output_file)) {
446 0         0 _cleanup_tmpdir();
447 0         0 return 0;
448             }
449             } elsif (defined $output_file && $output_type =~ /^(pbm|eps(?: .*)?|png|tgif)$/) {
450             #try to get rid of the ugly warnings when moving a file on freebsd
451 0 0       0 if ($^O eq 'freebsd') {
452 0         0 eval { #this is opportunistic, if it fails it doesn't really matter
453 0         0 my $gid = `/usr/bin/id -g`;
454 0         0 chomp($gid);
455 0         0 system('/usr/bin/chgrp',$gid,$plot_file);
456             };
457             }
458              
459 0         0 my $status = system("mv", "$plot_file", "$output_file");
460              
461 0 0       0 if (not _chk_status($status)) {
462 0 0       0 if ($Chart::Graph::debug) {
463 0         0 print STDERR "Couldn't mv $plot_file to $output_file: $!\n";
464             }
465 0         0 _cleanup_tmpdir();
466 0         0 return 0;
467             }
468             }
469 0         0 _cleanup_tmpdir();
470 0         0 return 1;
471             }
472              
473             #
474             #
475             # Subroutine: gnuplot_data_set()
476             #
477             # Description: this functions processes the X number
478             # of data sets that a user gives as
479             # arguments to gnuplot(). Again, please
480             # see http://www.caida.org/Tools/Graph/
481             # for the format of the dataset.
482             #
483              
484              
485            
486             sub _gnuplot_data_set {
487 59     59   153 my ($handle, $user_data_opts_ref, @data) = @_;
488 59         111 my (%data_opts);
489            
490             # set these values with empty string because we print them out later
491             # we don't want perl to complain of uninitialized value.
492 59         340 my ($title, $style, $axes, $ranges, $type,) = ("", "", "", "", "");
493 59         97 my ($using) = ("");
494 59         71 my $result;
495 59         271 my $filename = _make_tmpfile("data");
496            
497             ## check first arg for hash
498 59 50       196 if (ref($user_data_opts_ref) ne "HASH") {
499 0         0 carp "Data options must be a hash.";
500 0         0 return 0;
501             }
502              
503             # call to combine user options with default options
504 59         937 %data_opts = _mesh_opts($user_data_opts_ref, \%def_gnu_data_opts);
505              
506             # write data options to command file
507 59         1209 while (my ($key, $value) = each %data_opts) {
508            
509 295 100       956 if ($key eq "using") {
510 59         2121 $using = "using $value";
511             }
512              
513 295 100       711 if ($key eq "title") {
514 59         126 $title = "title \"$value\"";
515             }
516            
517 295 100       529 if ($key eq "style") {
518 59         99 $style = "with $value"
519             }
520            
521 295 100       1320 if ($key eq "axes") {
522 59         94 $axes = "axes $value";
523             }
524            
525 295 100       1873 if ($key eq "type") {
526 59         207 $type = $value;
527             }
528             }
529            
530 59 100       160 if ($type eq "function") {
531             #$ranges = "[t=:]"; # XXX ?
532 1         14 print $handle "$ranges " . $data[0] . " $axes $title $style";
533 1         21 return 1;
534             } else {
535 58         338 print $handle "$ranges \"$filename\" $using $axes $title $style";
536              
537             # we give the user 3 formats for supplying the data set
538             # 1) matrix
539             # 2) column
540             # 3) file
541             # please see the online docs for a description of these
542             # formats
543 58 100       185 if ($type eq "matrix") {
    100          
    50          
    0          
544 46         232 $result = _matrix_to_file($filename, @data);
545             } elsif ($type eq "columns") {
546 9         37 $result = _columns_to_file($filename, @data);
547             } elsif ($type eq "file") {
548 3         19 $result = _file_to_file($filename, @data);
549             } elsif ($type eq "") {
550 0         0 carp "Need to specify data set type";
551 0         0 return 0;
552             } else {
553 0         0 carp "Illegal data set type: $type";
554 0         0 return 0;
555             }
556             }
557 58         1162 return $result;
558             }
559              
560             #
561             # Subroutine: set_gnupaths()
562             #
563             # Description: set paths for external programs required by gnuplot()
564             # if they are not defined already
565             #
566              
567             sub _set_gnupaths {
568              
569 48 100   48   232 if (not defined($gnuplot)) {
570 1 50       118 if (not $gnuplot = _get_path("gnuplot")) {
571 1         6 return 0;
572             }
573             }
574            
575 47 50       366 if (not defined($ppmtogif)) {
576 0 0       0 if (not $ppmtogif = _get_path("ppmtogif")) {
577 0         0 return 0;
578             }
579             }
580 47         304 return 1;
581             }
582              
583             #
584             #
585             # Subroutine: print_tics()
586             # Description: this subroutine takes an array
587             # of graph tic labels and prints
588             # them to the gnuplot command file.
589             # This subroutine is called by gnuplot().
590             #
591             # Arguments: $tic_type: which axis to print the tics on
592             # @tics: the array of tics to print to the file
593             #
594              
595             sub _print_tics {
596 15     15   114 my ($handle, $tic_type, @tics) = @_;
597 15         31 my (@tic_array, $tics_formatted, $tic_label, $tic_index);
598            
599             # no tic set found, user entered empty tic array
600 15 50       156 if (not @tics) {
601 0         0 carp "Warning: empty tic set found";
602 0         0 return 1;
603             }
604              
605 15         35 foreach my $tic (@tics) {
606             #tics can come in two formats
607             #this one is [["label1", 10], ["label2", 20],...]
608 154 100       469 if (ref($tic) eq "ARRAY") {
609            
610 127 50       130 if ($#{$tic} != 1) {
  127         285  
611 0         0 carp "invalid tic format";
612 0         0 return 0;
613             }
614 127         204 $tic_label = $tic->[0];
615 127         159 $tic_index = $tic->[1];
616 127         356 push (@tic_array, "\"$tic_label\" $tic_index");
617             # this one is [10, 20,...]
618             } else {
619 27         85 push (@tic_array, "$tic");
620             }
621             }
622 15         86 $tics_formatted = join(",", @tic_array);
623 15         260 print $handle "set $tic_type ($tics_formatted)\n";
624 15         61 return 1;
625             }
626              
627             #
628             #
629             # Subroutine: matrix_to_file()
630             #
631             # Description: converts the matrix data input into a the gnuplot
632             # data file format. See www for the specific on the
633             # matrix format
634             #
635             #
636             sub _matrix_to_file {
637 46     46   89 my ($file, $matrix_ref) = @_;
638 46         84 my $entry_ref;
639             my $matrix_len;
640            
641 46 50       159 if (ref($matrix_ref) ne "ARRAY") {
642 0         0 carp "Matrix data must be a reference to an array";
643 0         0 return 0;
644             }
645            
646 46         9854 open (DATA, ">$file");
647            
648 46         188 $matrix_len = @{$matrix_ref};
  46         346  
649 46         355 for (my $i = 0; $i < $matrix_len; $i++) {
650 144         400 $entry_ref = $matrix_ref->[$i];
651            
652 144 50       511 if (ref($entry_ref) ne "ARRAY") {
653 0         0 carp "Matrix entry must be a reference to an array";
654 0         0 close DATA;
655 0         0 return 0;
656             }
657            
658             # prints blank lines for blank entries, this allows
659             # the user to tell gnuplot to not connect lines between
660             # all points when displaying data with lines.
661 144 50       156 if (@{$entry_ref} == 0)
  144         1284  
662             {
663 0         0 print DATA "\n";
664             }
665             else
666             {
667 144         134 if (0) {
668             # check that each entry ONLY has two entries
669             if (@{$entry_ref} != 2) {
670             carp "Each entry must be an array of size 2";
671             return 0;
672             }
673             print DATA $entry_ref->[0], "\t", $entry_ref->[1], "\n";
674             }
675             # XXX
676 144         219 print DATA join("\t", @{$entry_ref}), "\n";
  144         1339  
677             }
678             }
679 46         8261 close DATA;
680 46         269 return 1;
681             }
682              
683             #
684             #
685             # Subroutine: columns_to_file()
686             #
687             # Description: converts the column data input into a the gnuplot
688             # data file format. please see www page for specifics
689             # on this format.
690             #
691              
692             sub _columns_to_file {
693 9     9   22 my ($file, @columns) = @_;
694              
695 9         31 foreach my $dataset ( @columns ) {
696 30 50       71 if (!(ref($dataset) eq "ARRAY")) {
697 0         0 carp "Column data must be a reference to an array";
698 0         0 return 0;
699             }
700            
701 4 50   4   10145 if ($#{$dataset} != $#{$columns[$[]}) {
  4         2148  
  4         8249  
  30         34  
  30         41  
  30         170  
702 0         0 carp "All columns must be of same length";
703 0         0 return 0;
704             }
705             }
706              
707 9 50       15 if ($#{$columns[$[]} == 0) {
  9         34  
708 0         0 carp "Warning: Columns have no data!";
709             }
710              
711 9         1155 open (DATA, ">$file");
712            
713 9         27 for (my $i = 0; $i <= $#{$columns[$[]}; $i++) {
  60         222  
714 51         71 foreach my $dataset ( @columns ) {
715 174         582 print DATA "$dataset->[$i]\t";
716             }
717 51         106 print DATA "\n";
718             }
719              
720 9         386 close DATA;
721 9         31 return 1;
722             }
723              
724              
725             #
726             # Subroutine: file_to_file()
727             #
728             # Description: If a gnuplot data set was given in
729             # file format, we simply copy the data
730             # and read it into
731             #
732              
733             sub _file_to_file {
734 3     3   6 my ($file_out, $file_in) = @_;
735            
736 3 50       10 if (not $file_in) {
737 0         0 carp "Data set file missing";
738 0         0 return 0;
739             }
740              
741 3 50       52 if (not -f $file_in) {
742 0         0 carp "Data set file, '$file_in', does not exist.";
743 0         0 return 0;
744             }
745            
746 3         33339 my $status = system("cp", "$file_in", "$file_out");
747            
748 3 50       170 if (not _chk_status($status)) {
749 0         0 return 0;
750             }
751            
752 3         80 return 1;
753             }
754              
755             #
756             # Subroutine: exec_gnuplot()
757             #
758             # Description: this executes gnuplot on the command file
759             # and data sets that we have generated.
760             #
761              
762             sub _exec_gnuplot {
763 47     47   133 my ($command_file) = @_;
764 47         415632 my $status = system("$gnuplot", "$command_file");
765            
766 47 50       9446 if (not _chk_status($status)) {
767 47         1071 return 0;
768             }
769            
770 0         0 return 1;
771             }
772              
773             #
774             # Subroutine: exec_pbmtogif()
775             #
776             # Description: convert pbm file that gnuplot makes into
777             # a gif. usually used for web pages
778             #
779             sub _exec_pbmtogif {
780 0     0   0 my ($pbm_file, $gif_file) = @_;
781 0         0 my $status;
782 0         0 my $cmd = "$ppmtogif $pbm_file ";
783 0 0       0 if ($gif_file) {
784 0         0 $cmd .= "> $gif_file ";
785             }
786 0 0       0 unless ($Chart::Graph::debug) {
787 0         0 $cmd .= "2> /dev/null ";
788             }
789 0         0 $status = system($cmd);
790            
791 0 0       0 if (not _chk_status($status)) {
792 0         0 return 0;
793             }
794            
795 0         0 return 1;
796             }
797              
798             #
799             # Subroutine: gnuplot_date_utc()
800             #
801             # Description: wrapper function that handles UNIX
802             # time stamps as x values nicely
803             #
804             # Author: Ryan Koga - rkoga@caida.org
805             #
806              
807             sub _gnuplot_date_utc {
808 2     2   8 my ($start, $end, $samp_scale, $use_local_tz, $global_options) = @_;
809              
810 2         4 my $min_len = 60;
811 2         9 my $hour_len = $min_len*60;
812 2         8 my $day_len = $hour_len*24;
813 2         5 my $interval = $end - $start;
814 2         4 my $min_samp;
815             my @tics;
816              
817 2 50       10 if (!defined($samp_scale)) {
818 2         8 $samp_scale = 1;
819             }
820              
821 2 50       135 if ($interval < 10) {
    50          
    50          
    50          
    50          
    50          
    50          
    100          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
822 0         0 $min_samp = 1;
823             } elsif ($interval < 30) {
824 0         0 $min_samp = 4;
825             } elsif ($interval < $min_len) {
826 0         0 $min_samp = 10;
827             } elsif ($interval < 3*$min_len) {
828 0         0 $min_samp = 30;
829             } elsif ($interval < 10*$min_len) {
830 0         0 $min_samp = $min_len;
831             } elsif ($interval < $hour_len) {
832 0         0 $min_samp = 5*$min_len;
833             } elsif ($interval < 2*$hour_len) {
834 0         0 $min_samp = 10*$min_len;
835             } elsif ($interval < 3*$hour_len) {
836 1         2 $min_samp = 15*$min_len;
837             } elsif ($interval < 4*$hour_len) {
838 0         0 $min_samp = 20*$min_len;
839             } elsif ($interval < 5*$hour_len) {
840 0         0 $min_samp = 30*$min_len;
841             } elsif ($interval < 12*$hour_len) {
842 0         0 $min_samp = $hour_len;
843             } elsif ($interval < $day_len) {
844 0         0 $min_samp = 2*$hour_len;
845             } elsif ($interval < 2*$day_len) {
846 0         0 $min_samp = 4*$hour_len;
847             } elsif ($interval < 5*$day_len) {
848 0         0 $min_samp = 12*$hour_len;
849             } elsif ($interval < 7*$day_len) {
850 0         0 $min_samp = $day_len;
851             } elsif ($interval < 15*$day_len) {
852 0         0 $min_samp = 2*$day_len;
853             } elsif ($interval < 30*$day_len) {
854 0         0 $min_samp = 7*$day_len;
855             } elsif ($interval < 365*$day_len) {
856 0         0 $min_samp = 30*$day_len;
857             } elsif ($interval < 2*365*$day_len) {
858 0         0 $min_samp = 60*$day_len;
859             } else {
860 1         13 $min_samp = 120*$day_len;
861             }
862 2         10 $min_samp /= $samp_scale;
863 2         11 my $start_min = int($start/$min_samp);
864 2         7 my $end_min = int($end/$min_samp);
865              
866 2         10 for (my $curr_min = $start_min; $curr_min <= $end_min; $curr_min++) {
867 108         144 my $bucket = $curr_min*$min_samp;
868 108         291 my ($bucket_str,@time_data);
869 108 50       229 if ( $use_local_tz ) {
870 0         0 @time_data = localtime($bucket);
871             } else {
872 108         514 @time_data = gmtime($bucket);
873             }
874 108         194 $time_data[$#time_data] = -1; # unset dst data, broken strftime
875              
876             # keep compatibility with the undocumented 'utc_seconds' global var
877 108         113 $Chart::Graph::Gnuplot::show_seconds = $Chart::Graph::Gnuplot::utc_seconds;
878              
879 108 50 33     827 if ($min_samp >= $min_len && !$Chart::Graph::Gnuplot::show_seconds) {
880 108         5540 $bucket_str = strftime("%H:%M", @time_data);
881             } else {
882 0         0 $bucket_str = strftime("%H:%M:%S", @time_data);
883             }
884 108 100 100     675 if ($bucket_str =~ /^00:00(:00)?$/ || $curr_min == $start_min + 1) {
885 99         5076 $bucket_str .= strftime('\n%m/%d', @time_data);
886 99 50       258 if ($Chart::Graph::Gnuplot::show_year) {
887 0         0 $bucket_str .= strftime('\n%Y', @time_data);
888             }
889             }
890 108         1084 push @tics, [ $bucket_str, $bucket ];
891             }
892              
893             # must check to see if xtics were previously set in the globals
894             # if they are, we'll append them to the time stamp tics
895             # note: collisions are handled by the user
896              
897 2 100       11 if (defined ($global_options->{"xtics"})) {
898 1         2 push @tics, @{$global_options->{"xtics"}};
  1         4  
899             }
900              
901 2         11 $global_options->{"xtics"} = \@tics;
902 2         12 return 1;
903             }
904              
905              
906             sub _gnuplot_date_utc_normalize {
907 0     0     my ($start, $end, $samp_scale, $global_options) = @_;
908             ### this code used to be used as a workaround for an old gnuplot bug
909             ### newer versions don't need it
910 0           carp "'uts_normalize' is going to be depreciated in a future release\n";
911              
912 0           my $min_len = 60;
913 0           my $hour_len = $min_len*60;
914 0           my $day_len = $hour_len*24;
915 0           my $interval = $end - $start;
916 0           my $min_samp;
917              
918 0 0         if (!defined($samp_scale)) {
919 0           $samp_scale = 1;
920             }
921              
922 0 0         if ($interval < 10) {
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
923 0           $min_samp = 1;
924             } elsif ($interval < 30) {
925 0           $min_samp = 4;
926             } elsif ($interval < $min_len) {
927 0           $min_samp = 10;
928             } elsif ($interval < 3*$min_len) {
929 0           $min_samp = 30;
930             } elsif ($interval < 10*$min_len) {
931 0           $min_samp = $min_len;
932             } elsif ($interval < $hour_len) {
933 0           $min_samp = 5*$min_len;
934             } elsif ($interval < 2*$hour_len) {
935 0           $min_samp = 10*$min_len;
936             } elsif ($interval < 3*$hour_len) {
937 0           $min_samp = 15*$min_len;
938             } elsif ($interval < 4*$hour_len) {
939 0           $min_samp = 20*$min_len;
940             } elsif ($interval < 5*$hour_len) {
941 0           $min_samp = 30*$min_len;
942             } elsif ($interval < 12*$hour_len) {
943 0           $min_samp = $hour_len;
944             } elsif ($interval < $day_len) {
945 0           $min_samp = 2*$hour_len;
946             } elsif ($interval < 2*$day_len) {
947 0           $min_samp = 4*$hour_len;
948             } elsif ($interval < 5*$day_len) {
949 0           $min_samp = 12*$hour_len;
950             } elsif ($interval < 7*$day_len) {
951 0           $min_samp = $day_len;
952             } elsif ($interval < 15*$day_len) {
953 0           $min_samp = 2*$day_len;
954             } elsif ($interval < 30*$day_len) {
955 0           $min_samp = 3*$day_len;
956             } else {
957 0           $min_samp = 30*$day_len;
958             }
959 0           $min_samp /= $samp_scale;
960 0           my $start_min = int($start/$min_samp);
961 0           my $end_min = int($end/$min_samp);
962 0           my @tics;
963              
964 0           my $first_date_shown = 0;
965 0           for (my $curr_min = $start_min; $curr_min <= $end_min; $curr_min++) {
966 0           my $bucket = $curr_min*$min_samp;
967 0           my $bucket_str;
968 0           my @time_data = gmtime($bucket);
969 0           $time_data[$#time_data] = -1; # unset dst data, broken strftime
970 0 0         if ($min_samp >= $min_len) {
971 0           $bucket_str = strftime('%H:%M', @time_data);
972             } else {
973 0           $bucket_str = strftime('%H:%M:%S', @time_data);
974             }
975 0           my $show_date = 0;
976 0 0         if ($bucket_str =~ /^00:00(:00)?$/) {
977 0           $show_date = 1;
978 0           $first_date_shown = 1;
979             }
980 0 0 0       if ($curr_min == $start_min + 1 && !$first_date_shown) {
981 0           $show_date = 1;
982             }
983 0 0         if ($show_date) {
984 0           $bucket_str .= strftime('\n%m/%d', @time_data);
985             }
986 0           push @tics, [ $bucket_str, ($bucket - $start) / $end ];
987             }
988              
989             # must check to see if xtics were previously set in the globals
990             # if they are, we'll append them to the time stamp tics
991             # note: collisions are handled by the user
992              
993 0 0         if (defined ($global_options->{"xtics"})) {
994 0           push @tics, @{$global_options->{"xtics"}};
  0            
995             }
996            
997 0           $global_options->{"xtics"} = \@tics;
998 0           return 1;
999             }
1000              
1001             1;
1002              
1003             __END__