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

Merged
merged 56 commits into from
Aug 27, 2024
Merged

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

teunbrand commented Jul 19, 2024

So I've tried to figure out why the revdep failures exist and here is a short description of failures that occurred more than twice in order of frequency. Here is my digestion of the issues:

  • Failures via {plotly} (60 times)
  • Missing plot labels (38 times)
  • Failures {patchwork} (35 times)
  • Failures via {ggdist} (19 times)
  • Failures via {ggnewscale} (16 times)
  • Unknown reasons (15 times)
    • The 'I don't know: I give up' category of failures. These packages failed for reasons beyond my skillset to diagnose or will take a thorough deep dive to diagnose.
  • Accessing default values (8 times)
    • Packages using something like GeomPoint$default_aes$colour for whatever reason. These packages probably need a PR to wrap access to these default values.
  • Using width = NULL as parameter to layer() (5 times)
  • False positives (4 times)
    • Failures due to installed package size sitting on the 5Mb threshold and such. They shouldn't be related to this PR or even ggplot2.
  • Failures via {ggforce} (4 times)
  • Failures due to length(ggplot()) or names(ggplot()) (4 times)
  • Tests require updates (3 times)
    • Related to this PR, tests that require simple updates because "grey35" is now sometimes "#595959" and whatnot.
  • Miscellaneous reasons (28 times)
    • 22 other reasons that are (almost) unique

@teunbrand
Copy link
Collaborator Author

teunbrand commented Jul 23, 2024

The current status of this PR is as follows;
I've tried to remove most friction between this PR and reverse dependencies.
This included small tweaks to this PR, but also new PRs to e.g. {ggdist} and {plotly}.
There are some inevitable changes that dependencies would have to make.

Some reverse dependencies will need to update some of their code to deal with default aesthetics that no longer are constants.
To make this somewhat easier, I've made a get_geom_defaults() helper that resolves from_theme() aesthetics.
I can still send out PRs to these packages if necessary. The packages are {ggpol}, {inTextSummaryTable}, {xaringanthemer}, {entropart}, {geomtextpath}, {ggdark}, {gghighlight}.

I don't think there is any more work to be done on this PR at the moment and I'd recommend merging this after review so that unforeseen issues can be reported.

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.

Did we land on a decision on thin+thick, vs stroke+line (or something to that accord)?

Also, we should add linetype for completeness.

I'm approving so you are not blocked going forward, but let's clear the above questions before merging

Comment on lines +120 to +121
outlier.shape = NULL,
outlier.size = NULL,
Copy link
Member

Choose a reason for hiding this comment

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

Can you remind me again why we can NULLify these?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Eventually pch = outlier.shape %||% data$shape where data$shape has been filled from GeomBoxplot$default_aes. Not setting these to NULL would then block the theme-inherited aesthetics from reaching the points. The logic is the same for outlier.size.

@teunbrand
Copy link
Collaborator Author

Did we land on a decision on thin+thick, vs stroke+line (or something to that accord)?

I don't think we did, but I don't have strong feelings either way. What seems more appropriate to you?

Also, we should add linetype for completeness.

Will do!

@EvaMaeRey
Copy link

Did we land on a decision on thin+thick, vs stroke+line (or something to that accord)?

'outline' or 'border' instead of 'stroke' is probably more consistent with everyday terminology.

@teunbrand

This comment was marked as resolved.

@teunbrand teunbrand merged commit 2e08bba into tidyverse:main Aug 27, 2024
13 checks passed
@teunbrand teunbrand deleted the theme_geom_defaults branch August 27, 2024 12:43
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
4 participants