Compare commits

..

3 Commits

Author SHA1 Message Date
Dima Kogan
fa997f2c16 changelog bump 2014-08-22 17:26:39 -07:00
Dima Kogan
62a38826ee Merge commit '8cc51461a327a6c792e81617ab57b7604b1c9187' into stir_nopersist 2014-08-22 17:26:13 -07:00
Dima Kogan
8cc51461a3 disabling --persist because on our arm board it confuses things
with --persist enabled even something basic like

 seq 5 | feedgnuplot --terminal dumb

does not work. feedgnuplot simply sits there doing nothing. This is likely a
gnuplot bug. Those boards run an older gnuplot build, and I can't easily install
a new one to test. It's possible the newer gnuplots fix this, but it's easier to
release a new feedgnuplot instead
2014-08-22 17:18:30 -07:00
8 changed files with 262 additions and 634 deletions

58
Changes
View File

@@ -1,61 +1,3 @@
feedgnuplot (1.41)
* Histograms: --xlen can coexist with --xmin/--xmax
* Histograms: work as expected with --xlen and --monotonic
* Histograms: better sanity checking of options
-- Dima Kogan <dima@secretsauce.net> Fri, 24 Feb 2017 23:42:28 -0800
feedgnuplot (1.40)
* If the options couldn't be parsed I don't dump the whole manpage
* --style and --rangesize can now take a comma-separated list of IDs
* 'any' is from List::MoreUtils, not List::Util
* the sleep-forever delay at end is now > 1000 days
-- Dima Kogan <dima@secretsauce.net> Fri, 25 Nov 2016 14:45:06 -0800
feedgnuplot (1.39)
* by default, histograms are plotted in expected ways
-- Dima Kogan <dima@secretsauce.net> Sat, 15 Oct 2016 20:45:15 -0700
feedgnuplot (1.38)
* hardcopy defaults:
- no enhanced text mode
- larger font size
-- Dima Kogan <dima@secretsauce.net> Wed, 27 Jul 2016 22:15:11 -0700
feedgnuplot (1.37)
* At the end of a streaming plot, include the last chunk of data
* Added --equation to the completions
-- Dima Kogan <dima@secretsauce.net> Fri, 01 Jan 2016 08:09:43 -0800
feedgnuplot (1.36)
* Added --equation to plot symbolic equations
-- Dima Kogan <dima@secretsauce.net> Fri, 13 Nov 2015 11:08:26 -0800
feedgnuplot (1.35)
* replaced a 'say' with 'print'. Should work better with ancient perls
* an "exit" command now has effect even with triggered-only replotting
* More sophisticated handling of termination conditions:
- Without --exit, we always end up with an interactive plot when the
input data is exhausted or when the user sends a ^C to the pipeline
- When streaming, the first ^C does not kill feedgnuplot
* Removed threading
-- Dima Kogan <dima@secretsauce.net> Sun, 01 Nov 2015 12:50:33 -0800
feedgnuplot (1.34)
* Fix for "Use of implicit split to @_ is deprecated". Thanks to Corey

View File

@@ -64,7 +64,6 @@ WriteMakefile
PL_FILES => {},
EXE_FILES => [ 'bin/feedgnuplot' ],
BUILD_REQUIRES => { 'String::ShellQuote' => 0,
'List::MoreUtils' => 0,
'IPC::Run' => 0},
dist => { COMPRESS => 'gzip -9f', SUFFIX => 'gz', },
clean => { FILES => 'feedgnuplot-*' },

View File

