My ggplot has the following legend:
I want to group my individual legend variables, and add the group names and \"brackets\" like shown in legend below:
It's an interesting question and a legend like that would look very nice. There's no data so I just tried it on a different plot - the code could probably be generalized much more but it is a first step :)
First, the plot
library(ggplot2)
library(gtable)
library(grid)
df <- data.frame(
x = rep(c(2, 5, 7, 9, 12), 2),
y = rep(c(1, 2), each = 5),
z = factor(rep(1:5, each = 2)),
w = rep(diff(c(0, 4, 6, 8, 10, 14)), 2)
)
p <- ggplot(df, aes(x, y)) +
geom_tile(aes(fill = z, width = w), colour = "grey50") +
scale_fill_manual(values = c("1" = "red2", "2" = "darkorange3",
"3" = "gold2", "4" = "olivedrab3",
"5" = "olivedrab2"),
labels = c("High", "High", "High", "Low", "Low"))
p
And then the changes using gtable and grid libraries.
grb <- ggplotGrob(p)
# get legend gtable
legend_idx <- grep("guide", grb$layout$name)
leg <- grb$grobs[[legend_idx]]$grobs[[1]]
# separate into labels and rest
leg_labs <- gtable_filter(leg, "label")
leg_rest <- gtable_filter(leg, "background|title|key")
# connectors = 2 horizontal lines + one vertical one
connectors <- gTree(children = gList(linesGrob(x = unit(c(0.1, 0.8), "npc"), y = unit(c(0.1, 0.1), "npc")),
linesGrob(x = unit(c(0.1, 0.8), "npc"), y = unit(c(0.9, 0.9), "npc")),
linesGrob(x = unit(c(0.8, 0.8), "npc"), y = unit(c(0.1, 0.9), "npc"))))
# add both .. if many, could loop this
leg_rest <- gtable_add_grob(leg_rest, connectors, t = 4, b = 6, l = 3, r = 4, name = "high.group.lines")
leg_rest <- gtable_add_grob(leg_rest, connectors, t = 7, b = 8, l = 3, r = 4, name = "low.group.lines")
# get unique labels indeces (note that in the plot labels are High and Low, not High-1 etc.)
lab_idx <- cumsum(summary(factor(sapply(leg_labs$grobs, function(x) x$children[[1]]$label))))
# add cols for extra space, then add the unique labels.
# theyre centered automatically because i specify top and bottom, and x=0.5npc
leg_rest <- gtable_add_cols(leg_rest, convertWidth(rep(grobWidth(leg_labs$grobs[[lab_idx[1]]]), 2), "cm"))
leg_rest <- gtable_add_grob(leg_rest, leg_labs$grobs[[lab_idx[1]]], t = 4, b = 6, l = 5, r = 7, name = "label-1")
leg_rest <- gtable_add_grob(leg_rest, leg_labs$grobs[[lab_idx[2]]], t = 7, b = 8, l = 5, r = 7, name = "label-2")
# replace original with new legend
grb$grobs[[legend_idx]]$grobs[[1]] <- leg_rest
grid.newpage()
grid.draw(grb)
Potential problems are