我有一个不断更新的数据文件。我想使用 Gnuplot 动态绘制更新数据文件,可能使用最后 100 个数据点的窗口。
是否可以?如果是这样,一些指针表示赞赏。
这是使用 Gnuplot 和一些 bash 脚本完成它的一种方法:
# An updating data file
while :; do echo $((RANDOM%100)); sleep .1; done > datafile
使用 plot 命令初始化 Gnuplot,并让其他更新来自 replot:
(
echo "plot [0:100] [0:100] '< tail -n100 datafile' with lines";
while :; do sleep .4; echo replot; done
) | gnuplot -persist
这使得 Gnuplottail -n100 datafile
每 0.4 秒评估一次,并将结果用作数据集。tail 命令返回最后 100 行datafile
.
gnuplot
脚本(快速演示)只需尝试这两个命令:
.1 在后台填充动态数据文件
ping -i.2 google.com |
sed -ue 's/.*seq=\([0-9]\+\) .*time=\([0-9.]\+\) .*/\1 \2/p;d' > file.dat &
.2 使用内联脚本运行 gnuplot(随意替换MAX=40
为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 }"
您必须按Ctrl+C退出 gnuplot,然后 kill %%
停止运行ping
。
有一个小bash脚本维护数据文件,只保留最后 100 个值。这只是使用一个计数器,然后在计数器达到限制后删除数据文件中的第一个值:
#!/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
示例运行(加速大约 x15 动画 gif):
我编写了一个可以动态运行 gnuplot(并将尽可能多的后台任务 ping 在一起)的多重bash 脚本。
在这个脚本中,对 Nth last values 没有限制,但是这个脚本展示了如何从许多不同的流中读取数据,保持STDIO的交互性并寻址另一个流以将绘图升级到gnuplot
子流程。
你可以运行:
multiping.sh -pci .3 www.google.com www.stackexchange.com
目标是创建交互式 bash脚本来管理不同的子进程,用于输入和/或输出。
命令
在运行时,您可以与:
gnuplot
子流程进行绘图用法
命令行-h
开关将显示然后帮助:
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.
这是一个仅 gnuplot 的版本,不需要外部脚本。它也适用于 gnuplot 4.6.0(OP 提出问题时的版本)。由于我缺少不断更新的数据源,因此我在 gnuplot 本身内创建数据文件。如果您的文件由另一个程序从外部更新,请跳过标有# *skip
.
绘图在while
循环中运行(检查help while
),可以通过按停止x
,检查help bind
。通过设置适当的数字(检查help pause
)来调整绘图之间的时间延迟。
代码:
### 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
结果:(使用来自 gnuplot 4.6.0 上的 wxt 终端的 ScreenToGif 进行屏幕捕获)