6

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.

kebs
  • 6,387
  • 4
  • 41
  • 70
DJunior
  • 63
  • 1
  • 3

3 Answers3

5

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

Christoph
  • 47,569
  • 8
  • 87
  • 187
  • Oh, thank you for your response too. Now I have the choice to choose which script is better for my using (and put this script in C++ might be easy too). – DJunior Jun 30 '14 at 13:19
  • Very nice, the idea of doing it (almost) all using only gnuplot is interesting, your solution also avoids my `plot 0` command. – kebs Jun 30 '14 at 20:26
2

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
kebs
  • 6,387
  • 4
  • 41
  • 70
  • Waiting for your help, I used this command: `string commands << "cd '/tmp'\n" << "set terminal X11\n"; << "set multiplot layout 1,2\n" << "set title ' Packets Lost '\n" << "plot \"< tail -n +3 gstServer.log | sort -t\\\" \\\" -k 1,1 -k 2,2n | awk -F \\\" \\\" '{ if (x != $1 && x != NULL) print \\\"\\\\n\\\"$0; else print; };{x=$1}'\" using 2:3 notitle with lines\n" << "set autoscale x\n" ... Same with Jitter but not enough place in comment << "unset multiplot\n";` But that was not exactly what I wanted. – DJunior Jun 30 '14 at 13:13
  • So, Thanks a lot for your help, it might be very useful for my work. I will try to make this script in C++, but with the popen command it might be quite easy. Another time, thank you for you time spending to solve my problem. – DJunior Jun 30 '14 at 13:14
-1

I am not sure I understand your problem, but at least I can answer 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

Will produce this:

enter image description here

kebs
  • 6,387
  • 4
  • 41
  • 70
  • First of all, thanks for your response. This is what I want to do, but, as you can see on my "sample" data, there might be different IP and different port, but I don't know how many different IP:Port there can be (here in my example there is two different ones : 127.0.0.1:53091 and 127.0.0.1:53090). So my goal is to draw another line on each graphic every time there is another value in this field. Is it more clear or not really ? Sorry if not. – DJunior Jun 22 '14 at 08:59
  • I see. The problem indeed is that each line on a plot must correspond to a `plot` command (or a "sequence" in a plotting command). So I think this would need some data pre-processing in order to separate the different adresses, then generate a plot command for each of these. Not that easy, but I'll think about it, probably some `awk` processing. And if you want to thank me, you can upvote the answer... ;-) – kebs Jun 22 '14 at 13:16
  • Oh, and a question: only two ports numbers? Or maybe several others? Because my above comment considered the assumption that there could be several others. If only two, then it will be simpler. – kebs Jun 22 '14 at 13:18
  • No, there might be one or more (two, three, I don't know the number) different IP:Port (IP and Port can change). On your multiplot, there is no difference from the first column (the is two 4 values on the x-axis for example, but the IP:Port is different). So yes, maybe an awk processing. Thanks to spend time on my problem. I have to add something : my goal is to replot this graphic each x seconds, and different IP:Port value(s) can be added or removed between two loop. (My reputation is under 15, so I can't upvote :( ) – DJunior Jun 23 '14 at 06:45