Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

Loading…

grob gPath-names not unique #459

Closed
kollerma opened this Issue · 18 comments

5 participants

@kollerma

It would be cool to have unique grob names (again?).
I frequently just produce the grob and then edit some of the labels / names / titles afterwards according to some table. This allows me to quickly change notation and use expressions very easily. In editGrob() I need to specify a gPath and if the name of an element is not unique, this does not work reliably.

See below for an example and output.

Thanks!

require(ggplot2)
require(grid)
data <- expand.grid(v1=letters[1:4], v2=LETTERS[1:3])
data$y <- rnorm(12)

gp <- ggplot(data, aes(y, v1, color=v1, shape=v2)) + geom_point()
grob <- ggplotGrob(gp)
## get the labels 
lls <- getGrob(grob, gPath='label-', grep=TRUE, global=TRUE)
## now we would edit the labels using editGrob,
## but this doesn't work since the names are not unique, e.g.,
## both have the same name and vp
lls[[1]][c('name', 'vp', 'label')]
lls[[4]][c('name', 'vp', 'label')]

sessionInfo()

## this produces the following output:

## > Loading required package: ggplot2
## > Loading required package: grid
## > > > > > > > > > > > $name
## [1] "label-3-3-4-4"

## $vp
## layout::label-3-3-4-4 

## $label
## [1] "A"

## > $name
## [1] "label-3-3-4-4"

## $vp
## layout::label-3-3-4-4 

## $label
## [1] "a"

## > > R version 2.15.0 RC (2012-03-25 r58832)
## Platform: x86_64-unknown-linux-gnu (64-bit)

## locale:
##  [1] LC_CTYPE=de_CH.UTF-8       LC_NUMERIC=C               LC_TIME=en_US.UTF-8       
##  [4] LC_COLLATE=de_CH.UTF-8     LC_MONETARY=en_US.UTF-8    LC_MESSAGES=de_CH.UTF-8   
##  [7] LC_PAPER=C                 LC_NAME=C                  LC_ADDRESS=C              
## [10] LC_TELEPHONE=C             LC_MEASUREMENT=de_CH.UTF-8 LC_IDENTIFICATION=C       

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

## other attached packages:
## [1] ggplot2_0.9.0  fortunes_1.4-2 sfsmisc_1.0-20

## loaded via a namespace (and not attached):
##  [1] colorspace_1.1-1   dichromat_1.2-4    digest_0.5.2       MASS_7.3-17       
##  [5] memoise_0.1        munsell_0.3        plyr_1.7.1         proto_0.3-9.2     
##  [9] RColorBrewer_1.0-5 reshape2_1.2.1     scales_0.2.0       stringr_0.6       
## [13] tools_2.15.0      
## > 
@kohske
Collaborator

I totally agree. I hope this feature, the consistent naming of each grob, will appear in the future version.

@hadley
Owner

@wch If we implement this, we probably need automated tests. The gtable infrastructure should take care of most of the naming.

@wch
Collaborator

I think this is a good time to think about setting the names, now that the external gtable change is merged. Here's an example of the current names. Any thoughts on what should be changed?

p <- ggplot(mtcars, aes(x=wt, y=mpg, colour=cyl, size=disp)) +
     geom_point() +
     facet_wrap(~cyl)

g <- ggplotGrob(p)
grid.ls(g)
# GRID.gTree.10257
#   panel-1-4-4-4-4
#     grill.gTree.10119
#       panel.background.rect.10110
#       panel.grid.minor.y.polyline.10112
#       panel.grid.minor.x.polyline.10114
#       panel.grid.major.y.polyline.10116
#       panel.grid.major.x.polyline.10118
#     geom_point.points.10102
#     panel.border.zeroGrob.10107
#   panel-2-4-7-4-7
#     grill.gTree.10134
#       panel.background.rect.10125
#       panel.grid.minor.y.polyline.10127
#       panel.grid.minor.x.polyline.10129
#       panel.grid.major.y.polyline.10131
#       panel.grid.major.x.polyline.10133
#     geom_point.points.10104
#     panel.border.zeroGrob.10122
#   panel-3-4-10-4-10
#     grill.gTree.10149
#       panel.background.rect.10140
#       panel.grid.minor.y.polyline.10142
#       panel.grid.minor.x.polyline.10144
#       panel.grid.major.y.polyline.10146
#       panel.grid.major.x.polyline.10148
#     geom_point.points.10106
#     panel.border.zeroGrob.10137
#   strip_t-1-3-4-3-4
#     strip.background.rect.10202
#     strip.text.x.text.10199
#   strip_t-2-3-7-3-7
#     strip.background.rect.10208
#     strip.text.x.text.10205
#   strip_t-3-3-10-3-10
#     strip.background.rect.10214
#     strip.text.x.text.10211
#   axis_l-1-4-3-4-3
#     axis.line.y.zeroGrob.10187
#     axis.frame.10191
#       GRID.cellGrob.10192
#         axis.text.y.text.10186
#       GRID.cellGrob.10193
#         axis.ticks.y.polyline.10189
#   axis_l-2-4-6-4-6
#   axis_l-3-4-9-4-9
#   axis_b-1-5-4-5-4
#     axis.line.x.zeroGrob.10154
#     axis.frame.10158
#       GRID.cellGrob.10159
#         axis.text.x.text.10153
#       GRID.cellGrob.10160
#         axis.ticks.x.polyline.10156
#   axis_b-2-5-7-5-7
#     axis.line.x.zeroGrob.10165
#     axis.frame.10169
#       GRID.cellGrob.10170
#         axis.text.x.text.10164
#       GRID.cellGrob.10171
#         axis.ticks.x.polyline.10167
#   axis_b-3-5-10-5-10
#     axis.line.x.zeroGrob.10176
#     axis.frame.10180
#       GRID.cellGrob.10181
#         axis.text.x.text.10175
#       GRID.cellGrob.10182
#         axis.ticks.x.polyline.10178
#   xlab-7-10-7-4
#   ylab-4-2-4-2
#   guide-box-4-12-4-12
#     guides-2-2-2-2
#       background-1-6-5-1
#       bar-4-2-4-2
#       label-4-4-4-4
#       title-2-5-2-2
#       ticks-4-2-4-2
#     guides-4-2-4-2
#       background-1-6-8-1
#       title-2-5-2-2
#       key-3-1-bg-4-2-4-2
#       key-3-1-1-4-2-4-2
#       key-4-1-bg-5-2-5-2
#       key-4-1-1-5-2-5-2
#       key-5-1-bg-6-2-6-2
#       key-5-1-1-6-2-6-2
#       key-6-1-bg-7-2-7-2
#       key-6-1-1-7-2-7-2
#       label-3-3-4-4-4-4
#       label-4-3-5-4-5-4
#       label-5-3-6-4-6-4
#       label-6-3-7-4-7-4
#   title-2-10-2-4
@hadley
Owner

