使用gnuplot的直方图?


202

如果我的.dat文件已经具有正确的装箱数据,我知道如何在gnuplot中创建直方图(只需使用“ with box”)。有没有办法获取数字列表并让gnuplot根据用户提供的范围和容器大小提供直方图?


2
如果您没有得到答案,那么还有其他工具可以执行此操作。我在这里使用Root(root.cern.ch)很多其他人使用R,并且至少还有其他一些选择。
dmckee ---前主持人小猫,2010年

1
Bin是直方图中每个条形所收集的值的范围。每个bin都有一个下限和上限,所有具有该范围值的数据都计入该条形。Binned意味着我的数据文件已经按照每个bin中有多少个数据点进行了组织,因此可以将其绘制为直方图了。
玛丽

Answers:


225

是的,它的快速和简单虽然很隐蔽:

binwidth=5
bin(x,width)=width*floor(x/width)

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

看看help smooth freq上面的为什么会产生直方图

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


11
我认为,@ ChrisW的以下回答为想要在Gnuplot中制作直方图的任何人提供了重要的注意点。
Abhinav

2
请非常小心,这仅在集合中没有“缺失”仓的情况下有效。...此功能将缺失仓的y值固定为先前的非缺失仓的y值。这可能会令人误解!!!
PinkFloyd

1
我要补充set boxwidth binwidth到上面。这对我真的很有帮助。
Jaakko

90

我对Born2Smile的非常有用的答案有一些更正/补充:

  1. 空垃圾箱会导致相邻垃圾箱的盒子错误地伸入其空间;避免使用set boxwidth binwidth
  2. 在Born2Smile的版本中,垃圾箱以其下限为中心渲染。严格来说,它们应该从下限延伸到上限。可以通过修改bin函数来纠正此问题:bin(x,width)=width*floor(x/width) + width/2.0

10
实际上,第二部分应该是bin(x,width)=width*floor(x/width) + binwidth/2.0(浮点计算)
bgw 2010年

8
你是说bin(x,width)=width*floor(x/width) + width/2.0。如果我们将其width作为参数传递,则使用它。:-)
Mitar

78

请非常小心:此页面上的所有答案都隐含地决定了分箱的开始位置-如果需要,可以从用户的最左边的分箱的左边缘开始。如果用户将这些用于装箱数据的功能与他/她自己关于装箱开始位置的决定结合在一起(如上面链接的博客中所做的那样),则上述功能都是不正确的。对于将“ Min”进行分档的任意起点,正确的功能是:

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

您可以看到为什么这是顺序正确的(它有助于在其中一个箱中绘制一些箱和一个点)。从您的数据点减去Min,以查看它在合并范围内有多远。然后除以binwidth,以便您以“ bins”为单位有效地工作。然后将结果“底”移到该容器的左边缘,将0.5加到该容器的中间,再乘以宽度,这样您就不再以容器为单位,而是以绝对比例工作再次,然后最后重新添加您在开始时减去的最小偏移量。

考虑此功能的实际作用:

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中:

  • 此功能可将其正确映射到左侧垃圾箱(0.75)的中心;
  • Born2Smile的答案bin(x)= width * floor(x / width)错误地将其映射为1;
  • mas90的答案bin(x)= width * floor(x / width)+ binwidth / 2.0将其错误地映射为1.5。

仅当bin边界出现在(n + 0.5)* binwidth(其中n遍历整数)的情况下,Born2Smile的答案才是正确的。仅当bin边界出现在n * binwidth时,mas90的答案才是正确的。


48

您要绘制这样的图吗? 在此处输入图片说明 是?然后,您可以看一下我的博客文章:http : //gnuplot-surprising.blogspot.com/2011/09/statistic-analysis-and-histogram.html

代码中的关键行:

n=100 #number of intervals
max=3. #max value
min=-3. #min value
width=(max-min)/n #interval width
#function used to map a value to the intervals
hist(x,width)=width*floor(x/width)+width/2.0
set boxwidth width*0.9
set style fill solid 0.5 # fill style

#count and plot
plot "data.dat" u (hist($1,width)):(1.0) smooth freq w boxes lc rgb"green" notitle

10

像往常一样,Gnuplot是绘制精美图形的绝佳工具,可以执行各种计算。 但是,其意图是绘制数据而不是用作计算器,并且通常更容易使用外部程序(例如Octave)进行更“复杂”的计算,将这些数据保存在文件中,然后使用Gnuplot生成图。对于上述问题,请使用来检查“ hist”函数是否为Octave [freq,bins]=hist(data),然后使用来在Gnuplot中进行绘制

set style histogram rowstacked gap 0
set style fill solid 0.5 border lt -1
plot "./data.dat" smooth freq with boxes

7

我发现该讨论非常有用,但是我遇到了一些“四舍五入”的问题。

更准确地说,使用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; 可以用更多的条件语句来概括这一点,以获得更一般的东西。


6

我们不需要使用递归方法,它可能很慢。我的解决方案是使用内部函数int或floor的用户定义函数rint instesd。

rint(x)=(x-int(x)>0.9999)?int(x)+1:int(x)

这个功能会给rint(0.0003/0.0001)=3,而int(0.0003/0.0001)=floor(0.0003/0.0001)=2

为什么?请查看Perl int函数和填充零


4

我对Born2Smile的解决方案做了一些修改。

我知道这没有多大意义,但您可能希望以防万一。如果您的数据是整数,并且需要浮动大小(可能是为了与另一组数据进行比较,或者是在更细的网格中绘制密度),则需要在地板内添加一个介于0和1之间的随机数。否则,由于舍入误差会出现尖峰。floor(x/width+0.5)不会这样做,因为它将创建不适用于原始数据的模式。

binwidth=0.3
bin(x,width)=width*floor(x/width+rand(0))

1
您还没有遇到过这种情况,但是您可能以后会遇到。您可以使用带浮点sd的正态分布整数对其进行测试,并使用bin = 1和bin = sd绘制直方图,以查看使用和不使用rand(0)技巧所得到的结果。在查看他的手稿时,我发现了一个合作者的错误。他的结果从绝对的胡说八道变成了预期的美丽形象。
path4 2014年

好吧,也许解释太短了,以至于没有一个更具体的测试用例就无法理解它。我将对您的答案进行简短的编辑,以便我可以撤消不赞成投票的人;)
Christoph

考虑正态分布的整数。由于它们是整数,因此许多将具有相同的x /宽度。假设这个数字是1.3。使用floor(x / width + 0.5),所有这些都将分配到bin1。但是1.3的实际含义是,密度的70%应该在bin 1中,而30%应该在bin 2中。rand(0 )保持适当的密度。因此,0.5会产生尖峰,而rand(0)会保持真实。我敢打赌,使用rand(0)而不是0.5,hsxz的数字会更加平滑。这不仅是四舍五入,而且是四舍五入。
path4 2014年

3

关于合并功能,我没想到到目前为止提供的功能的结果。即,如果我的binwidth为0.001,则这些功能会将bin居中于0.0005点,而我觉得将bin居中于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
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.