Чтение значения набора данных в переменную gnuplot (начало серии X) - PullRequest
9 голосов
/ 24 сентября 2011

Первоначально я думал, что это может быть то же самое, что и gnuplot - начало серии X - Переполнение стека - но я думаю, что это немного более конкретно.

Так как меня интересует, так сказать, «начало серии X» - я попытаюсь уточнить на примере; скажем, у вас есть этот скрипт:

# generate data
system "cat > ./inline.dat <<EOF\n\
10.0 1 a 2\n\
10.2 2 b 2\n\
10.4 3 a 2\n\
10.6 4 b 2\n\
10.8 5 c 7\n\
11.0 5 c 7\n\
EOF\n"

# ranges 
set yrange [0:8]
set xrange [0:11.5]

plot "inline.dat" using 1:2 with impulses linewidth 2

Если вы построите график, вы заметите, что данные начинаются с 10 по оси x:

gnuplot-startx.png

Теперь, конечно, вы можете настроить xrange - но иногда вас интересуют «относительные позиции», которые начинаются, так сказать, с «0». Следовательно, хотелось бы, чтобы данные «двигались влево» по оси x, поэтому они начинаются с 0. Поскольку мы знаем, что данные начинаются с 10.0, мы могли бы вычесть это из первого столбца явно:

plot "inline.dat" using ($1-10.0):2 with impulses linewidth 2

... и это в основном помогает.

Но скажем, вы не хотите явно указать "10.0" в команде plot выше; затем - зная, что это первый элемент первого столбца данных, который уже загружен, можно надеяться, что есть способ как-то прочитать это значение в переменной - скажем, с помощью следующего псевдокода:

varval = "inline.dat"(1,1) # get first element of first column in variable
plot "inline.dat" using ($1-varval):2 with impulses linewidth 2

... и с чем-то подобным не нужно было бы указывать это значение «смещения x», так сказать, вручную в команде plot.

Итак, перефразируя, есть ли способ прочитать начало серии x (первое значение данного столбца в наборе данных) как переменную в gnuplot?

Ответы [ 4 ]

6 голосов
/ 25 сентября 2011

Два способа:

1.Сначала нарисуйте функцию и позвольте gnuplot указать минимальное значение x:

plot "inline.dat" using 1:2 with impulses linewidth 2

xmin = GPVAL_DATA_X_MIN
plot "inline.dat" using ($1-xmin):2 with impulses linewidth 2

2.Используйте внешний скрипт для определения минимального значения x:

xmin = `sort -nk 1 inline.dat | head -n 1 | awk '{print $1}'`
plot "inline.dat" using ($1-xmin):2 with impulses linewidth 2
3 голосов
/ 30 января 2013

Чтобы прочитать одно значение из файлов данных, рассмотрите следующую пользовательскую функцию:

at(file, row, col) = system( sprintf("awk -v row=%d -v col=%d 'NR == row {print $col}' %s", row, col, file) )
file="delta-fps" ; row=2 ; col=2
print at(file,row,col)

Конечно, ввод в awk должен быть очищен от пропущенного / недопустимого ввода (пустые строки, комментарии,так далее).Например:

at(file, row, col) = system( sprintf("grep -v '^#|^$' %s | awk -v row=%d -v col=%d 'NR == row {print $col}'", file, row, col) )

Тем не менее, эта функция не позволяет читать какой-либо набор данных, она ограничена файлами.Однако это ограничение можно преодолеть, проверив наличие символа перенаправления '<' в аргументе имени файла и заменив его разумным способом (см. Троичный оператор): </p>

at(file, row, col)=system( sprintf("%s | grep -v '^#\\|^$' | awk -v row=%d -v col=%d 'NR == row {print $col}'", (file[:1] eq '<') ? file[2:] :'cat '.file, row, col) )

Хорошая точка для определенияunction может быть вашим файлом инициализации .gnuplot.

