mirror of
https://github.com/dkogan/feedgnuplot.git
synced 2025-05-06 06:21:16 +08:00
better handling of non-timer-based replots
Previously I was ALWAYS replotting when triggered, ALWAYS replotting on a timer and NEVER replotting on domain rollover with --monotonic. I now have logic to do the right thing in all these cases. I now replot on domain rollover, unless it's happening too quickly.
This commit is contained in:
parent
3146dbdfe7
commit
70b7c98124
107
bin/feedgnuplot
107
bin/feedgnuplot
@ -2,7 +2,7 @@
|
|||||||
use strict;
|
use strict;
|
||||||
use warnings;
|
use warnings;
|
||||||
use Getopt::Long;
|
use Getopt::Long;
|
||||||
use Time::HiRes qw( usleep );
|
use Time::HiRes qw( usleep gettimeofday tv_interval );
|
||||||
use IO::Handle;
|
use IO::Handle;
|
||||||
use List::Util qw( first );
|
use List::Util qw( first );
|
||||||
use Scalar::Util qw( looks_like_number );
|
use Scalar::Util qw( looks_like_number );
|
||||||
@ -33,6 +33,18 @@ my $dataQueue;
|
|||||||
# latest domain variable present in our data
|
# latest domain variable present in our data
|
||||||
my $latestX;
|
my $latestX;
|
||||||
|
|
||||||
|
# The domain of the current point
|
||||||
|
my @domain;
|
||||||
|
|
||||||
|
# Whether any new data has arrived since the last replot
|
||||||
|
my $haveNewData;
|
||||||
|
|
||||||
|
# when the last replot happened
|
||||||
|
my $last_replot_time = [gettimeofday];
|
||||||
|
|
||||||
|
# whether the previous replot was timer based
|
||||||
|
my $last_replot_is_from_timer = 1;
|
||||||
|
|
||||||
my $streamingFinished : shared = undef;
|
my $streamingFinished : shared = undef;
|
||||||
|
|
||||||
if($options{stream})
|
if($options{stream})
|
||||||
@ -283,11 +295,12 @@ sub plotUpdateThread
|
|||||||
while(! $streamingFinished)
|
while(! $streamingFinished)
|
||||||
{
|
{
|
||||||
usleep( $options{stream} * 1e6 );
|
usleep( $options{stream} * 1e6 );
|
||||||
$dataQueue->enqueue('replot');
|
|
||||||
|
# indicate that the timer was the replot source
|
||||||
|
$dataQueue->enqueue('replot timertick');
|
||||||
}
|
}
|
||||||
|
|
||||||
$dataQueue->enqueue(undef);
|
$dataQueue->enqueue(undef);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sub mainThread
|
sub mainThread
|
||||||
@ -470,9 +483,6 @@ sub mainThread
|
|||||||
$pointRE .= '(' . join('\s+', ($numRE) x $valuesPerPoint) . ')';
|
$pointRE .= '(' . join('\s+', ($numRE) x $valuesPerPoint) . ')';
|
||||||
$pointRE = qr/$pointRE/;
|
$pointRE = qr/$pointRE/;
|
||||||
|
|
||||||
my @domain;
|
|
||||||
my $haveNewData;
|
|
||||||
|
|
||||||
# I should be using the // operator, but I'd like to be compatible with perl 5.8
|
# I should be using the // operator, but I'd like to be compatible with perl 5.8
|
||||||
while( $_ = (defined $dataQueue ? $dataQueue->dequeue() : <>))
|
while( $_ = (defined $dataQueue ? $dataQueue->dequeue() : <>))
|
||||||
{
|
{
|
||||||
@ -481,7 +491,12 @@ sub mainThread
|
|||||||
if( $options{stream} && /^clear/o )
|
if( $options{stream} && /^clear/o )
|
||||||
{ clearCurves(); }
|
{ clearCurves(); }
|
||||||
|
|
||||||
if(! /^replot/o)
|
elsif( $options{stream} && /^replot/o )
|
||||||
|
{
|
||||||
|
# /timertick/ determines if the timer was the source of the replot
|
||||||
|
replot( /timertick/ );
|
||||||
|
}
|
||||||
|
elsif(! /^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 ....
|
||||||
@ -507,7 +522,9 @@ sub mainThread
|
|||||||
if( defined $latestX && $domain[0] < $latestX )
|
if( defined $latestX && $domain[0] < $latestX )
|
||||||
{
|
{
|
||||||
# the x-coordinate of the new point is in the past, so I wipe out
|
# the x-coordinate of the new point is in the past, so I wipe out
|
||||||
# all the data and start anew
|
# all the data and start anew. Before I wipe the old data, I
|
||||||
|
# replot the old data
|
||||||
|
replot();
|
||||||
clearCurves();
|
clearCurves();
|
||||||
$latestX = undef;
|
$latestX = undef;
|
||||||
}
|
}
|
||||||
@ -537,26 +554,10 @@ sub mainThread
|
|||||||
if($1 ne '') {$id = $1;}
|
if($1 ne '') {$id = $1;}
|
||||||
else {$id++; }
|
else {$id++; }
|
||||||
|
|
||||||
$haveNewData = 1;
|
|
||||||
pushPoint(getCurve($id),
|
pushPoint(getCurve($id),
|
||||||
[@domain, split( /\s+/, $2)]);
|
[@domain, split( /\s+/, $2)]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
elsif($options{stream})
|
|
||||||
{
|
|
||||||
# we get here if we need to replot AND if we're streaming
|
|
||||||
next unless $haveNewData;
|
|
||||||
$haveNewData = undef;
|
|
||||||
|
|
||||||
if( $options{xlen} )
|
|
||||||
{
|
|
||||||
pruneOldData($domain[0] - $options{xlen});
|
|
||||||
plotStoredData($domain[0] - $options{xlen}, $domain[0]);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{ plotStoredData(); }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
# finished reading in all. Plot what we have
|
# finished reading in all. Plot what we have
|
||||||
@ -708,11 +709,66 @@ sub clearCurves
|
|||||||
{ splice( @$curve, 1 ); }
|
{ splice( @$curve, 1 ); }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sub replot
|
||||||
|
{
|
||||||
|
return unless $haveNewData;
|
||||||
|
$haveNewData = undef;
|
||||||
|
|
||||||
|
return if !$options{stream};
|
||||||
|
|
||||||
|
|
||||||
|
# The logic involving domain rollover replotting due to --monotonic is a bit
|
||||||
|
# tricky. I want this:
|
||||||
|
|
||||||
|
# if( domain rolls over slowly )
|
||||||
|
# {
|
||||||
|
# should update on a timer;
|
||||||
|
# when the domain rolls over, --monotonic should force a replot
|
||||||
|
# }
|
||||||
|
# if( domain rolls over quickly )
|
||||||
|
# {
|
||||||
|
# should update when the domain rolls over,
|
||||||
|
# at most as quickly as the timer indicates
|
||||||
|
# }
|
||||||
|
|
||||||
|
|
||||||
|
my ($replot_is_from_timer) = @_;
|
||||||
|
|
||||||
|
my $now = [gettimeofday];
|
||||||
|
|
||||||
|
if( # If there is no replot timer at all, replot at any indication
|
||||||
|
$options{stream} < 0 ||
|
||||||
|
|
||||||
|
# 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
|
||||||
|
!$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} )
|
||||||
|
{
|
||||||
|
# tests passed; do replot
|
||||||
|
if ( $options{xlen} )
|
||||||
|
{
|
||||||
|
pruneOldData($domain[0] - $options{xlen});
|
||||||
|
plotStoredData($domain[0] - $options{xlen}, $domain[0]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{ plotStoredData(); }
|
||||||
|
|
||||||
|
|
||||||
|
# update replot state
|
||||||
|
$last_replot_time = $now;
|
||||||
|
$last_replot_is_from_timer = $replot_is_from_timer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
# function to add a point to the plot. Assumes that the curve indexed by $idx already exists
|
# function to add a point to the plot. Assumes that the curve indexed by $idx already exists
|
||||||
sub pushPoint
|
sub pushPoint
|
||||||
{
|
{
|
||||||
my ($curve, $xy) = @_;
|
my ($curve, $xy) = @_;
|
||||||
push @$curve, $xy;
|
push @$curve, $xy;
|
||||||
|
$haveNewData = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -1072,7 +1128,8 @@ As an example, if line 3 of the input is "0 9 1 20"
|
|||||||
If a given x-variable is in the past, all data currently
|
If a given x-variable is in the past, all data currently
|
||||||
cached for this curve is purged. Without --monotonic, all
|
cached for this curve is purged. Without --monotonic, all
|
||||||
data is kept. Does not make sense with 3d plots.
|
data is kept. Does not make sense with 3d plots.
|
||||||
No --monotonic by default.
|
No --monotonic by default. The data is replotted before being
|
||||||
|
purged
|
||||||
|
|
||||||
--extraValuesPerPoint xxx
|
--extraValuesPerPoint xxx
|
||||||
How many extra values are given for each data point. Normally this
|
How many extra values are given for each data point. Normally this
|
||||||
|
Loading…
Reference in New Issue
Block a user