我有一个如下所示的数据文件:
"curve 0"
0 0.7800
10 0.333
12 0.5136
24 0.2096
26 -0.066
40 -0.674
42 -1.123
"curve 1"
0 0.876
2 0.73
4 0.693
6 0.672
10 0.70
12 0.88
16 0.95
148 -0.75
"curve 2"
8 2.2305
10 2.144
12 2.13
76 1.26
78 0.39
98 -0.97
我想使用gnuplot独立于其他数据块绘制每个数据块。这是我为此目的使用的代码:
plot 'file' i 0 u 1:2 w lines title columnheader(1),\
'file' i 1 u 1:2 w lines title columnheader(1),\
'file' i 2 u 1:2 w lines title columnheader(1),\
'file' i 3 u 1:2 w lines title columnheader(1)
工作正常。
现在,我想在每个数据块中确定具有最大y值的点(x,y),并使用与该数据块对应的曲线具有相同颜色的标记绘制它。我试着用
max_y = GPVAL_DATA_Y_MAX
replot 'file' u ($2 == max_y ? $2 : 1/0):1
在上一个代码之后,但似乎在整个第二列中找到包括所有块的最大值。
我想要做的第二件事是:对于每个数据块,并且标记具有不同的形状但颜色(曲线的颜色)与最大值的标记相同,绘制该块的第一行。
这两个任务是否可以使用gnuplot和我绘制曲线的方式(columnheader)?
答案 0 :(得分:5)
这可以做到。它将广泛使用stats命令和一个临时文件。在gnuplot 5中,可以使用命名数据块在内存中创建临时文件(请参阅help datablocks
)。
此外,由于您的绘图命令很大程度上是重复的,您可以使用绘图语法
plot for[in=0:2] 'file' i in u 1:2 w lines t columnheader(1)
将使用值0到2重复绘图命令变量in(您提供的命令使用四个数据块,但您提供的数据文件只有3个。)
以下脚本将实现您的目标:
stats 'file' u 1:2 nooutput
blocks = STATS_blocks
set print 'tempfile'
first_y = ""
first_x = ""
do for[i=0:blocks-1] {
stats 'file' index i u (first_x=($0==1)?sprintf("%s %f",first_x,$1):first_x,first_y=($0==1)?sprintf("%s %f",first_y,$2):first_y,$1):2 nooutput
print sprintf("%f %f",STATS_pos_max_y,STATS_max_y)
}
print ""
print ""
do for[i=1:blocks] {
print sprintf("%s %s",word(first_x,i),word(first_y,i))
}
set print
plot for[i=0:blocks-1] 'file' i i u 1:2 w lines title columnheader(1),\
for[i=0:1] 'tempfile' i i u 1:2:($0+1) w points pt (i==0?7:9) lc variable not
这会产生(使用您提供的数据文件)
在曲线0和2的情况下,第一个和最大点是相同的,因此符号被遮挡。
重新绘制它,但改变规范以将第一个点标记向上移动0.1,我们可以看到它们显示在它们应该的位置。
这一部分会很长,但我会详细解释代码并尽可能逐行地解释,因为这里有一些微妙的东西。
前两行
stats 'file' u 1:2 nooutput
blocks = STATS_blocks
对文件运行stats命令。由于命名列标题,如果我们不指定使用规范,统计函数将失败,因此我们给它u 1:2
规范。 nooutput
选项告诉stats命令捕获结果,但不输出它们。在这里我们只关心获得块的数量。我们将它存储在变量 blocks 中(因为后来的stats命令会覆盖变量)。我们可以给出一个命名前缀,但这样可以保存所有变量,没有理由这样做。在3个块的情况下,我们可以在下面的所有块中替换值3,而不是这两个命令,但是这样块的数量不是硬编码的。 / p>
接下来,我们使用set print 'tempfile'
将打印命令重定向到临时文件。我们将构建一个包含最大点和第一个点的新数据文件。
代码的下一部分
first_y = ""
first_x = ""
do for[i=0:blocks-1] {
stats 'file' index i u (first_x=($0==1)?sprintf("%s %f",first_x,$1):first_x,first_y=($0==1)?sprintf("%s %f",first_y,$2):first_y,$1):2 nooutput
print sprintf("%f %f",STATS_pos_max_y,STATS_max_y)
}
是最困难的,也是大多数魔法发生的地方。我们将创建我们的临时文件以具有两个数据块。第一个是最大值,第二个是第一个值。我们将计算内存中的第一个点,并在创建第一个数据块后添加它们。 x坐标和y坐标将存储在空格分隔的字符串变量中。
我们遍历所有数据块并为其计算stats命令。表达式
(first_x=($0==1)?sprintf("%s %f",first_x,$1):first_x,first_y=($0==1)?sprintf("%s %f",first_y,$2):first_y,$1)
为读入的每个点重新分配两个字符串变量。为此,它首先检查该点是否是串联的第一个点(由于0值对应于标题行,因此$ 0的值将为1)。如果是,则通过向其添加第一列的值来重建字符串变量(对于y坐标也是如此)。否则,它只是将相同的东西重新分配给变量。最后,它返回第一列中的值。当表达式放在括号中并以逗号分隔时,将依次计算每个表达式,并返回最终值。
因此stats命令的行为就像它
stats 'file' index i u 1:2 nooutput
但是这个小技巧允许我们读取第一行值并在它们进入时存储它们。最后打印出具有最大y值的点。这将进入临时文件。
现在我们需要将第一个点添加到临时文件中作为新的数据块。所以首先我们打印两个空行,然后我们再次遍历运行的块数
print sprintf("%s %s",word(first_x,i),word(first_y,i))
表示每个块(其中i是块的编号)。单词function将字符串变量视为空格分隔的单词列表,并拉出所请求的单词。此时我们的字符串变量看起来像
0.000000 0.000000 8.000000 # first_x
0.780000 0.876000 2.230500 # first_y
最后,我们发出set print
来恢复打印命令以打印到控制台。我们现在已经构建了一个看起来像
0.000000 0.780000
16.000000 0.950000
8.000000 2.230500
0.000000 0.780000
0.000000 0.876000
8.000000 2.230500
其中第一个数据块是具有最大y值的点,第二个数据块是第一个点。
最后,我们用
绘图plot for[i=0:blocks-1] 'file' i i u 1:2 w lines title columnheader(1),\
for[i=0:1] 'tempfile' i i u 1:2:($0+1) w points pt (i==0?7:9) lc variable not
这与前面的相同,只是使用了块变量而不是硬编码块的数量。
接下来,我们使用索引0和索引1绘制两次临时文件。线颜色根据行号(在这种情况下为0到2)而变化。我们添加一个来强制通常基于0的行号为1到3.这将与之前的数据块相对应。我们用点绘图并根据我们绘制的数据块选择点类型。在这种情况下,它可以是实心圆(对于最大值)或填充三角形(对于第一个点)。