Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

Already on GitHub? Sign in to your account

grob gPath-names not unique #459

Closed
kollerma opened this Issue Mar 28, 2012 · 18 comments

Comments

Projects
None yet
5 participants

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      
## > 
Collaborator

kohske commented Mar 30, 2012

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

Owner

hadley commented Jun 7, 2012

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

Collaborator

wch commented Jun 27, 2012

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
Owner

hadley commented Jun 27, 2012

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?

Contributor

baptiste commented Jun 28, 2012

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

Owner

hadley commented Jun 28, 2012

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)

Contributor

baptiste commented Jun 28, 2012

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?

Collaborator

kohske commented Jun 28, 2012

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

Owner

hadley commented Jun 28, 2012

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 .

Collaborator

kohske commented Jun 28, 2012

assign("index", 0, environment(grid:::grobAutoName))

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

Contributor

baptiste commented Jun 28, 2012

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.

Owner

hadley commented Jun 28, 2012

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.

Owner

hadley commented Jul 5, 2012

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?

Contributor

baptiste commented Jul 5, 2012

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

Owner

hadley commented Jul 6, 2012

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.

Collaborator

wch commented Jul 6, 2012

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

Owner

hadley commented Jul 11, 2012

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.

Owner

hadley commented Feb 24, 2014

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 Feb 24, 2014

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment