Gnuplot:按特定列为绘图分组数据

Gnuplot:按特定列为绘图分组数据,plot,gnuplot,grouping,histogram,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 PO

想象一下下面的文件格式

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
它应该代表一些基准测试运行的结果。我想根据列
类型将这些数据分成几组,根据
结果(y)和偏差(yMin和yMax),为每个
方法
,每组绘制一个方框。结果应该如下所示:

在gnuplot中是否可能出现类似的情况

在我的真实数据源中,它将是2组(“类型”),每组7条(“方法”)


我调查了一下,但我没能弄清楚这是否可以用于我的情节。如果我对文档理解正确,
histogram
为每一行启动一个新组,并为绘图中给定的每一列启动一个框(例如
plot'file.dat'使用2',使用4',使用6
将导致每组3条,每行一组)

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

Type Fast_Result Fast_Min Fast_Max Slow_Result Slow_Min Slow_Max
会让这件事变得微不足道。可以使用外部程序重新格式化数据。但是,不进行任何重新格式化也是可能的

我们需要假设类型和方法的名称中没有空格。这允许我们使用gnuplot字符串变量和word/words函数来模拟数组。如果不满足这一假设,那么要实现这一点就要困难得多

对于大多数情况,我将假设数据如下

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 key autotitle columnhead
将其设置为autoskip。事实上,使用这两个命令,其余的命令应该没有区别

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

types = "POGC G1"
methods = "Fast Slow"
我们首先将xaxis标签放置在每种类型的一组框的中间位置。我们为每个组添加一个额外的框,以在组之间设置一个空格。第一个tic设置命令有效地“清除”所有tic,以便我们逐个添加所需的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来绘图

产生


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

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

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

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

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


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

哇,这是一个非常长但非常好的书面答案。我不能投两次票,这是一个微不足道的问题!感谢您的帮助,我昨天也开始编写一些类似的代码,但是我不知道很多事情,比如
word
words
,或者
xtic add
。再次非常感谢:)@MarkusWeninger这些都是在你不得不这样做之前你可能不会遇到的功能。我第一次遇到它们是在试图解决一个非常类似的问题时,但涉及到方块和胡须图。我很高兴能帮上忙
getcolumnvalues(x) = sprintf('python -c "data=set([x.split(\";\")[%d] for x in open(\"data.txt\",\"r\")][1:]);print(*sorted(data))"',x-1)
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))