1

A similar sounding question is asked here. However, in the linked question, they put a bounding box around the legend and legend title. I was wondering if it's possible to put a bounding box around the legend graphic. For example,

library(ggplot2)

# Dummy data
x <- LETTERS[1:20]
y <- paste0("var", seq(1,20))
data <- expand.grid(X=x, Y=y)
data$Z <- runif(400, 0, 5)

# Heatmap 
ggplot(data, aes(X, Y, fill= Z)) + 
  geom_tile()+
  scale_fill_gradient(low = "white" ,high = "red")

The above code creates this plot: example plot

Whereas, I am trying to create something like this: Example with bounding box

I tried playing with legend.background function from ggplot but I can't get it to work for me.

Any suggestions as to how I would do this?

Electrino
  • 2,636
  • 3
  • 18
  • 40

1 Answers1

3

I don't think you can do this with theme() - you can do it with guides() though, e.g.

library(ggplot2)

# Dummy data
x <- LETTERS[1:20]
y <- paste0("var", seq(1,20))
data <- expand.grid(X=x, Y=y)
data$Z <- runif(400, 0, 5)

# Heatmap 
ggplot(data, aes(X, Y, fill= Z)) + 
  geom_tile()+
  scale_fill_gradient(low = "white" ,high = "red") +
  guides(fill = guide_colorbar(frame.colour = "black", frame.linewidth = 1.5))

example.png

Edit per comment

Looking at the source code for new_scale() there should be a way to apply this solution to two of the same scales, but I can't figure it out. I reckon you should post another question and see if someone can solve it. Until then, maybe this workaround based on cowplot will work for you e.g.

## (I changed 'fill' to 'color' here, but the concept is the same)

library(ggplot2)
library(ggnewscale)
library(cowplot)

# Dummy data
x <- LETTERS[1:20]
y <- paste0("var", seq(1,20))
data <- expand.grid(X=x, Y=y)
data$Z <- runif(400, 0, 5)

# Heatmap with both scales but legends aren't plotted
p1 <- ggplot(data, aes(X, Y, color = Z)) + 
  geom_tile() +
  scale_color_gradient(low = "white", high = "red") +
  new_scale_color() +
  geom_point(aes(color = Z)) +
  theme(legend.position = "none")

# Heatmap with only the first scale
p2 <- ggplot(data, aes(X, Y, color = Z)) + 
  geom_tile() +
  scale_color_gradient(low = "white", high = "red") +
  guides(color = guide_colorbar(frame.colour = "black", frame.linewidth = 1.5))

# Heatmap with only the second scale
p3 <- ggplot(data, aes(X, Y, color = Z)) + 
  geom_point(aes(color = Z)) +
  guides(color = guide_colorbar(frame.colour = "black", frame.linewidth = 1.5))

# Grab the legends using cowplot::get_legend()
p2_legend <- get_legend(p2)
p3_legend <- get_legend(p3)

# Combine the legends one on top of the other
legends <- plot_grid(p2_legend, p3_legend, ncol = 1, nrow = 2)

# Combine the heatmap with the legends
plot_grid(p1, legends, ncol = 2, align = "h", rel_widths = c(0.9, 0.1)) 

## You may need to tinker with spacing/scale/rel_widths/rel_heights to get it looking right, but it should work out ok with some effort

example_2.png

jared_mamrot
  • 22,354
  • 4
  • 21
  • 46
  • 1
    This works perfectly. Thank you! I have a follow up question. Not sure if I should open a different, new question. In my plot im using `new_scale_fill()` from the package `ggnewscale` and my plot has 2 different legends and scales. Is it possible to add a bounding box to both scales? I tried applying your suggestion but I can't get it to work. If you need more explanation, I will open a new question and ask. – Electrino Oct 28 '20 at 06:21
  • Updated my example with a workaround solution, although I think it would be worth posting a new question to see whether a more elegant solution exists. – jared_mamrot Oct 28 '20 at 10:27
  • 1
    Excellent answer. Thanks for all your help – Electrino Oct 28 '20 at 15:16