plot - Gnuplot:按特定列对数据进行分组以进行绘图

标签 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列将这些数据分成几组,给定Result,为每个Method每组绘制一个框(y) 和偏差(yMin 和 yMax)。结果应如下所示:

Example chart

gnuplot 中可能有这样的事情吗?

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

我调查set style histogram但我无法弄清楚这是否可以用于我的情节。如果我正确理解文档,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 将其设置为自动跳过。事实上,有了这两个命令,其余命令应该没有区别。

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

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

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

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 虽然具有一些强大的编程结构,但没有在大多数语言中保护我们的作用域规则。所有变量都是“全局”的,我们必须小心名称。

关于plot - Gnuplot:按特定列对数据进行分组以进行绘图,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35609965/

相关文章:

gnuplot - 自动绘制所有列

Gnuplot:如何绘制 45 度线?

Java group by 然后收集到自定义对象列表

svg - 在 ipython 中使用 igraph 绘制顶点标签的问题

r - 如何在 R 中使用 abline() 绘制简单的垂直线?

if-statement - 如何读取脚本中不规则编号的数据文件来制作gnuplot图像?

替换两个给定时间之间的列中的值

c - C 中的正则表达式 - 匹配组

python - 求解系统微分方程(太阳和木星轨迹)

matlab - 如何在 MATLAB 中绘制三阶张量