File Coverage

blib/lib/Gnuplot/Simple.pm
Criterion Covered Total %
statement 25 25 100.0
branch 1 2 50.0
condition n/a
subroutine 9 9 100.0
pod n/a
total 35 36 97.2


line stmt bran cond sub pod time code
1             package Gnuplot::Simple;
2             $Gnuplot::Simple::VERSION = '0.011';
3 1     1   14103 use Modern::Perl qw(2012);
  1         8453  
  1         6  
4 1     1   745 use Method::Signatures;
  1         51494  
  1         7  
5 1     1   963 use Types::Standard qw(ArrayRef Str);
  1         53199  
  1         11  
6 1     1   1311 use Text::CSV;
  1         8297  
  1         6  
7 1     1   524 use File::Slurp::Tiny qw(write_file read_file);
  1         3260  
  1         59  
8 1     1   834 use Exporter::Tidy all => [qw(exec_commands write_data)];
  1         9  
  1         5  
9 1     1   693 use File::Temp qw(tempfile);
  1         8351  
  1         60  
10 1     1   429 use Carp::Assert;
  1         896  
  1         5  
11              
12             BEGIN {
13 1 50   1   5640 system("which gnuplot > /dev/null") == 0 || die 'Gnuplot was not found from $PATH using which.';
14             }
15              
16             #ABSTRACT Gnuplot::Simple - A simple way to control Gnuplot
17              
18             =head1 NAME
19              
20             Gnuplot::Simple - A simple way to control Gnuplot
21              
22             =head1 SYNOPSIS
23              
24             Gnuplot can be controlled from Perl using a pipe. This modules faciliates the process
25             to allow more convenient graph plotting from perl e.g.
26              
27             use Gnuplot::Simple qw(write_data);
28              
29             write_data("file.txt", [[ 1,2 ],[ 2,3 ]] );
30              
31             For obvious reasons, gnuplot needs to be installed for this module to work. The presence
32             of gnuplot is checked using the "which" shell command to verify that it is reachable
33             via $PATH.
34              
35             =head1 FUNCTION/ATTRIBUTES
36              
37             =head2 func write_data($filename, $dataset)
38              
39             Write the $dataset to the file $filename to create a gnuplot data file.
40             Each element in $dataset should be of the form [[<c1>...<cn>],...]
41              
42             The column values must not contain newlines (\n or \r) or quote marks. They can be non-ascii unicode.
43              
44             =head2 func exec_commands ($c, $data, $placeholder = "__DATA__")
45              
46             Example usage:
47              
48             use Gnuplot::Simple qw(exec_commands);
49             my $d = [ [ 1,2 ],[ 2,3 ] ];
50             exec_commands(
51             qq{
52             set terminal png
53             set output "myfile.png"
54             plot __DATA__ u 1:2
55             }, $d
56             );
57              
58             The function takes a string of gnuplot commands $c that is piped to gnuplot. You can give a data set as well in the array ref $data.
59             Then, any occurences of __DATA__ in $c are replaced by a temp file containing $data transformed to gnuplot format as
60             done by write_data. The placeholder __DATA__ can be changed via the last parameter.
61              
62             The function throws the gnuplot error message if execution fails.
63              
64             =head1 LICENSE
65              
66             This software is licensed under the same terms as Perl itself.
67              
68             =cut
69              
70             func _is_valid (Str $r) {
71             $r =~ /^[^\n\r"]*\z/;
72             }
73              
74             func _check_constraint ( ArrayRef[ArrayRef] $data ) {
75             die 'Non-empty data not accepted'
76             unless @$data;
77             for (@$data) {
78             assert @$_ > 0, "There must be more than one column";
79             assert _is_valid( join "", @$_ ), '\n, \r or " chars not allowed in values.';
80             }
81             }
82              
83             func write_data ( Str $filename, $data ) {
84             _check_constraint($data);
85             write_file( $filename, _transform($data), binmode => ":utf8" );
86             }
87              
88             func _transform ( ArrayRef $data) {
89             my $csv = Text::CSV->new( { binary => 1, sep_char => "\t", quote_space => 1 } );
90             join( "\n", map { $csv->combine(@$_); $csv->string(); } @$data );
91             }
92              
93             func exec_commands ( Str $c, $data, $placeholder = "__DATA__" ) {
94              
95             my ( $eh, $errfile ) = tempfile();
96              
97             open my $proc, "|gnuplot 2>$errfile" or die "Could not open pipe to gnuplot.";
98              
99             my $tmp = File::Temp->new();
100             my $tfn = $tmp->filename();
101             write_data( $tfn, $data );
102              
103             #use placeholder to replace all occurences
104             $c =~ s/$placeholder/'$tfn'/g;
105              
106             binmode $proc, ":utf8";
107             ( print $proc $c ) or die "Failed to input commands to gnuplot: $!";
108              
109             close $proc;
110              
111             my $err = read_file( $errfile, binmode => ":utf8" );
112             $err && die "Gnuplot execution failed:\n$err";
113             }
114              
115             1;
116