Ggplot2: center legend below plot instead of pane area

ggplot

by default centers the legend under the panel, which is really frustrating in some situations. An example is shown below:

ggplot(diamonds, aes(cut, fill = clarity)) + geom_bar() + coord_flip() + 
  theme(legend.position = 'bottom')

      

enter image description here

You can see that the last label was clipped from the image, although there is some white space on the left side of the legend - it would be much better to use that.

Q : how can I center the legend below the graph and not try to get it to center below the pane to fix this problem?


Update : The following example on this issue:

df <- data.frame(
    x = sample(paste('An extremely long category label that screws up legend placement', letters[1:7]), 1e3, TRUE),
    y = sample(paste('Short label', letters[1:7]), 1e3, TRUE)
    )

ggplot(df, aes(x, fill = y)) + geom_bar() + coord_flip() +
  theme(legend.position = 'bottom')

      

enter image description here


What I did: I can use legend.direction

to manually place the label below the panel and add extra margin below the graph, for example:

ggplot(diamonds, aes(cut, fill = clarity)) + geom_bar() + coord_flip() + 
  theme(legend.position  = c(0.37, -0.1),
        legend.direction = 'horizontal',
        plot.margin      = grid::unit(c(0.1,0.1,2,0.1), 'lines'))

      

enter image description here

But in this way I have to calculate "manually" the optimal one legend.position

. Any suggestions?


Update . I place multiple plots next to each other, so I would rather not center the legend on the actual image, but on the same panel. For example:.

p1 <- ggplot(diamonds, aes(cut)) + geom_histogram()
p2 <- ggplot(diamonds, aes(cut, fill = clarity)) + geom_bar() + coord_flip() +
  theme(legend.position = 'bottom')
pushViewport(viewport(layout = grid.layout(nrow = 1, ncol = 2, widths = unit(c(1, 2), c("null", "null")))))
print(p1, vp = viewport(layout.pos.row = 1, layout.pos.col = 1))
print(p2, vp = viewport(layout.pos.row = 1, layout.pos.col = 2))

      

+3


source to share


2 answers


you can edit gtable,



library(gtable)

g <- ggplotGrob(p)
id <- which(g$layout$name == "guide-box")
g$layout[id, c("l","r")] <- c(1, ncol(g))
grid.newpage()
grid.draw(g)

      

+2


source


I was looking for a solution to this problem and realized that I can use Claus Wilke cowplot to split the plot into a grid. It's a bit of a hack but pretty easy.

df <- data.frame(
  x = sample(paste('An extremely long category label that screws up legend placement', letters[1:7]), 1e3, TRUE),
  y = sample(paste('Short label', letters[1:7]), 1e3, TRUE)
)

      

First, let's save the original graph for the object:

p1 <- ggplot(df, aes(x, fill = y)) + geom_bar() + coord_flip() +
  theme(legend.position = 'bottom')

      

Then we save another version without the legend and use cowplot get_legend()

to save the legend:



p2 <- p1 + theme(legend.position = "none")
le1 <- cowplot::get_legend(p1)

      

Draw a plot.

cowplot::plot_grid(p2, le1, nrow = 2, rel_heights = c(1, 0.2))

      

enter image description here

+1


source







All Articles