Compare commits

..

2 Commits

Author SHA1 Message Date
Dima Kogan
8ae16172ef test strptime stuff 2015-11-01 01:45:55 -07:00
Dima Kogan
11f568ddf2 streaming plots no longer exit when the input is closed. Pass --exit to do that 2015-11-01 01:45:55 -07:00
17 changed files with 266 additions and 698 deletions

50
Changes
View File

@@ -1,53 +1,3 @@
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;
use DateTime::Format::Strptime;
my $VERSION = 1.40;
my $VERSION = 1.34;
my %options;
interpretCommandline();
@@ -28,11 +29,19 @@ 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 $strptime;
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,16 +51,40 @@ 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 );
if($options{stream})
{
$dataQueue = Thread::Queue->new();
my $addThr = threads->create(\&mainThread);
# 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;
mainThread();
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(); }
@@ -90,7 +123,6 @@ sub interpretCommandline
$options{extracmds} = [];
$options{set} = [];
$options{unset} = [];
$options{equation} = [];
$options{curvestyleall} = '';
$options{styleall} = '';
@@ -104,12 +136,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
@@ -126,73 +159,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))
# --style and --curvestyle are synonyms, as are --styleall and
# --curvestyleall, so fill that in
if( $options{styleall} )
{
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;
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
@@ -242,9 +231,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.
@@ -274,6 +260,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
@@ -365,9 +362,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;
}
@@ -388,12 +385,16 @@ sub interpretCommandline
# and strftime, and those are integer-only
if( defined $options{xlen} )
{
# warning do I need to make sure this is an integer anymore?
if( $options{xlen} - int($options{xlen}) )
{
print STDERR "When streaming --xlen MUST be an integer. Rounding up to the nearest second\n";
$options{xlen} = 1 + int($options{xlen});
}
}
# $strptime = DateTime::Format::Strptime->new( pattern => $options{timefmt} );
}
}
@@ -411,6 +412,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) = @_;
@@ -435,75 +447,31 @@ sub makeDomainNumeric
{
my ($domain0) = @_;
if ( $options{timefmt} )
{
my $timepiece = Time::Piece->strptime( $domain0, $options{timefmt} )
or die "Couldn't parse time format. String '$domain0' doesn't fit format '$options{timefmt}'";
return $timepiece->epoch();
if( $options{timefmt})
{
# my $t = $strptime->parse_datetime($domain0);
# print STDERR "$domain0 $t\n";
}
# return $strptime->parse_datetime($domain0) if $options{timefmt};
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})
if( !$options{stream} && getGnuplotVersion() >= 4.3)
{
$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})
{
*PIPE = *STDOUT;
@@ -529,11 +497,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 &&
@@ -584,7 +552,7 @@ sub mainThread
print(PIPE "set view equal xy\n");
}
# For the specified values, set the legend entries to 'title "blah blah"'
# For the specified values, set the legend entries to 'title "blah blah"'
if(@{$options{legend}})
{
# @{$options{legend}} is a list where consecutive pairs are (curveID,
@@ -599,11 +567,13 @@ sub mainThread
}
}
# add the extra curve options
# add the extra curve options
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)
{
@@ -612,22 +582,22 @@ sub mainThread
}
}
# For the values requested to be printed on the y2 axis, set that
# For the values requested to be printed on the y2 axis, set that
addCurveOption($_, 'axes x1y2') foreach (@{$options{y2}});
# timefmt
# timefmt
if( $options{timefmt} )
{
print(PIPE "set timefmt '$options{timefmt}'\n");
print(PIPE "set xdata time\n");
}
# add the extra global options
# add the extra global options
print(PIPE "$_\n") foreach (@{$options{extracmds}});
print(PIPE "set $_\n") foreach (@{$options{set}});
print(PIPE "unset $_\n") foreach (@{$options{unset}});
# set up histograms
# set up histograms
$options{binwidth} ||= 1; # if no binwidth given, set it to 1
print PIPE
"set boxwidth $options{binwidth}\n" .
@@ -635,6 +605,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";
@@ -663,7 +638,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;
@@ -677,104 +653,128 @@ 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
}
# 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
#
# $options{domain} indicates whether the initial 'x' is given or not (if not, the line
# number is used)
# $options{dataid} indicates whether idX is given or not (if not, the point order in the
# line is used)
# 3d plots require $options{domain}, and dictate "x y" for the domain instead of just "x"
my @fields = split;
if($options{domain})
if(! /^replot/o)
{
if( $options{timefmt} )
{
# no point if doing anything unless I have at least the domain and
# 1 piece of data
next if @fields < $options{timefmt_Ncols}+1;
# 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
#
# $options{domain} indicates whether the initial 'x' is given or not (if not, the line
# number is used)
# $options{dataid} indicates whether idX is given or not (if not, the point order in the
# line is used)
# 3d plots require $options{domain}, and dictate "x y" for the domain instead of just "x"
$domain[0] = join (' ', splice( @fields, 0, $options{timefmt_Ncols}) );
$domain0_numeric = makeDomainNumeric( $domain[0] );
}
elsif(!$options{'3d'})
{
# no point if doing anything unless I have at least the domain and
# 1 piece of data
next if @fields < 1+1;
my @fields = split;
$domain[0] = $domain0_numeric = shift @fields;
if($options{domain})
{
if( $options{timefmt} )
{
# no point if doing anything unless I have at least the domain and
# 1 piece of data
next if @fields < $options{timefmt_Ncols}+1;
$domain[0] = join (' ', splice( @fields, 0, $options{timefmt_Ncols}) );
$domain0_numeric = makeDomainNumeric( $domain[0] );
}
elsif(!$options{'3d'})
{
# no point if doing anything unless I have at least the domain and
# 1 piece of data
next if @fields < 1+1;
$domain[0] = $domain0_numeric = shift @fields;
}
else
{
# no point if doing anything unless I have at least the domain and
# 1 piece of data
next if @fields < 2+1;
@domain = splice(@fields, 0, 2);
}
# domain0_numeric is only used for xlen and monotonic, I think. And
# this is the only thing that requires strptime. Shouldn't bother with
# strptime otherwise
if( $options{monotonic} )
{
if( defined $latestX && $domain0_numeric < $latestX )
{
# the x-coordinate of the new point is in the past, so I wipe out
# all the data and start anew. Before I wipe the old data, I
# replot the old data
replot( $domain0_numeric );
clearCurves();
$latestX = undef;
}
else
{ $latestX = $domain0_numeric; }
}
}
else
{
# no point if doing anything unless I have at least the domain and
# 1 piece of data
next if @fields < 2+1;
@domain = splice(@fields, 0, 2);
# 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] );
}
if( $options{monotonic} )
my $id = -1;
while(@fields)
{
if( defined $latestX && $domain0_numeric < $latestX )
{
# the x-coordinate of the new point is in the past, so I wipe out
# all the data and start anew. Before I wipe the old data, I
# replot the old data
replot( $domain0_numeric );
clearCurves();
$latestX = undef;
}
else
{ $latestX = $domain0_numeric; }
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};
last if @fields < $rangesize;
pushPoint(getCurve($id),
join(' ',
@domain,
splice( @fields, 0, $rangesize ) ) . "\n",
$domain0_numeric);
}
}
else
{
$domain[0] = $.;
$domain0_numeric = makeDomainNumeric( $domain[0] );
}
my $id = -1;
while(@fields)
{
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};
last if @fields < $rangesize;
pushPoint(getCurve($id),
join(' ',
@domain,
splice( @fields, 0, $rangesize ) ) . "\n",
$domain0_numeric);
}
}
# finished reading in all. Plot what we have
plotStoredData() unless $options{stream} && $options{exit};
plotStoredData() unless $options{stream};
if ( defined $options{hardcopy})
{
@@ -795,17 +795,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
@@ -845,9 +838,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"; }
@@ -876,6 +867,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 = '';
@@ -896,7 +900,7 @@ sub updateCurveOptions
$usingoptions = "using 1:" . join(':', @rest);
}
$curve->{options} = "$histoptions $usingoptions $titleoption $curve->{extraoptions} $options{curvestyleall}";
$curve->{options} = "$histoptions $usingoptions $titleoption $curve->{extraoptions} $curvestyleall";
}
sub getCurve
@@ -988,7 +992,7 @@ sub replot
# }
my ($domain0_numeric) = @_;
my ($domain0_numeric, $replot_is_from_timer) = @_;
my $now = [gettimeofday];
@@ -998,7 +1002,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} )
@@ -1014,7 +1018,7 @@ sub replot
{
# if we're using a timefmt, I need to convert my xmin range from
# seconds-since-the-epoch BACK to the timefmt. Sheesh
($xmin, $xmax) = map {Time::Piece->strptime( $_, '%s' )->strftime( $options{timefmt} ) } ($xmin, $xmax);
($xmin, $xmax) = map {$strptime->parse_datetime($_)} ($xmin, $xmax);
}
sendRangeCommand( "xrange", $xmin, $xmax );
}
@@ -1024,7 +1028,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;
}
}
@@ -1298,9 +1302,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
@@ -1535,11 +1537,11 @@ 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 x-values are I<not> drawn
in any way. Can be passed multiple times, or passed a comma- separated list
@@ -1555,24 +1557,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
@@ -1631,34 +1630,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
@@ -1675,17 +1646,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
@@ -1718,10 +1688,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>
@@ -1749,80 +1715,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
@@ -1876,25 +1772,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 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' \

