我知道如何在gnuplot中创建直方图(只是使用“带框”),如果我的.dat文件已经有正确的二进制数据。是否有一种方法可以获取数字列表,并让gnuplot根据用户提供的范围和bin大小提供一个直方图?


当前回答

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

其他回答

我发现这个讨论非常有用,但我也遇到过一些“四舍五入”的问题。

更准确地说,使用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=5
bin(x,width)=width*floor(x/width)

plot 'datafile' using (bin($1,binwidth)):(1.0) smooth freq with boxes

查看帮助平滑频率,看看为什么上面做了一个直方图

要处理范围,只需设置xrange变量。

关于分箱函数,到目前为止,我没有预料到函数提供的结果。也就是说,如果我的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

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

要非常小心:本页上的所有答案都隐含地决定了装箱从哪里开始——如果你喜欢的话,从最左边的箱子的左边边缘开始——而不是由用户决定。如果用户将这些函数中的任何一个与他/她自己决定的数据分箱开始位置相结合(就像在上面链接的博客上所做的那样),上述函数都是不正确的。对于bin 'Min'的任意起始点,正确的函数是:

bin(x) = width*(floor((x-Min)/width)+0.5) + Min

You can see why this is correct sequentially (it helps to draw a few bins and a point somewhere in one of them). Subtract Min from your data point to see how far into the binning range it is. Then divide by binwidth so that you're effectively working in units of 'bins'. Then 'floor' the result to go to the left-hand edge of that bin, add 0.5 to go to the middle of the bin, multiply by the width so that you're no longer working in units of bins but in an absolute scale again, then finally add back on the Min offset you subtracted at the start.

考虑这个函数:

Min = 0.25 # where binning starts
Max = 2.25 # where binning ends
n = 2 # the number of bins
width = (Max-Min)/n # binwidth; evaluates to 1.0
bin(x) = width*(floor((x-Min)/width)+0.5) + Min

例如,值1.1确实落在左bin中:

这个函数正确地将它映射到左bin的中心(0.75); Born2Smile的答案,bin(x)=width*floor(x/width),错误地将其映射为1; Mas90的答案,bin(x)=width*floor(x/width) + binwidth/2.0,错误地将其映射为1.5。

Born2Smile的答案只有在bin边界出现在(n+0.5)*binwidth (n经过整数)时才正确。Mas90的答案只有在bin边界出现在n*binwidth时才正确。