简体   繁体   中英

Position a ggplot Legend label directly over its fill colour

For a ggplot graph, I wish to have the values of the legend (here, 0 and 1) to be positioned over the colours they represent, and not to the side of them. By which I mean not to the left, right, above or below the coloured square, but within the square itself. This would result in a number 0 inside a red square and the number 1 inside a blue square. How can this be done?

ggplot(mtcars, aes(factor(cyl), fill = factor(vs))) +
geom_bar() +
theme(legend.position = "top", 
    legend.direction = "horizontal") +
guides(color = guide_legend(title.position = "left", label.position = "top")) 

Since you're using fill you need to use fill within guides then play with label.vjust and title.vjust to get everything to line up.

library(tidyverse)

ggplot(mtcars, aes(factor(cyl), fill = factor(vs))) +
  geom_bar() +
  theme(legend.position = "top", 
        legend.direction = "horizontal") +
  guides(fill = guide_legend(label.vjust = -7, label.position = "top", title.vjust = 0.2))

Created on 2018-11-23 by the reprex package (v0.2.1)

With minor adjustment, you can use the approach shown at change-geom-texts-default-a-legend-to-label-string-itself . This changes the key generating function, and so allows ggplot2 to calculate the positions to place the labels for you.

Th idea is to keep the original rectGrob for the geom_bar legend key and use an additional textGrob to place the label on top.

library(ggplot2)
library(grid)

oldK <- GeomBar$draw_key # to save for later

# see other answer on how to tweak function based n manual colours
GeomBar$draw_key <- function (data, params, size, 
                              var=unique(mtcars$vs),
                              cols=scales::hue_pal()(length(var))) {

    # match labels to the fill colour
    txt <- if(is.factor(var)) levels(var) else sort(var)
    txt <- txt[match(data$fill, cols)]

    # This is from the original GeomBar$draw_key -------------------
    lwd <- min(data$size, min(size)/4)
    rg <- rectGrob(width = unit(1, "npc") - unit(lwd, "mm"), height = unit(1, 
        "npc") - unit(lwd, "mm"), gp = gpar(col = data$colour, 
        fill = alpha(data$fill, data$alpha), lty = data$linetype, 
        lwd = lwd * .pt, linejoin = "mitre"))
    # ---------------------------------------------------------------

    # Add text label: lifted from other answer
    # hard-coded text size multiplier -- got to be a better way!
    tg <- textGrob(txt, 0.5, 0.5,  
             just="center", 
             gp = gpar(col = "black", 
                       fontfamily = data$family, 
                       fontface = data$fontface, 
                       fontsize = 10*data$size * .pt)) 
    # ---------------------------------------------------------------

    grobTree(rg, tg) # output new key
}

You can then plot

ggplot(mtcars, aes(factor(cyl), fill = factor(vs))) +
  geom_bar() +
  theme(
    legend.position = "top", 
    legend.direction = "horizontal",
    legend.text = element_blank())

# reset key function to original
GeomBar$draw_key <- oldK

在此输入图像描述

This should be fairly robust to resizing your plot.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM