Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Dynamic Gnuplot graphs

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.

like image 603
mlomailom Avatar asked Dec 06 '12 17:12

mlomailom


3 Answers

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.

like image 169
Thor Avatar answered Oct 12 '22 20:10

Thor


Dynamic plot using bash and gnuplot:

Only 100 last values

By 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.

By bash script

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):

Ping graph sample

Multiprocess demo script

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:

  • q to quit (close all FD, terminate all subprocess)
  • p to start plotting using new gnuplot subprocess
  • s to stop plotting
  • r to reset console terminal
  • h to print header line in console terminal

Usage

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.
like image 41
F. Hauri Avatar answered Oct 12 '22 20:10

F. Hauri


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)

enter image description here

like image 1
theozh Avatar answered Oct 12 '22 19:10

theozh