Compare commits

...

19 Commits
v1.37 ... v1.40

Author SHA1 Message Date
Dima Kogan
888583abe9 version bump 2016-11-25 14:45:47 -08:00
Dima Kogan
e17f110269 changelog bump 2016-11-25 14:45:35 -08:00
Dima Kogan
89a185f8a6 the sleep-forever delay at end is now > 1000 days 2016-11-25 14:42:49 -08:00
Dima Kogan
35ed74eaf1 'any' is from List::MoreUtils, not List::Util 2016-11-25 14:41:39 -08:00
Dima Kogan
07f574a929 added a new recipe 2016-11-25 14:39:22 -08:00
Dima Kogan
5dce1d8cda --style and --rangesize can now take a comma-separated list of IDs 2016-11-25 14:39:15 -08:00
Dima Kogan
048b0db65c Slightly better docs 2016-11-25 13:54:22 -08:00
Dima Kogan
b0877a8926 If the options couldn't be parsed I don't dump the whole manpage 2016-11-25 13:33:48 -08:00
Dima Kogan
4958bda912 version bump 2016-10-15 20:50:58 -07:00
Dima Kogan
3860d8281b version bump 2016-10-15 20:42:27 -07:00
Dima Kogan
4f9adb6e11 histograms have the correct default style 2016-10-15 20:35:48 -07:00
Dima Kogan
167e85d2a7 minor simplification
I delete the with option after I use it. This is defensive and clarifies the
intent
2016-10-15 20:17:08 -07:00
Dima Kogan
5123ca73d3 minor simplification
I delete the style and styleall options after I use them. This is defensive and
clarifies the intent
2016-10-15 20:14:33 -07:00
Dima Kogan
d4ca90e1bd minor simplification
curvestyle_hash doesn't really exist anymore
2016-10-15 20:08:24 -07:00
Dima Kogan
9e669044c7 can now ask for fnormal histograms 2016-09-08 23:02:31 -07:00
Dima Kogan
cacbedb336 added sample rpm spec file 2016-07-27 23:08:22 -07:00
Dima Kogan
18994e68e1 version bump 2016-07-27 22:16:34 -07:00
Dima Kogan
f8ed461571 No enhanced text mode in hardcopies, slightly larger font size 2016-07-11 10:11:06 -07:00
Dima Kogan
f01431dd1e removed unneeded old code 2016-01-22 00:48:59 -08:00
4 changed files with 193 additions and 81 deletions

23
Changes
View File

@@ -1,3 +1,26 @@
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) feedgnuplot (1.37)
* At the end of a streaming plot, include the last chunk of data * At the end of a streaming plot, include the last chunk of data

View File

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

View File

