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