Ggplot2: Correct use of aes()

So, with this data:

df <- data.frame(trt = c("a", "b", "c"), outcome = c(2.3, 1.9, 3.2))

I need help to standarize my plot creation flow. Option1 is my lifetime way of making a plot, but after reading Hadley's book I'm trying to call aes() inside the geom, but I'm getting error.

OPTION 1: works!

ggplot(df, aes(trt, outcome, label = outcome)) +
  geom_col() +
  geom_label(vjust = -0.5) +
  ylim(0,6)

But after reading http://r4ds.had.co.nz/data-visualisation.html

I'm trying:

OPTION 2: does not work! :frowning:

ggplot(df) +
  geom_col(aes(trt, outcome, label = outcome)) +
  geom_label(vjust = -0.5) +
  ylim(0,6)

But I'm getting this error:

Warning: Ignoring unknown aesthetics: label
Error: geom_label requires the following missing aesthetics: x, y, label

I understand that option 2 is mor concise with the theory shared in the data visualization of Hadley's book.

What am I missing to make the second option work?

Setting x and y in aes in the ggplot function sets a default x and y variable for all geoms. In your Option 2, geom_label has no x and y defaults, so it must be set explicitly:

ggplot(df) +
  geom_col(aes(trt, outcome)) +
  geom_label(aes(trt, outcome, label = outcome), vjust = -0.5) +
  ylim(0,6)
3 Likes

Got it! Thank you, Sir!

I've found the discussion of global vs. layer specific mappings at http://r4ds.had.co.nz/data-visualisation.html#aesthetic-mappings helpful for sorting out where to define the aesthetics.

9 Likes

I'm not sure if you were asking about the warning message, or just the error, but for the sake of completeness, I think the most concise version of your code that locates aesthetic mappings close to their geoms is:

ggplot(df, aes(trt, outcome)) +
  geom_col() +
  geom_label(aes(label = outcome), vjust = -0.5) +
  ylim(0,6)

geom_col doesn't take a label aesthetic, so that's what the warning was about. Your two geoms both use the same x and y aesthetic mappings, so it's more concise to provide those in the initial call to ggplot(), rather than repeating yourself in each geom call. Then geom_label() adds the extra label aesthetic that's specific to that geom.

As far as conciseness goes, I didn't see much wrong with your Option #1 --- sure, you were providing a default for the label aesthetic that was only going to be used in one geom, so maybe it's more conceptually clear to introduce that mapping within its geom's function (as I did above), but Option #1 and my code above are equivalently concise. In this case, where you put the label aesthetic mapping seems like a matter of what you think will be most clear to humans reading your code.

Does anybody know if there's any deeper reason to prefer putting label inside geom_label() here, rather than at the top level?

3 Likes