单个文件中的多个数据块和单个图表+每个块的标记

时间:2016-04-15 23:15:35

标签: plot gnuplot markers columnheader

我有一个如下所示的数据文件:

"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)?

1 个答案:

答案 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

这会产生(使用您提供的数据文件)

enter image description here

在曲线0和2的情况下,第一个和最大点是相同的,因此符号被遮挡。

重新绘制它,但改变规范以将第一个点标记向上移动0.1,我们可以看到它们显示在它们应该的位置。

enter image description here

这一部分会很长,但我会详细解释代码并尽可能逐行地解释,因为这里有一些微妙的东西。

前两行

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.这将与之前的数据块相对应。我们用点绘图并根据我们绘制的数据块选择点类型。在这种情况下,它可以是实心圆(对于最大值)或填充三角形(对于第一个点)。