@@ -9,12 +9,13 @@ use Time::HiRes qw( usleep gettimeofday tv_interval );
use IO::Handle; use IO::Handle;
use IO::Select; use IO::Select;
use List::Util qw( first ); use List::Util qw( first );
use List::MoreUtils 'any';
use Scalar::Util qw( looks_like_number ); use Scalar::Util qw( looks_like_number );
use Text::ParseWords; # for shellwords use Text::ParseWords; # for shellwords
use Pod::Usage; use Pod::Usage;
use Time::Piece; use Time::Piece;
my $VERSION = 1.37; my $VERSION = 1.40;
my %options; my %options;
interpretCommandline(); interpretCommandline();
@@ -108,9 +109,7 @@ sub interpretCommandline
'terminal=s', 'terminal=s',
'rangesize=s{2}', 'rangesizeall=i', 'extraValuesPerPoint=i', 'rangesize=s{2}', 'rangesizeall=i', 'extraValuesPerPoint=i',
'help', 'dump', 'exit', 'version', 'help', 'dump', 'exit', 'version',
'geometry=s') or pod2usage( -exitval => 1, 'geometry=s') or exit 1;
-verbose => 1, # synopsis and args
-output => \*STDERR );
# handle various cmdline-option errors # handle various cmdline-option errors
@@ -127,28 +126,72 @@ sub interpretCommandline
exit 0; 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 # expand options that are given as comma-separated lists
for my $listkey (qw(histogram y2)) for my $listkey (qw(histogram y2))
{ {
@{$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))
# --style and --curvestyle are synonyms, as are --styleall and
# --curvestyleall, so fill that in
if( $options{styleall} )
{ {
if($options{curvestyleall} ) next unless defined $options{$listkey};
{ my @in = @{$options{$listkey}};
$options{curvestyleall} .= " $options{styleall}"; my $N = @in / 2;
} my @out;
else for my $i (0..$N-1)
{ {
$options{curvestyleall} = $options{styleall}; my $key = $in[2*$i];
} my $value = $in[2*$i + 1];
} for my $key_new (split('\s*,\s*', $key))
push @{$options{curvestyle}}, @{$options{style}}; {
push @out, $key_new, $value;
}
}
@{$options{$listkey}} = @out;
}
# 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 # --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 # arrays in order to preserve the ordering. I parse both of these into hashes
@@ -231,17 +274,6 @@ 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}) if ($options{colormap})
{ {
# colormap styles all curves with palette. Seems like there should be a way to do this with a # colormap styles all curves with palette. Seems like there should be a way to do this with a
@@ -333,9 +365,9 @@ sub interpretCommandline
# --xlen implies an order to the data, so I force monotonicity # --xlen implies an order to the data, so I force monotonicity
$options{monotonic} = 1 if defined $options{xlen}; $options{monotonic} = 1 if defined $options{xlen};
if( $options{histstyle} !~ /freq|cum|uniq|cnorm/ ) if( $options{histstyle} !~ /freq|cum|uniq|cnorm|fnorm/ )
{ {
print STDERR "unknown histstyle. Allowed are 'freq...', 'cum...', 'uniq...', 'cnorm...'\n"; print STDERR "unknown histstyle. Allowed are 'freq...', 'fnorm...', 'cum...', 'uniq...', 'cnorm...'\n";
exit -1; exit -1;
} }
@@ -497,11 +529,11 @@ sub mainThread
} }
my %terminalOpts = my %terminalOpts =
( eps => 'postscript solid color enhanced eps', ( eps => 'postscript noenhanced solid color enhanced eps',
ps => 'postscript solid color landscape 10', ps => 'postscript noenhanced solid color landscape 12',
pdf => 'pdfcairo solid color font ",10" size 11in,8.5in', pdf => 'pdfcairo noenhanced solid color font ",12" size 11in,8.5in',
png => 'png size 1280,1024', png => 'png noenhanced size 1280,1024',
svg => 'svg'); svg => 'svg noenhanced');
if( !defined $options{terminal} && if( !defined $options{terminal} &&
defined $outputfileType && defined $outputfileType &&
@@ -571,9 +603,7 @@ sub mainThread
if(@{$options{curvestyle}}) if(@{$options{curvestyle}})
{ {
# @{$options{curvestyle}} is a list where consecutive pairs are (curveID, # @{$options{curvestyle}} is a list where consecutive pairs are (curveID,
# style). I use $options{curvestyle} here instead of # style).
# $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; my $n = scalar @{$options{curvestyle}}/2;
foreach my $idx (0..$n-1) foreach my $idx (0..$n-1)
{ {
@@ -605,11 +635,6 @@ sub mainThread
setCurveAsHistogram( $_ ) foreach (@{$options{histogram}}); 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}}) if(@{$options{y2}})
{ {
print PIPE "set ytics nomirror\n"; print PIPE "set ytics nomirror\n";
@@ -780,7 +805,7 @@ sub mainThread
# we persist gnuplot, so we shouldn't need this sleep. However, once # we persist gnuplot, so we shouldn't need this sleep. However, once
# gnuplot exits, but the persistent window sticks around, you can no # gnuplot exits, but the persistent window sticks around, you can no
# longer interactively zoom the plot. So we still sleep # longer interactively zoom the plot. So we still sleep
sleep(100000) unless $options{dump} || $options{exit}; sleep(100000000) unless $options{dump} || $options{exit};
} }
sub pruneOldData sub pruneOldData
@@ -851,19 +876,6 @@ sub updateCurveOptions
{ $title = $id; } { $title = $id; }
my $titleoption = defined $title ? "title \"$title\"" : "notitle"; 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 $histoptions = $curve->{histoptions} || '';
my $usingoptions = ''; my $usingoptions = '';
@@ -884,7 +896,7 @@ sub updateCurveOptions
$usingoptions = "using 1:" . join(':', @rest); $usingoptions = "using 1:" . join(':', @rest);
} }
$curve->{options} = "$histoptions $usingoptions $titleoption $curve->{extraoptions} $curvestyleall"; $curve->{options} = "$histoptions $usingoptions $titleoption $curve->{extraoptions} $options{curvestyleall}";
} }
sub getCurve sub getCurve
@@ -1286,7 +1298,9 @@ This command causes feedgnuplot to exit.
The script is able to produce hardcopy output with C<--hardcopy outputfile>. The 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>, 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, 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. 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.
=head2 Self-plotting data files =head2 Self-plotting data files
@@ -1521,11 +1535,11 @@ passing something like
C<--histogram curveID> C<--histogram curveID>
Set up a this specific curve to plot a histogram. The bin width is given with 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). C<--histogram> does I<not> the C<--binwidth> option (assumed 1.0 if omitted). If a drawing style is not
touch the drawing style. It is often desired to plot these with boxes, and this specified for this curve (C<--curvestyle>) or all curves (C<--with>,
I<must> be explicitly requested by C<--with boxes>. This works with C<--domain> 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>
and/or C<--stream>, but in those cases the x-value is used I<only> to cull old 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 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 in any way. Can be passed multiple times, or passed a comma- separated list
@@ -1544,23 +1558,21 @@ C<--histstyle style>
Normally, histograms are generated with the 'smooth frequency' gnuplot style. Normally, histograms are generated with the 'smooth frequency' gnuplot style.
C<--histstyle> can be used to select different C<smooth> settings (see the 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 gnuplot C<help smooth> page for more info). Allowed values are 'frequency' (the
default), 'unique', 'cumulative' and 'cnormal'. 'unique' indicates whether a bin default), 'fnormal' (available in very recent gnuplots), 'unique', 'cumulative'
has at least one item in it: instead of counting the items, it'll always report and 'cnormal'. 'fnormal' is a normalized histogram. 'unique' indicates whether a
0 or 1. 'cumulative' is the integral of the 'frequency' histogram. 'cnormal' is bin has at least one item in it: instead of counting the items, it'll always
like 'cumulative', but rescaled to end up at 1.0. Note that there's no report 0 or 1. 'cumulative' is the integral of the 'frequency' histogram.
normalized 'frequency' option because gnuplot does not provide one. 'cnormal' is like 'cumulative', but rescaled to end up at 1.0.
C<help smooth>
=item =item
C<--style curveID style> C<--style curveID style>
Additional styles per curve. With C<--dataid>, curveID is the ID. Otherwise, Additional styles per curve. With C<--dataid>, curveID is the ID. Otherwise,
it's the index of the curve, starting at 0. Use this option multiple times for it's the index of the curve, starting at 0. curveID can be a comma-separated
multiple curves. C<--styleall> does I<not> apply to curves that have a list of IDs to which the given style should apply. Use this option multiple
C<--style> times for multiple curves. C<--styleall> does I<not> apply to curves that have a
C<--style>.
=item =item
@@ -1663,16 +1675,17 @@ For 3D plots, set square aspect ratio for ONLY the x,y axes
C<--hardcopy xxx> C<--hardcopy xxx>
If not streaming, output to a file specified here. Format inferred from If not streaming, output to a file specified here. Format inferred from
filename, unless specified by C<--terminal> filename, unless specified by C<--terminal>. If C<--terminal> is given,
C<--hardcopy> sets I<only> the output filename.
=item =item
C<--terminal xxx> C<--terminal xxx>
String passed to 'set terminal'. No attempts are made to validate this. String passed to 'set terminal'. No attempts are made to validate this.
C<--hardcopy> sets this to some sensible defaults if --hardcopy is given .png, C<--hardcopy> sets this to some sensible defaults if C<--hardcopy> is set to a
.pdf, .ps, .eps or .svg. If any other file type is desired, use both filename ending in C<.png>, C<.pdf>, C<.ps>, C<.eps> or C<.svg>. If any other
C<--hardcopy> and C<--terminal> file type is desired, use both C<--hardcopy> and C<--terminal>
=item =item
@@ -1705,6 +1718,10 @@ 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 of a point for a particular curve. This overrides any defaults that may exist
for this curve only. 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 =item
C<--rangesizeall xxx> C<--rangesizeall xxx>
@@ -1862,10 +1879,23 @@ in a Thinkpad.
=head2 Plotting a histogram of file sizes in a directory, granular to 10MB =head2 Plotting a histogram of file sizes in a directory, granular to 10MB
$ ls -l | awk '{print $5/1e6}' | $ ls -l | awk '{print $5/1e6}' |
feedgnuplot --histogram 0 --with boxes feedgnuplot --histogram 0
--binwidth 10 --set 'style fill solid' --binwidth 10
--ymin 0 --xlabel 'File size (MB)' --ylabel Frequency --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.
=head1 ACKNOWLEDGEMENT =head1 ACKNOWLEDGEMENT
This program is originally based on the driveGnuPlots.pl script from This program is originally based on the driveGnuPlots.pl script from

58
feedgnuplot.spec Normal file
View File

@@ -0,0 +1,58 @@
# 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}