ggplot2 icon indicating copy to clipboard operation
ggplot2 copied to clipboard

Legend title is incorrectly aligned when horizontal

Open hadley opened this issue 7 years ago • 12 comments

library(ggplot2)

df <- data.frame(z = 1:5)
p <- ggplot(df, aes(1, 1, colour = z)) + geom_point()

# Title should be centered with legend
p + theme(legend.position = "top")

hadley avatar Feb 27 '18 19:02 hadley

@clauswilke have you seen this too? I quickly skimmed through your PRs but I didn't see anything that addressed this explicitly

hadley avatar May 01 '18 22:05 hadley

I haven't addressed or modified this in any way. What is happening is that the title is centered relative to the entire legend:

p + theme(legend.position = "top") + 
  theme(legend.spacing.y = grid::unit(50, "cm")) # 50 cm equals to 5 cm because of issue #2398
screen shot 2018-05-01 at 5 49 25 pm

clauswilke avatar May 01 '18 22:05 clauswilke

Note that guide_legend() behaves exactly the same:

df <- data.frame(z = 1:5)
p <- ggplot(df, aes(1, 1, colour = factor(z))) + 
  geom_point() + 
  scale_color_discrete(guide = guide_legend(label.position = "bottom"))

# Title should be centered with legend
p + theme(legend.position = "top") + theme(legend.spacing.y = grid::unit(5, "cm"))
screen shot 2018-05-01 at 5 56 08 pm

clauswilke avatar May 01 '18 22:05 clauswilke

Oh so this probably isn't a regression

hadley avatar May 01 '18 22:05 hadley

The bigger issue, in my mind, is that there is no simple workaround, because the vjust setting is ignored. I'm showing this here with both a discrete and a continuous scale, to show that they behave the same:

library(ggplot2)
p <- ggplot(mtcars, aes(hp, disp, color = mpg, shape = factor(cyl))) +
  geom_point(size = 2) +
  scale_shape_discrete(guide = guide_legend(label.position = "bottom")) + 
  theme(legend.position = "top")
p
screen shot 2018-05-06 at 3 14 39 pm
p + theme(legend.title = element_text(vjust = 1, colour = "red"))
screen shot 2018-05-06 at 3 14 29 pm (I've colored the legend title red to show that styling the legend title works, only the justification arguments are ignored.)

I'll see if there's a simple way to fix this that doesn't require touching much code. In the long run, I think the legend drawing code needs to be rethought from the ground up, but that's not for 2.3.0.

clauswilke avatar May 06 '18 20:05 clauswilke

Workaround of sorts:

library(ggplot2)
ggplot(mtcars, aes(hp, disp, color = mpg, shape = factor(cyl))) +
    geom_point(size = 2) +
    theme(legend.position = "top") +
    guides(shape = guide_legend(label.position = "bottom", 
            title.position = "left", title.vjust = 0.8), 
        color = guide_legend(label.position = "top", 
            title.position = "right", title.vjust=0.4))

Created on 2018-05-07 by the reprex package (v0.2.0).

ptoche avatar May 06 '18 21:05 ptoche

I now see that there are (at least) two separate issues. One is that vjust and hjust can't be set in the theme but can be set via the guide function. It is a simple fix to allow setting via the theme as well. The second is that the margin settings in legend.title are ignored. This is a problem because if we set vjust to a number other than 1 then the text is moved different amounts for grobs of different heights. I guess the workaround could be to manually fiddle with the title.vjust settings for each guide function until things look right, but if margins could be set that would be better I think.

library(ggplot2)
ggplot(mtcars, aes(hp, disp, color = mpg, shape = factor(cyl))) +
  geom_point(size = 2) + theme(legend.position = "top") +
  guides(color = guide_colorbar(title.vjust = .8),
         shape = guide_legend(title.vjust = .8)) +
  theme(legend.title = 
          element_text(
            debug = TRUE,
            margin = margin(10, 0, 0, 0, "pt") # margin setting is ignored
          )
       )
screen shot 2018-05-06 at 5 57 52 pm

clauswilke avatar May 06 '18 23:05 clauswilke

The latter issue about the margins for legend text/titles has been raised in #1502. I tried to tackle that after reworking titleGrob() last year, but wasn't able to wrap my head around the legend code enough to make any headway at the time.

karawoo avatar May 07 '18 00:05 karawoo

@karawoo I just opened a pull request (https://github.com/tidyverse/ggplot2/pull/2556) that provides a partial fix for this issue. I hadn't seen https://github.com/tidyverse/ggplot2/issues/1502 previously and will take a look. My fix for legend titles would likely work for legend text as well. (Meaning: we can use the same technique to fix legend text. But it isn't currently fixed in the pending pull request.)

clauswilke avatar May 07 '18 02:05 clauswilke

Also if you fiddle with title.vjust, the bounding box is unaffected. If you title is higher than the legend, this results in some seriously wrong spacing:

grafik

this is title.vjust = 5 to make the bar line up with the second line of the title.

flying-sheep avatar Dec 07 '18 11:12 flying-sheep

Dear @clauswilke and @hadley I was wondering how to position the legend title on top of an horizontal scale_colour_gradient key. Is this possible at all? Also it seems that the key does not fill completely. Cheers in advance!!! :)

image

ggraph(lay.ggraph) +
  geom_edge_link0(aes(color = links$weight), width = links$weight*10, lineend = "round") + 
  scale_edge_color_gradient(name = "Link Strength", low = "#6495ED85", high = "#C1403D85") +
  geom_node_point(shape = 21, fill = "#D3D3D3", 
                  color = "#808080", size = 15, stroke = 2) +
  foodweb_theme +
  theme(legend.position = c(0.9, 0.1),
        legend.direction = "horizontal") +
  labs(y = "TL")

ThomasDelSantoONeill avatar Apr 18 '20 20:04 ThomasDelSantoONeill

Hi again,

I did find a workaround solution. Only a bit of merging trickery was needed between ggraph and ggplot2. Basically everything missing needed to be inserted in the guide = guide_edge_colorbar(...) argument within scale_edge_color_gradient. For the "not enterly filled colorbar" key I set the upper limit a bit more than 1 (i.e. 1.1). Code:

ggraph(lay.ggraph) + 
  geom_edge_link0(aes(edge_colour = links$weight), edge_width = links$weight*10, lineend = "round") +
  scale_edge_color_gradient(name = "Link Strength", low = "#6495ED85", high = "#C1403D85",
                            limits = c(0,1.01),
                            guide = guide_edge_colorbar(title = "Link Strength", title.position = "top",
                                                        title.hjust = 0.5, ticks = TRUE, label = TRUE,
                                                        frame.colour = "black", barwidth = 7.5)) +
  geom_node_point(shape = 21, fill = "#D3D3D3", color = "#808080", size = 15, stroke = 2) +
  labs(y = "TL") +
  foodweb_theme

This produces:

image

All the absolute best!

ThomasDelSantoONeill avatar Apr 19 '20 14:04 ThomasDelSantoONeill

I think this is fixed now as you can tweak justification and margin settings as you please. The remaining issue now is that key-title alignment is uncomfortable, which is tracked in #1903. I'll close this for now, but feel free to re-open if there is a remaining part of this issue that isn't covered in #1903.

teunbrand avatar Nov 13 '23 15:11 teunbrand