tidyverse / ggplot2

An implementation of the Grammar of Graphics in R
https://ggplot2.tidyverse.org
Other
6.52k stars 2.02k forks source link

Shortcut for `scale_y_continuous(expand = expansion(c(0, 0.05))` #3962

Open thomas-neitmann opened 4 years ago

thomas-neitmann commented 4 years ago

When creating histogram or bar charts the standard expansion factor of 0.05 creates an unsighty gap between the bars and the x axis.

library(ggplot2)
data(mtcars)
ggplot(mtcars, aes(hp)) +
  geom_histogram()

image

To remove this gap currently one has to add scale_y_continuous(expand = expansion(c(0, 0.05)) to the plot. This is cumbersome to type, easy to forget and hard to grasp for beginners.

I'd love to have a shortcut for that, something like:

scale_y_tight <- function(...) {
  scale_y_continuous(expand = expansion(0, 0.05), ...)
}

This is in the same spirit as ylab() or ylim().

Thinking a bit further maybe this could even be an option:

exact_ylim <- function(...) {
  scale_y_continuous(limits = c(...), expand = expansion())
}

This would force the axis limits to be exactly those requested which is not the case currently with ylim().

clauswilke commented 4 years ago

I think this is a good idea, but I'd propose a different interface. We already have ylab() and ylim(), so it would make sense to add something like yexpand(). It could take either string arguments (e.g. "both", "none", "upper", "lower"), which would apply default expansions on both side, on neither side, or on the upper or lower end only, or numerical arguments similar to expansion().

Not sure how to implement this though. I'll have to look into how ylab() and ylim() communicate their arguments to the relevant scale.

thomas-neitmann commented 4 years ago

I like the idea of yexpand() but then the question arises what should be the default for the argument. For the use case I have in mind it should be "upper" which feels kind of unintuitive because you want to get rid of the lower expansion.

In any case, I'd be more than happy to implement something along these lines and make a pull request 😀

clauswilke commented 4 years ago

I've thought about this a bit and at this time I'm not sure how to implement this. xlab() and xlim() are implemented using entirely different mechanisms, and both seem ad-hoc. In general, we don't have a good approach to feeding in additional parameters into a scale that exists already. The same problems would arise if we wanted to, for example, set the breaks separately from the color mapping in a color scale. This has broader implications for other issues, such as default scales via theme (#2691), and we may have to think carefully about a good solution to this issue.

alanocallaghan commented 4 years ago

Seems like neither xlim nor xlab directly modify the scale, which seems non-ideal. This is, incidentally, something I've noticed already - if I use a function that uses ggplot2 internally to produce a plot, and I want to alter something about a scale (eg, add a transformation) I need to replace the scale entirely, which then triggers a message ("replacing scale for fill", or something along those lines. Apologies for being too lazy to generate one to check right now).

I guess if you make all aspects of all scales modifiable you have colour_lims, fill_lims etc (for all reasonable components of a scale and all types of scale) which may be a bit messy. Alternatively you could maybe have something like modify_scale(scale = "fill", trans = "log10") which doesn't require you to cover all bases but is maybe a bit less intuitive than things like xlim, ylab.