【问题标题】:How to plot single/multiple lines depending on values in a column with GNUPlot如何根据使用 GNUPlot 的列中的值绘制单条/多条线
【发布时间】:2014-06-20 10:24:53
【问题描述】:

我在使用 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

(我把那个“时间”用于测试,但它工作后会被日期时间取代)

我想绘制两个不同的图形,Time 列在 x 轴上,Packets 列(在第一个图形上)和抖动列(在第二个图形上)在 y 轴上。但是,正如您可能已经看到的,我不知道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

但它在同一个图形上(我还没有使用 multiplot,我尝试过让多行工作)。

有可能吗?如果是,如何在 gnuplot 中绘制这两个图形?
如果没有,我们可以删除 Jitter 图形,并仅在单个图形上绘制 Packets 列,但使用不同的 From 值。

【问题讨论】:

    标签: graphics plot gnuplot multiple-columns


    【解决方案1】:

    这是一个不需要外部文件的解决方案。首先,我提取第一列中的所有不同来源并将它们存储在 gnuplot 变量中:

    filename = 'data.log'
    from=system('tail -n +2 '.filename. '| cut -f 1 -d " " | sort | uniq')
    

    对于绘图期间的过滤,我使用awk 并定义了一个 gnuplot 函数

    select_source(w) = sprintf('< awk ''{if ($1 == "%s") print }'' %s', w, filename)
    

    现在您可以遍历存储在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
    

    【讨论】:

    • 哦,也谢谢你的回复。现在我可以选择更适合我使用的脚本(并且将此脚本放入 C++ 中可能也很容易)。
    • 非常好,(几乎)全部使用 gnuplot 的想法很有趣,您的解决方案也避免了我的 plot 0 命令。
    【解决方案2】:

    这是一个依赖于几个标准工具的解决方案,这些工具应该可以在任何标准 Linux 机器上使用,并且主要基于 bash。让我们从您提供的数据文件开始,没有第一行

    第 1 步:将数据拆分为每个字段 1 的一个文件:awk -f split.awk &lt; data.logsplit.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") }
    

    第 2 步:复制每个生成的数据文件的第一行(因为在 gnuplot 中使用其中一个字段作为标题会使该行在绘图时被忽略):

    for f in `ls file_*.dat`; do 
        head -n 1 $f > tmp.dat
        cat $f >> tmp.dat
        mv tmp.dat $f
    done;
    

    第 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
    

    FIY,最后一个“0”图只是因为要将多个文件绘制到一个图上,gnuplot 需要在行尾添加一个反斜杠。如果有一个,并且在下一行没有绘制任何内容,则会生成错误。所以我只能找到这个愚蠢的技巧来让它发挥作用......

    第四步:调用生成的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
    

    【讨论】:

    • 等待您的帮助,我使用了这个命令:string commands &lt;&lt; "cd '/tmp'\n" &lt;&lt; "set terminal X11\n"; &lt;&lt; "set multiplot layout 1,2\n" &lt;&lt; "set title ' Packets Lost '\n" &lt;&lt; "plot \"&lt; tail -n +3 gstServer.log | sort -t\\\" \\\" -k 1,1 -k 2,2n | awk -F \\\" \\\" '{ if (x != $1 &amp;&amp; x != NULL) print \\\"\\\\n\\\"$0; else print; };{x=$1}'\" using 2:3 notitle with lines\n" &lt;&lt; "set autoscale x\n" ... Same with Jitter but not enough place in comment &lt;&lt; "unset multiplot\n"; 但这并不是我想要的。
    • 所以,非常感谢您的帮助,它可能对我的工作非常有用。我会尝试用 C++ 编写这个脚本,但是使用 popen 命令可能会很容易。再次感谢您花时间解决我的问题。
    【解决方案3】:

    我不确定我是否理解你的问题,但至少我可以回答How can I plot this two graphics in gnuplot ?

    set multiplot layout 1,2
    plot 'data.log' using 3:xtic(2) title 'Packets' with lines
    plot 'data.log' using 4:xtic(2) title 'Jitter' with lines
    unset multiplot
    

    会产生这个:

    【讨论】:

    • 首先,感谢您的回复。这是我想要做的,但是,正如您在我的“示例”数据中看到的那样,可能有不同的 IP 和不同的端口,但我不知道可以有多少不同的 IP:Port(在我的示例中有两个不同的:127.0.0.1:53091 和 127.0.0.1:53090)。所以我的目标是每次在该字段中有另一个值时,在每个图形上画另一条线。是不是更清楚?对不起,如果没有。
    • 我明白了。问题确实是绘图上的每一行都必须对应于plot 命令(或绘图命令中的“序列”)。所以我认为这需要一些数据预处理来分离不同的地址,然后为每个地址生成一个绘图命令。没那么容易,但我会考虑一下,可能是一些awk 处理。如果你想感谢我,你可以投票给答案... ;-)
    • 哦,还有一个问题:只有两个端口号?或者可能还有其他几个?因为我上面的评论考虑了可能有其他几个的假设。如果只有两个,那就更简单了。
    • 不,可能有一个或多个(两个,三个,我不知道数字)不同的IP:Port(IP和Port可以改变)。在您的多图上,与第一列没有区别(例如,x 轴上有两个 4 值,但 IP:Port 不同)。所以是的,也许是一个 awk 处理。感谢您花时间解决我的问题。我必须添加一些内容:我的目标是每 x 秒重新绘制一次该图形,并且可以在两个循环之间添加或删除不同的 IP:Port 值。 (我的声望在 15 岁以下,所以我不能投票 :( )
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-07-25
    • 2011-06-02
    • 2020-09-05
    • 1970-01-01
    • 1970-01-01
    • 2021-08-28
    • 2016-11-10
    相关资源
    最近更新 更多