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