3 голосов
/ 24 января 2013

Хорошо, я продолжаю возвращаться к этому - так что я думаю, что мне нужно было следующее разъяснение:

Учитывая, что gnuplot, ну, ну, отображает наборы данных как 2D-графики - это данность, с которой как-то имеет дело2D структуры или массивы.Вот почему кто-то из C, Perl, Python и т. Д., Естественно, подумает, что можно каким-то образом проиндексировать набор данных и получить значение в заданной позиции строки и столбца;скажем, что-то вроде следующего псевдокода:

my_val = "inline.dat"[1][2]     # get value in 1st row and 2nd column

Или, альтернативно, псевдокод:
my_dataset = parse_dataset("inline.dat")
my_val = get_value(my_dataset, 1, 2)

И я потратилВ поисках чего-то подобного в gnuplot я потратил много времени и ничего подобного не мог найти (прямой доступ к значениям набора данных через индекс строк и столбцов).Кажется, что only вещь, которую можно сделать, это plot набор данных - и, возможно, доступ к значениям там через функцию, вызванную в части using.

Это означает, что если я хочу найти некоторые значения набора данных из gnuplot, у меня есть для итерации по набору данных путем вызова plot - даже если мне нужны именно эти значения дляпостроить правильное plot выражение :) И мне это как-то не нравится, думая, что первое plot может каким-то образом испортить второе :) Однако, как находит максимальное значение в наборе данных и вычитает изсюжет - comp.graphics.apps.gnuplot |Группы Google указывают, что один может plot в файл, также stdout или /dev/null, и получает простую таблицу в формате ASCII - так что, по крайней мере, я могу перенаправить первый вызов втаким образом, так что это не мешает действительному графическому терминалу второго вызова plot.

Итак, ниже приведен еще один пример кода, где первый элемент первого столбца в наборе данных "inline.dat" извлекается с помощью:

# print and get (in _drcv) first value of first data column:
eval print_dataset_row_column("inline.dat",0,1)

# must "copy" the "return" value manually:
first = _drcv

... так что график можетбыть смещенным на first непосредственно в вызове plot.

Обратите внимание, что print_dataset_row_column вызывает plot (перенаправляется через set table на /dev/null) - и, таким образом, каждый каждый раз, когда вы вызываете его для получения одиночное значение , оно будет вызывать итерацию по всему набору данных Весь !Так что если вам нужен первый элемент и последний элемент (и, возможно, другие вещи, такие как некоторая базовая статистика с помощью gnuplot ), вероятно, лучше переписать print_dataset_row_column, чтобы он извлекал все эти данные за один раз.

Также потребуется перезапись print_dataset_row_column, если вы используете некоторые специальные форматы в наборе данных и в строке using.Обратите внимание, что в этом примере третий столбец является строкой, которая по умолчанию не принимается в качестве столбца данных графика;и как таковые, вызовы функций print_dataset_* не будут выполнены, если им придется иметь дело с этим (см. также gnuplot plot из строки ).

Так вотпример кода - давайте назовем его test.gp:

# generate data
system "cat > ./inline.dat <<EOF\n\
10.0 1 a 2\n\
10.2 2 b 2\n\
10.4 3 a 2\n\
10.6 4 b 2\n\
10.8 5 c 7\n\
11.0 5 c 7\n\
EOF\n"

