我知道如何在gnuplot中创建直方图(只是使用“带框”),如果我的.dat文件已经有正确的二进制数据。是否有一种方法可以获取数字列表,并让gnuplot根据用户提供的范围和bin大小提供一个直方图?
当前回答
我发现这个讨论非常有用,但我也遇到过一些“四舍五入”的问题。
更准确地说,使用0.05的binwidth,我注意到,使用上面介绍的技术,读取0.1和0.15的数据点落在同一个bin中。这(显然是不想要的行为)很可能是由于“地板”功能。
下面是我的小贡献,试图规避这一点。
bin(x,width,n)=x<=n*width? width*(n-1) + 0.5*binwidth:bin(x,width,n+1)
binwidth = 0.05
set boxwidth binwidth
plot "data.dat" u (bin($1,binwidth,1)):(1.0) smooth freq with boxes
这个递归方法适用于x >=0;我们可以用更多的条件语句来概括它,从而得到更一般的结果。
其他回答
关于分箱函数,到目前为止,我没有预料到函数提供的结果。也就是说,如果我的binwidth是0.001,那么这些函数将箱子以0.0005点为中心,而我认为将箱子以0.001点为中心更直观。
换句话说,我想拥有
Bin 0.001 contain data from 0.0005 to 0.0014
Bin 0.002 contain data from 0.0015 to 0.0024
...
我想到的宾宁函数是
my_bin(x,width) = width*(floor(x/width+0.5))
这里有一个脚本来比较一些提供的bin函数:
rint(x) = (x-int(x)>0.9999)?int(x)+1:int(x)
bin(x,width) = width*rint(x/width) + width/2.0
binc(x,width) = width*(int(x/width)+0.5)
mitar_bin(x,width) = width*floor(x/width) + width/2.0
my_bin(x,width) = width*(floor(x/width+0.5))
binwidth = 0.001
data_list = "-0.1386 -0.1383 -0.1375 -0.0015 -0.0005 0.0005 0.0015 0.1375 0.1383 0.1386"
my_line = sprintf("%7s %7s %7s %7s %7s","data","bin()","binc()","mitar()","my_bin()")
print my_line
do for [i in data_list] {
iN = i + 0
my_line = sprintf("%+.4f %+.4f %+.4f %+.4f %+.4f",iN,bin(iN,binwidth),binc(iN,binwidth),mitar_bin(iN,binwidth),my_bin(iN,binwidth))
print my_line
}
这是输出
data bin() binc() mitar() my_bin()
-0.1386 -0.1375 -0.1375 -0.1385 -0.1390
-0.1383 -0.1375 -0.1375 -0.1385 -0.1380
-0.1375 -0.1365 -0.1365 -0.1375 -0.1380
-0.0015 -0.0005 -0.0005 -0.0015 -0.0010
-0.0005 +0.0005 +0.0005 -0.0005 +0.0000
+0.0005 +0.0005 +0.0005 +0.0005 +0.0010
+0.0015 +0.0015 +0.0015 +0.0015 +0.0020
+0.1375 +0.1375 +0.1375 +0.1375 +0.1380
+0.1383 +0.1385 +0.1385 +0.1385 +0.1380
+0.1386 +0.1385 +0.1385 +0.1385 +0.1390
是的,它快速而简单,但非常隐蔽:
binwidth=5
bin(x,width)=width*floor(x/width)
plot 'datafile' using (bin($1,binwidth)):(1.0) smooth freq with boxes
查看帮助平滑频率,看看为什么上面做了一个直方图
要处理范围,只需设置xrange变量。
同一数据集上不同数量的箱子可以揭示数据的不同特征。
不幸的是,没有通用的最佳方法可以确定箱子的数量。
其中一个强大的方法是Freedman-Diaconis规则,它根据给定数据集的统计数据自动确定箱子的数量,还有许多其他的替代方法。
因此,下面的代码可以在gnuplot脚本中使用Freedman-Diaconis规则:
假设你有一个文件,它只包含一列样本,samplesFile:
# samples
0.12345
1.23232
...
以下(基于ChrisW的回答)可以嵌入到现有的gnuplot脚本中:
...
## preceeding gnuplot commands
...
#
samples="$samplesFile"
stats samples nooutput
N = floor(STATS_records)
samplesMin = STATS_min
samplesMax = STATS_max
# Freedman–Diaconis formula for bin-width size estimation
lowQuartile = STATS_lo_quartile
upQuartile = STATS_up_quartile
IQR = upQuartile - lowQuartile
width = 2*IQR/(N**(1.0/3.0))
bin(x) = width*(floor((x-samplesMin)/width)+0.5) + samplesMin
plot \
samples u (bin(\$1)):(1.0/(N*width)) t "Output" w l lw 1 smooth freq
我对Born2Smile非常有用的答案有一些更正/补充:
空箱子导致相邻箱子的箱子不正确地延伸到它的空间;使用set boxwidth binwidth避免这种情况 在Born2Smile的版本中,箱子以下界为中心呈现。严格来说,它们应该从下界延伸到上界。这可以通过修改bin函数来纠正:bin(x,width)=width*floor(x/width) + width/2.0
As usual, Gnuplot is a fantastic tool for plotting sweet looking graphs and it can be made to perform all sorts of calculations. However, it is intended to plot data rather than to serve as a calculator and it is often easier to use an external programme (e.g. Octave) to do the more "complicated" calculations, save this data in a file, then use Gnuplot to produce the graph. For the above problem, check out the "hist" function is Octave using [freq,bins]=hist(data), then plot this in Gnuplot using
set style histogram rowstacked gap 0
set style fill solid 0.5 border lt -1
plot "./data.dat" smooth freq with boxes