3

How could I add box around legend key only for color not for size while keeping both legend keys. Code below add boxes to both mappings.

x<-1:6;
y<-factor(2:7);
z<-1:6;
df <- data.frame(x,y,z)

ggplot(df, aes(x,y)) + 
    geom_point(aes(colour=y, size = z) )   +
    theme(legend.key = element_rect(colour = '#bdbdbd', size = 0.6))

enter image description here

kurt
  • 91
  • 7
  • I don't think this is possible purely within ggplot. You could make two ggplots with different legend themes, extract the legends and use grid viewports to combine them, much like [in the answers to this question](http://stackoverflow.com/a/20132840/903061). – Gregor Thomas May 01 '15 at 22:46

1 Answers1

1

Here is one approach using the ggplot layout and gtable. It extracts the color legend from the layout, draws boxes around each key, re-assambles the legend, then inserts the legend back into the ggplot layout.

library(ggplot2)
library(gtable)
library(grid)

x<-1:6;
y<-factor(2:7);
z<-1:6;
df <- data.frame(x,y,z)

p = ggplot(df, aes(x,y)) + 
    geom_point(aes(colour=y, size = z) )   

# get ggplot grob
gt = ggplotGrob(p)

# Get the combined legend
leg = gtable_filter(gt, "guide-box")

# The legend has two parts.
# Get the second part - the color legend
leg2 = leg$grobs[[1]]$grobs[[2]]

# Get the locations of the top of each box containing the legend keys
# in this legend's layout
rects <- leg2$layout$t[grepl("bg", leg2$layout$name)]

# Draw boxes around each key
for(i in rects) leg2 = gtable_add_grob(leg2, grid.rect(gp = gpar(col = '#bdbdbd', fill = NA)), t = i, l = 2)


# Insert new color legend back into the combined legend   
leg$grobs[[1]]$grobs[2][[1]] <- leg2

# Insert combined legend back into ggplot grob
gt$grobs[gt$layout$name == "guide-box"][[1]] <- leg

# Draw it
grid.newpage()
grid.draw(gt)

enter image description here

Here is a second approach (based on @Baptiste's answer here) that draw two plots: one containing the size legend, and the other containing the color legend (with boxes around the keys). It then extracts the legends from each plot's layout, combines the two legends into a single legend, then inserts the combined legend back into one of the layouts.

library(ggplot2)
library(gtable)
library(grid)

x<-1:6;
y<-factor(2:7);
z<-1:6;
df <- data.frame(x,y,z)

p1 = ggplot(df, aes(x,y)) + 
    geom_point(aes(colour=y, size = z) ) +
    scale_colour_discrete(guide = "none")

p2 = ggplot(df, aes(x,y)) + 
    geom_point(aes(colour=y, size = z) ) +
    scale_size(guide = "none")   +
theme(legend.key = element_rect(colour = '#bdbdbd', size = 0.6))

# Get ggplot grobs
gt1 = ggplotGrob(p1)
gt2 = ggplotGrob(p2)

# Get the legends
leg1 = gtable_filter(gt1, "guide-box")
leg2 = gtable_filter(gt2, "guide-box")

# Combine the legends
leg <- rbind(leg1[["grobs"]][[1]],  leg2[["grobs"]][[1]], size = "first")

# Insert legend into g1 (or g2)
gt1$grobs[gt1$layout$name == "guide-box"][[1]] <- leg

# Draw it
grid.newpage()
grid.draw(gt1)

enter image description here

Community
  • 1
  • 1
Sandy Muspratt
  • 31,719
  • 12
  • 116
  • 122