plotpipe: Allow expressions.
This commit is contained in:
parent
fda9f25fdb
commit
cb49a0997a
|
@ -9,7 +9,7 @@ plotpipe - Plot CSV data from a pipe
|
||||||
|
|
||||||
=head1 SYNOPSIS
|
=head1 SYNOPSIS
|
||||||
|
|
||||||
I<datagenerator> | B<plotpipe> [-n] [-H] [-0] [--log axis] [-C str] [-h] [-V]
|
I<datagenerator> | B<plotpipe> [-n] [-H] [-0] [--log axis] [-C str] [-h] [-V] [I<expression>]
|
||||||
|
|
||||||
|
|
||||||
=head1 DESCRIPTION
|
=head1 DESCRIPTION
|
||||||
|
@ -24,6 +24,16 @@ titles on the plot.
|
||||||
|
|
||||||
=over 4
|
=over 4
|
||||||
|
|
||||||
|
=item I<expression>
|
||||||
|
|
||||||
|
Evaluate I<expression>. I<expression> consists of parts separated by
|
||||||
|
,. Each part is evaluated as a Perl expression. You can use {I<n>} as
|
||||||
|
the column value:
|
||||||
|
|
||||||
|
seq 10 | plotpipe '{1},{1},{1}**2,sqrt({1})'
|
||||||
|
(echo x y;paste <(seq 10) <(seq 11 20)) |
|
||||||
|
plotpipe {1},{2},{2}/{1}
|
||||||
|
|
||||||
=item B<--colsep> I<string>
|
=item B<--colsep> I<string>
|
||||||
|
|
||||||
=item B<-C> I<string>
|
=item B<-C> I<string>
|
||||||
|
@ -76,7 +86,7 @@ Use \0 (NUL) instead of newline (\n) as record separator.
|
||||||
|
|
||||||
=item B<-s> I<width>
|
=item B<-s> I<width>
|
||||||
|
|
||||||
Smooth values. Take the average of I<width> y-values.
|
Smooth values. Take the median of I<width> y-values.
|
||||||
|
|
||||||
|
|
||||||
=item B<--version>
|
=item B<--version>
|
||||||
|
@ -91,15 +101,15 @@ Show version
|
||||||
|
|
||||||
=head1 EXAMPLE
|
=head1 EXAMPLE
|
||||||
|
|
||||||
Plot the points (1,100) .. (100,1):
|
Plot (1,100) .. (100,1):
|
||||||
|
|
||||||
paste <(seq 100 -1 1) | plotpipe
|
paste <(seq 100 -1 1) | plotpipe
|
||||||
|
|
||||||
Plot the points (1,101) .. (100,200):
|
Plot (1,101) .. (100,200):
|
||||||
|
|
||||||
paste <(seq 100) <(seq 101 200) | plotpipe
|
paste <(seq 100) <(seq 101 200) | plotpipe
|
||||||
|
|
||||||
Plot the points (1,101) .. (100,200) and (1,300) .. (100,102):
|
Plot (1,101) .. (100,200) and (1,300) .. (100,102):
|
||||||
|
|
||||||
paste <(seq 100) <(seq 101 200) <(seq 300 -2 102) | plotpipe
|
paste <(seq 100) <(seq 101 200) <(seq 300 -2 102) | plotpipe
|
||||||
|
|
||||||
|
@ -146,11 +156,10 @@ input.csv:
|
||||||
You are not limited to a simple graph, but can also do XY-line plots.
|
You are not limited to a simple graph, but can also do XY-line plots.
|
||||||
|
|
||||||
seq 0 0.001 6.29 |
|
seq 0 0.001 6.29 |
|
||||||
perl -nE 'say sin($_*100)*0.3+0.5*cos($_*2),",",
|
plotpipe 'sin({1}*100)*0.3+0.5*cos({1}*2),
|
||||||
sin($_*2)-cos($_*100)*0.3,",",
|
sin({1}*2)-cos({1}*100)*0.3,
|
||||||
sin($_)+cos($_*99),",",
|
sin({1})+cos({1}*99),
|
||||||
sin($_*3)-cos($_*101)' |
|
sin({1}*3)-cos({1}*101)'
|
||||||
plotpipe
|
|
||||||
|
|
||||||
|
|
||||||
=head1 LIMITS
|
=head1 LIMITS
|
||||||
|
@ -189,7 +198,10 @@ B<pipeplot> uses B<gnuplot> and B<perl>.
|
||||||
|
|
||||||
=head1 SEE ALSO
|
=head1 SEE ALSO
|
||||||
|
|
||||||
B<gnuplot>, B<perl>
|
B<gnuplot>, B<perl>, B<ploticus>
|
||||||
|
(http://ploticus.sourceforge.net/doc/welcome.html), B<feedgnuplot>
|
||||||
|
(https://github.com/dkogan/feedgnuplot), B<ttyplot>
|
||||||
|
(https://github.com/tenox7/ttyplot)
|
||||||
|
|
||||||
|
|
||||||
=cut
|
=cut
|
||||||
|
@ -368,13 +380,15 @@ if(not GetOptions(options_hash())) {
|
||||||
}
|
}
|
||||||
|
|
||||||
$Global::progname = "plotpipe";
|
$Global::progname = "plotpipe";
|
||||||
$Global::version = 20210222;
|
$Global::version = 20210302;
|
||||||
if($opt::version) { version(); exit 0; }
|
if($opt::version) { version(); exit 0; }
|
||||||
if($opt::help) { help(); exit 0; }
|
if($opt::help) { help(); exit 0; }
|
||||||
if($opt::null) { $/ = "\0"; }
|
if($opt::null) { $/ = "\0"; }
|
||||||
|
|
||||||
|
my @eval_function = split/,/, join(" ",@ARGV);
|
||||||
|
|
||||||
# Read csv
|
# Read csv
|
||||||
my @csv = <>;
|
my @csv = <STDIN>;
|
||||||
|
|
||||||
# Title = lines starting with #
|
# Title = lines starting with #
|
||||||
my @title = map { s/^#//; s/"/''/g; $_ } map { "$_" } grep { /^#/ } @csv;
|
my @title = map { s/^#//; s/"/''/g; $_ } map { "$_" } grep { /^#/ } @csv;
|
||||||
|
@ -408,22 +422,41 @@ if($opt::header) {
|
||||||
}
|
}
|
||||||
|
|
||||||
# Convert input to perl table
|
# Convert input to perl table
|
||||||
my $ncols = split /$opt::colsep/, $csv[0];
|
|
||||||
my @tbl;
|
my @tbl;
|
||||||
if($ncols >= 2 and not $opt::nox) {
|
for(@csv) {
|
||||||
# Column 1 = x-axis
|
chomp;
|
||||||
for(@csv) {
|
my @row = split /$opt::colsep/, $_;
|
||||||
chomp;
|
push @tbl,\@row;
|
||||||
my @row = split /$opt::colsep/, $_;
|
}
|
||||||
push @tbl,\@row;
|
|
||||||
|
# Eval
|
||||||
|
if(@eval_function) {
|
||||||
|
for(@eval_function) {
|
||||||
|
my $new_header = $_;
|
||||||
|
$new_header =~ s/\{(\d+)\}/$header[$1-1] || "\\\\{$1\\\\}"/ge;
|
||||||
|
push @new_header, $new_header;
|
||||||
}
|
}
|
||||||
|
$opt::header = 1;
|
||||||
|
@header = @new_header;
|
||||||
|
for my $row (@tbl) {
|
||||||
|
my @newrow = map {
|
||||||
|
s/\{(\d+)\}/$row->[$1-1]/g;
|
||||||
|
eval "$_"
|
||||||
|
} map { $_ } @eval_function;
|
||||||
|
$row = \@newrow;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Add x-axis if needed
|
||||||
|
my $ncols = $#{$tbl[0]}+1;
|
||||||
|
if($ncols >= 2 and not $opt::nox) {
|
||||||
|
# Column 1 = x-axis => Data is fine
|
||||||
} else {
|
} else {
|
||||||
# All data = y-axis, invent x-axis
|
# All data = y-axis => Invent x-axis
|
||||||
my $x = 0;
|
my $x = 0;
|
||||||
for(@csv) {
|
for my $row (@tbl) {
|
||||||
chomp;
|
my @newrow = ($x++, @$row);
|
||||||
my @row = ($x++, split /$opt::colsep/, $_);
|
$row = \@newrow;
|
||||||
push @tbl,\@row;
|
|
||||||
}
|
}
|
||||||
# Prepend dummy header for x-axis
|
# Prepend dummy header for x-axis
|
||||||
unshift(@header,"");
|
unshift(@header,"");
|
||||||
|
@ -438,19 +471,42 @@ if($opt::smooth) {
|
||||||
exit(255);
|
exit(255);
|
||||||
}
|
}
|
||||||
my $smooth = $opt::smooth-1;
|
my $smooth = $opt::smooth-1;
|
||||||
for(my $x = 0; $x < $smooth; $x++) {
|
|
||||||
for (my $y = 0; $y <= $#{$tbl[$x]}; $y++) {
|
sub median {
|
||||||
$sum[$y] += $tbl[$x][$y] / $opt::smooth;
|
return ((sort { $a <=> $b } @_)[$#_/2]);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
for(my $x = $smooth; $x <= $#tbl; $x++) {
|
sub avg {
|
||||||
|
my $s=0;
|
||||||
|
map { $s += $_ } @_;
|
||||||
|
return ($s / ($#_+1));
|
||||||
|
}
|
||||||
|
|
||||||
|
for(my $x = 0; $x < $#tbl-$smooth; $x++) {
|
||||||
for (my $y = 0; $y <= $#{$tbl[$x]}; $y++) {
|
for (my $y = 0; $y <= $#{$tbl[$x]}; $y++) {
|
||||||
$sum[$y] += $tbl[$x][$y] / $opt::smooth;
|
my @med;
|
||||||
$new[$x-$smooth][$y] = $sum[$y];
|
for(my $m = $x; $m < $x+$smooth; $m++) {
|
||||||
$sum[$y] -= $tbl[$x-$smooth][$y] / $opt::smooth;
|
push @med, $tbl[$m][$y];
|
||||||
|
}
|
||||||
|
$new[$x+$smooth/2][$y] = median(@med);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@tbl = @new;
|
@tbl = @new;
|
||||||
|
|
||||||
|
sub do_average() {
|
||||||
|
for(my $x = 0; $x < $smooth; $x++) {
|
||||||
|
for (my $y = 0; $y <= $#{$tbl[$x]}; $y++) {
|
||||||
|
$sum[$y] += $tbl[$x][$y] / $opt::smooth;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for(my $x = $smooth; $x <= $#tbl; $x++) {
|
||||||
|
for (my $y = 0; $y <= $#{$tbl[$x]}; $y++) {
|
||||||
|
$sum[$y] += $tbl[$x][$y] / $opt::smooth;
|
||||||
|
$new[$x-$smooth][$y] = $sum[$y];
|
||||||
|
$sum[$y] -= $tbl[$x-$smooth][$y] / $opt::smooth;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@tbl = @new;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
# Save data to tmpfile that will be read by Gnuplot
|
# Save data to tmpfile that will be read by Gnuplot
|
||||||
|
|
Loading…
Reference in a new issue