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

Arbitrary positions for guides #5488

Merged
merged 40 commits into from
Dec 8, 2023
Merged

Conversation

teunbrand
Copy link
Collaborator

@teunbrand teunbrand commented Oct 17, 2023

When a plot has multiple guides, we're currently confined to exactly 1 side of the plot where guides are placed.
This PR adds a position argument to guides, that can overrule the side set in the theme.

Some details:

  • The Guides$build() method calls Guides$assemble() for every position, delivering 5 guide-boxes (left, right, top, bottom and manual), instead of just once for one position.
  • The code for adding guides to the plot's gtable has been isolated in a separate function. More so for my own sanity than necessity.
  • If there are guides, the plot's gtable will get appropriate column/rows for all positions, regardless of whether there are guides for any specific position. (i.e. if all legends are placed on the left, the gtable will also get rows for bottom/top).
  • The point above is mostly to make it easier for {patchwork} to align gtables, though this PR breaks patchwork at the moment.
devtools::load_all("~/packages/ggplot2")
#> ℹ Loading ggplot2

ggplot(mpg, aes(displ, hwy, colour = cty, shape = factor(cyl), fill = class)) +
  geom_point() +
  scale_shape_manual(values = 21:25) +
  guides(
    colour = guide_colourbar(position = "left"),
    shape  = guide_legend(position = "bottom", direction = "horizontal")
  )

There are still some details to hammer out, namely that the guide direction should follow a custom position is set. Notice in the plot below that the colourbar has also changed direction, though it probably shouldn't have. Another thing to hammer out is when a guide declares position = "manual", but the theme doesn't carry values for manual postions.

last_plot() + theme(legend.position = "top")

Created on 2023-10-17 with reprex v2.0.2

@teunbrand
Copy link
Collaborator Author

teunbrand commented Nov 1, 2023

A few updates.

  1. Had to slightly change approach due to Move guide building to ggplot_build() #5483. Guides$draw() has more responsibilities and Guides$package_box() wraps the legend box creation previously part of Guides$assemble().
  2. This made it easier to set the position-wise defaults, so that in the example above the colourbar isn't horizontal when placed on the left. See next example:
devtools::load_all("~/packages/ggplot2")
#> ℹ Loading ggplot2

ggplot(mpg, aes(displ, hwy, colour = cty, shape = factor(cyl), fill = class)) +
  geom_point() +
  scale_shape_manual(values = 21:25) +
  guides(
    colour = guide_colourbar(position = "left"),
    shape  = guide_legend(position = "bottom", direction = "horizontal")
  ) +
  theme(legend.position = "top")

  1. I've also separated out the coordinates from legend.position into a new theme element that purely controls the positioning of inside legends. Providing a <numeric> to legend.position is now deprecated and should use "inside" to set the default placement to inside the plot. By default, legend.position.inside takes on the value of legend.justification. I'm very much open to more intuitive naming here.
last_plot() + theme(legend.position = "inside", 
                    legend.position.inside = c(0.8, 0.8))

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

An open question is whether we should provide theme options to control justification on a per-side basis, for example justify left legends at the bottom and top legends on the right.

@teunbrand teunbrand changed the title POC: Arbitrary positions for guides WIP: Arbitrary positions for guides Nov 1, 2023
@teunbrand teunbrand marked this pull request as ready for review November 1, 2023 08:52
@teunbrand
Copy link
Collaborator Author

TODO: Add theme settings per position

@teunbrand teunbrand added this to the ggplot2 3.5.0 milestone Nov 7, 2023
Merge branch 'main' into guide_positioning

# Conflicts:
#	R/guide-legend.R
#	man/guide_legend.Rd
@teunbrand
Copy link
Collaborator Author

Now always includes rows/columns for every position and a <zeroGrob> when there are no legends for a position.

R/plot-build.R Outdated Show resolved Hide resolved
R/guides-.R Outdated Show resolved Hide resolved
R/guides-.R Outdated Show resolved Hide resolved
R/guides-.R Outdated Show resolved Hide resolved
R/plot-build.R Outdated Show resolved Hide resolved
R/plot-build.R Outdated Show resolved Hide resolved
R/plot-build.R Outdated Show resolved Hide resolved
R/theme.R Outdated Show resolved Hide resolved
R/theme.R Show resolved Hide resolved
Merge branch 'main' into guide_positioning

# Conflicts:
#	R/guides-.R
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.

LGTM

@teunbrand
Copy link
Collaborator Author

Thanks for the review Thomas!

@teunbrand teunbrand merged commit dad8a4b into tidyverse:main Dec 8, 2023
12 checks passed
@teunbrand teunbrand deleted the guide_positioning branch December 8, 2023 10:38
teunbrand added a commit to teunbrand/ggplot2 that referenced this pull request Dec 11, 2023
@teunbrand teunbrand mentioned this pull request Dec 11, 2023
teunbrand added a commit that referenced this pull request Dec 11, 2023
* colourbar size is defined in npcs

* backport `unitType`

* guide assembly preserves null units

* Handle null units at guide boxes

* set legend size to 1npc during build

* better unit recognitionin R3.6

* smart distribution of null units

* better detection of relative legend sizes

* document use of null units

* Add tests

* Adapt to #5488

* Fix title spacing bug
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants