2

The following was tested with R 2.15.3, ggplot2 0.9.3.1 and gtable 0.1.2 on Debian squeeze.

In the course of debugging this ggplot2 issue multiple calls to annotation_custom fail in certain cases, I came across something I don't know how to debug. I've created a repository in Bitbucket with the relevant information github-ggplot2-817.

The relevant README from that repos is copied below. If you don't want to use Mercurial, the relevant file with serialized R data can be downloaded directly from addgrob.asc.save.

To reproduce addgrob.asc.save, you could use the Debian packaging in https://bitbucket.org/faheem/gtable-debian, or if you prefer, just the patch to gtable, namely gtableaddgrob.diff, along with the script save.R.

Summary of the issue: running R's str function on an object (here called x) gives an error if ggplot2 is loaded, but not otherwise. I'm not sure what is going on, so any pointers would be appreciated.

###############################################################

To reproduce this bug, do the following.

Start R. Then

> ls()
character(0)
> load("addgrob.asc.save")
> ls()
[1] "grobs"  "layout" "x"

> str(x, max.level=1)
List of 10
 $ grobs   :List of 8
 $ layout  :'data.frame':       8 obs. of  7 variables:
   $ widths  :Class 'unit'  atomic [1:6] 1.5 6.096 0.762 1.961 0 ...
  .. ..- attr(*, "unit")= chr "mm"
  .. ..- attr(*, "valid.unit")= int 7
 $ heights :Class 'unit'  atomic [1:7] 1.5 2.53 1.52 6.1 6.1 ...
  .. ..- attr(*, "unit")= chr "mm"
  .. ..- attr(*, "valid.unit")= int 7
 $ respect : logi FALSE
 $ rownames: NULL
 $ colnames: NULL
 $ name    : chr "layout"
 $ gp      : NULL
 $ vp      : NULL
 - attr(*, "class")= chr [1:3] "gtable" "grob" "gDesc"

## Now update x
> x$grobs <- c(x$grobs, grobs)
> x$layout <- rbind(x$layout, layout)

> str(x, max.level=1)
List of 10
 $ grobs   :List of 11
 $ layout  :'data.frame':       11 obs. of  7 variables:
   $ widths  :Class 'unit'  atomic [1:6] 1.5 6.096 0.762 1.961 0 ...
  .. ..- attr(*, "unit")= chr "mm"
  .. ..- attr(*, "valid.unit")= int 7
 $ heights :Class 'unit'  atomic [1:7] 1.5 2.53 1.52 6.1 6.1 ...
  .. ..- attr(*, "unit")= chr "mm"
  .. ..- attr(*, "valid.unit")= int 7
 $ respect : logi FALSE
 $ rownames: NULL
 $ colnames: NULL
 $ name    : chr "layout"
 $ gp      : NULL
 $ vp      : NULL
 - attr(*, "class")= chr [1:3] "gtable" "grob" "gDesc"

> library(ggplot2)

> str(x, max.level=1)
List of 11
 $ grobs   :List of 11
 $ layout  :'data.frame':       11 obs. of  7 variables:
   $ widths  :Class 'unit'  atomic [1:6] 1.5 6.096 0.762 1.961 0 ...
  .. ..- attr(*, "unit")= chr "mm"
  .. ..- attr(*, "valid.unit")= int 7
 $ heights :Class 'unit'  atomic [1:7] 1.5 2.53 1.52 6.1 6.1 ...
  .. ..- attr(*, "unit")= chr "mm"
  .. ..- attr(*, "valid.unit")= int 7
 $ respect : logi FALSE
 $ rownames: NULL
 $ colnames: NULL
 $ name    : chr "layout"
 $ gp      : NULL
 $ vp      : NULL
 $ NA:Error in object[[i]] : subscript out of bounds

Loading ggplot2 does not cause the earlier version of x to error out str.

> ls()
character(0)
> load("addgrob.asc.save")
l> ls()
[1] "grobs"  "layout" "x"     
> library(ggplot2)
> str(x, max.level=1)
List of 8
 $ grobs   :List of 8
 $ layout  :'data.frame':       8 obs. of  7 variables:
 $ widths  :Class 'unit'  atomic [1:6] 1.5 6.096 0.762 1.961 0 ...
  .. ..- attr(*, "unit")= chr "mm"
  .. ..- attr(*, "valid.unit")= int 7
 $ heights :Class 'unit'  atomic [1:7] 1.5 2.53 1.52 6.1 6.1 ...
  .. ..- attr(*, "unit")= chr "mm"
  .. ..- attr(*, "valid.unit")= int 7
 $ respect : logi FALSE
 $ rownames: NULL
 $ colnames: NULL
 $ name    : chr "layout"
 - attr(*, "class")= chr [1:3] "gtable" "grob" "gDesc"

The output of traceback() is

> traceback()
2: str.default(x, max.level = 1)
1: str(x, max.level = 1)

ADDENDUM: In Python it is possible to set things up so that all lines of code called when a function is executed are written to a file.This can be rather voluminous, but if this was possible in R, it would help to clarify things. I did a Google search, but all I came up with were various debugging utilities.

ADDENDUM2: I've created the issue The str function fails with error on ggplot2 objects for this.

4

2 回答 2

2

可以使用以下方法更简单地重新创建错误:

x[11]