123
debian/changelog vendored
View File

@@ -1,123 +0,0 @@
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
feedgnuplot (1.34-1) unstable; urgency=medium
* Very minor upstream update
* gnuplot-nox can no satisfy the gnuplot dependency for feedgnuplot
-- Dima Kogan <dima@secretsauce.net> Wed, 06 Aug 2014 15:19:56 -0700
feedgnuplot (1.33-1) unstable; urgency=low
* Upstream update: fixed incorrect plotting of --timefmt --rangesize
plots
-- Dima Kogan <dima@secretsauce.net> Thu, 06 Feb 2014 23:19:02 -0800
feedgnuplot (1.32-1) unstable; urgency=low
* Added --rangesize and --rangesizeall. Different curves can now plot
different-size tuples
-- Dima Kogan <dima@secretsauce.net> Wed, 05 Feb 2014 14:00:44 -0800
feedgnuplot (1.30-1) unstable; urgency=low
* made the VCS links canonical
* added --set, --unset, --with, --style, --styleall
-- Dima Kogan <dima@secretsauce.net> Fri, 24 Jan 2014 15:50:03 -0800
feedgnuplot (1.28-1) unstable; urgency=low
* Upstream update:
- Removed example debianization
- Removed unreliable unit tests from automated testing (Closes: #731080)
* gnuplot dependency now favors graphical gnuplot packages
* Removed Anton Gladky from the Uploaders
-- Dima Kogan <dima@secretsauce.net> Wed, 04 Dec 2013 02:05:08 -0800
feedgnuplot (1.26-1) unstable; urgency=low
[ Dima Kogan ]
* Minor POD update
* Added test suite
* Added initial support for --timefmt. Currently time/date data is
supported only at the x-axis domain
* Added --exit option for force feedgnuplot to return even if gnuplot
may not yet be done rendering (patch by Eric Schulte)
* Reformatted the documentation
* y2-axis curves no longer have a thicker line by default
* --hardcopy now handles piped output (gnuplot 'set output |process'
syntax)
[ Anton Gladky ]
* Add libipc-run-perl to Build-Depends to execute tests
-- Dima Kogan <dima@secretsauce.net> Sun, 20 Oct 2013 01:19:51 -0700
feedgnuplot (1.24-2) unstable; urgency=low
* Now building the html documentation from the correct POD source
-- Dima Kogan <dima@secretsauce.net> Sun, 28 Apr 2013 17:42:52 -0700
feedgnuplot (1.24-1) unstable; urgency=low
* Fixed regression in --monotonic. This works again now
* moved POD back into the main source file. This fixes the broken usage
messages
* added --version
* fixed watchfile to work with newer github pages
* priority now optional
-- Dima Kogan <dima@secretsauce.net> Fri, 08 Feb 2013 02:01:32 -0800
feedgnuplot (1.23-2) unstable; urgency=low
* Initial Debian release (Closes: #686413)
-- Dima Kogan <dima@secretsauce.net> Tue, 30 Oct 2012 11:14:01 -0700

1
debian/compat vendored
View File

@@ -1 +0,0 @@
9

21
debian/control vendored
View File

@@ -1,21 +0,0 @@
Source: feedgnuplot
Section: science
Priority: optional
Build-Depends: debhelper (>= 9), libstring-shellquote-perl, perl, gawk, gnuplot, libipc-run-perl
Maintainer: Debian Science Maintainers <debian-science-maintainers@lists.alioth.debian.org>
Uploaders: Dima Kogan <dima@secretsauce.net>
Standards-Version: 3.9.4
Homepage: https://github.com/dkogan/feedgnuplot
Vcs-Git: git://anonscm.debian.org/debian-science/packages/feedgnuplot.git
Vcs-Browser: http://anonscm.debian.org/gitweb/?p=debian-science/packages/feedgnuplot.git
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
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
data representations are supported, as is hardcopy output and streaming display
of live data.

24
debian/copyright vendored
View File

@@ -1,24 +0,0 @@
Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
Source: https://github.com/dkogan/feedgnuplot
Upstream-Contact: Dima Kogan, <dima@secretsauce.net>
Upstream-Name: feedgnuplot
Files: *
Copyright: 2011, Dima Kogan <dima@secretsauce.net>
License: Artistic or GPL-1+
License: Artistic
This program is free software; you can redistribute it and/or modify
it under the terms of the Artistic License, which comes with Perl.
.
On Debian GNU/Linux systems, the complete text of the Artistic License
can be found in `/usr/share/common-licenses/Artistic'.
License: GPL-1+
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 1, or (at your option)
any later version.
.
On Debian GNU/Linux systems, the complete text of version 1 of the
General Public License can be found in `/usr/share/common-licenses/GPL-1'.

View File

@@ -1,9 +0,0 @@
Document: feedgnuplot
Title: Feedgnuplot Manual
Author: Dima Kogan
Abstract: Formatted manpage for feedgnuplot
Section: Science/Data Analysis
Format: HTML
Index: /usr/share/doc/feedgnuplot/feedgnuplot.html
Files: /usr/share/doc/feedgnuplot/feedgnuplot.html

View File

@@ -1 +0,0 @@
feedgnuplot.html

View File

@@ -1,2 +0,0 @@
completions/bash/feedgnuplot /etc/bash_completion.d/
completions/zsh/_feedgnuplot /usr/share/zsh/vendor-completions

4
debian/gbp.conf vendored
View File

@@ -1,4 +0,0 @@
[DEFAULT]
debian-branch = debian
upstream-tag = v%(version)s
pristine-tar = True

12
debian/rules vendored
View File

@@ -1,12 +0,0 @@
#!/usr/bin/make -f
%:
dh $@
override_dh_auto_build:
dh_auto_build
pod2html --title=feedgnuplot bin/feedgnuplot > feedgnuplot.html
override_dh_auto_clean:
rm -rf feedgnuplot.html pod2htm*
dh_auto_clean

View File

@@ -1 +0,0 @@
3.0 (quilt)

4
debian/watch vendored
View File

@@ -1,4 +0,0 @@
version=3
opts=uversionmangle=s/(\d)[_\.\-\+]?((RC|rc|pre|dev|beta|alpha|b|a)\d*)$/$1~$2/,dversionmangle=s/\+(debian|dfsg|ds|deb)\d*$// \
https://github.com/dkogan/feedgnuplot/tags .*/v?(\d.*)\.(?:tgz|tbz2|txz|tar\.(?:gz|bz2|xz))
# Bart Martens <bartm@debian.org> Sat, 22 Dec 2012 12:54:18 +0000

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}