DJu*_*ior 5 graphics plot gnuplot multiple-columns
我在使用 gnuplot 时遇到了一些问题。这是我的数据文件:
From Time Packets Jitter
127.0.0.1:53091 1 0 274
127.0.0.1:53091 2 0 417
127.0.0.1:53091 3 36 53
127.0.0.1:53091 4 215 55
127.0.0.1:53090 4 215 55
127.0.0.1:53091 5 215 33
127.0.0.1:53090 6 256 78
Run Code Online (Sandbox Code Playgroud)
(我把那个“时间”用于测试,但它会在它工作后被日期时间替换)
我想绘制两个不同的图形,Time在 x 轴上都有列,在 y 轴上有Packets列(在第一个图形上)和抖动列(在第二个图形上)。但是,正如您可能已经看到的,我不知道From列中有多少个不同的值(最小 1,但我不知道最大值,数据文件将被刷新,并且每个 x 将添加一些值秒)。
所以我的问题是我想From在两个图形上制作另一条“线”,每个不同的值。
实际上,在行From标题中具有值(例如:“127.0.0.1:53091”)。
如果可以更改列顺序,我想补充一点。
我试过:
plot 'data.log' using 3:xtic(2) title 'Packets' with lines, \
'data.log' using 4:xtic(2) title 'Jitter' with lines
Run Code Online (Sandbox Code Playgroud)
但它在同一个图形上(我还没有使用 multiplot,我之前尝试使多条线起作用)。
是否可以 ?如果是,我如何在 gnuplot 中绘制这两个图形?
如果没有,我们可以删除Jitter图形,只在Packets单个图形上绘制列,但具有不同的From值。
这是一个不需要外部文件的解决方案。首先,我提取第一列中的所有不同源并将它们存储在 gnuplot 变量中:
filename = 'data.log'
from=system('tail -n +2 '.filename. '| cut -f 1 -d " " | sort | uniq')
Run Code Online (Sandbox Code Playgroud)
对于绘图期间的过滤,我使用awk并定义了 gnuplot 函数
select_source(w) = sprintf('< awk ''{if ($1 == "%s") print }'' %s', w, filename)
Run Code Online (Sandbox Code Playgroud)
现在您可以迭代存储在from. 完整的gnuplot脚本如下:
filename = 'data.log'
from=system('tail -n +2 '.filename. '| cut -f 1 -d " " | sort | uniq')
select_source(w) = sprintf('< awk ''{if ($1 == "%s") print }'' %s', w, filename)
set style data linespoints
set multiplot layout 1,2
set title 'Packets'
plot for [f in from] select_source(f) using 2:3 title f
set title 'Jitter'
plot for [f in from] select_source(f) using 2:4 title f
unset multiplot
Run Code Online (Sandbox Code Playgroud)

这是一个依赖于几个标准工具的解决方案,这些工具应该在任何标准 Linux 机器上都可用,并且主要基于 bash。让我们从您提供的数据文件开始,没有第一行。
第 1 步:将数据拆分为每个字段 1 的一个文件:awk -f split.awk < data.log,其中包含以下内容split.awk:
#!/usr/bin/awk -f
# erase previous files
BEGIN { system("rm file_*.dat"); }
# print each line in a specific file
{ print $0 >>( "file_" $1 ".dat") }
Run Code Online (Sandbox Code Playgroud)
第2步:复制每个生成的数据文件的第一行(因为在 gnuplot 中使用其中一个字段作为标题会使绘图时忽略该行):
for f in `ls file_*.dat`; do
head -n 1 $f > tmp.dat
cat $f >> tmp.dat
mv tmp.dat $f
done;
Run Code Online (Sandbox Code Playgroud)
步骤3:生成一个 gnuplot 脚本,其中包含plot绘制不同文件的命令(请参阅下面的完整脚本)。
echo "plot \\" >> plot.plt
for f in `ls file_*.dat`; do
echo " '$f' using 2:3 title columnheader(1) with linespoints lw 2, \\" >> plot.plt
done;
echo " 0 notitle" >> plot.plt
Run Code Online (Sandbox Code Playgroud)
仅供参考,最后一个“0”图之所以存在,只是因为要将多个文件绘制到单个图上,gnuplot 需要在行末尾添加反斜杠。如果有一个,并且下一行没有任何内容可绘制,则会生成错误。所以我只能找到这个愚蠢的技巧来让它发挥作用......
步骤4:调用生成的gnuplot脚本。
根据您提供的数据,下面的脚本最终如下:

可能可以更短,但我喜欢保持内容的可读性。
完整脚本:
#!/bin/bash
# 1 - split data into one file per field 1
awk -f split.awk < data.log
# 2 - duplicate first line (useful for gnuplot)
for f in `ls file_*.dat`; do
head -n 1 $f > tmp.dat
cat $f >> tmp.dat
mv tmp.dat $f
done;
# 3 - generate gnuplot script
echo "set terminal pngcairo size 800,500" > plot.plt
echo "set output 'b.png'" >> plot.plt
echo "set multiplot layout 1,2" >> plot.plt
echo "set title 'Packets'" >> plot.plt
echo "plot \\" >> plot.plt
for f in `ls file_*.dat`; do
echo " '$f' using 2:3 title columnheader(1) with linespoints lw 2, \\" >> plot.plt
done;
echo " 0 notitle" >> plot.plt
echo "set title 'Jitter'" >> plot.plt
echo "plot \\" >> plot.plt
for f in `ls file_*.dat`; do
echo " '$f' using 2:4 title columnheader(1) with linespoints lw 2, \\" >> plot.plt
done;
echo " 0 notitle" >> plot.plt
echo "unset multiplot" >> plot.plt
# 4 - call gnuplot script
gnuplot plot.plt
Run Code Online (Sandbox Code Playgroud)