Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

getGrob() and str(ggplotGrob(...)) not working anymore #661

Closed
kollerma opened this Issue · 9 comments

3 participants

@kollerma

Hi

The following example shows the issues I have with the new version of ggplot2.

require(ggplot2)
require(grid)
require(lme4)
plt <- ggplot(Penicillin, aes(diameter, plate, color = sample)) + geom_point()
grob <- ggplotGrob(plt)

lls <- getGrob(grob, gPath='xlab-', grep=TRUE, global=TRUE)
## Error in getGrob(grob, gPath = "xlab-", grep = TRUE, global = TRUE) : 
##   It is only valid to get a child from a 'gTree'

## also str(grob) results in an error:
str(grob)
## [cut]
## .. .. .. ..$ NA:Error in object[[i]] : subscript out of bounds

When using ggplot2 version 0.9.1 the above code works just fine.

Thanks for having a look,

Manuel

sessionInfo()
## R version 2.15.1 (2012-06-22)
## Platform: x86_64-unknown-linux-gnu (64-bit)

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

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

## other attached packages:
## [1] ggplot2_0.9.2  fortunes_1.5-0 sfsmisc_1.0-20

## loaded via a namespace (and not attached):
##  [1] colorspace_1.1-1   dichromat_1.2-4    digest_0.5.2       grid_2.15.1       
##  [5] gtable_0.1.1       labeling_0.1       MASS_7.3-21        memoise_0.1       
##  [9] munsell_0.3        plyr_1.7.1         proto_0.3-9.2      RColorBrewer_1.0-5
## [13] reshape2_1.2.1     scales_0.2.2       stringr_0.6.1      tools_2.15.1   
@hadley
Owner

What are you trying to do? Working directly with grobs has never been advisable.

@kollerma

I want to be able to modify legend, axis texts, etc, so that I can put expressions everywhere, rename things, etc. without having to modify the data. Basically what I did here:
http://cran.r-project.org/web/packages/robustbase/vignettes/lmrob_simulation.pdf, e.g., Figure 8.

@hadley
Owner

Unfortunately using grid is a fragile way to modify ggplot2 graphics (at least until we finalise finalise the naming conventions). But there doesn't seem to be anything on that pdf you can't do with standard ggplot2.

@kollerma

It sure is a lot easier to modify the grob instead of using labeller, creating a new scale with another breaks or name, etc. depending on where I want my expressions to be.

Btw. I would very much appreciate it if there was a link in the documentation to a list of, e.g., labellers, instead of a labeller: NULL, which only leaves me with google.

@kollerma

To illustrate my above comment a little:
Say I have a plot with four facets where four different scenarios are shown. Additionally, there is a fifth scenario that is added as a reference to all the facets. It seems to me, the easiest way to do this is to add another geom_point using the data argument. If the data.frame does not contain the variable that is used to create the facets, it will show up in all four facets. This works very nicely with ggplot, if there is a color variable, we even get the correct legend, namely all the levels of colors in the four facets plus the reference.
But if I want to replace the labels of the color scale with my own labels, this gives me a major headache. I have to figure out the levels in the legend and make sure the legend is correct myself.

@fmitha

I'm having a similar issue with ggplotGrob. @kollerma did you ever figure out what was going on here?

@kollerma

I am not sure, whether it still applies to the above mentioned problem, but I got back the functionality I was looking for with the code appended below. Most of the expressions I need in plots can be placed by using things like the labeller argument in facet_grid. But putting expressions in facet titles facet_wrap still seems not to be supported, so I change them in the grobs directly using the code below.

If I recall correctly, the only things I had to change were to use not the returned object of ggplotGrob (g below) but g$grobs and skip over all elements of class gTree.

require(ggplot2)
require(grid)

## this is just a helper function
replaceLabel <- function(label, legend.mod) {
    if (!is.null(label) && !is.expression(label) &&
        length(label) > 0 && label %in% names(legend.mod)) {
        return(legend.mod[[label]])
    } else {
        return(label)
    }
}

## this function does the actual work
grobApplyLegend <- function(grob, legend.mod) {
    if (!inherits(grob, "gTree")) return(grob)
    ## edit grob: change legends, axis and strip text
    lls <- getGrob(grob, gPath='(xlab-|ylab-|title-|label-|legend.text.text|strip.text.x.text|strip.text.y.text|axis.text.y.text)',
                   grep=TRUE, global=TRUE)
    if (is.grob(lls)) lls <- gList(lls)
    ## walk all legend texts
    for(le in lls) {
        if (is.expression(le$label)) next
        newlabels <- sapply(le$label, replaceLabel, legend.mod = legend.mod)
        if (length(newlabels) > 0 &&
            (any(is.expression(newlabels)) || any(newlabels != le$label))) {
            grob <- editGrob(grob, gPath=le$name, label = newlabels)
        }
    }
    ## also: remove alpha in legend key points
    lls <- getGrob(grob, gPath='key.points', grep=TRUE, global=TRUE)
    for (le in lls) {
        if (is.character(le$gp$col) && grepl('^\\#', le$gp$col)) {
            lgp <- le$gp
            lgp$col <- substr(lgp$col, 1, 7)
            grob <- editGrob(grob, gPath=le$name, gp=lgp)
        }
    }
    ## also: change spacing of legends
    grob$children$legends$framevp$layout$heights <-
        grob$children$legends$framevp$layout$heights * .91
    grob
}

## and I replaced print.ggplot by this function
## that has the additional argument legend.mod
print.ggplot <- function(x, newpage = is.null(vp), vp = NULL, ...,
                         legend.mod = NULL)
{
    ggplot2:::set_last_plot(x)
    if (newpage)
        grid.newpage()
    g <- ggplotGrob(x, ...)
    if (packageVersion("ggplot2") > "0.9.1") {
        g$grobs <- lapply(g$grobs, grobApplyLegend, legend.mod=legend.mod)
    } else g <- grobApplyLegend(g, legend.mod)
    grid.draw(g)
}

## test it with this basic example
data <- data.frame(Type=factor(c("SMD.Wtau", "SMDM.Wtau", "MM.Avar1")),
                   x=1:3, y=1:3)

## replace labels that match the names of this list
## with the corresponding expressions.
legend.mod <- list(`SMD.Wtau` = expression(paste('SMD.W',tau)),
                   `SMDM.Wtau` = expression(paste('SMDM.W',tau)),
                   `MM.Avar1` = expression(paste('MM.',Avar[1])))

print(ggplot(data, aes(x, y)) + geom_point() + facet_wrap(~ Type),
      legend.mod=legend.mod)
@fmitha

@kollerma I wasn't notified of your message, though I am watching this thread. To be clear,
I was asking about the "out of bounds" error you got.
I ran into something similar recently - see
http://stackoverflow.com/q/17127339/350713

It seems you've worked around the problem. Is that correct?

@kollerma

@fmitha I see. Sorry, I don't really have a workaround for the out of bounds problem. After having figured out that I can do everything within $grobs, this was no issue anymore for me.

@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.