Skip to content

Stacked axes #5473

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

Merged
merged 18 commits into from
Dec 6, 2023
Merged

Stacked axes #5473

merged 18 commits into from
Dec 6, 2023

Conversation

teunbrand
Copy link
Collaborator

@teunbrand teunbrand commented Oct 11, 2023

This PR is a proof-of-concept for an axis guide that stacks other axis guides.

For context: I don't really think stacked axes are all too useful for data visualisation except maybe to display two different units of the same measurement on an axis (degree celsius/fahrenheit, metres/inches etc.). Certainly in its current form, this PR cannot even do that (but that might be amended by #5410). Arguably, that functionality shouldn't live in ggplot2 but in extension packages.

However, the display of multiple units is not the goal of this axis guide. The goal of this axis guide is to incorporate flexibility in axis composition into ggplot2 itself. That way, the following should be possible:

  • A package can develop an axis annotation guide. With stacked axes, this annotation guide needn't worry about rendering the typical line, ticks and text and can just focus on providing the annotations.
  • Package A can develop a 'typical' axis and package B can develop an 'annotation' axis and they can just be composed by users as they see fit.

To give a more concrete example for this, one could view the guide displayed here as a regular axis + annotation for ranges.

Here is some nightmare fuel to show that it works:

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

axis1 <- guide_axis(angle = 45)
axis2 <- guide_axis(cap = "both")
axis3 <- guide_axis(n.dodge = 2)
stack <- guide_axis_stack(axis1, axis2, axis3)

ggplot(mpg, aes(displ, hwy)) +
  geom_point() +
  guides(
    x = stack, x.sec = stack,
    y = stack, y.sec = stack
  ) +
  theme(axis.line = element_line())

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

), i = "Guides need to handle {.field x} and {.field y} aesthetics."))
}

params <- lapply(axes, `[[`, name = "params")
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Keep track of #5474

@thomasp85 thomasp85 added this to the ggplot2 3.5.0 milestone Oct 24, 2023
@teunbrand teunbrand changed the title POC: Stacked axes Stacked axes Oct 24, 2023
@teunbrand

This comment was marked as resolved.

@teunbrand
Copy link
Collaborator Author

Now also compatible with coord_radial() and guide_axis_theta().

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

p <- ggplot(mtcars, aes(hp, disp)) +
  geom_point() +
  coord_radial(start = 0.25 * pi, end = 1.75 * pi, donut = 0.5) +
  guides(
    theta = guide_axis_stack("axis_theta", guide_axis_theta(cap = "both")),
    theta.sec = guide_axis_stack("axis_theta", guide_axis_theta(cap = "both")),
    r = guide_axis_stack("axis", guide_axis(cap = "both")),
    r.sec = guide_axis_stack("axis", guide_axis(cap = "both"))
  ) +
  theme(axis.line = element_line())
p

Where the stacked ring appears depends on the size of the labels. It may go outside the bounding box of the panel and start to overlap with axis titles. I don't think there is a good solution for this, as the dimensions of the ring depend both on the panel size in relative units and the size of the axis in absolute units. However, people can always adjust margins manually if they insist.

p + scale_x_continuous(
  breaks = c(100, 200, 300), 
  labels = rep("long label", 3)
)

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

Also some weirdness may occur if the donut hole is too small to fit all theta.sec axes, but this should be very niche and I don't expect people to run into this on a regular basis.

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

p <- ggplot(mtcars, aes(hp, disp)) +
  geom_point() +
  coord_radial(start = 0.25 * pi, end = 1.75 * pi, donut = 0.1) +
  guides(
    theta.sec = guide_axis_stack("axis_theta", "axis_theta", "axis_theta")
  ) +
  theme(axis.line = element_line())
p

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

@teunbrand teunbrand requested a review from thomasp85 November 24, 2023 19:22
@teunbrand
Copy link
Collaborator Author

Should we add a way to individually control the theme of every axis in the stack?

@teunbrand teunbrand mentioned this pull request Dec 1, 2023
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.

It's a bit annoying that the radial axis needs to have so much extra logic for the off-chance that it is stacked, but I see no way around it. And at least it is not mingled in with all the other code

@teunbrand
Copy link
Collaborator Author

Yeah it is a shame that it is so non-trivial to calculate the width of the ring.

Merge branch 'main' into stacked_axis

# Conflicts:
#	man/ggplot2-ggproto.Rd
@teunbrand teunbrand merged commit b38caa3 into tidyverse:main Dec 6, 2023
@teunbrand teunbrand deleted the stacked_axis branch December 6, 2023 09:14
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