#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, поэтому я не могу проголосовать : ( )