Merge branch 'master' into debian

This commit is contained in:
Dima Kogan 2013-10-20 00:56:39 -07:00
commit d7e30ac655
6 changed files with 2324 additions and 127 deletions

14
Changes
View File

@ -1,3 +1,17 @@
feedgnuplot (1.25) unstable; urgency=low
* 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)
-- Dima Kogan <dima@secretsauce.net> Sun, 20 Oct 2013 00:09:36 -0700
feedgnuplot (1.24) unstable; urgency=low feedgnuplot (1.24) unstable; urgency=low
* Fixed regression in --monotonic. This works again now * Fixed regression in --monotonic. This works again now

View File

@ -1,7 +1,7 @@
Makefile.PL Makefile.PL
MANIFEST MANIFEST
bin/feedgnuplot bin/feedgnuplot
t/00-load.t
t/manifest.t t/manifest.t
t/plots.t
Changes Changes
LICENSE LICENSE

View File

@ -63,7 +63,7 @@ WriteMakefile
: ()), : ()),
PL_FILES => {}, PL_FILES => {},
EXE_FILES => [ 'bin/feedgnuplot' ], EXE_FILES => [ 'bin/feedgnuplot' ],
PREREQ_PM => { 'Test::Script::Run' => 0}, BUILD_REQUIRES => { 'String::ShellQuote' => 0},
dist => { COMPRESS => 'gzip -9f', SUFFIX => 'gz', }, dist => { COMPRESS => 'gzip -9f', SUFFIX => 'gz', },
clean => { FILES => 'feedgnuplot-*' }, clean => { FILES => 'feedgnuplot-*' },
); );

View File