That looks pretty good to me - the main thing to worry about are the names starting with GRID and I think they all come from code in guides-axis that should be converted to use gtable.

And maybe all uses of _ should be converted to - for consistency?

And maybe the top level element should be called ggplot?

@baptiste

I'm wondering, could we replace unique numbers as in axis.ticks.x.polyline.10178 with an alternative that is more reproducible? This last number, as far as I can tell, is constructed internally by grid, and will vary from user to user, and even from plot to plot in a given session.

It makes post-processing more difficult than it could be; for example one might want to be sure that a particular grob has an exact name, no matter what the drawing context may be, to attach a SVG decoration to it; alternatively the structure of two plots could be compared in a text representation using diff tools, etc.

BTW, there's a pdf documenting the lattice naming convention, http://lattice.r-forge.r-project.org/Vignettes/src/naming-scheme/namingScheme.pdf

@hadley
Owner

I'm not sure it's possible to make it completely reproducible - what happens if you then want to combine two ggplots on one graphics device? The ids need to be unique. (Also that link didn't work)

@baptiste

I don't know to be honest, it might be worth asking Paul Murrell for advice. I imagine if two plots are on the same device / display list, the low-level grobs remain children of their unique parent and don't become delocalised or anything. If you specify the full grob path, starting from the unique parent id, it should find only one instance of the grob, right?

@kohske
Collaborator

IIRC there is the way to reset index in grid.
Resetting it before plot will make thing reproducible.

@hadley
Owner

I'm pretty sure the whole reason why the arbitrary integers are on the names is so that grobs have globally unique names. I'm not sure I see much point in fixing it - it's fairly easy to ignore anything after the last .

@kohske
Collaborator
assign("index", 0, environment(grid:::grobAutoName))

can reset the index, but I don't recommend.
As @hadley suggested, we can ignore the suffix.

@baptiste

I've never read that a unique id was required (grobAutoName is merely used when the user doesn't supply a name, which doesn't have to be unique: most of the above aren't if you push two identical plots on a device!), in fact my guess is that it is a relic of an old implementation.
I can check with Paul if you want; if it's not needed it just adds noise to an otherwise very clean and consistent naming scheme.

@hadley
Owner

Yeah, maybe I'm misremembering - if you could check with Paul that would be great. It should be a simple fix to remove the trailing digits.

@hadley
Owner

I've made one small change to eliminate the trailing unique integers. But we need to a think a bit about the naming scheme, because it's currently a bit inconsistent. Should we use . or - to separate components? Should all names containing the class of the grob as the last component?

@baptiste

sorry i've been busy and haven't found the time to summarise Paul's reply here

@hadley
Owner

Ok, this is harder than I thought - as well as fixing ggname, I think Geom$draw_groups also needs to modified to rename all of the children geoms.

@wch
Collaborator
wch commented

I believe this is the same problem: hadley/gtable#24.

@hadley
Owner

To do this properly is pretty hard with the current structure of geoms. We'll fix it once and for all (hopefully!) as part of the geom/stat rewrite and conversion to s3.

@hadley
Owner

This sounds like a great feature, but unfortunately we don't currently have the development bandwidth to support it. If you'd like to submit a pull request that implements this feature, please follow the instructions in the development vignette.

@hadley hadley closed this
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Something went wrong with that request. Please try again.