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

Unexpected results using guides(x = guide_axis(position = ...)) #4650

Closed
jtlandis opened this issue Oct 27, 2021 · 9 comments · Fixed by #4879
Closed

Unexpected results using guides(x = guide_axis(position = ...)) #4650

jtlandis opened this issue Oct 27, 2021 · 9 comments · Fixed by #4879
Labels
bug an unexpected problem or unintended behavior guides 📏

Comments

@jtlandis
Copy link
Contributor

When attempting to change the axis position with guide_axis it seems that the title is not correctly pulled unless manually specified.

library(ggplot2)

p <- ggplot(iris, aes(Sepal.Width, Sepal.Length, color = Species)) +
  geom_point() 

Currently you can swap the placement with scale_(x|y)_*(postion = ...) pretty reliably

p + scale_x_continuous(position = "top")

But trying to swap scales with guides() doesn’t seem to include the title

p + guides(x = guide_axis(position = "top"))

Even though the argument title = waiver() it doesn’t seem to work. But works when manually set.

p + guides(x = guide_axis(position = "top", title = "test"))

Created on 2021-10-27 by the reprex package (v2.0.1)

@thomasp85
Copy link
Member

@paleolimbot is this something you have time to look at (if not, that is fair)? I guess it is mainly your code

@paleolimbot
Copy link
Member

Definitely my code! I'll have a look at this tomorrow.

@paleolimbot
Copy link
Member

Ok...I did a bit of sleuthing. I'm going to suggest that this not get fixed until (1) second axes have been deprecated in favour of axis guides (with a transform) and (2) the axis guides are being used on all the Coord subclasses. Or perhaps one of you can see a better solution that's staring me in the nose!

Relevant code:

https://github.com/tidyverse/ggplot2/blob/main/R/coord-cartesian-.r#L154-L173

https://github.com/tidyverse/ggplot2/blob/main/R/layout.R#L234-L258

Implementation that fixes this problem but creates many more:

main...paleolimbot:issue-4650-position-scale-label

Situations to consider:

library(ggplot2)

p <- ggplot(iris, aes(Sepal.Width, Sepal.Length)) +
  geom_point()

# defaults
p

# with setting position in scale
p +
  scale_x_continuous(position = "top") +
  scale_y_continuous(position = "right")

# when title = waiver() and specified in guides()
p + 
  guides(
    x = guide_axis(position = "top", title = waiver()),
    y = guide_axis(position = "right", title = waiver()),
  )

# when title set explicitly
p + 
  guides(
    x = guide_axis(position = "top", title = "explicit x title"),
    y = guide_axis(position = "right", title = "explicit y title"),
  )

# what happens if you set labels(x, y)
p + 
  guides(
    x = guide_axis(position = "top", title = waiver()),
    y = guide_axis(position = "right", title = waiver())
  ) +
  labs(
    x = "x label specified in labels()",
    y = "y label specified in labels()"
  )

# what happens if you set labels(sec.x, sec.y)
p + 
  guides(
    x = guide_axis(position = "top", title = waiver()),
    y = guide_axis(position = "right", title = waiver())
  ) +
  labs(
    sec.x = "sec.x label specified in labels()",
    sec.y = "sec.y label specified in labels()"
  )

# what happens when you specify a second axis
p + 
  scale_x_continuous(sec.axis = sec_axis(trans = ~ . * 10, name = waiver())) +
  scale_y_continuous(sec.axis = sec_axis(trans = ~ . * 10, name = waiver()))

p + 
  scale_x_continuous(sec.axis = sec_axis(trans = ~ . * 10, name = derive())) +
  scale_y_continuous(sec.axis = sec_axis(trans = ~ . * 10, name = derive()))

p + 
  scale_x_continuous(sec.axis = sec_axis(trans = ~ . * 10, name = NULL)) +
  scale_y_continuous(sec.axis = sec_axis(trans = ~ . * 10, name = NULL))

p + 
  scale_x_continuous(sec.axis = sec_axis(trans = ~ . * 10, name = "explicit x title")) +
  scale_y_continuous(sec.axis = sec_axis(trans = ~ . * 10, name = "explicit y title"))

Created on 2021-11-11 by the reprex package (v2.0.1)

# ...and what happens when you do literally all of that using coord_flip()

