将数据集值读入 gnuplot 变量(X 系列的开始)

发布于 2024-12-06 07:54:11 字数 1248 浏览 1 评论 0原文

我最初认为这可能与 gnuplot - X 系列的开始 - Stack Overflow 相同 - 但是我认为这稍微具体一些。

因为我有兴趣找到“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

如果你绘制它,你会注意到数据从 x 轴上的 10 开始:

gnuplot-startx .png

现在,您当然可以调整 xrange - 但有时您对从“0”开始的“相对位置”感兴趣,可以这么说。因此,人们希望看到数据在 x 轴上“向左移动”,因此它从 0 开始。因为我们知道数据从 10.0 开始,所以我们可以从第一列中显式地减去它:

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

...这基本上就是这样窍门。

但是假设您不想在上面的plot命令中显式指定“10.0”;然后 - 知道它是已加载的数据第一列的第一个元素,人们希望有一种方法可以以某种方式读取变量中的该值 - 例如,使用类似于以下伪代码的内容:

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 偏移”值。

那么 - 换句话来说 - 有没有办法将 x 系列的开头(数据集中给定列的第一个值)读取为 gnuplot 中的变量?

I originally thought this may be the same as gnuplot - start of X series - Stack Overflow - but I think this is slightly more specific.

Since I'm interested in finding the "start of X series", so to speak - I'll try to clarify with an example; say you have this script:

# 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

If you plot it, you'll notice the data starts from 10 on x-axis:

gnuplot-startx.png

Now, of course you can adjust the xrange - but sometimes you're interested in "relative positions" which start "from 0", so to speak. Therefore, one would like to see the data "moved left" on the x-axis, so it starts at 0. Since we know the data starts at 10.0, we could subtract that from first column explicitly:

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

... and that basically does the trick.

But say you don't want to specify the "10.0" explicitly in the plot command above; then - knowing that it is the first element of the first column of the data which is already loaded, one would hope there is a way to somehow read this value in a variable - say, with something like the following pseudocode:

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

... and with something like this, one wouldn't have to specify this "x offset" value, so to speak, manually in the plot command.

So - to rephrase - is there a way to read the start of x series (the first value of a given column in a dataset) as a variable in gnuplot?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

远山浅 2024-12-13 07:54:11

两种方式:

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

Two ways:

1.
Plot the function first and let gnuplot to tell the minimum x value:

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.
Use external script to figure out what is the minimum x value:

xmin = `sort -nk 1 inline.dat | head -n 1 | awk '{print $1}'`
plot "inline.dat" using ($1-xmin):2 with impulses linewidth 2
我的痛♀有谁懂 2024-12-13 07:54:11

好吧,我不断地回到这个问题 - 所以我认为我需要在这里进行以下澄清:

鉴于 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 中寻找类似的东西,但找不到类似的东西(通过行和列索引直接变量访问数据集值)。似乎唯一可以做的事情就是绘制数据集 - 并可能通过在 using 部分中调用的函数访问那里的值。

这意味着,如果我想从 gnuplot 中查找一些数据集值,我必须通过调用 plot 来迭代数据集 - 即使我精确地需要这些值来构建正确的 plot 语句 :) 我有点不喜欢这样,认为第一个 plot 可能会以某种方式搞砸之后第二个 :) 但是,如 查找数据集中的最大值并从绘图中减去 - comp。图形.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< 进行偏移/code> 直接在 plot 调用中。

再次注意,print_dataset_row_column 调用 plot(通过 set table 重定向到 /dev/null)——因此,每次调用它来检索单个值时,都会导致整个数据集的迭代!因此,如果您需要第一个元素和最后一个元素(可能还有其他内容,例如 gnuplot 的一些基本统计数据),最好重写 print_dataset_row_column 以便它可以在一个中检索所有这些数据 去。

如果您在数据集和 using 行中使用某些特殊格式,则还需要重写 print_dataset_row_column 。请注意,在此示例中,第三列是一个字符串 - 默认情况下不接受该字符串作为绘图数据列;因此,如果必须处理它,对 print_dataset_* 函数的调用将会失败(另请参阅gnuplot 字符串绘图)。

 

所以这里是示例代码 - 让我们称之为 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 开始 - 并且以下内容在终端中输出(第一个一些表格打印输出是通过 set table 重定向到 stdoutplot 的实际输出):

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

OK, I keep coming back to this - so I think I needed the following clarification here:

Given that gnuplot, well, plots datasets as 2D plots - it's a given that it somehow deals with 2D structures or arrays. That is why someone coming from C, Perl, Python etc. would naturally think it is possible to somehow index the dataset, and be able to retrieve a value at a given row and column position; say, something like the following pseudocode:

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

Or alternately, pseudocode:
my_dataset = parse_dataset("inline.dat")
my_val = get_value(my_dataset, 1, 2)

And I spent a ton of time looking for something like this in gnuplot, and cannot find anything like that (a direct variable access to dataset values through row and column index). It seems that the only thing one can do, is plot the dataset - and possibly access values there, via function called in the using part.

