File Coverage

blib/lib/Gnuplot/Simple.pm
Criterion Covered Total %
statement 27 27 100.0
branch 1 2 50.0
condition n/a
subroutine 10 10 100.0
pod n/a
total 38 39 97.4


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