Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to plot single/multiple lines depending on values in a column with GNUPlot

I have a little problem using gnuplot. Here is my datafile:

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

(I put that "time" for the test, but it will be replaced by a datetime after it works)

I want to draw two different graphics, with Time column in x axis on both, and Packets column (on a first graphic) & Jitter column (on a second graphic) in y axis. But, as you may have seen, I don't know how many different values from the From column I will have (minimum 1, but I don't know the maximum, the data file will be refresh and some values will be added each x seconds).
So my problem is that I want to make another 'line' each different From values on both graphics.
In fact, having the From value in title of lines (example : "127.0.0.1:53091").
I want to add that if it's possible to change column order.

I tried:

plot 'data.log' using 3:xtic(2) title 'Packets' with lines, \
     'data.log' using 4:xtic(2) title 'Jitter' with lines

But it's on the same graphic (I don't use multiplot yet, I tried to make the multiple lines works before).

Is it possible ? If it is, How can I plot this two graphics in gnuplot ?
If not, we can remove the Jitter graphic, and plot only the Packets column on a single graphic but with the different From values.

like image 426
DJunior Avatar asked Jun 20 '14 10:06

DJunior


2 Answers

Here is a solution, which doesn't need external files. First I extract all the different sources in the first column and store them in a gnuplot variable:

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

For the filtering during plotting I use awk and define a gnuplot function

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

Now you can iterate over all source stored in from. The complete gnuplot script is as follows:

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

enter image description here

like image 166
Christoph Avatar answered Nov 01 '22 12:11

Christoph


Here is a solution relying on several standard tools that should be available on any standard Linux box, and mostly based on bash. Lets starts with the datafile you provide, without the first line.

Step 1: split data into one file per field 1 : awk -f split.awk < data.log, with the following in 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") }

Step 2: duplicate first line of each produced datafile (because using one of the fields as title in gnuplot makes this line ignored when plotting):

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

Step 3: generate a gnuplot script that holds a plot command that plots the different files (see full script below).

 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, the last "0" plot is there only because to plot several files onto a single plot, gnuplot needs a trailing backslash at the end of the line. And if there is one, and nothing to plot at the following line, an error is generated. So I could only find this dumb trick to make it work...

Step 4: call the generated gnuplot script.

With the data you provided, the script below ends up as: enter image description here

Probably could have been shorter, but I like to keep things readable.

Full script:

#!/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
like image 33
kebs Avatar answered Nov 01 '22 14:11

kebs