Default breaks in ggplot2 - where are the break limits dropped for legend guides and polar coordinate y axis labels
Asked Answered
B

1

3

This is essentially a follow up question on How does ggplot calculate its default breaks? and I came across this when trying to find a slightly more elegant solution for How to add y-axis labels inside coord_polar graph ggplot?.

Apparently, the breaks are always calculated with scales::extended_breaks. However, it seems that the limits of those breaks are dropped with polar coordinates, as well as with a legend guide on continuous data.

Where does this happen?

library(ggplot2)

ggplot(mtcars, aes(x = mpg, y = mpg, size = hp)) +
  geom_point() +
  coord_polar() +
  labs(color = 'am')

Compare with


scales::extended_breaks()(mtcars$mpg)
#> [1] 10 15 20 25 30 35
scales::extended_breaks()(mtcars$hp)
#> [1]  50 100 150 200 250 300 350

Created on 2023-04-01 with reprex v2.0.2

Bulldog answered 1/4, 2023 at 15:31 Comment(1)
Just had a quick look. But as far as I get it's not the limits which get dropped, it's the scale or the limits which does not get expanded, i.e. only the position scales have an expand argument. And for coord_polar even the expansion of the positional scales is set to zero which happens in CoordPolar$setup_panel_params. Actually you get the same breaks for the x and y scale with coord_cartesian when you remove the expansion via expand=c(0, 0).Ens
E
2

As I mentioned in my comment the issue with both the guides for non-positional scales and coord_polar is that the scale or more exactly the limits don't get expanded. For coord_polar even the default exapnsion is set to zero which happens in CoordPolar$setup_panel_params:

...
if (self$theta == n) {
  expansion <- ggplot2:::default_expansion(scale, c(0, 0.5), c(0, 0))
} else {
  expansion <- ggplot2:::default_expansion(scale, c(0, 0),   c(0, 0))
}
...

As a consequence the lower and upper breaks returned by scales::breaks_extended will in general get dropped as it does not fall inside the limits.

This said, one option would be to extend the limits or to use a custom function which does this by computing the limits as range(scales::breaks_extended()):

library(ggplot2)

limits_extended <- function() {
  function(x) {
    range((scales::breaks_extended())(x))
  }
}

ggplot(mtcars, aes(x = mpg, y = mpg, size = hp)) +
  geom_point() +
  scale_x_continuous(limits = limits_extended()) +
  scale_y_continuous(limits = limits_extended()) +
  scale_size(limits = limits_extended()) +
  coord_polar() +
  labs(color = 'am')

Ens answered 1/4, 2023 at 18:47 Comment(2)
Interesting enough, the actual magic - as alluded to in the other post - seems to happen in labeling::extended, not a very easy to understand function, where the breaks must be calculated relative to the "extended" (expanded!) range of your data, but then, as you say, when there is no expansion, the limits will be "dropped".Bulldog
As always a very nice question which reminded me to keep an eye on the limits and teached me something new about coord_polar. A good opportunity to once again dig a bit deeper into the ggplot2 source code. (:Ens

© 2022 - 2024 — McMap. All rights reserved.