library(ggplot2)

p <- ggplot(iris, aes(Sepal.Width, Sepal.Length)) +
  geom_point() +
  coord_flip()

# defaults
p

# with setting position in scale
p +
  scale_x_continuous(position = "top") +
  scale_y_continuous(position = "right")

# when title = waiver() and specified in guides()
p + 
  guides(
    x = guide_axis(position = "top", title = waiver()),
    y = guide_axis(position = "right", title = waiver()),
  )

# when title set explicitly
p + 
  guides(
    x = guide_axis(position = "top", title = "explicit x title"),
    y = guide_axis(position = "right", title = "explicit y title"),
  )

# what happens if you set labels(x, y)
p + 
  guides(
    x = guide_axis(position = "top", title = waiver()),
    y = guide_axis(position = "right", title = waiver())
  ) +
  labs(
    x = "x label specified in labels()",
    y = "y label specified in labels()"
  )

# what happens if you set labels(sec.x, sec.y)
p + 
  guides(
    x = guide_axis(position = "top", title = waiver()),
    y = guide_axis(position = "right", title = waiver())
  ) +
  labs(
    sec.x = "sec.x label specified in labels()",
    sec.y = "sec.y label specified in labels()"
  )

# what happens when you specify a second axis
p + 
  scale_x_continuous(sec.axis = sec_axis(trans = ~ . * 10, name = waiver())) +
  scale_y_continuous(sec.axis = sec_axis(trans = ~ . * 10, name = waiver()))

p + 
  scale_x_continuous(sec.axis = sec_axis(trans = ~ . * 10, name = derive())) +
  scale_y_continuous(sec.axis = sec_axis(trans = ~ . * 10, name = derive()))

p + 
  scale_x_continuous(sec.axis = sec_axis(trans = ~ . * 10, name = NULL)) +
  scale_y_continuous(sec.axis = sec_axis(trans = ~ . * 10, name = NULL))

p + 
  scale_x_continuous(sec.axis = sec_axis(trans = ~ . * 10, name = "explicit x title")) +
  scale_y_continuous(sec.axis = sec_axis(trans = ~ . * 10, name = "explicit y title"))

Created on 2021-11-11 by the reprex package (v2.0.1)

@hadley
Copy link
Member

hadley commented Apr 19, 2022

Somewhat more minimal reprex:

library(ggplot2)

df <- data.frame(x = 1:2, y = 1:2)

ggplot(df, aes(x, y)) + 
  geom_point() + 
  labs(x = "Long axis label") + 
  guides(x = guide_axis(position = "top"))

Created on 2022-04-19 by the reprex package (v2.0.1)

@yutannihilation
Copy link
Member

While #3972 will provide a slightly better result (at least the axis title won't disappear), it seems something is still wrong.

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

df <- data.frame(x = 1:2, y = 1:2)

ggplot(df, aes(x, y)) + 
  geom_point() + 
  labs(x = "Long axis label") + 
  guides(x = guide_axis(position = "top"))

Created on 2022-07-07 by the reprex package (v2.0.1)

@yutannihilation
Copy link
Member

yutannihilation commented Jul 8, 2022

