ggplot2 icon indicating copy to clipboard operation
ggplot2 copied to clipboard

Justifying the legend with respect to the full plot area rather than the panel

Open LiRogers opened this issue 5 years ago • 9 comments
trafficstars

Now that the plot titles and captions can be aligned with respect to the full plot area, it would be great if the same was true for the legend. At the moment, if the legend is positioned at the top of the plot below the title it is aligned to the plot panel, making it misaligned with the title:

library(ggplot2)

ggplot(data = diamonds, mapping = aes(x = carat, y = price, color = cut)) +
  geom_point() +
  labs(title = "A plot title") +
  theme(plot.title.position = "plot",
        legend.position = "top",
        legend.justification = "left")

Created on 2020-05-22 by the reprex package (v0.3.0)

Experimenting with negative values in legend.justification = c(x,y) can get the legend to align with the title, but the value is dependent on the size of the y-axis labels

LiRogers avatar May 22 '20 13:05 LiRogers

Yes, that's a good point. Marking this as TODO for ggplot2 3.4.

clauswilke avatar May 22 '20 14:05 clauswilke

Possibly related, #3989 also proposes more legend alignment options

teunbrand avatar May 22 '20 14:05 teunbrand

Agreed that this would make sense

thomasp85 avatar May 22 '20 14:05 thomasp85

Would it be possible to do the same for plot.tag.position? If the tag position is set to "topleft" it's also misaligned with the title.

library(ggplot2)

ggplot(data = diamonds, mapping = aes(x = carat, y = price, color = cut)) +
  geom_point() +
  labs(title = "A plot title",
       tag = 'Figure 1') +
  theme(plot.title.position = "plot",
        plot.tag.position = 'topleft')

diamonds_tag

malcalakovalski avatar Aug 04 '21 22:08 malcalakovalski

@malcalakovalski Use plot.tag.position = c(0, 1):

library(ggplot2)

ggplot(data = diamonds, mapping = aes(x = carat, y = price, color = cut)) +
  geom_point() +
  labs(
    title = "A plot title",
    tag = "Figure 1"
  ) +
  theme(
    plot.title.position = "plot",
    plot.tag.position = c(0, 1),
    plot.tag = element_text(hjust = 0, vjust = 1)
  )

Screen Shot 2021-08-04 at 7 08 59 PM

clauswilke avatar Aug 05 '21 00:08 clauswilke

@clauswilke Thank you! But is there a way to do that such that the tag is above the title?

malcalakovalski avatar Aug 05 '21 17:08 malcalakovalski

You could add some top margin to the title with plot.title = element_text(margin = margin(16, 0, 0, 0)). Not sure if there's a different, more elegant approach.

clauswilke avatar Aug 05 '21 17:08 clauswilke

That works for my current purposes. Thank you!

malcalakovalski avatar Aug 05 '21 18:08 malcalakovalski

Is there a workaround for it?

brunomioto avatar Jul 26 '22 02:07 brunomioto

This should not be terribly difficult to implement, as Hadley already left the solution in his comments:

https://github.com/tidyverse/ggplot2/blob/0d0de37decd4e5c101d70d3f4a4764622e3c70e5/R/plot-build.r#L232-L234

However, this brings us to a harder problem: what would the name of this argument be?

teunbrand avatar Dec 11 '22 16:12 teunbrand

There are a bunch of *.position arguments like plot.title.position, plot.caption.position, plot.tag.position that all decide between aligning to the plot or to the panels. For consistency purposes it would be best to name it legend.position. However, legend.position already exists and means something different. We could do legend.position.align = "panel"/"plot" though.

I also like the strip.placement name that can be paralleled in legend.placement = "panel"/"plot". Any other thoughts?

teunbrand avatar Jan 17 '23 21:01 teunbrand

Does anyone have an idea of how to make this work now until a full solution is implemented? Not knowing much about the ggplot internals, I'm not sure I follow @teunbrand's suggestion above.

mfherman avatar Oct 21 '23 18:10 mfherman

It was not a suggestion. The only thing that has prevented me so far from putting in a PR to fix this is that I don't know what the setting should be named.

teunbrand avatar Oct 21 '23 19:10 teunbrand

Ah, I see. legend.position.align = "panel"/"plot" makes sense to me - although there are other *.align settings that take (0, 1), so this may be slightly confusing?

mfherman avatar Oct 22 '23 17:10 mfherman

Considering this fixed by #5488.

teunbrand avatar Dec 27 '23 15:12 teunbrand

@teunbrand I might be missing how to do this in v3.5.0. How would you modify the original example to have it start justified to the plot?

library(ggplot2)

ggplot(
  data = diamonds |> dplyr::slice_sample(prop = 0.01), 
  mapping = aes(x = carat, y = price, color = cut)
) +
  geom_point() +
  labs(title = "A plot title") +
  theme(
    plot.title.position = "plot",
    legend.position = "top",
    legend.justification = c(0, 1)
  )

kylebutts avatar Feb 17 '24 17:02 kylebutts

Should be possible by adding legend.location = "plot" to the theme.

teunbrand avatar Feb 17 '24 22:02 teunbrand