1

I have a ggplot object. I want to use annotate() to add a label to the top of the plot, so that the upper edge of the label is also the upper edge of the plot. When using default settings, this doesn't seem possible: adding an annotation at the upper edge of the plot causes the upper y-limit to increase.

One can get around this problem by specifying scale_y_continuous(expand = c(0, 0)) when creating the plot. But I don't want to do that, partly because I like the y limits created by the default expand setting. Given this constraint, is it possible to use annotate() to position a label at the top of the plot?

Here is a minimal example that demonstrates the problem:

library(ggplot2)
p    <- ggplot(mtcars, aes(mpg, wt)) + geom_point()
yMax <- layer_scales(p)$y$range$range[2]  # upper y-limit
p + annotate("label", x = 30, y = yMax, vjust = "top", label = "X")

And here is the result:

enter image description here

You see that the annotation is not at the top of the plot. Instead, consistent with the default "expand" settings, the y-limit of the plot has changed.

Possible solutions:

  1. Figure out the y-limits implied by the default expand setting. Then use scale_y_continuous() to both set the y limits and set expand = c(0, 0). This solution will give me the y limits that I want, and it will place the label appropriately. I know how to implement it, but it seems a bit cumbersome. It would also prevent other annotations at the top of the figure from changing the y-limit of the plot -- and I don't want the solution to affect annotations other than the one that I describe here.

  2. Use annotation_custom(), which doesn't change plot limits in the same way. @baptiste suggests a solution like that in this answer to a different question. But annotation_custom() requires a grob. In practice, the annotations that I use may be more complicated than the label in this example, and I won't always know how to create them as a grob that can be passed to annotation_custom(). In addition, I've had some trouble positioning grobs with annotation_custom() while also specifying their exact sizes.

That said, I am quite open to annotation_custom()-based solutions. And perhaps there are solutions other than the two that I've sketched above.

I've read many SO posts on changing plot limits, but I haven't found any that speak to this problem.

user697473
  • 2,165
  • 1
  • 20
  • 47

2 Answers2

2

A simple solution for that is setting y = Inf instead of using the maximum value found of the y-axis (yMax). The code would be like that then:

# load library
library(ggplot2)
# load data
data(mtcars)
# define plot
p <- ggplot(mtcars, aes(mpg, wt)) + geom_point()
p + annotate("label", x = 30, y = Inf, vjust = "top", label = "X")

Here is the output:

enter image description here

Let me know if this is what you're looking for.

rodolfoksveiga
  • 1,181
  • 4
  • 17
  • Thank you. I didn't know that `Inf` could be used to prevent the plot-expanding behavior that I described in my post. – user697473 Sep 04 '20 at 12:22
1

Does this help?

library(ggplot2)

data(mtcars)

ggplot(mtcars, aes(mpg, wt)) +
  geom_point() +
  geom_text(label = "X", x = 30, y = max(mtcars$wt))
Hydro
  • 1,057
  • 12
  • 25
  • Thank you -- but it's not quite right. If you run the code, you'll see that positioning the label in this way increases the upper y-limit of the plot. As a result, the label isn't positioned at the top of the plot. – user697473 Sep 04 '20 at 12:21