vrajs5
vrajs5

Reputation: 4126

Duplicate Same Legend Twice in Ggplot2

I am preparing a chart where I have client's requirement to put same legend on top and bottom. Using ggplot I can put it either at top or at bottom. But I am not aware about option of duplicating at both the places.

I have tried putting legend.position as c('top','bottom') but that is giving me error and I know if should give error.

Can it be done with other libraries? I want to same legend twice at top and at bottom?

Take this code for an instance

library(ggplot2)
bp <- ggplot(data=PlantGrowth, aes(x=group, y=weight, fill=group)) + geom_boxplot()
bp <- bp + theme(legend.position="bottom")
bp

Upvotes: 0

Views: 996

Answers (2)

Michael Lee
Michael Lee

Reputation: 333

Depending on the use case, a center-aligned top legend may not be appropriate as in the contributed answer by @MrGrumble here: https://stackoverflow.com/a/46725487/5982900

Alternatively, you can copy the "guide-box" element of the ggplotGrob, append it to your grob object, and reset the coordinates to the top of the ggplot.

createTopLegend <- function(ggplot, heightFromTop = 1) {
    g <- ggplotGrob(ggplot)
    nGrobs <- (length(g$grobs))
    legendGrob <- which(g$layout$name == "guide-box")
    g$grobs[[nGrobs+ 1]] <- g$grobs[[legendGrob]]
    g$layout[nGrobs+ 1,] <- g$layout[legendGrob,]
    rightLeft <- unname(unlist(g$layout[legendGrob, c(2,4)]))
    g$layout[nGrobs+ 1, 1:4] <- c(heightFromTop, rightLeft[1], heightFromTop, rightLeft[2])
    g
}

Load the gridExtra package. From your ggplot object bp, use createTopLegend to duplicate another legend, then use grid.draw to produce your final figure. Note you may need to alter your plot margins depending on your figure.

library(ggplot2)
library(grid)
library(gridExtra)
bp <- ggplot(data=PlantGrowth, aes(x=group, y=weight, fill=group)) + geom_boxplot()
bp <- bp + theme(legend.position="bottom",  plot.margin = unit(c(2,0,0,0), "lines"))
g <- createTopLegend(bp)
grid.draw(g)
# dev.off()

This will ensure the legend is aligned in the same way horizontally as it appears in your original ggplot.

Upvotes: 0

MrGumble
MrGumble

Reputation: 5776

You have to work with the intermediate graphic objects (grobs) that ggplot2 uses when being plotted.

I grabbed a function that was flowing around here on StackOverflow to extract the legend, and put it into a package that is now on CRAN.

Here's a solution:

library(lemon)
bp <- bp + theme(legend.position='bottom')
g <- ggplotGrob(bp)
l <- g_legend(g)
grid.arrange(g, top=l)

g_legend accepts both the grob-version (that cannot be manipulated with ggplot2 objects) and the ordinary ggplot2 objects. Using ggplotGrob is a one-way street; once converted you cannot convert it back to ggplot2. But, as in the example, we keep the original ggplot2 object. ;)

Upvotes: 1

Related Questions