9

When coord_fixed() is used with ggplot2, it does not appear to be possible to set the background color of the entire plot. Consider this simple example:

library(ggplot2)
test_data <- data.frame(x=1:10)
test_data$y <- sqrt(test_data$x)
p1 <- ggplot(test_data) + geom_point(aes(x, y))
p1

Simple example plot

I can easily make the background another color, such as a garish green color:

p1 + theme(plot.background=element_rect(fill="green"))

enter image description here

But what if I want to use coord_fixed() and color the background green? When I try this ggplot2 leaves a white strip on the bottom and top of the plot:

p1 + theme(plot.background=element_rect(fill="green")) + coord_fixed()

enter image description here

How do I completely fill the background of the above plot (without the white strips on the top and bottom)? I am producing a number of subplots in a loop to be used with the animation package, and I need to ensure the backgrounds of all the subplots are the same (non-white) color, including one on which I need to use coord_fixed().

Alex Zvoleff
  • 442
  • 2
  • 13

3 Answers3

7

This will do what you want:

p2 <- p1 + theme(
  plot.background=element_rect(fill="green", color="green")
) + coord_fixed()
grid:::grid.rect(gp=gpar(fill="green", col="green"))
ggplot2:::print.ggplot(p2, newpage=FALSE)

First, we set the border and fill to green, then we plot a grid rectangle in the same color to fill the viewport, and finally we plot with ggplot2:::print setting the newpage parameter to false so that it overplots on top of our grid rectangle:

enter image description here

Note that the problem isn't with ggplot, but it's just that you are plotting into a viewport that is the wrong size. If you pre-shape your viewport to the correct aspect ratio, you won't need to worry about setting the viewport contents to green first.

BrodieG
  • 51,669
  • 9
  • 93
  • 146
4

If you want to achieve this effect without relying on non-exported ggplot2 functions, you can also use ggdraw() from cowplot:

test_data <- data.frame(x=1:10)
test_data$y <- sqrt(test_data$x)
p1 <- ggplot(test_data) + geom_point(aes(x, y))
p2 <- p1 + theme(plot.background=element_rect(fill="green", color = NA)) + coord_fixed()

# note, don't load cowplot, since it may change your theme
cowplot::ggdraw(p2) + 
  theme(plot.background = element_rect(fill="green", color = NA))

enter image description here

The function ggdraw() wraps your plot into a new ggplot object that you can then draw onto or style as you wish.

Claus Wilke
  • 16,992
  • 7
  • 53
  • 104
4

There's a way to do this in ggplot by using a secret (undocumented, passed to device in ...) argument bg to ggsave().

library(ggplot2)

test_data <- data.frame(x = 1:10)
test_data$y <- sqrt(test_data$x)

p1 <- ggplot(test_data) + 
  geom_point(aes(x, y)) +
  theme(plot.background = element_rect(fill = "green", color = "green")) +
  coord_fixed()

ggsave("test.png", bg = "green", h = 5)

I came here originally because I was using geom_sf to plot maps which are by definition fixed to a ratio, and wanted to add a dark background. The bg argument also applies to gganimate::animate(), if you need to add a background color to a fixed ratio animation.

enter image description here

pasipasi
  • 1,176
  • 10
  • 8
  • I tried to use ggsave but I had some trouble with plot dimensions. Another alternative is using x11() to create a graphic device for plots and savePlot() for saving them. – lubrum Jun 12 '20 at 00:04
  • There's no easy way to automate plot dimensions when the ratio is fixed and possibly also unknown. I like to create my own save function where I combine ggsave with `magick::` `image_read()`, `image_trim()` and `image_write()` to shave off all the whitespace. – pasipasi Sep 22 '21 at 10:47