The Problem
I want to place the legend of my plot above the plot. I also want to place the legend key symbol (colored squares) above the legend key labels (legend text). Unfortunately, when I do this, the legend key symbol "stretches" to fit the size of the label. I imagine ggplot2 is working fine, but how could I manually override this feature?
How do I keep a consistent legend key symbol across the top with labels of variable lengths?
Reproducible Example
(It's not necessarily a minimal example, just in case the structure of my actual code, like the coord_flip
and fill
calls, has an impact)
library(dplyr)
library(ggplot2)
dataFrame <- diamonds %>%
group_by(color, cut) %>%
summarise(count = n()) %>%
group_by(color) %>%
mutate(percent = count/sum(count),
pretty_label = paste0(round(percent*100, 1), "%")) %>%
ungroup()
p <- ggplot(data = dataFrame, mapping = aes(x=color, y = percent, group = cut))+
geom_bar(aes(fill = cut), stat = "identity", position = "fill")+
geom_text(aes(label = pretty_label), position=position_fill(vjust=0.5), colour="white", stat = "identity")+
coord_flip()+
theme(legend.position="top")+
guides(fill = guide_legend(label.position = "bottom", reverse = TRUE))
plot(p)
Notice how each of the legend symbols are different sizes, depending on the length of the label.
What I have already tried
I imagine it has something to do with guides, but I can't seem to get it right. Using the plot above (p
), I have tried the following and more:
From here and here: p + guides(colour = guide_legend(override.aes = list(size=3)))
From here: p + guides(colour = guide_legend(keywidth = .5, keyheight = .5))
and
p + guides(colour = guide_legend(keywidth = unit(.5, "cm"), keyheight = unit(.5, "cm")))
From here: (Trying to wrap labels) p + guides(color = guide_legend(nrow = 2))
I've tried other, less "logical" attempts just because. None of which worked.
Final Thoughts
I could just be having a difficult time knowing what to search for. I am always open to figuring out the problem myself, if you are able to point me in the right direction. Any additional resources are more than welcome.
Thanks, in advance!
Session Output
> sessionInfo()
R version 3.5.1 (2018-07-02)
Platform: x86_64-w64-mingw32/x64 (64-bit)
Running under: Windows >= 8 x64 (build 9200)
Matrix products: default
locale:
[1] LC_COLLATE=English_United States.1252 LC_CTYPE=English_United States.1252 LC_MONETARY=English_United States.1252
[4] LC_NUMERIC=C LC_TIME=English_United States.1252
attached base packages:
[1] stats graphics grDevices utils datasets methods base
other attached packages:
[1] bindrcpp_0.2.2 ggplot2_3.0.0 dplyr_0.7.6
loaded via a namespace (and not attached):
[1] Rcpp_0.12.18 bindr_0.1.1 magrittr_1.5 tidyselect_0.2.4 munsell_0.5.0 colorspace_1.3-2 viridisLite_0.3.0
[8] R6_2.2.2 rlang_0.2.1 plyr_1.8.4 tools_3.5.1 grid_3.5.1 gtable_0.2.0 withr_2.1.2
[15] yaml_2.1.19 lazyeval_0.2.1 assertthat_0.2.0 digest_0.6.17 tibble_1.4.2 purrr_0.2.5 glue_1.2.0
[22] labeling_0.3 compiler_3.5.1 pillar_1.2.3 scales_0.5.0 pkgconfig_2.0.1
I don't know if there's a way to control the width of the legend color boxes separately from the text (other than hacking the legend grobs). However, if you add legend.key.width=unit(1.5, "cm")
in your theme statement, all of the color boxes will be expanded to the same width (you may have to tweak the 1.5 up or down a bit to get the desired box widths).
library(scales)
ggplot(dataFrame, aes(x=color, y = percent))+
geom_bar(aes(fill = cut), stat = "identity") +
geom_text(aes(label = pretty_label), position=position_fill(vjust=0.5),
colour="white", size=3)+
coord_flip()+
theme(legend.position="top",
legend.key.width=unit(1.5, "cm"))+
guides(fill = guide_legend(label.position = "bottom", reverse = TRUE)) +
scale_y_continuous(labels=percent)
You can save a little space by putting Very Good
on two lines:
library(forcats)
ggplot(dataFrame, aes(x=color, y = percent, fill = fct_recode(cut, "Very\nGood"="Very Good")))+
geom_bar(stat = "identity") +
geom_text(aes(label = pretty_label), position=position_fill(vjust=0.5),
colour="white", size=3)+
coord_flip()+
theme(legend.position="top",
legend.key.width=unit(1.2, "cm"))+
guides(fill = guide_legend(label.position = "bottom", reverse = TRUE)) +
labs(fill="Cut") +
scale_y_continuous(labels=percent)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With