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) +

But after reading

I’m trying:

OPTION 2: does not work! :frowning:

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

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) +


Got it! Thank you, Sir!


I’ve found the discussion of global vs. layer specific mappings at helpful for sorting out where to define the aesthetics.


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) +

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?