I have a continuously updating data file. I want to use Gnuplot to dynamically plot the updating data file, possibly using a window of the last 100 data points.
Is it possible? If so, some pointers are appreciated.
Here's one way you can accomplish it with Gnuplot and some bash scripting:
# An updating data file
while :; do echo $((RANDOM%100)); sleep .1; done > datafile
Initialize Gnuplot with a plot command, and let the other updates come from replot:
(
echo "plot [0:100] [0:100] '< tail -n100 datafile' with lines";
while :; do sleep .4; echo replot; done
) | gnuplot -persist
This makes Gnuplot evaluate tail -n100 datafile
every .4 seconds and use the result as the data set. The tail command returns the last 100 lines of datafile
.
gnuplot
script (quick demo)Simply try this two commands:
.1 populate dynamic datafile in background
ping -i.2 google.com |
sed -ue 's/.*seq=\([0-9]\+\) .*time=\([0-9.]\+\) .*/\1 \2/p;d' > file.dat &
.2 run gnuplot with inline script (feel free replacing MAX=40
by MAX=100
;-)
MAX=40
gnuplot -e "while(1){pause 0.1;stats 'file.dat' u 0 nooutput;
lPnts=STATS_records<$MAX?0: STATS_records-$MAX;
plot 'file.dat' using 1:2 skip lPnts title 'google' w st }"
You have to hit Ctrl+C to quit gnuplot, then kill %%
to stop running ping
.
There is a little bash script maintaining data file keeping only last 100 values. This simply use a counter, then delete 1st value in data file once counter reach limit:
#!/bin/bash
declare TMPDIR=/tmp DEST=${1:-google.com} DELAY=${2:-.25} MAXDATA=100
[ -d /dev/shm ] && [ -w /dev/shm ] && TMPDIR=/dev/shm
read -r TMPDAT < <(mktemp -p "$TMPDIR" --suffix .dat plot-XXXXXXXXXX)
exec {PFD}> >(exec gnuplot)
closExit() { exec {PFD}>&- ; [ -f "$TMPDAT" ] && rm "$TMPDAT" ; exit ;}
trap closExit 0 1 2 3 6 15
getDatas() {
read -r data < <(
ping -c 1 -n "$DEST" 2>&1 |
sed -u 's/^64.*time=\([0-9.]\+\) .*$/\1/p;d'
)
now=$EPOCHREALTIME
printf '%.6f %s\n' >>"$TMPDAT" "$now" "$data"
(( cnt++ > MAXDATA )) && sed -e 1d -i "$TMPDAT"
printf ' %8d %(%a %b %d %T)T.%s %s\n' \
"$cnt" "${now%.*}" "${now#*.}" "$data"
}
getDatas
echo >&$PFD "set term wxt noraise persist title 'Ping $DEST';"
echo >&$PFD "set xdata time;"
echo >&$PFD "set timefmt '%s';"
while ! read -rsn 1 -t "$DELAY" ;do
getDatas
echo >&$PFD "plot '$TMPDAT' using 1:2 with line title 'ping $DEST';"
done
Sample run (accelerated approx x15 animated gif):
I wrote a multiping bash script that could dynamically run gnuplot (and ping together as many background tasks).
In this script, there was no limit to Nth last values, but this script show how to read datas from many different streams, keeping STDIO for interactivity and addressing another stream for ordering plot upgrade to gnuplot
sub-process.
You could run:
multiping.sh -pci .3 www.google.com www.stackexchange.com
The goal there was to create interactive bash script managing different sub-process, for input and/or output.
Commands
While running, you could interact with:
gnuplot
subprocessUsage
Command line -h
switch will show then help:
Usage: multiping.sh [-[cdhp]] [-i N] <host or ip> [host or ip] [host or ip]...
Options:
-c colors (red for no answer, green for higher "seq" number)
-d Debug this (by opening 2 xterm windows... look at script)
-h help (print this)
-iN Interval for ping command (min 0.2 in user mode)
-p Plot dynamically (require gnuplot)
All following argument will be "target" for "ping" command.
Here is a gnuplot-only version without the need of an external script.
It also works with gnuplot 4.6.0 (the version at the time of OP's question).
Since I'm lacking a data source which is updated constantly, I create the datafile within gnuplot itself. If you have your file updated externally by another program skip the lines marked with # *skip
.
The plotting is running in a while
loop (check help while
) and can be stopped by pressing x
, check help bind
. Adjust the time delay between to plots by setting an appropriate number (check help pause
).
Code:
### dynamic plotting of last 20 points
reset
FILE = 'Test.dat'
bind x 'stop = 1' # stop loop via pressing x
stop = 0
N = 20
set yrange [0:3]
set print FILE # *skip these lines if your file is updated by another program
set print FILE append # *skip
idx = 0 # *skip
while (!stop) {
print sprintf("%g %g",idx=idx+1,sin(idx/3.)+rand(0)*0.5+1) # *skip
pause 0.05 # pause in seconds
stats [*:*][*:*] FILE u 0 nooutput
LastN = STATS_records<N ? 0 : STATS_records-N
plot FILE u 1:2 every ::LastN w lp pt 7
}
set print # *skip
### end of code
Result: (Screen capture using ScreenToGif from a wxt terminal on gnuplot 4.6.0)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With