ggplot2
ggplot2 copied to clipboard
Justifying the legend with respect to the full plot area rather than the panel
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
Yes, that's a good point. Marking this as TODO for ggplot2 3.4.
Possibly related, #3989 also proposes more legend alignment options
Agreed that this would make sense
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')

@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)
)
@clauswilke Thank you! But is there a way to do that such that the tag is above the title?
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.
That works for my current purposes. Thank you!
Is there a workaround for it?
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?
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?
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.
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.
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?
Considering this fixed by #5488.
@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)
)

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