@@ -7,15 +7,16 @@ use warnings;
use Getopt::Long;
use Time::HiRes qw( usleep gettimeofday tv_interval );
use IO::Handle;
use IO::Select;
use List::Util qw( first );
use List::MoreUtils 'any';
use Scalar::Util qw( looks_like_number );
use Text::ParseWords; # for shellwords
use Text::ParseWords;
use threads;
use threads::shared;
use Thread::Queue;
use Pod::Usage;
use Time::Piece;
my $VERSION = 1.41;
my $VERSION = 1.34;
my %options;
interpretCommandline();
@@ -28,11 +29,16 @@ interpretCommandline();
# with --xlen, the offsets are preserved by using $curve->{datastring_offset} to
# represent the offset IN THE ORIGINAL STRING of the current start of the
# datastring
my @curves = ();
# list mapping curve names to their indices in the @curves list
my %curveIndices = ();
# now start the data acquisition and plotting threads
my $dataQueue;
# Whether any new data has arrived since the last replot
my $haveNewData;
@@ -42,31 +48,44 @@ my $last_replot_time = [gettimeofday];
# whether the previous replot was timer based
my $last_replot_is_from_timer = 1;
my $streamingFinished : shared = undef;
my $prev_timed_replot_time = [gettimeofday];
my $this_replot_is_from_timer;
my $stdin = IO::Handle->new();
die "Couldn't open STDIN" unless $stdin->fdopen(fileno(STDIN),"r");
my $selector = IO::Select->new( $stdin );
mainThread();
sub getRangeSize
if($options{stream})
{
my ($id) = @_;
$dataQueue = Thread::Queue->new();
my $addThr = threads->create(\&mainThread);
# I'd like to use //, but I guess some people are still on perl 5.8
return
exists $options{rangesize_hash}{$id} ?
$options{rangesize_hash}{$id} :
$options{rangesize_default};
# spawn the plot updating thread. If I'm replotting from a data trigger, I don't need this
my $plotThr = threads->create(\&plotUpdateThread) if $options{stream} > 0;
while(<>)
{
chomp;
last if /^exit/;
# place every line of input to the queue, so that the plotting thread can process it. if we are
# using an implicit domain (x = line number), then we send it on the data queue also, since
# $. is not meaningful in the plotting thread
if(!$options{domain})
{
$_ .= " $.";
}
$dataQueue->enqueue($_);
}
$streamingFinished = 1;
$dataQueue->enqueue(undef);
$plotThr->join() if defined $plotThr;
$addThr->join();
}
else
{ mainThread(); }
sub interpretCommandline
{
@@ -101,7 +120,6 @@ sub interpretCommandline
$options{extracmds} = [];
$options{set} = [];
$options{unset} = [];
$options{equation} = [];
$options{curvestyleall} = '';
$options{styleall} = '';
@@ -115,12 +133,13 @@ sub interpretCommandline
'zmin=f', 'zmax=f', 'y2=s@',
'style=s{2}', 'curvestyle=s{2}', 'curvestyleall=s', 'styleall=s', 'with=s', 'extracmds=s@', 'set=s@', 'unset=s@',
'square!', 'square_xy!', 'hardcopy=s', 'maxcurves=i', 'monotonic!', 'timefmt=s',
'equation=s@',
'histogram=s@', 'binwidth=f', 'histstyle=s',
'terminal=s',
'rangesize=s{2}', 'rangesizeall=i', 'extraValuesPerPoint=i',
'help', 'dump', 'exit', 'version',
'geometry=s') or exit 1;
'geometry=s') or pod2usage( -exitval => 1,
-verbose => 1, # synopsis and args
-output => \*STDERR );
# handle various cmdline-option errors
@@ -137,73 +156,29 @@ sub interpretCommandline
exit 0;
}
# --style and --curvestyle are synonyms, as are --styleall and
# --curvestyleall, so fill that in
if( $options{styleall} )
{
if($options{curvestyleall} ) { $options{curvestyleall} .= " $options{styleall}"; }
else { $options{curvestyleall} = $options{styleall}; }
delete $options{styleall};
}
push @{$options{curvestyle}}, @{$options{style}};
delete $options{style};
if( $options{curvestyleall} && $options{with} )
{
print STDERR "--curvestyleall and --with are mutually exclusive. Please just use one.\n";
exit -1;
}
if( $options{with} )
{
$options{curvestyleall} = "with $options{with}";
delete $options{with};
}
# expand options that are given as comma-separated lists
for my $listkey (qw(histogram y2))
{
@{$options{$listkey}} = map split('\s*,\s*', $_), @{$options{$listkey}}
if defined $options{$listkey};
}
for my $listkey (qw(curvestyle rangesize))
{
next unless defined $options{$listkey};
my @in = @{$options{$listkey}};
my $N = @in / 2;
my @out;
for my $i (0..$N-1)
{
my $key = $in[2*$i];
my $value = $in[2*$i + 1];
for my $key_new (split('\s*,\s*', $key))
{
push @out, $key_new, $value;
}
}
@{$options{$listkey}} = @out;
# --style and --curvestyle are synonyms, as are --styleall and
# --curvestyleall, so fill that in
if( $options{styleall} )
{
if($options{curvestyleall} )
{
$options{curvestyleall} .= " $options{styleall}";
}
else
{
$options{curvestyleall} = $options{styleall};
}
}
push @{$options{curvestyle}}, @{$options{style}};
# If we're plotting histograms, then set the default histogram options for
# each histogram curve
#
# Apply this to plain (non-cumulative) histograms
if( !$options{curvestyleall} && $options{histstyle} =~ /freq|fnorm/ )
{
for my $hist_curve(@{$options{histogram}})
{
# If we don't specify any options specifically for this histogram, use
# the defaults: filled boxes with borders
if( !any { $options{curvestyle}[$_*2] eq $hist_curve } 0..(@{$options{curvestyle}}/2 - 1) )
{
push @{$options{curvestyle}}, ($hist_curve, 'with boxes fill solid border lt -1');
}
}
}
# --legend and --curvestyle options are conceptually hashes, but are parsed as
# 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
@@ -233,10 +208,7 @@ sub interpretCommandline
# I now set up the rangesize to always be
#
# $options{rangesize_hash}{$id} // $options{rangesize_default}
#
# which is available as getRangeSize($id)
if ( $options{rangesizeall} )
{
$options{rangesize_default} = $options{rangesizeall};
@@ -256,9 +228,6 @@ sub interpretCommandline
# -1 for triggered replotting
# >0 for timed replotting
# undef if not streaming
#
# Note that '0' is not allowed, so !$options{stream} will do the expected
# thing
if(defined $options{stream})
{
# if no streaming period is given, default to 1Hz.
@@ -288,6 +257,17 @@ sub interpretCommandline
}
}
if( $options{curvestyleall} && $options{with} )
{
print STDERR "--curvestyleall and --with are mutually exclusive. Please just use one.\n";
exit -1;
}
if( $options{with} )
{
$options{curvestyleall} = "with $options{with}";
$options{with} = '';
}
if ($options{colormap})
{
# colormap styles all curves with palette. Seems like there should be a way to do this with a
@@ -295,13 +275,6 @@ sub interpretCommandline
$options{curvestyleall} .= ' palette';
}
if ( defined $options{binwidth} && !@{$options{histogram}} )
{
print STDERR "--binwidth doesn't make sense without any histograms\n";
exit -1;
}
if ( $options{'3d'} )
{
if ( !$options{domain} )
@@ -334,7 +307,7 @@ sub interpretCommandline
exit -1;
}
if ( @{$options{histogram}} )
if ( defined $options{binwidth} || @{$options{histogram}} )
{
print STDERR "--3d does not make sense with histograms\n";
exit -1;
@@ -368,16 +341,6 @@ sub interpretCommandline
print STDERR "--square_xy only makes sense with --3d\n";
exit -1;
}
for my $hist_curve(@{$options{histogram}})
{
my $hist_dim = getRangeSize($hist_curve);
if( $hist_dim != 1 )
{
print STDERR "I only support 1D histograms, but curve '$hist_curve' has '$hist_dim'-D data\n";
exit -1;
}
}
}
if(defined $options{xlen} && !$options{stream} )
@@ -387,8 +350,7 @@ sub interpretCommandline
}
if($options{stream} && defined $options{xlen} &&
( defined $options{xmin} || defined $options{xmax}) &&
!defined $options{histogram})
( defined $options{xmin} || defined $options{xmax}))
{
print STDERR "With --stream and --xlen the X bounds are set, so neither --xmin nor --xmax make sense\n";
exit -1;
@@ -397,9 +359,9 @@ sub interpretCommandline
# --xlen implies an order to the data, so I force monotonicity
$options{monotonic} = 1 if defined $options{xlen};
if( $options{histstyle} !~ /freq|cum|uniq|cnorm|fnorm/ )
if( $options{histstyle} !~ /freq|cum|uniq|cnorm/ )
{
print STDERR "unknown histstyle. Allowed are 'freq...', 'fnorm...', 'cum...', 'uniq...', 'cnorm...'\n";
print STDERR "unknown histstyle. Allowed are 'freq...', 'cum...', 'uniq...', 'cnorm...'\n";
exit -1;
}
@@ -422,7 +384,7 @@ sub interpretCommandline
{
if( $options{xlen} - int($options{xlen}) )
{
print STDERR "When streaming --xlen MUST be an integer. Rounding up to the nearest second\n";
say STDERR "When streaming --xlen MUST be an integer. Rounding up to the nearest second";
$options{xlen} = 1 + int($options{xlen});
}
}
@@ -443,6 +405,17 @@ sub getGnuplotVersion
return $gnuplotVersion;
}
sub plotUpdateThread
{
while(! $streamingFinished)
{
usleep( $options{stream} * 1e6 );
# indicate that the timer was the replot source
$dataQueue->enqueue('replot timertick');
}
}
sub sendRangeCommand
{
my ($name, $min, $max) = @_;
@@ -478,63 +451,9 @@ sub makeDomainNumeric
return $domain0;
}
sub getNextLine
{
while(1)
{
$this_replot_is_from_timer = undef;
# if we're not streaming, or we're doing triggered-only replotting, simply
# do a blocking read
return $stdin->getline()
if (! $options{stream} || $options{stream} < 0);
my $now = [gettimeofday];
my $time_remaining = $options{stream} - tv_interval($prev_timed_replot_time, $now);
if ( $time_remaining < 0 )
{
$prev_timed_replot_time = $now;
$this_replot_is_from_timer = 1;
return 'replot';
}
if ($selector->can_read($time_remaining))
{
return $stdin->getline();
}
}
}
sub mainThread
{
local *PIPE;
my $dopersist = '';
if( getGnuplotVersion() >= 4.3 && # --persist not available before this
# --persist is needed for the "half-alive" state (see documentation for
# --exit). This state is only used with these options:
!$options{stream} && $options{exit})
{
$dopersist = '--persist';
}
# We trap SIGINT to kill the data input, but keep the plot up. see
# documentation for --exit
if ($options{stream} && !$options{exit})
{
$SIG{INT} = sub
{
print STDERR "$0 received SIGINT. Send again to quit\n";
$SIG{INT} = undef;
};
}
if(exists $options{dump})
{
@@ -544,7 +463,7 @@ sub mainThread
{
my $geometry = defined $options{geometry} ?
"-geometry $options{geometry}" : '';
open PIPE, "|gnuplot $geometry $dopersist" or die "Can't initialize gnuplot\n";
open PIPE, "|gnuplot $geometry" or die "Can't initialize gnuplot\n";
}
autoflush PIPE 1;
@@ -561,11 +480,11 @@ sub mainThread
}
my %terminalOpts =
( eps => 'postscript noenhanced solid color enhanced eps',
ps => 'postscript noenhanced solid color landscape 12',
pdf => 'pdfcairo noenhanced solid color font ",12" size 11in,8.5in',
png => 'png noenhanced size 1280,1024',
svg => 'svg noenhanced');
( eps => 'postscript solid color enhanced eps',
ps => 'postscript solid color landscape 10',
pdf => 'pdfcairo solid color font ",10" size 11in,8.5in',
png => 'png size 1280,1024',
svg => 'svg');
if( !defined $options{terminal} &&
defined $outputfileType &&
@@ -635,7 +554,9 @@ sub mainThread
if(@{$options{curvestyle}})
{
# @{$options{curvestyle}} is a list where consecutive pairs are (curveID,
# style).
# style). I use $options{curvestyle} here instead of
# $options{curvestyle_hash} because I create a new curve when I see a new
# one, and the hash is unordered, thus messing up the ordering
my $n = scalar @{$options{curvestyle}}/2;
foreach my $idx (0..$n-1)
{
@@ -667,6 +588,11 @@ sub mainThread
setCurveAsHistogram( $_ ) foreach (@{$options{histogram}});
# set all the axis ranges
# If a bound isn't given I want to set it to the empty string, so I can communicate it simply to
# gnuplot
print PIPE "set xtics\n";
if(@{$options{y2}})
{
print PIPE "set ytics nomirror\n";
@@ -695,7 +621,8 @@ sub mainThread
# number of seconds since the UNIX epoch.
my $domain0_numeric;
while( defined ($_ = getNextLine()) )
# I should be using the // operator, but I'd like to be compatible with perl 5.8
while( $_ = (defined $dataQueue ? $dataQueue->dequeue() : <>))
{
next if /^#/o;
@@ -709,13 +636,16 @@ sub mainThread
if(/^replot/o )
{
replot( $domain0_numeric );
# /timertick/ determines if the timer was the source of the replot
replot( $domain0_numeric, /timertick/ );
next;
}
last if /^exit/o;
# /exit/ is handled in the data-reading thread
}
if(! /^replot/o)
{
# parse the incoming data lines. The format is
# x id0 dat0 id1 dat1 ....
# where idX is the ID of the curve that datX corresponds to
@@ -772,8 +702,17 @@ sub mainThread
}
}
else
{
# since $. is not meaningful in the plotting thread if we're using the data queue, we pass
# $. on the data queue in that case
if(defined $dataQueue)
{
$domain[0] = pop @fields;
}
else
{
$domain[0] = $.;
}
$domain0_numeric = makeDomainNumeric( $domain[0] );
}
@@ -781,10 +720,20 @@ sub mainThread
while(@fields)
{
if($options{dataid}) { $id = shift @fields; }
else { $id++; }
if($options{dataid})
{
$id = shift @fields;
}
else
{
$id++;
}
# I'd like to use //, but I guess some people are still on perl 5.8
my $rangesize = exists $options{rangesize_hash}{$id} ?
$options{rangesize_hash}{$id} :
$options{rangesize_default};
my $rangesize = getRangeSize($id);
last if @fields < $rangesize;
pushPoint(getCurve($id),
@@ -794,9 +743,16 @@ sub mainThread
$domain0_numeric);
}
}
}
# if we were streaming, we're now done!
if( $options{stream} )
{
return;
}
# finished reading in all. Plot what we have
plotStoredData() unless $options{stream} && $options{exit};
plotStoredData();
if ( defined $options{hardcopy})
{
@@ -817,17 +773,10 @@ sub mainThread
return;
}
# data exhausted. If we're killed now, then we should peacefully die.
if($options{stream} && !$options{exit})
{
print STDERR "Input data exhausted\n";
$SIG{INT} = undef;
}
# we persist gnuplot, so we shouldn't need this sleep. However, once
# gnuplot exits, but the persistent window sticks around, you can no
# longer interactively zoom the plot. So we still sleep
sleep(100000000) unless $options{dump} || $options{exit};
sleep(100000) unless $options{dump} || $options{exit};
}
sub pruneOldData
@@ -867,9 +816,7 @@ sub plotStoredData
my @nonemptyCurves = grep { $_->{datastring} } @curves;
my @extraopts = map {$_->{options}} @nonemptyCurves;
my $body = join('', map { "$_," } @{$options{equation}});
$body .= join(', ' , map({ "'-' $_" } @extraopts) );
my $body = join(', ' , map({ "'-' $_" } @extraopts) );
if($options{'3d'}) { print PIPE "splot $body\n"; }
else { print PIPE "plot $body\n"; }
@@ -898,6 +845,19 @@ sub updateCurveOptions
{ $title = $id; }
my $titleoption = defined $title ? "title \"$title\"" : "notitle";
my ($curvestyleall);
if( defined $options{curvestyle_hash}{$id} )
{
# I have a curve-specific style set with --curvestyle. This style lives in
# $curve->{extraoptions}, and it overrides the global styles
$curvestyleall = '';
}
else
{
$curvestyleall = $options{curvestyleall};
}
my $histoptions = $curve->{histoptions} || '';
my $usingoptions = '';
@@ -908,12 +868,17 @@ sub updateCurveOptions
# as 1 + rangesize). I also need to start the range at the first column
# past the timefmt
my @rest = map {$_ + $options{timefmt_Ncols}} (1..getRangeSize($id));
# I'd like to use //, but I guess some people are still on perl 5.8
my $rangesize = exists $options{rangesize_hash}{$id} ?
$options{rangesize_hash}{$id} :
$options{rangesize_default};
my @rest = map {$_ + $options{timefmt_Ncols}} (1..$rangesize);
$usingoptions = "using 1:" . join(':', @rest);
}
$curve->{options} = "$histoptions $usingoptions $titleoption $curve->{extraoptions} $options{curvestyleall}";
$curve->{options} = "$histoptions $usingoptions $titleoption $curve->{extraoptions} $curvestyleall";
}
sub getCurve
@@ -939,22 +904,6 @@ sub getCurve
$curveIndices{$id} = $#curves;
updateCurveOptions($curves[$#curves], $id);
# --xlen has a meaning if we're not plotting histograms at all or if we're
# plotting ONLY histograms. If we're doing both at the same time, there's no
# consistent way to assign meaning to xlen
if ( defined $options{xlen} &&
# have at least some histograms
@{$options{histogram}} &&
# there are more curves than histogram curves, i.e. there're some
# non-histogram curves
@curves > @{$options{histogram}} ) {
print STDERR "--xlen only makes sense when plotting ONLY histograms or ONLY NON-histograms\n";
exit -1;
}
}
return $curves[$curveIndices{$id}];
}
@@ -982,10 +931,6 @@ 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);
@@ -1025,7 +970,7 @@ sub replot
# }
my ($domain0_numeric) = @_;
my ($domain0_numeric, $replot_is_from_timer) = @_;
my $now = [gettimeofday];
@@ -1035,7 +980,7 @@ sub replot
# if the last replot was timer-based, but this one isn't, force a replot.
# This makes sure that a replot happens for a domain rollover shortly
# after a timer replot
!$this_replot_is_from_timer && $last_replot_is_from_timer ||
!$replot_is_from_timer && $last_replot_is_from_timer ||
# if enough time has elapsed since the last replot, it's ok to replot
tv_interval ( $last_replot_time, $now ) > 0.8*$options{stream} )
@@ -1053,11 +998,7 @@ sub replot
# seconds-since-the-epoch BACK to the timefmt. Sheesh
($xmin, $xmax) = map {Time::Piece->strptime( $_, '%s' )->strftime( $options{timefmt} ) } ($xmin, $xmax);
}
# if we have any histograms, then I'm not really visualizing the domain at
# all, and I don't set the range.
sendRangeCommand( "xrange", $xmin, $xmax )
unless @{$options{histogram}};
sendRangeCommand( "xrange", $xmin, $xmax );
}
plotStoredData();
@@ -1065,7 +1006,7 @@ sub replot
# update replot state
$last_replot_time = $now;
$last_replot_is_from_timer = $this_replot_is_from_timer;
$last_replot_is_from_timer = $replot_is_from_timer;
}
}
@@ -1306,12 +1247,7 @@ windowsize> can be given. This will create an constantly-updating, scrolling
view of the recent past. C<windowsize> should be replaced by the desired length
of the domain window to plot, in domain units (passed-in values if C<--domain>
or line numbers otherwise). If the domain is a time/date via C<--timefmt>, then
C<windowsize> is and I<integer> in seconds. If we're plotting a histogram, then
C<--xlen> causes a histogram over a moving window to be computed. The subtlely
here is that with a histogram you don't actually I<see> the domain since only
the range is analyzed. But the domain is still there, and can be utilized with
C<--xlen>. With C<--xlen> we can plot I<only> histograms or I<only>
I<non>-histograms.
C<windowsize> is and I<integer> in seconds.
=head3 Special data commands
@@ -1344,9 +1280,7 @@ This command causes feedgnuplot to exit.
The script is able to produce hardcopy output with C<--hardcopy outputfile>. The
output type can be inferred from the filename, if B<.ps>, B<.eps>, B<.pdf>,
B<.svg> or B<.png> is requested. If any other file type is requested,
C<--terminal> I<must> be passed in to tell gnuplot how to make the plot. If
C<--terminal> is passed in, then the C<--hardcopy> argument only provides the
output filename.
C<--terminal> I<must> be passed in to tell gnuplot how to make the plot.
=head2 Self-plotting data files
@@ -1545,12 +1479,7 @@ C<--xlen xxx>
When using C<--stream>, sets the size of the x-window to plot. Omit this or set
it to 0 to plot ALL the data. Does not make sense with 3d plots. Implies
C<--monotonic>. If we're plotting a histogram, then C<--xlen> causes a histogram
over a moving window to be computed. The subtlely here is that with a histogram
you don't actually I<see> the domain since only the range is analyzed. But the
domain is still there, and can be utilized with C<--xlen>. With C<--xlen> we can
plot I<only> histograms or I<only> I<non>-histograms.
C<--monotonic>
=item
@@ -1586,15 +1515,14 @@ passing something like
C<--histogram curveID>
Set up a this specific curve to plot a histogram. The bin width is given with
the C<--binwidth> option (assumed 1.0 if omitted). If a drawing style is not
specified for this curve (C<--curvestyle>) or all curves (C<--with>,
C<--curvestyleall>) then the default histogram style is set: filled boxes with
borders. This is what the user generally wants. This works with C<--domain>
the C<--binwidth> option (assumed 1.0 if omitted). C<--histogram> does I<not>
touch the drawing style. It is often desired to plot these with boxes, and this
I<must> be explicitly requested by C<--with boxes>. This works with C<--domain>
and/or C<--stream>, but in those cases the x-value is used I<only> to cull old
data because of C<--xlen> or C<--monotonic>. I.e. the domain values are I<not>
drawn in any way. Can be passed multiple times, or passed a comma- separated
list
data because of C<--xlen> or C<--monotonic>. I.e. the x-values are I<not> drawn
in any way. Can be passed multiple times, or passed a comma- separated list
=item
@@ -1607,24 +1535,21 @@ in the plot. Defaults to 1.0 if not given.
C<--histstyle style>
Normally, histograms are generated with the 'smooth frequency' gnuplot style.
C<--histstyle> can be used to select different C<smooth> settings (see the
gnuplot C<help smooth> page for more info). Allowed values are 'frequency' (the
default), 'fnormal' (available in very recent gnuplots), 'unique', 'cumulative'
and 'cnormal'. 'fnormal' is a normalized histogram. 'unique' indicates whether a
bin has at least one item in it: instead of counting the items, it'll always
report 0 or 1. 'cumulative' is the integral of the 'frequency' histogram.
'cnormal' is like 'cumulative', but rescaled to end up at 1.0.
Normally, histograms are generated with the 'smooth freq' gnuplot style.
C<--histstyle> can be used to select different 'smooth' settings. Allowed are
'unique', 'cumulative' and 'cnormal'. 'unique' indicates whether a bin has at
least one item in it: instead of counting the items, it'll always report 0 or 1.
'cumulative' is the integral of the "normal" histogram. 'cnormal' is like
'cumulative', but rescaled to end up at 1.0.
=item
C<--style curveID style>
Additional styles per curve. With C<--dataid>, curveID is the ID. Otherwise,
it's the index of the curve, starting at 0. curveID can be a comma-separated
list of IDs to which the given style should apply. Use this option multiple
times for multiple curves. C<--styleall> does I<not> apply to curves that have a
C<--style>.
it's the index of the curve, starting at 0. Use this option multiple times for
multiple curves. C<--styleall> does I<not> apply to curves that have a
C<--style>
=item
@@ -1683,34 +1608,6 @@ times.
=item
C<--equation xxx>
Gnuplot can plot both data and symbolic equations. C<feedgnuplot> generally
plots data, but with this option can plot symbolic equations I<also>. This is
generally intended to augment data plots, since for equation-only plots you
don't need C<feedgnuplot>. C<--equation> can be passed multiple times for
multiple equations. The given strings are passed to gnuplot directly without any
thing added or removed, so styling and such should be applied in the string. A
basic example:
seq 100 | awk '{print $1/10, $1/100}' |
feedgnuplot --with 'lines lw 3' --domain --ymax 1
--equation 'sin(x)/x' --equation 'cos(x)/x with lines lw 4'
Here I plot the incoming data (points along a line) with the given style (a line
with thickness 3), I<and> I plot two damped sinusoids on the same plot. The
sinusoids are not affected by C<feedgnuplot> styling, so their styles are set
separately, as in this example. More complicated example:
seq 360 | perl -nE '$th=$_/360 * 3.14*2; $c=cos($th); $s=sin($th); say "$c $s"' |
feedgnuplot --domain --square
--set parametric --set "trange [0:2*3.14]" --equation "sin(t),cos(t)"
Here the data I generate is points along the unit circle. I plot these as
points, and I I<also> plot a true circle as a parametric equation.
=item
C<--square>
Plot data with aspect ratio 1. For 3D plots, this controls the aspect ratio for
@@ -1727,17 +1624,16 @@ For 3D plots, set square aspect ratio for ONLY the x,y axes
C<--hardcopy xxx>
If not streaming, output to a file specified here. Format inferred from
filename, unless specified by C<--terminal>. If C<--terminal> is given,
C<--hardcopy> sets I<only> the output filename.
filename, unless specified by C<--terminal>
=item
C<--terminal xxx>
String passed to 'set terminal'. No attempts are made to validate this.
C<--hardcopy> sets this to some sensible defaults if C<--hardcopy> is set to a
filename ending in C<.png>, C<.pdf>, C<.ps>, C<.eps> or C<.svg>. If any other
file type is desired, use both C<--hardcopy> and C<--terminal>
C<--hardcopy> sets this to some sensible defaults if --hardcopy is given .png,
.pdf, .ps, .eps or .svg. If any other file type is desired, use both
C<--hardcopy> and C<--terminal>
=item
@@ -1770,10 +1666,6 @@ C<--rangesize> is used to set how many values are needed to represent the range
of a point for a particular curve. This overrides any defaults that may exist
for this curve only.
With C<--dataid>, curveID is the ID. Otherwise, it's the index of the curve,
starting at 0. curveID can be a comma-separated list of IDs to which the given
rangesize should apply.
=item
C<--rangesizeall xxx>
@@ -1801,80 +1693,10 @@ is possible to send the output produced this way to gnuplot directly.
C<--exit>
This controls the details of what happens when the input data is exhausted, or
when some part of the C<feedgnuplot> pipeline is killed. This option does
different things depending on whether C<--stream> is active, so read this
closely.
With interactive gnuplot terminals (qt, x11, wxt), the plot windows live in a
separate process from the main C<gnuplot> process. It is thus possible for the
main C<gnuplot> process to exit, while leaving the plot windows up (a caveat is
that such decapitated windows aren't interactive). To be clear, there are 3
possible states:
=over
=item Alive: C<feedgnuplot>, C<gnuplot> alive, plot window process alive, no
shell prompt (shell busy with C<feedgnuplot>)
=item Half-alive: C<feedgnuplot>, C<gnuplot> dead, plot window process alive
(but non-interactive), shell prompt available
=item Dead: C<feedgnuplot>, C<gnuplot> dead, plot window process dead, shell
prompt available
=back
The C<--exit> option controls the details of this behavior. The possibilities
are:
=over
=item No C<--stream>, input pipe is exhausted (all data read in)
=over
=item default; no C<--exit>
Alive. Need to Ctrl-C to get back into the shell
=item C<--exit>
Half-alive. Non-interactive prompt up, and the shell accepts new commands.
Without C<--stream> the goal is to show a plot, so a Dead state is not useful
here.
=back
=item C<--stream>, input pipe is exhausted (all data read in) or the
C<feedgnuplot> process terminated
=over
=item default; no C<--exit>
Alive. Need to Ctrl-C to get back into the shell
=item C<--exit>
Dead. No plot is shown, and the shell accepts new commands. With C<--stream> the
goal is to show a plot as the data comes in, which we have been doing. Now that
we're done, we can clean up everything.
=back
=back
Note that one usually invokes C<feedgnuplot> as a part of a shell pipeline:
$ write_data | feedgnuplot
If the user terminates this pipeline with ^C, then I<all> the processes in the
pipeline receive SIGINT. This normally kills C<feedgnuplot> and all its
C<gnuplot> children, and we let this happen unless C<--stream> and no C<--exit>.
If C<--stream> and no C<--exit>, then we ignore the first ^C. The data feeder
dies, and we behave as if the input data was exhausted. A second ^C kills us
also.
Terminate the feedgnuplot process after passing data to gnuplot. The window will
persist but will not be interactive. Without this option feedgnuplot keeps
running and must be killed by the user. Note that this option works only with
later versions of gnuplot and only with some gnuplot terminals.
=item
@@ -1928,36 +1750,10 @@ in a Thinkpad.
$ while true; do cat /proc/acpi/ibm/thermal | awk '{$1=""; print}' ; sleep 1; done |
feedgnuplot --stream --xlen 100 --lines --autolegend --ymax 100 --ymin 20 --ylabel 'Temperature (deg C)'
=head2 Plotting a histogram of file sizes in a directory, granular to 10MB
=head2 Plotting a histogram of file sizes in a directory
$ ls -l | awk '{print $5/1e6}' |
feedgnuplot --histogram 0
--binwidth 10
--ymin 0 --xlabel 'File size (MB)' --ylabel Frequency
=head2 Plotting a live histogram of the ping round-trip times for the past 20 seconds
$ ping -A -D 8.8.8.8 |
perl -anE 'BEGIN { $| = 1; }
$F[0] =~ s/[\[\]]//g or next;
$F[7] =~ s/.*=//g or next;
say "$F[0] $F[7]"' |
feedgnuplot --stream --domain --histogram 0 --binwidth 10 \
--xlabel 'Ping round-trip time (s)' \
--ylabel Frequency --xlen 20
=head2 Plotting points on top of an existing image
This can be done by using C<--equation> to pass arbitrary plot input to gnuplot:
$ < features_xy.data
feedgnuplot --points --domain
--equation '"image.png" binary filetype=png flipy with rgbimage'
Here an existing image is given to gnuplot verbatim, and data to plot on top of
it is interpreted by feedgnuplot as usual. C<flipy> is useful here because
usually the y axis points up, but when looking at images, this is usually
reversed: the origin is the top-left pixel.
feedgnuplot --histogram 0 --with boxes --ymin 0 --xlabel 'File size (MB)' --ylabel Frequency
=head1 ACKNOWLEDGEMENT

View File

@@ -20,7 +20,6 @@ complete -W \
--extracmds \
--set \
--unset \
--equation \
--geometry \
--hardcopy \
--help \

View File

@@ -32,7 +32,6 @@ _arguments -S
'*--extracmds[Additional gnuplot commands]:command' \
'*--set[Additional 'set' gnuplot commands]:set-option' \
'*--unset[Additional 'unset' gnuplot commands]:unset-option' \
'*--equation[Raw symbolic equation]:equation' \
'--square[Plot data with square aspect ratio]' \
'--square_xy[For 3D plots, set square aspect ratio for ONLY the x,y axes]' \
'--hardcopy[Plot to a file]:filename' \

53
debian/changelog vendored
View File

@@ -1,55 +1,8 @@
feedgnuplot (1.41-1) unstable; urgency=medium
feedgnuplot (1.34stir1-1) unstable; urgency=medium
* Upstream update:
- Histograms: --xlen can coexist with --xmin/--xmax
- Histograms: work as expected with --xlen and --monotonic
- Histograms: better sanity checking of options
* disabled --persist because on our arm board it confuses things
-- Dima Kogan <dkogan@debian.org> Fri, 24 Feb 2017 23:53:27 -0800
feedgnuplot (1.40-1) unstable; urgency=medium
* Upstream update:
- If the options couldn't be parsed I don't dump the whole manpage
- --style and --rangesize can now take a comma-separated list of IDs
- 'any' is from List::MoreUtils, not List::Util
- the sleep-forever delay at end is now > 1000 days
-- Dima Kogan <dkogan@debian.org> Fri, 25 Nov 2016 14:49:36 -0800
feedgnuplot (1.39-1) unstable; urgency=medium
* Upstream update:
- by default, histograms are plotted in expected ways
- No enhanced text mode in hardcopies, slightly larger font size
-- Dima Kogan <dkogan@debian.org> Sat, 15 Oct 2016 20:45:15 -0700
feedgnuplot (1.37-1) unstable; urgency=medium
* Upstream update: At the end of a streaming plot, include the last
chunk of data
-- Dima Kogan <dima@secretsauce.net> Fri, 01 Jan 2016 08:14:23 -0800
feedgnuplot (1.36-1) unstable; urgency=medium
* Upstream update: added --equation to plot symbolic equations
-- Dima Kogan <dima@secretsauce.net> Fri, 13 Nov 2015 11:14:30 -0800
feedgnuplot (1.35-1) unstable; urgency=medium
* Upstream update: fancier handling of termination conditions, no more
threading code
-- Dima Kogan <dima@secretsauce.net> Mon, 02 Nov 2015 13:55:32 -0800
feedgnuplot (1.34-2) unstable; urgency=medium
* Depends now works with the 'gnuplot5' packages
-- Dima Kogan <dima@secretsauce.net> Fri, 10 Oct 2014 14:05:17 -0700
-- Dima Kogan <dima@secretsauce.net> Fri, 22 Aug 2014 14:59:05 -0700
feedgnuplot (1.34-1) unstable; urgency=medium

4
debian/control vendored
View File

@@ -11,9 +11,7 @@ Vcs-Browser: http://anonscm.debian.org/gitweb/?p=debian-science/packages/feedgnu
Package: feedgnuplot
Architecture: all
Depends: ${misc:Depends}, ${perl:Depends},
liblist-moreutils-perl,
gnuplot-qt | gnuplot-x11 | gnuplot-nox | gnuplot5-qt | gnuplot5-x11 | gnuplot5-nox | gnuplot
Depends: ${misc:Depends}, ${perl:Depends}, gnuplot-qt | gnuplot-x11 | gnuplot-nox
Description: Pipe-oriented frontend to Gnuplot
Flexible, command-line-oriented frontend to Gnuplot. Creates plots from data
coming in on STDIN or given in a filename passed on the commandline. Various

View File

@@ -1,58 +0,0 @@
# Sample spec file for rpm-based systems. Debian-based systems already have this
# packaged, so we do not ship those here
Name: feedgnuplot
Version: 1.38
Release: 1%{?dist}
Summary: Pipe-oriented frontend to Gnuplot
BuildArch: noarch
License: Artistic or GPL-1+
URL: https://www.github.com/dkogan/feedgnuplot/
Source0: https://www.github.com/dkogan/feedgnuplot/archive/v%{version}.tar.gz#/%{name}-%{version}.tar.gz
BuildRequires: /usr/bin/pod2html
BuildRequires: perl-String-ShellQuote
BuildRequires: perl-ExtUtils-MakeMaker
BuildRequires: perl
BuildRequires: gawk
BuildRequires: gnuplot
BuildRequires: perl-IPC-Run
Requires: gnuplot
%description
Flexible, command-line-oriented frontend to Gnuplot. Creates plots from data
coming in on STDIN or given in a filename passed on the commandline. Various
data representations are supported, as is hardcopy output and streaming display
of live data.
%prep
%setup -q
%build
perl Makefile.PL INSTALLDIRS=vendor
make
pod2html --title=feedgnuplot bin/feedgnuplot > feedgnuplot.html
%install
make install DESTDIR=%{buildroot} PREFIX=/usr
mkdir -p %{buildroot}%{_defaultdocdir}/%{name}
cp Changes LICENSE feedgnuplot.html %{buildroot}%{_defaultdocdir}/%{name}
mkdir -p %{buildroot}%{_datadir}/zsh/site-functions
cp completions/zsh/* %{buildroot}%{_datadir}/zsh/site-functions
mkdir -p %{buildroot}%{_datadir}/bash-completion/completions
cp completions/bash/* %{buildroot}%{_datadir}/bash-completion/completions
rm -rf %{buildroot}/usr/lib64
%files
%{_bindir}/*
%{_datadir}/zsh/*
%{_datadir}/bash-completion/*
%doc %{_defaultdocdir}/%{name}/*
%doc %{_mandir}