Как отобразить одну / несколько строк в зависимости от значений в столбце с помощью GNUPlot

#graphics #plot #gnuplot #multiple-columns

#графика #график #gnuplot #несколько столбцов

Вопрос:

У меня есть небольшая проблема с использованием 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 значениями.

Ответ №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
 

введите описание изображения здесь

Комментарии:

1. О, спасибо и вам за ваш ответ. Теперь у меня есть выбор, какой скрипт лучше для моего использования (и поместить этот скрипт на C тоже может быть легко).

2. Очень приятно, идея сделать это (почти) все, используя только gnuplot, интересна, ваше решение также избегает моей plot 0 команды.

Ответ №2:

Вот решение, основанное на нескольких стандартных инструментах, которые должны быть доступны в любом стандартном окне 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") }
 

Шаг 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
 

К сожалению, последний график «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
 

Комментарии:

1. Ожидая вашей помощи, я использовал эту команду: string commands << "cd '/tmp'n" << "set terminal X11n"; << "set multiplot layout 1,2n" << "set title ' Packets Lost 'n" << "plot "< 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 linesn" << "set autoscale xn" ... Same with Jitter but not enough place in comment << "unset multiplotn"; Но это было не совсем то, чего я хотел.

2. Итак, большое спасибо за вашу помощь, это может быть очень полезно для моей работы. Я попытаюсь создать этот скрипт на 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
 

Приведет к этому:

введите описание изображения здесь

Комментарии:

1. Прежде всего, спасибо за ваш ответ. Это то, что я хочу сделать, но, как вы можете видеть в моих «образцовых» данных, могут быть разные IP и разные порты, но я не знаю, сколько разных IP:Port может быть (здесь в моем примере есть два разных: 127.0.0.1: 53091 и 127.0.0.1: 53090). Итак, моя цель — рисовать еще одну строку на каждом графике каждый раз, когда в этом поле есть другое значение. Это более понятно или не совсем? Извините, если нет.

2. Я вижу. Проблема действительно в том, что каждая строка на графике должна соответствовать plot команде (или «последовательности» в команде построения графика). Поэтому я думаю, что для этого потребуется предварительная обработка некоторых данных, чтобы разделить разные адреса, а затем сгенерировать команду построения для каждого из них. Не так просто, но я подумаю об этом, возможно, некоторая awk обработка. И если вы хотите поблагодарить меня, вы можете проголосовать за ответ … 😉

3. О, и вопрос: только два номера портов? Или, может быть, несколько других? Потому что в моем приведенном выше комментарии рассматривалось предположение, что может быть несколько других. Если только две, тогда будет проще.

4. Нет, может быть один или несколько (два, три, я не знаю номер) разных IP:Port (IP и порт могут меняться). На вашем мультиплоте нет разницы с первым столбцом (например, это два значения 4 на оси x, но IP: порт отличается). Так что да, возможно, обработка awk. Спасибо, что потратил время на мою проблему. Я должен кое-что добавить: моя цель — повторять эту графику каждые x секунд, и разные значения IP: Port могут быть добавлены или удалены между двумя циклами. (Моя репутация меньше 15, поэтому я не могу проголосовать : ( )