Adding some tweak to Layout$xlabel() and Layout$ylabel() seems to work at least with CoordCartesian`. Not sure if I can push this into the next release at the moment...

ff2e38f

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

df <- data.frame(x = 1:2, y = 1:2)

ggplot(df, aes(x, y)) + 
  geom_point() + 
  labs(x = "Long axis label") + 
  guides(x = guide_axis(position = "top"))

Created on 2022-07-08 by the reprex package (v2.0.1)

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

p <- ggplot(iris, aes(Sepal.Width, Sepal.Length)) +
  geom_point()

# defaults
p

# with setting position in scale
p +
  scale_x_continuous(position = "top") +
  scale_y_continuous(position = "right")

# when title = waiver() and specified in guides()
p + 
  guides(
    x = guide_axis(position = "top", title = waiver()),
    y = guide_axis(position = "right", title = waiver()),
  )

# when title set explicitly
p + 
  guides(
    x = guide_axis(position = "top", title = "explicit x title"),
    y = guide_axis(position = "right", title = "explicit y title"),
  )

# what happens if you set labels(x, y)
p + 
  guides(
    x = guide_axis(position = "top", title = waiver()),
    y = guide_axis(position = "right", title = waiver())
  ) +
  labs(
    x = "x label specified in labels()",
    y = "y label specified in labels()"
  )

# what happens if you set labels(sec.x, sec.y)
p + 
  guides(
    x = guide_axis(position = "top", title = waiver()),
    y = guide_axis(position = "right", title = waiver())
  ) +
  labs(
    sec.x = "sec.x label specified in labels()",
    sec.y = "sec.y label specified in labels()"
  )

# what happens when you specify a second axis
p + 
  scale_x_continuous(sec.axis = sec_axis(trans = ~ . * 10, name = waiver())) +
  scale_y_continuous(sec.axis = sec_axis(trans = ~ . * 10, name = waiver()))

p + 
  scale_x_continuous(sec.axis = sec_axis(trans = ~ . * 10, name = derive())) +
  scale_y_continuous(sec.axis = sec_axis(trans = ~ . * 10, name = derive()))

p + 
  scale_x_continuous(sec.axis = sec_axis(trans = ~ . * 10, name = NULL)) +
  scale_y_continuous(sec.axis = sec_axis(trans = ~ . * 10, name = NULL))

p + 
  scale_x_continuous(sec.axis = sec_axis(trans = ~ . * 10, name = "explicit x title")) +
  scale_y_continuous(sec.axis = sec_axis(trans = ~ . * 10, name = "explicit y title"))

Created on 2022-07-08 by the reprex package (v2.0.1)

@teunbrand
Copy link
Collaborator

I can probably take this along in #4879. It appears as if we can drop the panel_guide_label and Coord$labels, if we evaluate the guide titles in Layout$xlabel and Layout$ylabel, which puts us in a position to fix this issue.

@teunbrand
Copy link
Collaborator

Another thing I encountered is the following:

library(ggplot2)
#> Warning: package 'ggplot2' was built under R version 4.2.1
ggplot(mpg, aes(displ, hwy)) +
  geom_point() +
  guides(x = guide_axis(position = "top", title = "Foo"),
         x.sec = guide_axis(title = "Bar"))
#> Warning: guide_axis(): Discarding guide on merge. Do you have more than one
#> guide with the same position?
#> Warning: guide_axis(): Discarding guide on merge. Do you have more than one
#> guide with the same position?

Created on 2022-08-13 by the reprex package (v2.0.1)

Where I'd think it is not unreasonable to presume that the x.sec guide implicitly has (or should get) position = "bottom".

@teunbrand
Copy link
Collaborator

This should work now with the PR, but it is nowhere near finished yet. I've taken an approach similar to yutannihilation's approach (thanks for the inspiration!), but with some extra finagling around for coord_flip().

teunbrand added a commit that referenced this issue Apr 24, 2023
The guide system, as the last remaining chunk of ggplot2, has been rewritten 
in ggproto. The axes and legends now inherit from a <Guide> class, which makes
them extensible in the same manner as geoms, stats, facets and coords 
(#3329, @teunbrand). In addition, the following changes were made:
    * Styling theme parts of the guide now inherit from the plot's theme 
      (#2728). 
    * Styling non-theme parts of the guides accept <element> objects, so that
      the following is possible: `guide_colourbar(frame = element_rect(...))`.
    * Primary axis titles are now placed at the primary guide, so that
      `guides(x = guide_axis(position = "top"))` will display the title at the
      top by default (#4650).
    * Unknown secondary axis guide positions are now inferred as the opposite 
      of the primary axis guide when the latter has a known `position` (#4650).
    * `guide_colourbar()`, `guide_coloursteps()` and `guide_bins()` gain a
      `ticks.length` argument.
    * In `guide_bins()`, the title no longer arbitrarily becomes offset from
      the guide when it has long labels.
    * The `order` argument of guides now strictly needs to be a length-1 
      integer (#4958).
    * More informative error for mismatched 
     `direction`/`theme(legend.direction = ...)` arguments (#4364, #4930).
    * `guide_coloursteps()` and `guide_bins()` sort breaks (#5152).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug an unexpected problem or unintended behavior guides 📏
Projects
None yet
Development

Successfully merging a pull request may close this issue.

6 participants