### "dry-run" functions:
# iterate through dataset by calling
# `plot`, redirected to file output (via `set table`)
#
# note: eval (not print) cannot be inside a user-defined function:
#  a(b) = eval('c=3') ; print a(4) ==> "undefined function: eval"
# nor you can make multistatement functions with semicolon:
#  f(x) = (2*x ; x=x+2) ==> ')' expected (at ';')
#
# so these functions are defined as strings - and called through eval
#
# through a single column spec in `using`:
# (`plot` prints table to stdout)
#
print_dataset_column(filename,col) = "set table '/dev/stdout' ;\
plot '".filename."' using ".col." ;\
unset table"
#
# through two column spec in `using`:
# (`plot` prints table to stdout)
#
print_dataset_twocolumn(filename,colA,colB) = "set table '/dev/stdout' ;\
plot '".filename."' using ".colA.":".colB." ;\
unset table"
#
# print value of row:column in dataset, saving it as _drcv variable
#
# init variable
#
_drcv = 0
#
# create _drc helper function; note assign and "return" in
# true branch of ternary clause
#
_drc(ri, colval, col) = (ri == _row) ? _drcv = colval : colval
#
# define the callable function:
#
print_dataset_row_column(filename,row,col) = "_row = ".row." ;\
set table '/dev/null' ;\
plot '".filename."' using (_drc($0, $".col.", ".col.")) ;\
unset table ;\
print '".filename."[r:".row.",c:".col."] = ',_drcv"
#
#
### end dry run functions


#
# test print_dataset_* functions:
#

eval print_dataset_column("inline.dat",0)
eval print_dataset_twocolumn("inline.dat",0,0)

# string column - cannot directly:
# set table '/dev/stdout' ;plot 'inline.dat' using 3 ;unset table
#                                                  ^
# line 69: warning: Skipping data file with no valid points
# line 69: x range is invalid
#~ eval print_dataset_column("inline.dat",3)

eval print_dataset_column("inline.dat",1)
eval print_dataset_twocolumn("inline.dat",1,2)

eval print_dataset_row_column("inline.dat",4,1)
eval print_dataset_row_column("inline.dat",4,2)

# will fail - 3 is string column
# line 82: warning: Skipping data file with no valid points
# line 82: x range is invalid
#~ eval print_dataset_row_column("inline.dat",4,3)


#
# do a plot offset by first element position
#

# print and get (in _drcv) first value of first data column:
eval print_dataset_row_column("inline.dat",0,1)
# must "copy" the "return" value manually:
first = _drcv

# ranges
set yrange [0:8]
set xrange [0:11.5]

# plot finally:
plot "inline.dat" using ($1-first):2 with impulses linewidth 2

Когда этот скрипт вызывается, набор данных в OP строится смещением, начиная с 0 - и в терминале выводится следующее (первые несколькораспечатки таблицы - это фактический вывод от plot, перенаправленный через set table до stdout):

gnuplot> load './test.gp'

# Curve 0 of 1, 6 points
# Curve title: "'inline.dat' using 0"
# x y type
 0  0  i
 1  1  i
 2  2  i
 3  3  i
 4  4  i
 5  5  i


# Curve 0 of 1, 6 points
# Curve title: "'inline.dat' using 0:0"
# x y type
 0  0  i
 1  1  i
 2  2  i
 3  3  i
 4  4  i
 5  5  i


# Curve 0 of 1, 6 points
# Curve title: "'inline.dat' using 1"
# x y type
 0  10  i
 1  10.2  i
 2  10.4  i
 3  10.6  i
 4  10.8  i
 5  11  i


# Curve 0 of 1, 6 points
# Curve title: "'inline.dat' using 1:2"
# x y type
 10  1  i
 10.2  2  i
 10.4  3  i
 10.6  4  i
 10.8  5  i
 11  5  i

inline.dat[r:4,c:1] = 10.8
inline.dat[r:4,c:2] = 5.0
inline.dat[r:0,c:1] = 10.0
2 голосов
/ 24 сентября 2011

Хммм ... Хорошо, я кое-что получил:

initer(x) = (!exists("first")) ? first = x : first ;
plot "inline.dat" using ($1-initer($1)):2 with impulses linewidth 2

... но это больше похоже на "захват" переменной, чем ее чтение (, поскольку функция initer используется для сканирования потока чисел, обнаружения первого и возврата его значения ) :) Надеюсь, есть лучший способ сделать это ....

...