我认为正在发生的事情是您的“x”对象是在具有“[”-“gtable”对象的方法的工作环境中创建的。你现在把它带回到一个最初没有的工作区,然后随着 ggplot2 的加载,现在有某种由 ggplot2 引用的“[”-方法,即使该gtables包仍未加载。

我无法通过加载 pkg:gtable 解决问题。但我不相信“gtable”是一个格式正确的包,因为尽管报告成功,sessionInfo()但拒绝报告其注册。require(gtable)

> require(gtable)
Loading required package: gtable
> `[.gtable`(x, 11)
Error: could not find function "[.gtable"
No suitable frames for recover()
> x[11]
Error in if (any(index < 0)) { : missing value where TRUE/FALSE needed

Enter a frame number, or 0 to exit   

1: x[11]
2: `[.gtable`(x, 11)
3: x$heights[rows]
4: `[.unit`(x$heights, rows)

Selection: 0
> sessionInfo()

R version 3.0.0 RC (2013-03-31 r62463)
Platform: x86_64-apple-darwin10.8.0 (64-bit)

locale:
[1] en_US.UTF-8/en_US.UTF-8/en_US.UTF-8/C/en_US.UTF-8/en_US.UTF-8

attached base packages:
[1] grid      grDevices datasets  splines   graphics  utils     stats    
[8] methods   base     

other attached packages:
 [1] gtable_0.1.2        RCurl_1.95-4.1      bitops_1.0-5       
 [4] data.table_1.8.8    gplots_2.11.0       MASS_7.3-26        
 [7] KernSmooth_2.23-10  caTools_1.14        gdata_2.12.0       
[10] gtools_2.7.1        ggplot2_0.9.3.1     gridExtra_0.9.1    
[13] HH_2.3-36           colorspace_1.2-1    reshape_0.8.4      
[16] plyr_1.8            latticeExtra_0.6-24 RColorBrewer_1.0-5 
[19] leaps_2.9           multcomp_1.2-17     mvtnorm_0.9-9994   
[22] rms_3.6-3           Hmisc_3.10-1        survival_2.37-4    
[25] sos_1.3-5           brew_1.0-6          lattice_0.20-15    

loaded via a namespace (and not attached):
 [1] cluster_1.14.4  dichromat_2.0-0 digest_0.6.3    fortunes_1.5-0 
 [5] labeling_0.1    munsell_0.4     proto_0.3-10    reshape2_1.2.2 
 [9] scales_0.2.3    stringr_0.6.2   tools_3.0.0  

(我确实安装了 gtable 0.1.2。)

附录:可以用这个代码重现:

test <- data.frame(x=1:20, y=21:40, 
                  facet.a=rep(c(1,2), 10), 
                  facet.b=rep(c(1,2), each=20))
p <- qplot(data=test, x=x, y=y, facets=facet.b~facet.a)
# get gtable object
z <- ggplot_gtable(ggplot_build(p))
length(z)
#[1] 16
z[16]  # drops into browser
于 2013-06-15T23:44:00.137 回答
2

我猜问题是str.default看gtable的长度,它被定义为grobs的数量,但随后迭代它并遇到不存在的元素,因为[.gtable它是为了访问gtable的单元格(单元格矩阵),而不是 grobs,并且这些单元格可以少于 grobs 的数量。

我可以想到两种方法来解决这个问题,

  1. 定义str.gtable提供更紧凑信息的方法(并修复此索引错误)

  2. 重新定义[.gtable一个索引 (g[1]) 以访问 grobs 列表(相当于布局 data.frame 的行),而不是“单元矩阵”

这是一个建议的str.gtable功能;我想知道是否有明确的规则来定义这些(默认方法是相当的野兽),

str.gtable <- function(object, ...){
  cat(c("gtable, containing \ngrobs (", 
        length(object[["grobs"]]), "), with names :"), sep="")
  utils::str(names(object[["grobs"]]))
  cat("layout :\n")
  utils::str(object[["layout"]])
  cat("widths :\nunit vector of length", 
      length(object[["widths"]]), "\n")
  cat("heights :\nunit vector of length", 
      length(object[["heights"]]), "\n")
  for(element in c("respect", "rownames", 
                   "name", "gp", "vp")){
    cat(element, ":\n")
    utils::str(object[[element]])
  }
}
library(gridExtra)

g <- tableGrob(head(iris))
str(g)

屈服

gtable, containing 
grobs (84), with names : chr [1:84] "" "" "" "" "" "" "" "" "" "" "" "" ...
layout :
'data.frame':   84 obs. of  7 variables:
 $ t   : int  1 2 3 4 5 6 7 1 2 3 ...
 $ l   : int  1 1 1 1 1 1 1 1 1 1 ...
 $ b   : int  1 2 3 4 5 6 7 1 2 3 ...
 $ r   : int  1 1 1 1 1 1 1 1 1 1 ...
 $ z   : num  1 2 3 4 5 6 7 0 0 0 ...
 $ clip: chr  "on" "on" "on" "on" ...
 $ name: chr  "rowhead-fg" "rowhead-fg" "rowhead-fg" "rowhead-fg" ...
widths :
unit vector of length 6 
heights :
unit vector of length 7 
respect :
 logi FALSE
rownames :
 NULL
name :
 chr "rowhead-fg"
gp :
 NULL
vp :
 NULL
于 2015-07-22T00:53:29.553 回答