Reputation: 6213
I am trying to place a horizontal legend at the bottom-right corner, outside of the plotting area.
I realize that this has been discussed before. However, after a long frustrating morning, I wasn't able to reach a "size-robust" solution.
Here are the 3 solutions I've found:
legend.position
to bottom
: The legend is placed at
the bottom-center, yet I fail to push it to the right side using
legend.justification
legend.position
to c(1,0)
: the legend is placed at
the bottom-right corner. However, the legend is placed inside the plot.plot.margin
and push the legend.position
further down:
the legend is placed at the bottom-right corner and outside of the plot. However, when I change the size of the plotting area, the legend is not correctly positioned any more.Incorrect positioning of third solution:
Reproducible code:
# Generate random data------
sample.n = 50
sample.data = data.frame(x = runif(sample.n,0,1), y = runif(sample.n,0,1), value = runif(sample.n,0,10))
# Plot ------
library(ggplot2)
# Margins are fine. And If I change the size of the plotting area, the legend will always be bottom- centered
# Problem: Can't push it to the right side
ggplot(sample.data, aes(x = x, y = y, color = value)) + geom_point() +
theme(legend.direction = "horizontal", legend.position = "bottom")
# Pushed to the bottom-right Successfully
# Problem: Legend inside the plot
ggplot(sample.data, aes(x = x, y = y, color = value)) + geom_point() +
theme(legend.direction = "horizontal",legend.position = c(1,0)) # Problem: inside plot
# Placed at the bottom-right corner outside the plot region
# Problem: If I change the size of the plotting region, the legend will not be cornred
ggplot(sample.data, aes(x = x, y = y, color = value)) + geom_point() +
theme(legend.direction = "horizontal", legend.position = c(0.9,-0.2),
plot.margin = unit(c(1, 1, 5, 1), "lines"))
Theme-Legend's documentation:
legend.position the position of legends ("none", "left", "right", "bottom", "top", or two-element numeric vector)
legend.justification anchor point for positioning legend inside plot ("center" or two-element numeric vector)
Upvotes: 4
Views: 3666
Reputation: 32789
Edit Using 2.2.0, the legend can be pushed to the right using legend.justification
and legend.margin
in the theme.
# Generate random data------
sample.n = 50
sample.data = data.frame(x = runif(sample.n,0,1), y = runif(sample.n,0,1), value = runif(sample.n,0,10))
# Plot ------
library(ggplot2)
library(gtable)
library(grid)
p = ggplot(sample.data, aes(x = x, y = y, color = value)) + geom_point() +
theme(legend.direction = "horizontal", legend.position = "bottom",
legend.box.background = element_rect(colour = "black"))
p + theme(legend.justification = "right",
legend.margin = margin(t = 2, r = 0, b = 2, l = 2, unit = "mm"))
For what it is worth, I leave the original answer but updated to ggplot version 2.2.0.
What I have done here is extract the legend from the plot, wrap the legend in a viewport so that the viewport is positioned to the right, put the legend back into the plot, and remove the original legend.
# Generate random data------
sample.n = 50
sample.data = data.frame(x = runif(sample.n,0,1), y = runif(sample.n,0,1), value = runif(sample.n,0,10))
# Plot ------
library(ggplot2)
library(gtable)
library(grid)
p = ggplot(sample.data, aes(x = x, y = y, color = value)) + geom_point() +
theme(legend.direction = "horizontal", legend.position = "bottom")
# Get the ggplot grob
g = ggplotGrob(p)
# Get the legend
index = which(g$layout$name == "guide-box")
leg = g$grobs[[index]]
# Wrap the legend in a viewport
leg$vp = viewport(x = unit(1, "npc"), width = sum(leg$widths), just = "right")
### Put the legend back into the plot
# First, get the current location of the legend
pos = g$layout[index, ]
g = gtable_add_grob(g, leg, t = pos$t, l = pos$l)
# Remove the original legend
g$grobs <- g$grobs[-index]
g$layout <- g$layout[-index, ]
# Draw the chart
grid.newpage()
grid.draw(g)
Note that the legend has been moved to the right, but that the right edge of the legend does not quite align with the right edge of the plot panel. This is because the legend has an internal margin. The legend itself has a margin but that margin is set to 0 mm. To get the legend to align with the plot panel requires a bit more fiddling. In what follows, the internal margin (and the legend margin) are set to 0. Also, the legend and the internal part of the legend are wrapped in right justified viewports.
# Get the ggplot grob
g = ggplotGrob(p)
# Get the legend
index = which(g$layout$name == "guide-box")
leg = g$grobs[[index]]
# Remove the legend right margin and an internal margin
leg$widths[4] = unit(0, "mm")
leg$grobs[[1]]$widths[5] = unit(0, "mm")
# Wrap the legend in a viewport
leg$vp = viewport(x = unit(1, "npc"), width = sum(leg$widths), just = "right")
# Wrap the internal part of the legend in a right justified viewport
leg$grobs[[1]]$vp = viewport(x = unit(1, "npc"), width = sum(leg$grobs[[1]]$widths), just = "right")
### Put the legend back into the plot
# First, get the current location of the legend
pos = g$layout[index, ]
g = gtable_add_grob(g, leg, t = pos$t, l = pos$l)
# Remove the original legend
g$grobs <- g$grobs[-index]
g$layout <- g$layout[-index, ]
# Draw the chart
grid.newpage()
grid.draw(g)
Upvotes: 3