【问题标题】:Gnuplot: Grouping data by certain column for plotGnuplot:按特定列对数据进行分组以进行绘图
【发布时间】:2016-02-24 18:18:49
【问题描述】:

想象以下文件格式

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)。结果应如下所示:

在 gnuplot 中可以实现这样的事情吗?

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

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

【问题讨论】:

标签: plot gnuplot grouping histogram


【解决方案1】:

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

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 datafile separator comma。如果第一行是标题行,我们可以使用set key autotitle columnhead 将其设置为自动跳过。其实这两条命令,剩下的命令应该没什么区别了。

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

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

生产


至于设置我们的初始类型和方法变量,我们要么必须在脚本中设置它们,要么使用外部程序。我们将假设数据采用分号分隔的 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 虽然有一些强大的编程结构,但没有在大多数语言中保护我们的范围规则。所有变量都是“全局的”,我们必须注意名称。

【讨论】:

  • 哇,这是一个非常长但非常出色的书面答案。可惜我不能投票两次!感谢您的所有帮助,我昨天也开始使用一些类似的代码,但我不知道很多东西,例如word、words 或xtic add。再次感谢:)
  • @MarkusWeninger 这些都是您可能不会遇到的所有功能,除非您必须执行此类操作。我在尝试解决一个非常相似的问题时第一次遇到它们,但涉及箱须图。我很高兴能帮上忙。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-07-05
  • 2023-01-11
  • 2022-12-05
  • 2021-11-16
  • 1970-01-01
相关资源
最近更新 更多