16

I am trying to use geom_point to illustrate the count of my data. I would also like to annotate a few of the points in my graph with geom_text. When I add the call to geom_text, it appears that it is plotting something underneath the points in the legend. I've tried reversing the order of the layers to no avail. I can't wrap my head around why it is doing this. Has anyone seen this before?

set.seed(42)
df <- data.frame(x = 1:10
    , y = 1:10
    , label = sample(LETTERS,10, replace = TRUE)
    , count = sample(1:300, 10, replace = FALSE)
)

p <- ggplot(data = df, aes(x = x, y = y, size = count)) + geom_point()
p + geom_text(aes(label = label, size = 150, vjust = 2))

alt text

hrbrmstr
  • 77,368
  • 11
  • 139
  • 205
Chase
  • 67,710
  • 18
  • 144
  • 161

2 Answers2

25

This happened to me all the time. The trick is knowing that aes() maps data to aesthetics. If there's no data to map (e.g., if you have a single value that you determine), there's no reason to use aes(). I believe that only things inside of an aes() will show up in your legend.

Furthermore, when you specify mappings inside of ggplot(aes()), those mappings apply to every subsequent layer. That's good for your x and y, since both geom_point and geom_text use them. That's bad for size = count, as that only applies to the points.

So these are my two rules to prevent this kind of thing:

  1. Only put data-based mappings inside of aes(). If the argument is taking a single pre-determined value, pass it to the layer outside of aes().
  2. Map data only for those layers that will use it. Corollary: only map data inside of ggplot(aes()) if you're confident that every subsequent layer will use it. Otherwise, map it at the layer level.

So I would plot this thusly:

p <- ggplot(data = df, aes(x = x, y = y)) + geom_point(aes(size = count)) 
p + geom_text(aes(label = label), size = 4, vjust = 2) 
Matt Parker
  • 26,709
  • 7
  • 54
  • 72
  • 2
    Your two rules are pertinent! – kohske Nov 19 '10 at 01:22
  • Very useful tips to know for the future, I'm still trying to wrap my head around best practices w/ ggplot2. Do you have any suggestions for subsetting the data object to plot? For example, if you only want to annotate the first and last point? I've been using something like `geom_text(data = df[grep("xxx", df$label) , ] , aes(x = ...))`. Is there a better way to go about doing that? – Chase Nov 19 '10 at 01:35
  • Chase - that's a good question. It might be wise to make a new question out of it; I have some vague notions, but chances are somebody else has a concrete idea. – Matt Parker Nov 19 '10 at 05:18
  • the `directlabels` package facilitates this sort of custom annotations, IIRC – baptiste Dec 26 '11 at 08:09
19

or, if you need to specify the size of text inside the aes, then legend = FALSE suppress drawing the legends of the geom:

p <- ggplot(data = df, aes(x = x, y = y, size = count)) + geom_point()
p + geom_text(aes(label = label, size = 150, vjust = 2), show_guide = FALSE)
Roman Luštrik
  • 69,533
  • 24
  • 154
  • 197
kohske
  • 65,572
  • 8
  • 165
  • 155
  • 1
    Ah, it never occurred to me to use that at the layer level. Nicely done. – Matt Parker Nov 19 '10 at 01:18
  • 2
    Just a small info: "legend" has been replaced by "show_guides": "legend" argument in geom_XXX and stat_XXX is deprecated. Use show_guide = TRUE or show_guide = FALSE for display or suppress the guide display." – Andreas Sep 02 '12 at 08:41