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

Tags at panels #5167

Merged
merged 22 commits into from
May 2, 2023
Merged

Tags at panels #5167

merged 22 commits into from
May 2, 2023

Conversation

teunbrand
Copy link
Collaborator

@teunbrand teunbrand commented Jan 30, 2023

This PR aims to fix #4297.

Briefly, it adds the option to use plot.tag.position = c({position}, "panel") and draw the plot tag in the panel. It should also work with the patchwork package.

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

p <- ggplot(mpg, aes(displ, hwy)) +
  geom_point()

p +
  labs(tag = "A)") +
  theme(plot.tag.position = c("panel", "topright"))

library(patchwork)

(p + p) + plot_annotation(tag_levels = 'A') &
  theme(plot.tag.position = "panel")

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

Some side-notes:

  • I separated out the tag logic from the already enormous ggplot_gtable.ggplot_built() method. I refactored a little bit along the way.
  • Instead of adding yet another theme argument, I expanded the use of the already existing one. I think a lot in the theme, related to positions and alignments, is named confusingly, so I didn't want to pile on this already dizzying naming scheme (also nagged about this here).
  • I once again ran into this bug, so I fixed it in the same way.

R/plot-build.r Outdated
Comment on lines 365 to 366
# Initialise the tag margins
table <- gtable_add_padding(table, unit(0, "pt"))
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Patchwork for some reason assumes this padding is present regardless of whether it was needed, so I left this in.

Copy link
Member

Choose a reason for hiding this comment

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

yes, thanks... We should generally try to be predictable wrt the gtable structure that ggplot2 produces as it makes aligning multiple plots easier for patchwork

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

That makes good sense to me :)

R/plot-build.r Outdated
Comment on lines 429 to 432
if (top) table$heights <- unit.c(height, table$heights[-1])
if (left) table$widths <- unit.c(width, table$widths[-1])
if (right) table$widths <- unit.c(table$widths[-n_col], width)
if (bottom) table$heights <- unit.c(table$heights[-n_row], height)
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I think this pattern was some workaround for grid units not handling subassignment in R3.2 and earlier. Can we subassign units now?

@teunbrand teunbrand marked this pull request as draft February 4, 2023 12:36
@teunbrand
Copy link
Collaborator Author

teunbrand commented Feb 4, 2023

Should merge #5175 before this. Then update this PR to revert changes in 5dd6c2a.

@teunbrand teunbrand marked this pull request as ready for review February 21, 2023 18:59
@thomasp85
Copy link
Member

With this PR there will be 3 different placement strategies for tags. Either in the margin (adding space for it), on top of the full plot area (not adding space), or in the panel area (not adding space). Do all three have a name in this new API?

@teunbrand
Copy link
Collaborator Author

Currently, not all three placements have names, but for consistency's sake, maybe they should.

We could make it so that we have the following names:

  • "margin" for how currently character placement works.
    • "topleft" would be the same as c("margin", "topleft").
  • "plot" for how currently numeric placement works.
    • c("plot", "topleft") would then mean the same as c(0, 1).
  • "panel" for the new placement works.
    • c("panel", "topleft")

@teunbrand
Copy link
Collaborator Author

teunbrand commented Mar 21, 2023

I also found that if you use the margin placement, hjust/vjust is ignored. This is isn't as much as issue if you use the plot placement, as the two numbers you give essentially determine the hjust/vjust.

To illustrate:

library(ggplot2)

p <- ggplot(mpg, aes(displ, hwy)) +
  geom_point() +
  labs(tag = "Foobar")

In the plot below, I'd expect the tag to be in the top left, with a left margin for the plot, but not a top margin for the plot.

p + theme(plot.tag.position = "left",
          plot.tag = element_text(vjust = 1))

Likewise, here I would have expected the text to be at the top right, with a plot margin on top but not on the right.

p + theme(plot.tag.position = "top",
          plot.tag = element_text(hjust = 1))

Created on 2023-03-21 with reprex v2.0.2

I feel that this might be a separate issue, but since I'm tinkering with this code anyway, might as well include adherence to hjust/vjust settings.

@thomasp85
Copy link
Member

I like the "margin" name and think we should include that for completeness...

As for alignment, it works "correctly" right now in that it is perfectly aligned to the textbook that closely wraps the tag text. It is not given that the alignment is relative to the panel size.

I can see the argument for having it as you describe because the alignment is right now useless but I don't think it is obviously a bug as it is

@teunbrand
Copy link
Collaborator Author

One could now do these things:

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

p <- ggplot(mpg, aes(displ, hwy)) +
  geom_point() +
  labs(tag = "Foobar")

p + theme(plot.tag.position = c("panel", "topleft"))

p + theme(plot.tag.position = c("plot", "bottomright"))

p + theme(plot.tag.position = c("margin", "top"))

Created on 2023-03-27 with reprex v2.0.2

NEWS.md Outdated Show resolved Hide resolved
@thomasp85
Copy link
Member

Can we somehow make this new alignment work with numeric positions..?

@teunbrand
Copy link
Collaborator Author

We could in theory, but the way it is setup right now it isn't straightforward, as we cannot pass a mixed type character/numeric to the plot.tag.position setting. There is currently some flexibility of placement, in that you can set the hjust/vjust if only one of the directions is fixed:

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

p <- ggplot(mpg, aes(displ, hwy)) +
  geom_point() +
  labs(tag = "Foobar")

p + theme(plot.tag.position = c("panel", "top"),
          plot.tag = element_text(hjust = 0.75))

Created on 2023-04-15 with reprex v2.0.2

I think we might be able to extend this by not having the position default to 'topleft' for the 'panel' setting.

@thomasp85
Copy link
Member

yeah, I know the limitations of the current setup. I was thinking we should maybe considering a different setup such as providing an additional theme element (e.g. plot.tag.location) that holds the margin/plot/panel info... this would also bring it somewhat more in line with other location styles

@teunbrand
Copy link
Collaborator Author

We could make that work, but how should a numeric value interact with plot.tag.location = "margin"?

@thomasp85
Copy link
Member

yeah, that's a good question...

But I think having that not work (and documented) is better than the alternative

@teunbrand
Copy link
Collaborator Author

I'm just throwing an error now with numeric plot.tag.position and plot.tag.location = "margin".

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 teunbrand merged commit f89212d into tidyverse:main May 2, 2023
@teunbrand teunbrand deleted the panel_tag branch May 2, 2023 19:31
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.

tag position inside plot borders
2 participants