Gnuplot:按照某些列对数据进行分组

时间:2016-02-24 18:18:50

标签: plot gnuplot grouping histogram

想象一下文件格式

Type Method Result Min  Max
-------------------------------
POGC Fast   10.4   9.4  15.6
POGC Slow   20.3   14.2 25.5
G1   Fast   5.0    4.4  5.2
G1   Slow   11.1   6.8  13.0

或,以CSV格式

Type;Method;Result;Min;Max
POGC;Fast;10.4;9.4;15.6
POGC;Slow;20.3;14.2;25.5
G1;Fast;5.0;4.4;5.2
G1;Slow;11.1;6.8;13.0

应代表某些基准运行的结果。我想要的是根据列Type将这些数据拆分成组,为每个Method绘制一个框,给定Result(y)和偏差(yMin和YMAX)。结果应如下所示:

Example chart

gnuplot可以这样吗?

在我的真实数据源中,每组有2组(“类型”)和7条(“方法”)。

我调查set style histogram但我无法弄清楚这是否可以用于我的情节。如果我理解文档正确,histogram为每一行开始一个新组,并且每个组中每个组一个框(如plot 'file.dat' using 2, '' using 4, '' using 6将导致每组3个条,一组每行)

1 个答案:

答案 0 :(得分:2)

将数据重新格式化为不同的设计可能更容易。使用像

这样的设计
Type Fast_Result Fast_Min Fast_Max Slow_Result Slow_Min Slow_Max

会让这件事变得微不足道。外部程序可用于重新格式化数据。但是,可以不进行任何重新格式化。

我们需要假设类型和方法在名称中没有空格。这允许我们使用gnuplot字符串变量和单词/单词函数来模拟它们的数组。如果不满足这个假设,那么要完成起来要困难得多。

对于大部分内容,我假设数据看起来像

POGC Fast   10.4   9.4  15.6
POGC Slow   20.3   14.2 25.5
G1   Fast   5.0    4.4  5.2
G1   Slow   11.1   6.8  13.0

如果我们使用CSV文件,我们就可以set datafile separator comma。如果第一行是标题行,我们可以将其设置为使用set key autotitle columnhead进行自动提示。实际上,使用这两个命令,其余命令应该没有区别。

假设我们有两个变量, types methods ,包含所有可能类型和方法的值

types = "POGC G1"
methods = "Fast Slow"

我们首先将xaxis标签放在每种类型的盒子的中间位置。我们为每个组添加一个额外的框以在组之间设置空格。第一个tic设置命令有效地“清除”所有抽搐,以便我们逐个添加所需的抽搐

set xtics ()
set for[i=1:words(types)] xtic add (word(types,i) (1+words(methods))/2.0+(i-1)*(words(types)+1))

现在,我们将使用set boxwidth 0.9明确设置boxwidth。我们使用略小于1的值来允许每个框之间存在间隙。

接下来,我们需要一些功能。一个将获得其中一个列表变量的索引,另一个将确定放置一个框的x坐标。

wordix(list,word) = sum[i=1:words(list)] (word(list,i) eq word)?i:0
xval(ty,me) = (wordix(types,ty)-1)*(words(methods)+1)+wordix(methods,me)

由于框样式倾向于截断框的底部,我们将使用set yrange[0:*]明确设置范围。

对于这些框,我们需要迭代每种类型,一次一个地绘制它们,以确保它们使用与键中不同的样式。这要求我们使用条件检查来查看要绘制的框。在条件中,如果我们使用该框,我们将选择第三列,如果不使用,则选择无效值1/0,这将导致gnuplot跳过该框。我们将使用矢量样式绘制范围线。我们可以立刻做到这些,因为它们的风格都是一样的。现在,我们可以用 1

进行绘图
plot for[z=1:words(methods)] "data.txt" u (xval(strcol(1),strcol(2))):(strcol(2) eq word(methods,z)?$3:1/0) with boxes lt z t word(methods,z), \
     "" u (xval(strcol(1),strcol(2)):4:(0):($5-$4) with vectors lc black nohead not

生产

enter image description here

至于设置我们的初始类型和方法变量,我们要么必须在脚本中设置它们,要么使用外部程序。我们假设数据采用分号取消的csv格式,带有标题行,并命名为 data.txt

如果python3可用,请定义一个函数(使用windows shell引用)

getcolumnvalues(x) = sprintf('python -c "data=set([x.split(\";\")[%d] for x in open(\"data.txt\",\"r\")][1:]);print(*sorted(data))"',x-1)

或者,如果python3不可用,但标准的unix程序(awk,sort,uniq和paste)是,我们可以将其定义为(再次使用windows shell引用)

getcolumnvalues(x) = sprintf('awk -F; "(NR>1) {print $%d;}" data.txt | sort | uniq | paste -s -d" "',x)

现在,我们可以将变量设置为

types = system(getcolumnvalues(1))
methods = system(getcolumnvalues(2))

1 我通常喜欢使用 i 作为我的迭代变量,但请注意 wordix 函数使用相同的变量进行迭代。当我们在每次迭代期间调用该函数时(通过 xval 函数),我们需要为绘图迭代使用不同的变量。这是一个容易错过的错误(我在打字时花了大约15分钟试图弄清楚它为什么不能正常工作)。在这种情况下,重要的是要记住gnuplot虽然具有一些强大的编程结构,但没有在大多数语言中保护我们的范围规则。所有变量都是“全局的”,我们必须小心名称。