@ -13,7 +13,7 @@ use Thread::Queue;
use Pod::Usage; use Pod::Usage;
use Time::Piece; use Time::Piece;
my $VERSION = 1.24; my $VERSION = 1.25;
my %options; my %options;
interpretCommandline(); interpretCommandline();
@ -59,6 +59,8 @@ if($options{stream})
{ {
chomp; chomp;
last if /^exit/;
# place every line of input to the queue, so that the plotting thread can process it. if we are # 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 # using an implicit domain (x = line number), then we send it on the data queue also, since
# $. is not meaningful in the plotting thread # $. is not meaningful in the plotting thread
@ -163,8 +165,8 @@ sub interpretCommandline
if ( defined $options{hardcopy} && defined $options{stream} ) if ( defined $options{hardcopy} && defined $options{stream} )
{ {
print STDERR "Warning: since we're making a hardcopy, I'm disabling streaming\n"; print STDERR "--stream doesn't make sense together with --hardcopy\n";
delete $options{stream}; exit -1;
} }
# parse stream option. Allowed only numbers >= 0 or 'trigger'. After this code # parse stream option. Allowed only numbers >= 0 or 'trigger'. After this code
@ -245,6 +247,12 @@ sub interpretCommandline
print STDERR "--3d does not make sense with histograms\n"; print STDERR "--3d does not make sense with histograms\n";
exit -1; exit -1;
} }
if ( defined $options{circles} )
{
print STDERR "--3d does not make sense with circles (gnuplot doesn't support this)\n";
exit -1;
}
} }
else else
{ {
@ -306,6 +314,17 @@ sub interpretCommandline
$options{timefmt_Ncols} = $Nfields; $options{timefmt_Ncols} = $Nfields;
my $regex_str = join( '\s+', ('\S+') x $Nfields ); my $regex_str = join( '\s+', ('\S+') x $Nfields );
$options{timefmt_regex} = qr/$regex_str/; $options{timefmt_regex} = qr/$regex_str/;
# make sure --xlen is an integer. With a timefmt xlen goes through strptime
# and strftime, and those are integer-only
if( defined $options{xlen} )
{
if( $options{xlen} - int($options{xlen}) )
{
say STDERR "When streaming --xlen MUST be an integer. Rounding up to the nearest second";
$options{xlen} = 1 + int($options{xlen});
}
}
} }
} }
@ -400,11 +419,15 @@ sub mainThread
my $outputfile; my $outputfile;
my $outputfileType; my $outputfileType;
if( $options{hardcopy}) if( defined $options{hardcopy})
{ {
$outputfile = $options{hardcopy}; $outputfile = $options{hardcopy};
$outputfile =~ /\.(eps|ps|pdf|png|svg)$/i; if( $outputfile =~ /^[^|] # starts with anything other than |
$outputfileType = $1 ? lc $1 : ''; .* # stuff in the middle
\.(eps|ps|pdf|png|svg)$/ix) # ends with a known extension
{
$outputfileType = lc $1;
}
my %terminalOpts = my %terminalOpts =
( eps => 'postscript solid color enhanced eps', ( eps => 'postscript solid color enhanced eps',
@ -413,8 +436,12 @@ sub mainThread
png => 'png size 1280,1024', png => 'png size 1280,1024',
svg => 'svg'); svg => 'svg');
$options{terminal} ||= $terminalOpts{$outputfileType} if( !defined $options{terminal} &&
if $terminalOpts{$outputfileType}; defined $outputfileType &&
$terminalOpts{$outputfileType} )
{
$options{terminal} = $terminalOpts{$outputfileType};
}
die "Asked to plot to file '$outputfile', but I don't know which terminal to use, and no --terminal given" die "Asked to plot to file '$outputfile', but I don't know which terminal to use, and no --terminal given"
unless $options{terminal}; unless $options{terminal};
@ -493,7 +520,7 @@ sub mainThread
{ {
foreach (@{$options{y2}}) foreach (@{$options{y2}})
{ {
addCurveOption($_, 'axes x1y2 linewidth 3'); addCurveOption($_, 'axes x1y2');
} }
} }
@ -574,15 +601,25 @@ sub mainThread
{ {
next if /^#/o; next if /^#/o;
if( $options{stream} && /^clear/o ) if( $options{stream} )
{ clearCurves(); } {
if(/^clear/o )
{
clearCurves();
next;
}
elsif( $options{stream} && /^replot/o ) if(/^replot/o )
{ {
# /timertick/ determines if the timer was the source of the replot # /timertick/ determines if the timer was the source of the replot
replot( $domain0_numeric, /timertick/ ); replot( $domain0_numeric, /timertick/ );
next;
} }
elsif(! /^replot/o)
# /exit/ is handled in the data-reading thread
}
if(! /^replot/o)
{ {
# parse the incoming data lines. The format is # parse the incoming data lines. The format is
# x id0 dat0 id1 dat1 .... # x id0 dat0 id1 dat1 ....
@ -649,16 +686,29 @@ sub mainThread
} }
} }
# if we were streaming, we're now done!
if( $options{stream} )
{
return;
}
# finished reading in all. Plot what we have # finished reading in all. Plot what we have
plotStoredData(); plotStoredData();
if ( $options{hardcopy}) if ( defined $options{hardcopy})
{ {
print PIPE "set output\n"; print PIPE "set output\n";
# sleep until the plot file exists, and it is closed. Sometimes the output is
# still being written at this point # sleep until the plot file exists, and it is closed. Sometimes the output
# is still being written at this point. If the output filename starts with
# '|', gnuplot pipes the output to that process, instead of writing to a
# file. In that case I don't make sure the file exists, since there IS not
# file
if( $options{hardcopy} !~ /^\|/ )
{
usleep(100_000) until -e $outputfile; usleep(100_000) until -e $outputfile;
usleep(100_000) until(system("fuser -s \"$outputfile\"")); usleep(100_000) until(system("fuser -s \"$outputfile\""));
}
print "Wrote output to $outputfile\n"; print "Wrote output to $outputfile\n";
return; return;
@ -1008,14 +1058,6 @@ instead of I<Y> as a function of I<X>). Thus the first 2 values on each line are
interpreted as the domain instead of just 1. The rest of the processing happens interpreted as the domain instead of just 1. The rest of the processing happens
the same way as before. the same way as before.
=head3 Special data commands
Other than the raw data, 2 special commands are interpreted if they appear in
the input. These are C<replot> and C<clear>. If a line of data begins with
C<replot> and we're plotting in realtime with C<--stream>, the plot will be
refreshed immediately. If a line of data begins with C<clear>, the plot is
cleared, to be re-filled with any data following the C<clear>.
=head3 Time/date data =head3 Time/date data
If the input data domain is a time/date, this can be interpreted with If the input data domain is a time/date, this can be interpreted with
@ -1030,7 +1072,7 @@ given, some other options act a little bit differently:
=item =item
C<--xlen> is in seconds C<--xlen> is an I<integer> in seconds
=item =item
@ -1052,6 +1094,10 @@ C<--timefmt>. Example:
This plots the 'idle' CPU consumption against time. This plots the 'idle' CPU consumption against time.
Note that while gnuplot supports the time/date on any axis, I<feedgnuplot>
currently supports it I<only> as the x-axis domain. This may change in the
future.
=head2 Real-time streaming data =head2 Real-time streaming data
To plot real-time data, pass in the C<--stream [refreshperiod]> option. Data To plot real-time data, pass in the C<--stream [refreshperiod]> option. Data
@ -1060,14 +1106,41 @@ C<refreshperiod> seconds. If the period isn't specified, a 1Hz refresh rate is
used. To refresh at specific intervals indicated by the data, set the used. To refresh at specific intervals indicated by the data, set the
refreshperiod to 0 or to 'trigger'. The plot will then I<only> be refreshed when refreshperiod to 0 or to 'trigger'. The plot will then I<only> be refreshed when
a data line 'replot' is received. This 'replot' command works in both triggered a data line 'replot' is received. This 'replot' command works in both triggered
and timed modes, but in triggered mode, it's the only way to replot. and timed modes, but in triggered mode, it's the only way to replot. Look in
L<Special data commands> for more information.
To plot only the most recent data (instead of I<all> the data), C<--xlen To plot only the most recent data (instead of I<all> the data), C<--xlen
windowsize> can be given. This will create an constantly-updating, scrolling 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 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> 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 or line numbers otherwise). If the domain is a time/date via C<--timefmt>, then
C<windowsize> is in seconds. C<windowsize> is and I<integer> in seconds.
=head3 Special data commands
If we are reading streaming data, the input stream can contain special commands
in addition to the raw data. Feedgnuplot looks for these at the start of every
input line. If a command is detected, the rest of the line is discarded. These
commands are
=over
=item C<replot>
This command refreshes the plot right now, instead of waiting for the next
refresh time indicated by the timer. This command works in addition to the timed
refresh, as indicated by C<--stream [refreshperiod]>.
=item C<clear>
This command clears out the current data in the plot. The plotting process
continues, however, to any data following the C<clear>.
=item C<exit>
This command causes feedgnuplot to exit.
=back
=head2 Hardcopy output =head2 Hardcopy output
@ -1218,7 +1291,7 @@ Interpret the X data as a time/date, parsed with the given format
Show a colormapped xy plot. Requires extra data for the color. zmin/zmax can be Show a colormapped xy plot. Requires extra data for the color. zmin/zmax can be
used to set the extents of the colors. Automatically increments used to set the extents of the colors. Automatically increments
extraValuesPerPoint C<--extraValuesPerPoint>
=item =item
@ -1226,8 +1299,8 @@ extraValuesPerPoint
Plot the data as it comes in, in realtime. If period is given, replot every Plot the data as it comes in, in realtime. If period is given, replot every
period seconds. If no period is given, replot at 1Hz. If the period is given as period seconds. If no period is given, replot at 1Hz. If the period is given as
0 or 'trigger', replot ONLY when the incoming data dictates this. See the 0 or 'trigger', replot I<only> when the incoming data dictates this. See the
"Real-time streaming data" section of the man page. L<Real-time streaming data> section of the man page.
=item =item
@ -1246,31 +1319,8 @@ Do [not] draw points
--circles --circles
Plot with circles. This requires a radius be specified for each point. Plot with circles. This requires a radius be specified for each point.
Automatically increments extraValuesPerPoint Automatically increments C<--extraValuesPerPoint). C<Not> supported for 3d
plots.
=item
--xlabel xxx
Set x-axis label
=item
--ylabel xxx
Set y-axis label
=item
--y2label xxx
Set y2-axis label. Does not apply to 3d plots
=item
--zlabel xxx
Set y-axis label. Only applies to 3d plots
=item =item
@ -1280,9 +1330,9 @@ Set the title of the plot
=item =item
--legend curveID lege --legend curveID legend
nd Set the label for a curve plot. Use this option multiple times for multiple Set the label for a curve plot. Use this option multiple times for multiple
curves. With --dataid, curveID is the ID. Otherwise, it's the index of the curves. With --dataid, curveID is the ID. Otherwise, it's the index of the
curve, starting at 0 curve, starting at 0
@ -1302,51 +1352,18 @@ to 0 to plot ALL the data. Does not make sense with 3d plots. Implies
=item =item
--xmin xxx --xmin/xmax/ymin/ymax/y2min/y2max/zmin/zmax xxx
Set the range for the x axis. These are ignored in a streaming plot Set the range for the given axis. These x-axis bounds are ignored in a streaming
plot. The y2-axis bound do not apply in 3d plots. The z-axis bounds apply
I<only> to 3d plots or colormaps.
=item =item
--xmax xxx --xlabel/ylabel/y2label/zlabel xxx
Set the range for the x axis. These are ignored in a streaming plot Label the given axis. The y2-axis label does not apply to 3d plots while the
z-axis label applies I<only> to 3d plots.
=item
--ymin xxx
Set the range for the y axis.
=item
--ymax xxx
Set the range for the y axis.
=item
--y2min xxx
Set the range for the y2 axis. Does not apply to 3d plots.
=item
--y2max xxx
Set the range for the y2 axis. Does not apply to 3d plots.
=item
--zmin xxx
Set the range for the z axis. Only applies to 3d plots or colormaps.
=item
--zmax xxx
Set the range for the z axis. Only applies to 3d plots or colormaps.
=item =item
@ -1354,7 +1371,14 @@ Set the range for the z axis. Only applies to 3d plots or colormaps.
Plot the data specified by this curve ID on the y2 axis. Without --dataid, the Plot the data specified by this curve ID on the y2 axis. Without --dataid, the
ID is just an ordered 0-based index. Does not apply to 3d plots. Can be passed ID is just an ordered 0-based index. Does not apply to 3d plots. Can be passed
multiple times, or passed a comma-separated list multiple times, or passed a comma-separated list. By default the y2-axis curves
look the same as the y-axis ones. I.e. the viewer of the resulting plot has to
be told which is which via an axes label, legend, etc. Prior to version 1.25 of
feedgnuplot the curves plotted on the y2 axis were drawn with a thicker line.
This is no longer the case, but that behavior can be brought back by passing
something like
--y2 curveid --curvestyle curveid 'linewidth 3'
=item =item
@ -1518,13 +1542,13 @@ Looks at wlan0 on Linux.
gawk '/wlan0/ {if(b) {print $2-b; fflush()} b=$2}' | gawk '/wlan0/ {if(b) {print $2-b; fflush()} b=$2}' |
feedgnuplot --lines --stream --xlen 10 --ylabel 'Bytes/sec' --xlabel seconds feedgnuplot --lines --stream --xlen 10 --ylabel 'Bytes/sec' --xlabel seconds
=head2 Realtime plot of battery charge =head2 Realtime plot of battery charge in respect to time
Uses the result of the C<acpi> command. Uses the result of the C<acpi> command.
$ while true; do acpi; sleep 15; done | $ while true; do acpi; sleep 15; done |
perl -nE 'BEGIN{ $| = 1; } /([0-9]*)%/; say join(" ", $./4, $1);' | perl -nE 'BEGIN{ $| = 1; } /([0-9]*)%/; say join(" ", time(), $1);' |
feedgnuplot --stream --ymin 0 --ymax 100 --domain --xlabel 'Time (seconds)' --ylabel "Battery charge (%)" feedgnuplot --stream --ymin 0 --ymax 100 --lines --domain --xlabel 'Time' --timefmt '%s' --ylabel "Battery charge (%)"
=head2 Realtime plot of temperatures in an IBM Thinkpad =head2 Realtime plot of temperatures in an IBM Thinkpad

View File

@ -1,16 +0,0 @@
#!/usr/bin/perl
# require a threaded perl for my tests. This block lifted verbatim from the cpantesters wiki
BEGIN {
use Config;
if (! $Config{'useithreads'}) {
print("1..0 # Skip: Perl not compiled with 'useithreads'\n");
exit(0);
}
}
use Test::More tests => 1;
use Test::Script::Run;
run_ok( 'feedgnuplot', ['--help'], 'feedgnuplot can run');

2175
t/plots.t Normal file

File diff suppressed because it is too large Load Diff