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
142
bin/feedgnuplot
142
bin/feedgnuplot
@ -91,6 +91,7 @@ sub interpretCommandline
|
||||
$options{curvestyle} = [];
|
||||
$options{style} = [];
|
||||
$options{every} = [];
|
||||
$options{using} = [];
|
||||
$options{histogram} = [];
|
||||
$options{x1y2} = [];
|
||||
$options{x2y1} = [];
|
||||
@ -121,6 +122,7 @@ sub interpretCommandline
|
||||
'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@',
|
||||
'every=s{2}', 'everyall=s',
|
||||
'using=s{2}', 'usingall=s',
|
||||
'square!', 'square_xy!', 'square-xy!', 'squarexy!', 'hardcopy=s', 'maxcurves=i', 'monotonic!', 'timefmt=s',
|
||||
'equation=s@', 'equation-below=s@', 'equation-above=s@',
|
||||
'image=s',
|
||||
@ -185,7 +187,7 @@ sub interpretCommandline
|
||||
@{$options{$listkey}} = map split('\s*,\s*', $_), @{$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};
|
||||
my @in = @{$options{$listkey}};
|
||||
@ -260,7 +262,7 @@ sub interpretCommandline
|
||||
# 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
|
||||
# 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"} = {};
|
||||
|
||||
@ -810,6 +812,7 @@ sub mainThread
|
||||
|
||||
for my $what_options_prefix_suffix ( ['curvestyle', 'extraoptions', '', ' ' ],
|
||||
['every', 'everyoptions', 'every ', ' ' ],
|
||||
['using', 'usingoptions', 'using ', ' ' ],
|
||||
['legend', 'title', '', '' ])
|
||||
{
|
||||
my ($what, $options, $prefix, $suffix) = @$what_options_prefix_suffix;
|
||||
@ -843,8 +846,16 @@ sub mainThread
|
||||
print PIPE
|
||||
"set boxwidth $options{binwidth}\n" .
|
||||
"histbin(x) = $options{binwidth} * floor(0.5 + x/$options{binwidth})\n";
|
||||
|
||||
setCurveAsHistogram( $_ ) foreach (@{$options{histogram}});
|
||||
foreach my $id (@{$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}})
|
||||
{
|
||||
@ -1185,10 +1196,14 @@ sub updateCurveOptions
|
||||
{ $title = $id; }
|
||||
|
||||
my $titleoption = defined $title ? "title \"$title\"" : "notitle";
|
||||
my $histoptions = $curve->{histoptions} || '';
|
||||
|
||||
my $usingoptions = '';
|
||||
if( $options{timefmt} && !$histoptions )
|
||||
my $usingoptions = $curve->{usingoptions};
|
||||
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
|
||||
# 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
|
||||
@ -1241,6 +1256,9 @@ sub getCurve
|
||||
everyoptions => (!exists $options{every_hash}{$id} &&
|
||||
exists $options{everyall}) ?
|
||||
"every $options{everyall} " : ' ',
|
||||
usingoptions => (!exists $options{using_hash}{$id} &&
|
||||
exists $options{usingall}) ?
|
||||
"using $options{usingall} " : '',
|
||||
title => '',
|
||||
datastring => '',
|
||||
datastring_meta => [],
|
||||
@ -1274,25 +1292,14 @@ sub getCurve
|
||||
|
||||
sub addOption
|
||||
{
|
||||
my ($id, $which, $str) = @_;
|
||||
my ($id, $which, $str, $do_not_override) = @_;
|
||||
|
||||
my $curve = getCurve($id);
|
||||
if(!$do_not_override || length($curve->{$which})==0)
|
||||
{
|
||||
$curve->{$which} .= $str;
|
||||
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
|
||||
@ -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
|
||||
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
|
||||
|
||||
To plot real-time data, pass in the C<--stream [refreshperiod]> option. Data
|
||||
@ -2044,6 +2124,22 @@ I<all> the curves.
|
||||
|
||||
=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>
|
||||
|
||||
Additional commands to pass on to gnuplot verbatim. These could contain extra
|
||||
|
@ -67,4 +67,6 @@ complete -W \
|
||||
--zmax \
|
||||
--zmin \
|
||||
--xticlabels \
|
||||
--using \
|
||||
--usingall \
|
||||
--vnlog ' feedgnuplot
|
||||
|
@ -58,6 +58,8 @@ _arguments -S
|
||||
'*--style[Additional styles for a curve]:curve id: :style:' \
|
||||
'*--every[Decimation factor for a curve]:curve id: :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:' \
|
||||
'--binwidth:Histogram bin width:' \
|
||||
'--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 IPC::Run 'run';
|
||||
use String::ShellQuote;
|
||||
@ -298,6 +298,21 @@ tryplot( testname => 'every-individual',
|
||||
options => [qw(--points --every 0 2 --every 1 3)],
|
||||
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:
|
||||
{
|
||||
|
||||
|
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