Q:

ggplot2 annotate layer position in R

In my plot I have both legends and text annotations. For legends, I can specify 
legend.justification=c(1,0), legend.position=c(1,0) 
to locate the position relative to the plotting region (e.g. topright, bottomleft). However, when I put an annotate layer (http://docs.ggplot2.org/0.9.3.1/annotate.html), it seems that I can only specify the coordinates of the text
annotate("text", x = 8e-7, y = 1e-5, label=data.note, size = 5) 
instead of the position of the plotting region (I want to put the text in the bottomleft corner). The length of the text (label) may vary for different plots. Is there a way to achieve this? Thanks!

A:

You can use the fact that -Inf and Inf will get mapped to the extremes of the position scales without extending them to place it in the bottom left corner. hjust and vjust are needed to make the reference point the lower left corner of your text. [using jlhoward's mock data.]
set.seed(1)
df <- data.frame(x=rnorm(100),y=rnorm(100))

ggplot(df, aes(x,y)) +geom_point()+
  annotate("text",x=-Inf,y=-Inf,hjust=0,vjust=0,label="Text annotation")

A:

Is this what you're looking for??

set.seed(1)
df <- data.frame(x=rnorm(100),y=rnorm(100))
ggplot(df, aes(x,y)) +geom_point()+
  annotate("text",x=min(df$x),y=min(df$y),hjust=.2,label="Text annotation")

There will probably be a bit of experimentation with hjust=... needed to get this exactly at the bottom left.

A:

The "Inf" solution has problems when you want multi-line text. In addition, it there is no margin between the text and the panel edge, which is ugly. The other solution requires explicit mention of the data which is not good either.
The desired effect can be achieved nicely with annotation_custom (or in my example, the proto Geom directly). You have configurable margin, text and box justification.
The added bonus in the following code is that you can specify which facet to annotate with something like facets=data.frame(cat1='blue', cat2='tall').
library("ggplot2")
annotate_textp <- function(label, x, y, facets=NULL, hjust=0, vjust=0, color='black', alpha=NA,
                          family=thm$text$family, size=thm$text$size, fontface=1, lineheight=1.0,
                          box_just=ifelse(c(x,y)<0.5,0,1), margin=unit(size/2, 'pt'), thm=theme_get()) {
  x <- scales::squish_infinite(x)
  y <- scales::squish_infinite(y)
  data <- if (is.null(facets)) data.frame(x=NA) else data.frame(x=NA, facets)

  tg <- grid::textGrob(
    label, x=0, y=0, hjust=hjust, vjust=vjust,
    gp=grid::gpar(col=alpha(color, alpha), fontsize=size, fontfamily=family, fontface=fontface, lineheight=lineheight)
  )
  ts <- grid::unit.c(grid::grobWidth(tg), grid::grobHeight(tg))
  vp <- grid::viewport(x=x, y=y, width=ts[1], height=ts[2], just=box_just)
  tg <- grid::editGrob(tg, x=ts[1]*hjust, y=ts[2]*vjust, vp=vp)
  inner <- grid::grobTree(tg, vp=grid::viewport(width=unit(1, 'npc')-margin*2, height=unit(1, 'npc')-margin*2))

  layer(
    data = NULL,
    stat = StatIdentity,
    position = PositionIdentity,
    geom = GeomCustomAnn,
    inherit.aes = TRUE,
    params = list(
      grob=grid::grobTree(inner), 
      xmin=-Inf, 
      xmax=Inf, 
      ymin=-Inf, 
      ymax=Inf
    )
  )
}

qplot(1:10,1:10) + annotate_text2('some long text\nx = 1', x=0.5, y=0.5, hjust=1)

