Skip to content
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

Geom aesthetics based on theme #5833

Open
wants to merge 28 commits into
base: main
Choose a base branch
from

Conversation

teunbrand
Copy link
Collaborator

This PR aims to partially fix #2239 and is intended to replace #2749.
It is a work in progress as a few things might need to happen before this is viable (more at the end about this).

The main gist is that there is a from_theme() function that works in a similar fashion to after_stat()/after_scale()/stage().
During Geom$use_defaults(), this will be used for masked evaluation from a new theme element.
See example below for a quick demo:

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

p <- ggplot(mpg, aes(displ, hwy)) +
  theme(geom = element_geom(ink = "purple"))

p + geom_point(aes(colour = from_theme(ink)))

It also works from the geom defaults, but this isn't implemented in any geom yet, as a few geoms (notably geom_sf()) are recalcitrant to this method.

update_geom_defaults("point", aes(colour = from_theme(ink)))

p + geom_point()

Created on 2024-04-08 with reprex v2.1.0

There are a few topics for discussion that mostly mirror those in #2749.

  • Current colour options in element_geom() are ink, paper and accent. You can think of ink and paper as foreground and background respectively and could be renamed fg and bg if that is deemed more intuitive.
  • The main reason I didn't went with colour_1, colour_2, fill_1, fill_2 etc as discussed in Allow default geom aesthetics to be set from theme #2749, is because from_theme() could allow you to mix colours on the spot and you wouldn't need a large number of colours to account for all the different grayscale defaults in the geoms. See also next point.
  • I would like a colour mixing function so that we could hypothetically do the following for e.g. GeomRect:
    default_aes = list(
      ...,
      fill = from_theme(col_mix(ink, paper, amount = 0.35))
    )
    
    This probably has a more comfortable home in the {scales} package, as I think we'd need {farver} for this and ggplot2 only indirectly depends on {farver}.
  • geom_sf() performs typical Geom tasks (like setting defaults) in the sf_grob() and would require a bit of refactoring to wire this geom up directly.

@teunbrand
Copy link
Collaborator Author

Update: added text parameters to element_geom(), which are set when using complete themes.
base_family and base_size populate these parameters.

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

ggplot(mtcars, aes(wt, mpg, label = rownames(mtcars))) +
  geom_text() +
  theme_gray(base_family = "Montserrat", base_size = 22)

Created on 2024-04-17 with reprex v2.1.0

@teunbrand
Copy link
Collaborator Author

teunbrand commented Apr 17, 2024

This is in a useable state now, with almost all geoms completing colour/fill/linewidth/family/(font)size defaults from the theme.
Because from_theme() can have expressions, we can generate the whole grayscale gradient by mixing the paper (white) and ink (black) settings.

What isn't done up to this point:

expect_true(attr(p$plot$theme, "complete"))

Aside from these points, I'd be happy for any feedback on the direction, so I'm un-WIP-ping this PR.

@teunbrand teunbrand marked this pull request as ready for review April 17, 2024 14:57
@teunbrand teunbrand changed the title WIP: Geom aesthetics based on theme Geom aesthetics based on theme Apr 17, 2024
Merge branch 'main' into theme_geom_defaults

# Conflicts:
#	R/geom-.R
#	R/geom-sf.R
@teunbrand
Copy link
Collaborator Author

Small update:

  • geom_sf() now has themeable defaults.
  • Failling test was removed. Assumption earlier was that theme wasn't built/completed after ggplot_build(), and now it is.
devtools::load_all("~/packages/ggplot2")
#> ℹ Loading ggplot2

nc <- sf::st_read(system.file("shape/nc.shp", package = "sf"), quiet = TRUE)

ggplot(nc) +
  geom_sf() +
  theme(
    geom = element_geom(ink = "forestgreen")
  )

Created on 2024-04-29 with reprex v2.1.0

@teunbrand
Copy link
Collaborator Author

I've added pointsize and pointshape to element_geom() and propagated these to the relevant geoms.
This had a visual change in some snapshots, due to pointsize scaling with the theme's base_size argument, but this is somewhat intended.
For geom_boxplot(), I had to set the outlier.shape and outlier.size defaults to NULL in order to retrieve these from the GeomBoxplot$default_aes field.

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

ggplot(mpg, aes(class, hwy)) +
  geom_boxplot() +
  theme(geom = element_geom(
    pointsize = 1, pointshape = 3,
    ink = "red", paper = "grey80"
  ))

Created on 2024-04-30 with reprex v2.1.0

I think this is now ready for proper review.

Copy link
Member

@thomasp85 thomasp85 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Apart from my one comment this generally looks good. I'm slightly unsure about the need for the "paper" colour. The fact that it is always white in ggplot2 makes me feel like it is wasted on encoding that. Do you have examples of extension themes where it would be set to something else and that would lead to good defaults with all the mixing?

Aside, I'd really like @clauswilke and @yutannihilation to have a look at this as they were involved in the superseded PR

R/geom-pointrange.R Outdated Show resolved Hide resolved
Co-authored-by: Thomas Lin Pedersen <thomasp85@gmail.com>
@teunbrand
Copy link
Collaborator Author

teunbrand commented Apr 30, 2024

The paper colour is essentially for when you have a dark theme.
I can't really demonstrate directly as {ggdark} overrides geom defaults, but getting a rough grasp of it:

It is very hard to read out these boxplots:

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

# Very simplified dark theme
dark_theme <- theme(
  plot.background = element_rect(fill = "black"),
  panel.background = element_rect(fill = "grey10"),
  axis.text = element_text(colour = "white"),
  axis.ticks = element_line(colour = "white"),
  panel.grid = element_line(colour = "grey5"),
  axis.title = element_text(colour = "white")
)

ggplot(mpg, aes(class, displ)) +
  geom_boxplot() +
  dark_theme

But it is way easier when you swap light/dark in ink/paper:

last_plot() + theme(geom = element_geom(ink = "white", paper = "grey10"))

Created on 2024-04-30 with reprex v2.1.0

@teunbrand
Copy link
Collaborator Author

Addional idea that popped up, but probably best for a different PR;
We could have the entire theme be mixtures of ink and paper so that it is really trivial to make a darkmode plot.

@yutannihilation
Copy link
Member

Aside, I'd really like @ clauswilke and @ yutannihilation to have a look at this as they were involved in the superseded PR

I hope I can have time to take a look! By the way, which PR do you mean? I might get lost.

@teunbrand
Copy link
Collaborator Author

Thanks! The previous PR for tackling this issue is #2749.

@yutannihilation
Copy link
Member

Oh, thanks. I can't remember how I involved in #2749, so I was wondering if there was a different one. But, that's fine. I'll try to get the context...!

@teunbrand
Copy link
Collaborator Author

TODO: Taken from #5886:

we should also keep at least two fonts in the geom defaults inside themes

@teunbrand
Copy link
Collaborator Author

teunbrand commented May 11, 2024

As in the issue that Hiroaki linked, there might be some revdep fallout for packages that want to compare values from the default aesthetics. We can consider doing a proper revdepcheck to assess the scope of the problem.

@yutannihilation
Copy link
Member

As in the issue that Hiroaki linked, there might be some revdep fallout for packages that want to compare values from the default aesthetics

Yeah, while the linked one is simply my fault, I was wondering whether it can be any problem or not to lose access to the actual values of default_aess.

@thomasp85
Copy link
Member

I agree, but I think this is a case of not being able to have a cake and eat it. Here I think the pro's outweigh the con's

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

Successfully merging this pull request may close these issues.

Geoms and scales: default settings in theme
3 participants