That means, that if I want to find some dataset values from gnuplot, I have to iterate through the dataset by calling plot - even if I need those values precisely to construct a proper plot statement :) And I kind of dislike that, thinking that the first plot may somehow screw up the second afterwards :) However, as finding maximum value in a data set and subtracting from plot - comp.graphics.apps.gnuplot | Google Groups points out, one can plot to a file, also stdout or /dev/null, and get a plain ASCII formatted table - so at least I can redirect the first call in that way, so it doesn't interfere with the actual plotting terminal of the second call to plot.

So, below is another code example, where the first element of first column in the "inline.dat" dataset is retrieved via:

# 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

... so then the plot can be offset by first directly in the plot call.

Note again that print_dataset_row_column calls plot (redirected via set table to /dev/null) -- and as such, each time you call it to retrieve a single value, it will cause iteration through the entire dataset! So if you need first element and last element (and possibly other stuff, like some basic statistics with gnuplot), it's probably better to rewrite print_dataset_row_column so it retrieves all of those in one go.

Also a print_dataset_row_column rewrite would be needed if you use some special formats in your dataset and the using line. Note that in this example, the third column is a string - which is not by default accepted as a plot data column; and as such, calls to the print_dataset_* functions will fail if they have to deal with it (see also gnuplot plot from string).

 

So here is the example code - let's call it 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

When this script is called, the dataset in the OP is plotted moved, starting from 0 - and the following is output in terminal (the first few table printouts are the actual output from plot redirected via set table to 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
意中人 2024-12-13 07:54:11

要从数据文件中读取单个值,请考虑以下用户定义的函数:

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 '^#|^

不过,该函数不允许读取任何数据集,它仅限于文件。但是,可以通过检查重定向字符“<”来克服此限制。在文件名参数中并以合理的方式替换它(请参阅三元运算符):

at(file, row, col)=system( sprintf("%s | grep -v '^#\\|^

定义此类函数的一个好点可能是您的 .gnuplot 初始化文件。

%s | awk -v row=%d -v col=%d 'NR == row {print $col}'", file, row, col) )

不过,该函数不允许读取任何数据集,它仅限于文件。但是,可以通过检查重定向字符“<”来克服此限制。在文件名参数中并以合理的方式替换它(请参阅三元运算符):


定义此类函数的一个好点可能是您的 .gnuplot 初始化文件。

| awk -v row=%d -v col=%d 'NR == row {print $col}'", (file[:1] eq '<') ? file[2:] :'cat '.file, row, col) )

定义此类函数的一个好点可能是您的 .gnuplot 初始化文件。

%s | awk -v row=%d -v col=%d 'NR == row {print $col}'", file, row, col) )

不过,该函数不允许读取任何数据集,它仅限于文件。但是,可以通过检查重定向字符“<”来克服此限制。在文件名参数中并以合理的方式替换它(请参阅三元运算符):

定义此类函数的一个好点可能是您的 .gnuplot 初始化文件。

To read a single value from a data files consider the following user defined function:

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)

Of course, the input to awk has to be cleared of ignored/invalid input (blank lines, comments, etc). For example:

at(file, row, col) = system( sprintf("grep -v '^#|^

Still, this function will not allow reading any dataset, it is restricted to files. However, this limitation can be overcome by checking for the redirection character '<' in the file name argument and replacing it in a sensible way (see the ternary operator):

at(file, row, col)=system( sprintf("%s | grep -v '^#\\|^

A good point to define such a unction may be your .gnuplot init file.

%s | awk -v row=%d -v col=%d 'NR == row {print $col}'", file, row, col) )

Still, this function will not allow reading any dataset, it is restricted to files. However, this limitation can be overcome by checking for the redirection character '<' in the file name argument and replacing it in a sensible way (see the ternary operator):


A good point to define such a unction may be your .gnuplot init file.

| awk -v row=%d -v col=%d 'NR == row {print $col}'", (file[:1] eq '<') ? file[2:] :'cat '.file, row, col) )

A good point to define such a unction may be your .gnuplot init file.

%s | awk -v row=%d -v col=%d 'NR == row {print $col}'", file, row, col) )

Still, this function will not allow reading any dataset, it is restricted to files. However, this limitation can be overcome by checking for the redirection character '<' in the file name argument and replacing it in a sensible way (see the ternary operator):

A good point to define such a unction may be your .gnuplot init file.

涫野音 2024-12-13 07:54:11

嗯...好吧,我得到了一些信息:

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

...但这看起来更像是“捕获”一个变量,而不是读取它(因为函数 initer 被用来扫描一个流数字,检测第一个,并返回其值):)希望有更好的方法来做到这一点......

Hmmm... OK, I got something:

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

... but this looks more like "capturing" a variable, than reading it (as the function initer is being used to scan a stream of numbers, detect the first one, and return its value) :) Hope there is a better way of doing this ....

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文