Skip to content

Use non-mapped, static aesthetic in ggplot() function as global default for geometries #6445

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
stragu opened this issue May 1, 2025 · 7 comments

Comments

@stragu
Copy link
Contributor

stragu commented May 1, 2025

Just like it is possible to have "global" aesthetic mappings to variables inside ggplot()'s mapping = aes(), I think it would make sense to be able to set global defaults for static aesthetics as well. (They are currently ignored.)

For example:

library(ggplot2)
ggplot(data = mpg,
       mapping = aes(x = displ, y = hwy),
       colour = "orange") +
  geom_density_2d() +
  geom_point() +
  geom_smooth()
#> `geom_smooth()` using method = 'loess' and formula = 'y ~ x'

# ... should be equivalent to:
ggplot(data = mpg,
       mapping = aes(x = displ, y = hwy)) +
  geom_density_2d(colour = "orange") +
  geom_point(colour = "orange") +
  geom_smooth(colour = "orange")
#> `geom_smooth()` using method = 'loess' and formula = 'y ~ x'

Created on 2025-05-01 with reprex v2.1.1, ggplot2 3.5.2 and R 4.5.0.

(Apologies if this has been discussed before, I couldn't find a duplicate.)

@stragu
Copy link
Contributor Author

stragu commented May 1, 2025

I believe it also is what is expected based on the current documentation (emphasis mine):

ggplot() initializes a ggplot object. It can be used to declare the input data frame for a graphic and to specify the set of plot aesthetics intended to be common throughout all subsequent layers unless specifically overridden.

@teunbrand
Copy link
Collaborator

Thanks for the request! The spirit of this idea is already implemented in the development version. Therein, we can use the theme to control various geom defaults.

devtools::load_all('~/packages/ggplot2/')
#> ℹ Loading ggplot2

ggplot(data = mpg,
       mapping = aes(x = displ, y = hwy)) +
  geom_density_2d() +
  geom_point() +
  geom_smooth() +
  theme(geom = element_geom(ink = "orange", accent = "orange"))
#> `geom_smooth()` using method = 'loess' and formula = 'y ~ x'

Created on 2025-05-01 with reprex v2.1.1

@stragu
Copy link
Contributor Author

stragu commented May 1, 2025

Interesting, and serendipitous!
I really like that solution using theming, and it makes perfect sense to have this kind of feature!

However, what about the consistency in aesthetics definition, and matching the documentation, without adding complexity? I assume I am not the first one to expect this to work just like the aesthetics mapped to scales, using keywords (aesthetic names) and concepts (global vs local) users are already familiar with. And saving some typing, even compared to the + theme(geom = element_geom()) solution.

And it wouldn't be the first time one thing can be done in two (or more!) different ways 😃. E.g. guides turned off via scale_*(guide = "none"), guides(* = "none"), or theme(legend.position = "none").

Or am I missing something that makes my syntax not desirable?

@thomasp85
Copy link
Member

The ability to do the same thing in multiple places is a horrible design mistake that we are still atoning for. We don't want to add to this

@smouksassi
Copy link

I don't agree that we can call this aesthetics definition, as in ggplot aesthetics is when you map something versus when you set something to one value, you are effectively overriding the aesthetics. colour ="orange" will have a whole different meaning if it is inside the aes(). Indeed, having many ways to do the same thing steepens the learning curve for new adopters.

library(ggplot2)
ggplot(data = mpg,
       mapping = aes(x = displ, y = hwy)) +
  geom_point(aes(colour = factor(cyl)) ,size=6) +
  geom_point(aes(colour = factor(cyl)), colour = "white", size=4) +
  geom_point(aes(colour = "orange") ,size=2)

Created on 2025-05-01 with reprex v2.1.1

@teunbrand
Copy link
Collaborator

To avoid confusion, let's make sure we're all talking about the same terms. I have the following mental model:

  • Aesthetic: a value for a graphical property
  • Mapping: A link between data (columns) and aesthetics.

So while I think it is valueable to set aesthetics locally in layers, or globally using the theme, I don't think it would make sense for mappings. The theme system is decidedly a collection of non-data settings and mappings are explicitly data related.

@stragu
Copy link
Contributor Author

stragu commented May 1, 2025

@smouksassi

I don't agree that we can call this aesthetics definition, as in ggplot aesthetics is when you map something versus when you set something to one value, you are effectively overriding the aesthetics. colour ="orange" will have a whole different meaning if it is inside the aes().

This distinction is something I clarify every time I teach ggplot2, and I often have to explain it in detail in other settings as questions keep coming up. So yes, definitely a source of confusion, and something important to understand when using ggplot2.

But in explaining my idea, I tried to make things clear by sticking to using the terms the documentation currently uses. The documentation says:

  • for a geom_*()'s mapping argument: "Set of aesthetic mappings created by aes()"
    • in aes(): "Aesthetic mappings" and "List of name-value pairs in the form aesthetic = variable"
  • for a geom_*()'s ... argument, the first option: "Static aesthetics that are not mapped to a scale, but are at a fixed value and apply to the layer as a whole."

....which is why I used "aesthetic mappings to variables/scale" vs "static aesthetics" to differentiate them.

If you don't think we should use the term "aesthetics" for static aesthetics, that would be a different request to change the documentation.

@teunbrand

So while I think it is valueable to set aesthetics locally in layers, or globally using the theme, I don't think it would make sense for mappings. The theme system is decidedly a collection of non-data settings and mappings are explicitly data related.

But I am not talking about changing anything about mappings, I'm only talking about making things more consistent in being able to set global static aesthetics in ggplot() just like we already are able to do it for mapped aesthetics, passing them to .... I definitely don't think aesthetic mappings to variables belong in the theme() function, to be extra clear.

@thomasp85

The ability to do the same thing in multiple places is a horrible design mistake that we are still atoning for. We don't want to add to this

Agreed, but in this case I think we would be making it more consistent and wouldn't introduce any new argument name, function or concept.

But I understand if the maintainers would rather not. In which case, I think the ggplot() documentation should be amended to say something like:

ggplot() initializes a ggplot object. It can be used to declare the input data frame for a graphic and to specify the set of aesthetic mappings intended to be common throughout all subsequent layers unless specifically overridden.

and further down, in "Details":

Static aesthetics can't be set globally with ... like they would in geom_*() functions. To change global static aesthetic values for geometries, use the geom argument in the theme() function.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants