mirror of
https://github.com/dkogan/feedgnuplot.git
synced 2025-05-05 22:11:12 +08:00
added --using, --usingall
This commit is contained in:
parent
83139d7ad0
commit
d68b331af6
140
bin/feedgnuplot
140
bin/feedgnuplot
@ -91,6 +91,7 @@ sub interpretCommandline
|
|||||||
$options{curvestyle} = [];
|
$options{curvestyle} = [];
|
||||||
$options{style} = [];
|
$options{style} = [];
|
||||||
$options{every} = [];
|
$options{every} = [];
|
||||||
|
$options{using} = [];
|
||||||
$options{histogram} = [];
|
$options{histogram} = [];
|
||||||
$options{x1y2} = [];
|
$options{x1y2} = [];
|
||||||
$options{x2y1} = [];
|
$options{x2y1} = [];
|
||||||
@ -121,6 +122,7 @@ sub interpretCommandline
|
|||||||
'x2=s@', 'y2=s@', 'x1y2=s@', 'x2y1=s@', 'x2y2=s@',
|
'x2=s@', 'y2=s@', 'x1y2=s@', 'x2y1=s@', 'x2y2=s@',
|
||||||
'style=s{2}', 'curvestyle=s{2}', 'curvestyleall=s', 'styleall=s', 'with=s', 'extracmds=s@', 'set=s@', 'unset=s@',
|
'style=s{2}', 'curvestyle=s{2}', 'curvestyleall=s', 'styleall=s', 'with=s', 'extracmds=s@', 'set=s@', 'unset=s@',
|
||||||
'every=s{2}', 'everyall=s',
|
'every=s{2}', 'everyall=s',
|
||||||
|
'using=s{2}', 'usingall=s',
|
||||||
'square!', 'square_xy!', 'square-xy!', 'squarexy!', 'hardcopy=s', 'maxcurves=i', 'monotonic!', 'timefmt=s',
|
'square!', 'square_xy!', 'square-xy!', 'squarexy!', 'hardcopy=s', 'maxcurves=i', 'monotonic!', 'timefmt=s',
|
||||||
'equation=s@', 'equation-below=s@', 'equation-above=s@',
|
'equation=s@', 'equation-below=s@', 'equation-above=s@',
|
||||||
'image=s',
|
'image=s',
|
||||||
@ -185,7 +187,7 @@ sub interpretCommandline
|
|||||||
@{$options{$listkey}} = map split('\s*,\s*', $_), @{$options{$listkey}}
|
@{$options{$listkey}} = map split('\s*,\s*', $_), @{$options{$listkey}}
|
||||||
if defined $options{$listkey};
|
if defined $options{$listkey};
|
||||||
}
|
}
|
||||||
for my $listkey (qw(curvestyle rangesize tuplesize every))
|
for my $listkey (qw(curvestyle rangesize tuplesize every using))
|
||||||
{
|
{
|
||||||
next unless defined $options{$listkey};
|
next unless defined $options{$listkey};
|
||||||
my @in = @{$options{$listkey}};
|
my @in = @{$options{$listkey}};
|
||||||
@ -260,7 +262,7 @@ sub interpretCommandline
|
|||||||
# arrays in order to preserve the ordering. I parse both of these into hashes
|
# arrays in order to preserve the ordering. I parse both of these into hashes
|
||||||
# because those are useful to have later. After this I can access individual
|
# because those are useful to have later. After this I can access individual
|
||||||
# legends with $options{legend_hash}{curveid}
|
# legends with $options{legend_hash}{curveid}
|
||||||
for my $listkey (qw(legend curvestyle rangesize every))
|
for my $listkey (qw(legend curvestyle rangesize every using))
|
||||||
{
|
{
|
||||||
$options{"${listkey}_hash"} = {};
|
$options{"${listkey}_hash"} = {};
|
||||||
|
|
||||||
@ -810,6 +812,7 @@ sub mainThread
|
|||||||
|
|
||||||
for my $what_options_prefix_suffix ( ['curvestyle', 'extraoptions', '', ' ' ],
|
for my $what_options_prefix_suffix ( ['curvestyle', 'extraoptions', '', ' ' ],
|
||||||
['every', 'everyoptions', 'every ', ' ' ],
|
['every', 'everyoptions', 'every ', ' ' ],
|
||||||
|
['using', 'usingoptions', 'using ', ' ' ],
|
||||||
['legend', 'title', '', '' ])
|
['legend', 'title', '', '' ])
|
||||||
{
|
{
|
||||||
my ($what, $options, $prefix, $suffix) = @$what_options_prefix_suffix;
|
my ($what, $options, $prefix, $suffix) = @$what_options_prefix_suffix;
|
||||||
@ -843,8 +846,16 @@ sub mainThread
|
|||||||
print PIPE
|
print PIPE
|
||||||
"set boxwidth $options{binwidth}\n" .
|
"set boxwidth $options{binwidth}\n" .
|
||||||
"histbin(x) = $options{binwidth} * floor(0.5 + x/$options{binwidth})\n";
|
"histbin(x) = $options{binwidth} * floor(0.5 + x/$options{binwidth})\n";
|
||||||
|
foreach my $id (@{$options{histogram}})
|
||||||
setCurveAsHistogram( $_ ) foreach (@{$options{histogram}});
|
{
|
||||||
|
# With histograms I have 2d plots with rangesize=1. I thus give gnuplot two
|
||||||
|
# values for each point: a domain and a range. For histograms I ignore the
|
||||||
|
# domain, so I get the statistics of the 2nd column: $2
|
||||||
|
addOption($id,
|
||||||
|
'usingoptions',
|
||||||
|
'using (histbin($2)):(1.0) smooth ' . $options{histstyle},
|
||||||
|
'do-not-override');
|
||||||
|
}
|
||||||
|
|
||||||
if(@{$options{x2y1}} || @{$options{x2y2}})
|
if(@{$options{x2y1}} || @{$options{x2y2}})
|
||||||
{
|
{
|
||||||
@ -1185,10 +1196,14 @@ sub updateCurveOptions
|
|||||||
{ $title = $id; }
|
{ $title = $id; }
|
||||||
|
|
||||||
my $titleoption = defined $title ? "title \"$title\"" : "notitle";
|
my $titleoption = defined $title ? "title \"$title\"" : "notitle";
|
||||||
my $histoptions = $curve->{histoptions} || '';
|
|
||||||
|
|
||||||
my $usingoptions = '';
|
my $usingoptions = $curve->{usingoptions};
|
||||||
if( $options{timefmt} && !$histoptions )
|
if( length($usingoptions) )
|
||||||
|
{
|
||||||
|
# user specified a 'using' option. I just do that, and don't look at
|
||||||
|
# anything else
|
||||||
|
}
|
||||||
|
elsif( $options{timefmt} )
|
||||||
{
|
{
|
||||||
# with --timefmt I need an explicit 'using' specification. I specify the
|
# with --timefmt I need an explicit 'using' specification. I specify the
|
||||||
# columns as 1:2:3..... I need the right number of columns (this is given
|
# columns as 1:2:3..... I need the right number of columns (this is given
|
||||||
@ -1214,7 +1229,7 @@ sub updateCurveOptions
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$curve->{options} = "$curve->{everyoptions} $histoptions $usingoptions $titleoption $curve->{extraoptions}";
|
$curve->{options} = "$curve->{everyoptions} $usingoptions $titleoption $curve->{extraoptions}";
|
||||||
}
|
}
|
||||||
|
|
||||||
sub getCurve
|
sub getCurve
|
||||||
@ -1241,6 +1256,9 @@ sub getCurve
|
|||||||
everyoptions => (!exists $options{every_hash}{$id} &&
|
everyoptions => (!exists $options{every_hash}{$id} &&
|
||||||
exists $options{everyall}) ?
|
exists $options{everyall}) ?
|
||||||
"every $options{everyall} " : ' ',
|
"every $options{everyall} " : ' ',
|
||||||
|
usingoptions => (!exists $options{using_hash}{$id} &&
|
||||||
|
exists $options{usingall}) ?
|
||||||
|
"using $options{usingall} " : '',
|
||||||
title => '',
|
title => '',
|
||||||
datastring => '',
|
datastring => '',
|
||||||
datastring_meta => [],
|
datastring_meta => [],
|
||||||
@ -1274,25 +1292,14 @@ sub getCurve
|
|||||||
|
|
||||||
sub addOption
|
sub addOption
|
||||||
{
|
{
|
||||||
my ($id, $which, $str) = @_;
|
my ($id, $which, $str, $do_not_override) = @_;
|
||||||
|
|
||||||
my $curve = getCurve($id);
|
my $curve = getCurve($id);
|
||||||
|
if(!$do_not_override || length($curve->{$which})==0)
|
||||||
|
{
|
||||||
$curve->{$which} .= $str;
|
$curve->{$which} .= $str;
|
||||||
updateCurveOptions($curve, $id);
|
updateCurveOptions($curve, $id);
|
||||||
}
|
}
|
||||||
|
|
||||||
sub setCurveAsHistogram
|
|
||||||
{
|
|
||||||
my ($id, $str) = @_;
|
|
||||||
|
|
||||||
my $curve = getCurve($id);
|
|
||||||
|
|
||||||
# With histograms I have 2d plots with rangesize=1. I thus give gnuplot two
|
|
||||||
# values for each point: a domain and a range. For histograms I ignore the
|
|
||||||
# domain, so I get the statistics of the 2nd column: $2
|
|
||||||
$curve->{histoptions} = 'using (histbin($2)):(1.0) smooth ' . $options{histstyle};
|
|
||||||
|
|
||||||
updateCurveOptions($curve, $id);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
# remove all the curve data
|
# remove all the curve data
|
||||||
@ -1612,6 +1619,79 @@ Note that while gnuplot supports the time/date on any axis, I<feedgnuplot>
|
|||||||
currently supports it I<only> as the x-axis domain. This may change in the
|
currently supports it I<only> as the x-axis domain. This may change in the
|
||||||
future.
|
future.
|
||||||
|
|
||||||
|
=head3 'using' expressions
|
||||||
|
|
||||||
|
We just described how feedgnuplot parses its input data. When passing this data
|
||||||
|
to gnuplot, each curve is sent independently. The domain appears in the leading
|
||||||
|
columns followed by C<--rangesize> columns to complete each row. Without
|
||||||
|
C<--domain>, feedgnuplot explicitly writes out sequential integers. gnuplot then
|
||||||
|
knows how many values it has for each point, and it knows which style we're
|
||||||
|
using, so it's able to interpret the data appropriately, and to make the correct
|
||||||
|
plot.
|
||||||
|
|
||||||
|
As an example, if gnuplot is passed 2 columns of data, and it is plotting C<with
|
||||||
|
points>, it will use column 1 for the x coordinate and column 2 for the y
|
||||||
|
coordinate. This is the default behavior, but the meaning of each column can be
|
||||||
|
controlled via a C<using> expression in gnuplot (not feedgnuplot; keep reading).
|
||||||
|
The default is sequential integers, so this example uses C<using 1:2> by
|
||||||
|
default. We can flip the meaning of the columns by passing C<using 2:1>.
|
||||||
|
Arbitrary expressions may be specified by enclosing each field in C<()>, and
|
||||||
|
using C<$> to denote each data column. So to use the 2nd column as the x
|
||||||
|
coordinate and the sum of the two columns as the y coordinate, C<using
|
||||||
|
2:($1+$2)> is passed. Furthermore, the number of columns can vary. For instance
|
||||||
|
gnuplot can read the same two columns of data, but produce a plot with the extra
|
||||||
|
column encoding the sum as the color: C<using 1:2:($1+$2) with points palette>.
|
||||||
|
Please see the gnuplot documentation for lots of detail.
|
||||||
|
|
||||||
|
That's how I<gnuplot> works. Most of the time, I<feedgnuplot> doesn't pass any
|
||||||
|
C<using> expressions at all, and gnuplot does the default thing. But if we want
|
||||||
|
to do something fancy, feedgnuplot supports C<--using curveID expression> and
|
||||||
|
C<--usingall expression>. So we can plot a parabola:
|
||||||
|
|
||||||
|
seq 100 | feedgnuplot --lines --usingall '1:($2*$2)'
|
||||||
|
|
||||||
|
This is powerful, but there are some things to keep in mind:
|
||||||
|
|
||||||
|
=over
|
||||||
|
|
||||||
|
=item
|
||||||
|
|
||||||
|
C<--using> overrides whatever C<using> expression feedgnuplot was going to pass.
|
||||||
|
feedgnuplot passes a C<using> expression only if C<--histogram> or C<--timefmt>
|
||||||
|
or C<--xticlabels> are given. So if C<--using> is given together with any of
|
||||||
|
these, the user must take care to do the right thing (whatever that means at
|
||||||
|
that time).
|
||||||
|
|
||||||
|
=item
|
||||||
|
|
||||||
|
The C<--tuplesize> controls the data passed to feedgnuplot and the data then
|
||||||
|
passed to gnuplot. It does I<not> directly control how gnuplot eventually
|
||||||
|
interprets the data: C<--using> does that. So for instance we can plot
|
||||||
|
color-coded points:
|
||||||
|
|
||||||
|
seq 10 | feedgnuplot --with 'points pt 7 palette' --usingall '1:2:2'
|
||||||
|
|
||||||
|
Here feedgnuplot read 1 column of data. It defauled to C<--tuplesize 2>, so it
|
||||||
|
passed 2 columns of data to gnuplot. gnuplot then produced 3 values for each
|
||||||
|
point, and plotted them as indicated with the C<points palette> style.
|
||||||
|
|
||||||
|
=item
|
||||||
|
|
||||||
|
You I<always> need a column of data to generate a curve. You might want to use a
|
||||||
|
C<using> expression to plot a time series I<and> its cumulative integral. The
|
||||||
|
C<using> expression can compute the integral, but you I<must> pass in the data
|
||||||
|
twice; once for each curve to plot:
|
||||||
|
|
||||||
|
seq 100 | \
|
||||||
|
awk '{print $1,$1}' | \
|
||||||
|
feedgnuplot \
|
||||||
|
--extracmds 'sum=0' \
|
||||||
|
--extracmds 'accum(x) = (sum=sum+x)' \
|
||||||
|
--using 1 '1:(accum($2))' \
|
||||||
|
--lines --y2 1
|
||||||
|
|
||||||
|
=back
|
||||||
|
|
||||||
=head2 Real-time streaming data
|
=head2 Real-time streaming data
|
||||||
|
|
||||||
To plot real-time data, pass in the C<--stream [refreshperiod]> option. Data
|
To plot real-time data, pass in the C<--stream [refreshperiod]> option. Data
|
||||||
@ -2044,6 +2124,22 @@ I<all> the curves.
|
|||||||
|
|
||||||
=item
|
=item
|
||||||
|
|
||||||
|
C<--using curveID expression>
|
||||||
|
|
||||||
|
Specifies a C<using> expression to micromanage the plot. This is a powerful
|
||||||
|
option that allows gnuplot to interpret the input data in arbitrary ways. A
|
||||||
|
C<using> expression tells gnuplot how to map the input columns of data to tuples
|
||||||
|
expected by the plotting style. Please see the L</"'using' expressions"> section above for more detail.
|
||||||
|
|
||||||
|
=item
|
||||||
|
|
||||||
|
C<--usingall expression>
|
||||||
|
|
||||||
|
Global "using" expressions. This works exactly like C<--using>, except it
|
||||||
|
applies to I<all> the curves.
|
||||||
|
|
||||||
|
=item
|
||||||
|
|
||||||
C<--extracmds xxx>
|
C<--extracmds xxx>
|
||||||
|
|
||||||
Additional commands to pass on to gnuplot verbatim. These could contain extra
|
Additional commands to pass on to gnuplot verbatim. These could contain extra
|
||||||
|
@ -67,4 +67,6 @@ complete -W \
|
|||||||
--zmax \
|
--zmax \
|
||||||
--zmin \
|
--zmin \
|
||||||
--xticlabels \
|
--xticlabels \
|
||||||
|
--using \
|
||||||
|
--usingall \
|
||||||
--vnlog ' feedgnuplot
|
--vnlog ' feedgnuplot
|
||||||
|
@ -58,6 +58,8 @@ _arguments -S
|
|||||||
'*--style[Additional styles for a curve]:curve id: :style:' \
|
'*--style[Additional styles for a curve]:curve id: :style:' \
|
||||||
'*--every[Decimation factor for a curve]:curve id: :decimation factor:' \
|
'*--every[Decimation factor for a curve]:curve id: :decimation factor:' \
|
||||||
'--everyall[Decimation factor for ALL curves]:decimation factor' \
|
'--everyall[Decimation factor for ALL curves]:decimation factor' \
|
||||||
|
'*--using[Column specification for a curve]:curve id: :column specification:' \
|
||||||
|
'--usingall[Column specification ALL curves]:column specification' \
|
||||||
'(--3d)*--histogram:plot to treat as a histogram:' \
|
'(--3d)*--histogram:plot to treat as a histogram:' \
|
||||||
'--binwidth:Histogram bin width:' \
|
'--binwidth:Histogram bin width:' \
|
||||||
'--histstyle:Style of histogram:(frequency fnormal unique cumulative cnormal)' \
|
'--histstyle:Style of histogram:(frequency fnormal unique cumulative cnormal)' \
|
||||||
|
17
t/plots.t
17
t/plots.t
@ -39,7 +39,7 @@ BEGIN {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
use Test::More tests => 88;
|
use Test::More tests => 92;
|
||||||
use File::Temp 'tempfile';
|
use File::Temp 'tempfile';
|
||||||
use IPC::Run 'run';
|
use IPC::Run 'run';
|
||||||
use String::ShellQuote;
|
use String::ShellQuote;
|
||||||
@ -298,6 +298,21 @@ tryplot( testname => 'every-individual',
|
|||||||
options => [qw(--points --every 0 2 --every 1 3)],
|
options => [qw(--points --every 0 2 --every 1 3)],
|
||||||
refplot => 'every-individual.ref' );
|
refplot => 'every-individual.ref' );
|
||||||
|
|
||||||
|
tryplot( testname => 'usingall',
|
||||||
|
cmd => q{seq 12 | gawk '{print $1,$1+1}'},
|
||||||
|
options => [qw(--style 0), 'with points pt variable',
|
||||||
|
qw(--style 1), 'with linespoints pt variable',
|
||||||
|
qw(--usingall 1:2:($2) --unset grid)],
|
||||||
|
refplot => 'usingall.ref' );
|
||||||
|
|
||||||
|
tryplot( testname => 'using-individual',
|
||||||
|
cmd => q{seq 12 | gawk '{print $1,$1+1}'},
|
||||||
|
options => [qw(--style 0), 'with points pt variable',
|
||||||
|
qw(--using 0 1:2:($2)),
|
||||||
|
qw(--using 1 1:(12-$2)),
|
||||||
|
qw(--unset grid)],
|
||||||
|
refplot => 'using-individual.ref' );
|
||||||
|
|
||||||
SKIP:
|
SKIP:
|
||||||
{
|
{
|
||||||
|
|
||||||
|
39
t/using-individual.ref
Normal file
39
t/using-individual.ref
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
12 +------------------------------------------------------------------------------------------+
|
||||||
|
| + + + + + |
|
||||||
|
| |
|
||||||
|
| K |
|
||||||
|
| |
|
||||||
|
10 |-+ B J +-|
|
||||||
|
| |
|
||||||
|
| |
|
||||||
|
| B I |
|
||||||
|
| |
|
||||||
|
8 |-+ B H +-|
|
||||||
|
| |
|
||||||
|
| |
|
||||||
|
| B G |
|
||||||
|
| |
|
||||||
|
6 |-+ B F +-|
|
||||||
|
| |
|
||||||
|
| |
|
||||||
|
| E B |
|
||||||
|
| |
|
||||||
|
| |
|
||||||
|
4 |-+ D B +-|
|
||||||
|
| |
|
||||||
|
| C B |
|
||||||
|
| |
|
||||||
|
| |
|
||||||
|
2 |-+ B B +-|
|
||||||
|
| |
|
||||||
|
| A B |
|
||||||
|
| |
|
||||||
|
| |
|
||||||
|
0 |-+ B +-|
|
||||||
|
| |
|
||||||
|
| |
|
||||||
|
| |
|
||||||
|
| + + + + + |
|
||||||
|
-2 +------------------------------------------------------------------------------------------+
|
||||||
|
0 2 4 6 8 10 12
|
||||||
|
|
39
t/usingall.ref
Normal file
39
t/usingall.ref
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
14 +------------------------------------------------------------------------------------------+
|
||||||
|
| + + + + + |
|
||||||
|
| |
|
||||||
|
| ##|
|
||||||
|
| #### |
|
||||||
|
12 |-+ #L# +-|
|
||||||
|
| ## |
|
||||||
|
| ## |
|
||||||
|
| ##K# K |
|
||||||
|
| #### |
|
||||||
|
10 |-+ #J# J +-|
|
||||||
|
| ## |
|
||||||
|
| ## |
|
||||||
|
| ##I# I |
|
||||||
|
| #### |
|
||||||
|
8 |-+ #H# H +-|
|
||||||
|
| ## |
|
||||||
|
| ## |
|
||||||
|
| #G# G |
|
||||||
|
| ### |
|
||||||
|
| ## |
|
||||||
|
6 |-+ ##F# F +-|
|
||||||
|
| #### |
|
||||||
|
| #E# E |
|
||||||
|
| ## |
|
||||||
|
| ## |
|
||||||
|
4 |-+ ##D# D +-|
|
||||||
|
| #### |
|
||||||
|
| #C# C |
|
||||||
|
| ## |
|
||||||
|
| ## |
|
||||||
|
2 |-+ B# B +-|
|
||||||
|
| |
|
||||||
|
| A |
|
||||||
|
| |
|
||||||
|
| + + + + + |
|
||||||
|
0 +------------------------------------------------------------------------------------------+
|
||||||
|
0 2 4 6 8 10 12
|
||||||
|
|
Loading…
Reference in New Issue
Block a user