如何在 gnuplot 中对数据块进行排序?
How to sort a datablock in gnuplot?
要按列对 文件 进行排序,Linux 用户拥有实用程序 sort
。
Windows 用户必须安装,例如CoreUtils
从 GnuWin 获得相同(或相似)的功能。
因此,首先按 column1 然后按 column2 对文件进行排序,然后绘制文件的最少代码如下所示:
plot '<sort -k 1,2 "myFile.dat"' u 1:2
但是现在,我有一个数据块$Data
:
$Data <<EOD
1 6
4 8
3 7
2 5
1 4
2 3
EOD
到目前为止,我尝试过的所有命令都以错误消息告终:
plot '<sort -k 1,2' $Data u 1:2
#--> Bad data on line 1 of file <sort -k 1,2
plot '<sort -k 1,2 $Data' u 1:2
plot '<sort -k 1,2 <$Data' u 1:2
#--> warning: Skipping data file with no valid points
#--> x range is invalid
plot '<sort -k 1,2 '<$Data u 1:2
#--> Column number or datablock line expected
我不想先将数据块写入文件,然后再从文件中读取。我目前不知道如何将 $Data
的内容重定向到 sort
的标准输入。 Windows 和 Linux 有什么解决方案吗?
更新:
使用@Ethan 建议的代码时,我得到以下结果。请注意我预期的 2 5
和 2 3
行(Ethan 也有)。
# Curve 0 of 1, 6 points
# Curve title: "$Data_1 using 1:2:1"
# x y type
1 4 i
1 6 i
2 5 i
2 3 i
3 7 i
4 8 i
知道这是为什么吗?我是 运行 Win10 上的 gnuplot 5.4.1。
将 $Data 发送到排序实用程序的标准输入的语法是 set print "| sort"; print $Data
。但这不会做你想要的。相反,让我们在 gnuplot 中执行双重排序。
$Data <<EOD
1 6
4 8
3 7
2 5
1 4
2 3
EOD
set table $Data_1
plot $Data using 1:2:2 smooth zsort with points
set table $Data_2
plot $Data_1 using 1:2:1 smooth zsort with points
unset table
print $Data_2
# Curve 0 of 1, 6 points
# Curve title: "$Data_1 using 1:2:1"
# x y type
1 4 i
1 6 i
2 3 i
2 5 i
3 7 i
4 8 i
如果没有解决方法,就不会是 gnuplot。嗯,有点麻烦,但它似乎工作。
显然,smooth zsort
分别对每个子块进行排序。因此,在第一次排序之后,只要第一列中的值发生变化,您就“简单地”需要将数据拆分为子块。
- 按第一列排序
- 在第一列中的值更改之前插入一个空行
- 按第二列排序
- 将其绘制成 table 以再次删除空行
代码:(编辑:使用图形表示更容易说明 zsort
的不良行为(仅在 Windows 下))
### sorting datablock, "bug": Windows zsort does not preserve order
reset session
# create some random test data
set print $Data
do for [i=1:100] {
print sprintf("%g %g", int(rand(0)*10), int(rand(0)*10))
}
set print
# order not preserving (only under Windows)
set table $Data1
plot $Data u 1:2:2 smooth zsort
set table $Data2
plot $Data1 u 1:2:1 smooth zsort
unset table
# order preserving (even under Windows, but cumbersome)
set table $Data3
plot $Data u 1:2:1 smooth zsort
unset table
set print $Data4
do for [i=1:|$Data3|] {
print $Data3[i]
if (i<|$Data3|) { if (word($Data3[i],1) ne word($Data3[i+1],1)) { print "" } }
}
set print
set table $Data5
plot $Data4 u 1:2:2 smooth zsort
set table $Data6
plot $Data5 u 1:2 w table
unset table
set key out
set rmargin 20
set multiplot layout 3,1
plot $Data w lp pt 7 lc "black" ti "Random"
plot $Data2 w lp pt 7 lc "red" ti "zsort"
plot $Data6 w lp pt 7 lc "web-green" ti "Workaround"
unset multiplot
### end of code
结果:
我要备份并建议您重新考虑您最初对使用临时文件的限制。最直接的解决方案是:
set print "| sort -k 1,2 > sorted.dat"
print $Data
unset print
plot 'sorted.dat'
如果您解释了为什么您不想使用临时文件,也许这个问题的答案与排序问题无关。
如果问题是临时文件的 name,那么可能是这样的:
tempfile = system("mktemp")
set print "| sort -k 1,2 > ".tempfile
print $Data
unset print
plot tempfile with points
要按列对 文件 进行排序,Linux 用户拥有实用程序 sort
。
Windows 用户必须安装,例如CoreUtils
从 GnuWin 获得相同(或相似)的功能。
因此,首先按 column1 然后按 column2 对文件进行排序,然后绘制文件的最少代码如下所示:
plot '<sort -k 1,2 "myFile.dat"' u 1:2
但是现在,我有一个数据块$Data
:
$Data <<EOD
1 6
4 8
3 7
2 5
1 4
2 3
EOD
到目前为止,我尝试过的所有命令都以错误消息告终:
plot '<sort -k 1,2' $Data u 1:2
#--> Bad data on line 1 of file <sort -k 1,2
plot '<sort -k 1,2 $Data' u 1:2
plot '<sort -k 1,2 <$Data' u 1:2
#--> warning: Skipping data file with no valid points
#--> x range is invalid
plot '<sort -k 1,2 '<$Data u 1:2
#--> Column number or datablock line expected
我不想先将数据块写入文件,然后再从文件中读取。我目前不知道如何将 $Data
的内容重定向到 sort
的标准输入。 Windows 和 Linux 有什么解决方案吗?
更新:
使用@Ethan 建议的代码时,我得到以下结果。请注意我预期的 2 5
和 2 3
行(Ethan 也有)。
# Curve 0 of 1, 6 points
# Curve title: "$Data_1 using 1:2:1"
# x y type
1 4 i
1 6 i
2 5 i
2 3 i
3 7 i
4 8 i
知道这是为什么吗?我是 运行 Win10 上的 gnuplot 5.4.1。
将 $Data 发送到排序实用程序的标准输入的语法是 set print "| sort"; print $Data
。但这不会做你想要的。相反,让我们在 gnuplot 中执行双重排序。
$Data <<EOD
1 6
4 8
3 7
2 5
1 4
2 3
EOD
set table $Data_1
plot $Data using 1:2:2 smooth zsort with points
set table $Data_2
plot $Data_1 using 1:2:1 smooth zsort with points
unset table
print $Data_2
# Curve 0 of 1, 6 points
# Curve title: "$Data_1 using 1:2:1"
# x y type
1 4 i
1 6 i
2 3 i
2 5 i
3 7 i
4 8 i
如果没有解决方法,就不会是 gnuplot。嗯,有点麻烦,但它似乎工作。
显然,smooth zsort
分别对每个子块进行排序。因此,在第一次排序之后,只要第一列中的值发生变化,您就“简单地”需要将数据拆分为子块。
- 按第一列排序
- 在第一列中的值更改之前插入一个空行
- 按第二列排序
- 将其绘制成 table 以再次删除空行
代码:(编辑:使用图形表示更容易说明 zsort
的不良行为(仅在 Windows 下))
### sorting datablock, "bug": Windows zsort does not preserve order
reset session
# create some random test data
set print $Data
do for [i=1:100] {
print sprintf("%g %g", int(rand(0)*10), int(rand(0)*10))
}
set print
# order not preserving (only under Windows)
set table $Data1
plot $Data u 1:2:2 smooth zsort
set table $Data2
plot $Data1 u 1:2:1 smooth zsort
unset table
# order preserving (even under Windows, but cumbersome)
set table $Data3
plot $Data u 1:2:1 smooth zsort
unset table
set print $Data4
do for [i=1:|$Data3|] {
print $Data3[i]
if (i<|$Data3|) { if (word($Data3[i],1) ne word($Data3[i+1],1)) { print "" } }
}
set print
set table $Data5
plot $Data4 u 1:2:2 smooth zsort
set table $Data6
plot $Data5 u 1:2 w table
unset table
set key out
set rmargin 20
set multiplot layout 3,1
plot $Data w lp pt 7 lc "black" ti "Random"
plot $Data2 w lp pt 7 lc "red" ti "zsort"
plot $Data6 w lp pt 7 lc "web-green" ti "Workaround"
unset multiplot
### end of code
结果:
我要备份并建议您重新考虑您最初对使用临时文件的限制。最直接的解决方案是:
set print "| sort -k 1,2 > sorted.dat"
print $Data
unset print
plot 'sorted.dat'
如果您解释了为什么您不想使用临时文件,也许这个问题的答案与排序问题无关。 如果问题是临时文件的 name,那么可能是这样的:
tempfile = system("mktemp")
set print "| sort -k 1,2 > ".tempfile
print $Data
unset print
plot tempfile with points