geom_histogram:错误的垃圾箱?

Arn*_*aud 4 r ggplot2

我正在使用ggplot 2.1.0来绘制直方图,并且我对直方图箱有意想不到的行为.我在这里给出了一个左闭合箱的例子(即[0,0.1 [],其宽度为0.1).

mydf <- data.frame(myvar=c(-1,-0.5,-0.4,-0.1,-0.1,0.05,0.1,0.1,0.25,0.5,1))
myplot <- ggplot(mydf, aes(myvar)) + geom_histogram(aes(y=..count..),binwidth = 0.1, boundary=0.1,closed="left")
myplot
ggplot_build(myplot)$data[[1]]
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

在这个例子中,人们可能期望值-0.4在bin [-0.4,-0.3 [,但它在([神秘地)在bin [-0.5,-0.4 [.值-0.1的值相同,它落在[-0.2,-0.1 [而不是[-0.1,0 [...等].

这里有什么东西我不完全理解(特别是新的"中心"和"边界"参数)?或者是ggplot2在那里做奇怪的事情?

在此先感谢,最好的问候,Arnaud

PS:还问这里:https://github.com/hadley/ggplot2/issues/1651

Pat*_*ckT 6

编辑:下面描述的问题已在最近的版本中修复ggplot2.

您的问题是可重现的,并且似乎是由舍入错误引起的,正如Roland的评论中所建议的那样.在这一点上,这看起来就像版本中引入的错误ggplot2_2.0.0.我在下面推测它的起源,但首先让我提出一个基于该boundary选项的解决方法.

问题:

df <- data.frame(var = seq(-100,100,10)/100)
as.list(df) # check the data
$var
 [1] -1.0 -0.9 -0.8 -0.7 -0.6 -0.5 -0.4 -0.3 -0.2
[10] -0.1  0.0  0.1  0.2  0.3  0.4  0.5  0.6  0.7
[19]  0.8  0.9  1.0
library("ggplot2")
p <- ggplot(data = df, aes(x = var)) + 
    geom_histogram(aes(y = ..count..), 
        binwidth = 0.1, 
        boundary = 0.1, 
        closed = "left")
p
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

调整boundary参数.在这个例子中,设置低于1,比如0.99,可以工作.您的用例也应该适合调整.

ggplot(data = df, aes(x = var)) + 
    geom_histogram(aes(y = ..count..), 
        binwidth = 0.05, 
        boundary = 0.99, 
        closed = "left")
Run Code Online (Sandbox Code Playgroud)

(我已经使binwidth更窄,以获得更好的视觉效果)

在此输入图像描述

另一种解决方法是引入您自己的模糊性,例如将数据乘以1加略小于机器零点(见eps下文).在ggplot2模糊性通过1E-7(早期版本)或1E-8(以后的版本)相乘.

原因:

问题清楚地出现在ncount:

str(ggplot_build(p)$data[[1]])
##  'data.frame':   20 obs. of  17 variables:
##   $ y       : num  1 1 1 1 1 2 1 1 1 0 ...
##   $ count   : num  1 1 1 1 1 2 1 1 1 0 ...
##   $ x       : num  -0.95 -0.85 -0.75 -0.65 -0.55 -0.45 -0.35 -0.25 -0.15 -0.05 ...
##   $ xmin    : num  -1 -0.9 -0.8 -0.7 -0.6 -0.5 -0.4 -0.3 -0.2 -0.1 ...
##   $ xmax    : num  -0.9 -0.8 -0.7 -0.6 -0.5 -0.4 -0.3 -0.2 -0.1 0 ...
##   $ density : num  0.476 0.476 0.476 0.476 0.476 ...
##   $ ncount  : num  0.5 0.5 0.5 0.5 0.5 1 0.5 0.5 0.5 0 ...
##   $ ndensity: num  1.05 1.05 1.05 1.05 1.05 2.1 1.05 1.05 1.05 0 ...
##   $ PANEL   : int  1 1 1 1 1 1 1 1 1 1 ...
##   $ group   : int  -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 ...
##   $ ymin    : num  0 0 0 0 0 0 0 0 0 0 ...
##   $ ymax    : num  1 1 1 1 1 2 1 1 1 0 ...
##   $ colour  : logi  NA NA NA NA NA NA ...
##   $ fill    : chr  "grey35" "grey35" "grey35" "grey35" ...
##   $ size    : num  0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 ...
##   $ linetype: num  1 1 1 1 1 1 1 1 1 1 ...
##   $ alpha   : logi  NA NA NA NA NA NA ...

ggplot_build(p)$data[[1]]$ncount
##  [1] 0.5 0.5 0.5 0.5 0.5 1.0 0.5 0.5 0.5 0.0 1.0 0.5
## [13] 0.5 0.5 0.0 1.0 0.5 0.0 1.0 0.5
Run Code Online (Sandbox Code Playgroud)

圆角错误?

好像:

    df <- data.frame(var = as.integer(seq(-100,100,10)))
# eps <- 1.000000000000001 # on my system
eps <- 1+10*.Machine$double.eps
p <- ggplot(data = df, aes(x = eps*var/100)) + 
    geom_histogram(aes(y = ..count..), 
                   binwidth = 0.05, 
                   closed = "left")
p
Run Code Online (Sandbox Code Playgroud)

(我完全删除了boundary选项)

在此输入图像描述

此行为出现一段时间后ggplot2_1.0.1.查看源代码,例如bin.Rstat-bin.rhttps://github.com/hadley/ggplot2/blob/master/R,和跟踪的计算count导致功能bin_vector(),它包含下列行:

bin_vector <- function(x, bins, weight = NULL, pad = FALSE) {
 ... STUFF HERE I HAVE DELETED FOR CLARITY ...
cut(x, bins$breaks, right = bins$right_closed,
include.lowest = TRUE)
... STUFF HERE I HAVE DELETED FOR CLARITY ...
}
Run Code Online (Sandbox Code Playgroud)

通过将这些函数的当前版本与旧函数进行比较,您应该能够找到不同行为的原因......继续......

总结调试

通过"patching"bin_vector功能并将输出打印到屏幕,看起来:

  1. bins$fuzzy 正确存储模糊参数

  2. 非模糊bins$breaks用于计算,但据我所知(并纠正我,如果我错了)bins$fuzzy不是.

  3. 如果我只是在顶部替换bins$breaks,则返回正确的绘图.不是一个bug的证明,而是一个建议,也许可以做更多的事情来模仿以前版本的行为.bins$fuzzybin_vectorggplot2

  4. bin_vector我的顶部,我期望找到一个条件,返回bins$breaksbins$fuzzy.我认为现在已经不见了.

修补剂

对于"patch"bin_vector函数,从github源复制函数定义,或者更方便地从终端复制函数定义:

 ggplot2:::bin_vector
Run Code Online (Sandbox Code Playgroud)

修改它(修补它)并将其分配到命名空间中:

library("ggplot2")
bin_vector <- function (x, bins, weight = NULL, pad = FALSE) 
{
... STUFF HERE I HAVE DELETED FOR CLARITY ...
## MY PATCH: Replace bins$breaks with bins$fuzzy
bin_idx <- cut(x, bins$fuzzy, right = bins$right_closed,
include.lowest = TRUE)
... STUFF HERE I HAVE DELETED FOR CLARITY ...
ggplot2:::bin_out(bin_count, bin_x, bin_widths)
## THIS IS THE PATCHED FUNCTION
}
assignInNamespace("bin_vector", bin_vector, ns = "ggplot2")
df <- data.frame(var = seq(-100,100,10)/100)
ggplot(data = df, aes(x = var)) + geom_histogram(aes(y = ..count..), binwidth = 0.05, boundary = 1, closed = "left")
Run Code Online (Sandbox Code Playgroud)

为了清楚起见,上面的代码是为了清晰起见而编辑的:该函数有很多类型检查和其他我已经删除的计算,但是你需要修补这个函数.在运行修补程序之前,请重新启动R会话或detach当前加载的会话ggplot2.

老版本

意外的行为是不是在版本观察2.0.9.32.1.0.1并显示在当前版本中发起2.2.0.1(或者更早2.2.0.0,当我试图把它这给了我一个错误).

要安装和加载旧版本,比如说ggplot2_0.9.3,创建一个单独的目录(覆盖当前版本没有意义),请说ggplot2093:

URL <- "http://cran.r-project.org/src/contrib/Archive/ggplot2/ggplot2_0.9.3.tar.gz" 
install.packages(URL, repos = NULL, type = "source", 
    lib = "~/R/testing/ggplot2093") 
Run Code Online (Sandbox Code Playgroud)

要加载旧版本,请从本地目录中调用它:

library("ggplot2", lib.loc = "~/R/testing/ggplot2093") 
Run Code Online (Sandbox Code Playgroud)