4

I am trying to make striped plots (with altering white and grey background) when plotting 5 box plots in a row. Why is the background color not being applied to the whole plot in my code? The background color does change when I plot the box plots individually.

set.seed(42)
dev.off()
windows(width=6, height=4)
par(mfrow=c(1,5))
par(mar=c(2,4,1,1)) # bottom, left, top and right

par(bg = 'white')
boxplot(rnorm(20), ylab = "A")
title(xlab="n = 54", line=0)

par(bg = 'grey')
boxplot(rnorm(20),  ylab = "B")
title(xlab="n = 54", line=0)

par(bg = 'white')
boxplot(rnorm(20),  ylab = "C")
title(xlab="n = 54", line=0)

par(bg = 'grey')
boxplot(rnorm(20),  ylab = "D")
title(xlab="n = 26", line=0)

par(bg = 'white')
boxplot(rnorm(20),  ylab = "E")
title(xlab="n = 6", line=0)

To clarify, I want the area inside red rectangles in the figure below to be grey.

enter image description here

d.b
  • 32,245
  • 6
  • 36
  • 77
  • I am not sure what you are asking, but this might help: http://stackoverflow.com/questions/14604439/plot-multiple-boxplot-in-one-graph Your code suggests to me that you are interested in the fill color of the box plot rather than the background color of the plot. – Mark Miller Jan 11 '17 at 23:23
  • 1
    So _not_ just the plot area as in my solution, but the whole region – G5W Jan 11 '17 at 23:40
  • 1
    BTW, the appearance of mine can be improved by adding `col="white"` to the second time you print the boxplots with the grey backgrounds – G5W Jan 12 '17 at 00:00

3 Answers3

3

Sorry, This is not pretty, but I fear that it all that you can do.

As you discovered bg merely controls the background color of the box itself, not the whole plot. This solution has the ugly feature of plotting the data twice. Once to get where everything will be plotted, using that to display a background rectangle, then plotting the data again. But I believe that this is what you were looking for.

set.seed(42)
dev.off()
windows(width=6, height=4)
par(mfrow=c(1,5))
par(mar=c(2,4,1,1)) # bottom, left, top and right

Data = rnorm(20)
boxplot(Data,  ylab = "A")
rect(par("usr")[1],par("usr")[3],par("usr")[2],par("usr")[4],col = "white")
boxplot(Data,  ylab = "A", add=TRUE)
title(xlab="n = 54", line=0)

Data = rnorm(20)
boxplot(Data,  ylab = "B")
rect(par("usr")[1],par("usr")[3],par("usr")[2],par("usr")[4],col = "grey")
boxplot(Data,  ylab = "B", add=TRUE)
title(xlab="n = 54", line=0)

Data = rnorm(20)
boxplot(Data,  ylab = "C")
rect(par("usr")[1],par("usr")[3],par("usr")[2],par("usr")[4],col = "white")
boxplot(Data,  ylab = "C", add=TRUE)
title(xlab="n = 54", line=0)

Data = rnorm(20)
boxplot(Data,  ylab = "D")
rect(par("usr")[1],par("usr")[3],par("usr")[2],par("usr")[4],col = "grey")
boxplot(Data,  ylab = "D", add=TRUE)
title(xlab="n = 26", line=0)

Data = rnorm(20)
boxplot(Data,  ylab = "E")
rect(par("usr")[1],par("usr")[3],par("usr")[2],par("usr")[4],col = "white")
boxplot(Data,  ylab = "E", add=TRUE)
title(xlab="n = 6", line=0)

Boxplots with background

G5W
  • 36,531
  • 10
  • 47
  • 80
2

Here's a ggplot alternative which requires less hard-coding.

library(ggplot2)
library(gridExtra)

df <- data.frame(grp = rep(letters[1:5], c(12, 8, 11, 9, 10)), y = rnorm(50))

grp <- unique(df$grp)
cols <- c("grey80", "white")

l <- vector(length = length(grp), "list")

for(i in seq_along(grp)){
  dat <- df[df$grp == grp[i], ]
  col <- cols[i %% 2 + 1]
  p <- ggplot(dat) +  
    geom_boxplot(aes(x = factor(1), y = y), fill = col) +
    theme(plot.background = element_rect(fill = col),
          panel.background = element_rect(fill = col),
          panel.border = element_rect(fill = NA, colour = "black"),
          panel.grid = element_blank()) +
    scale_x_discrete(breaks = NULL) +
    xlab(paste0(grp[i], "\n", "n = ", nrow(dat)))
  l[[i]] <- p
}

do.call(grid.arrange, c(l, nrow = 1))

enter image description here


Explanation:

  1. Put the values used for the plots in a data.frame with a relevant grouping variable ('grp') which distinguishes the values
  2. Create a vector of unique groups ('grp'), pre-allocate a list ('l') to store the plots in, and set the desired fill colors ('cols')
  3. Loop over the indices of the groups (for(i in seq_along(grp)))
  4. Subset the data based on group (df[df$grp == grp[i], ])
  5. Select background color using a numeric vector indicating odd / even values of the group indices (i %% 2 + 1), to alternate grey and white background.
  6. Plot (ggplot)
  7. Fill relevant elements with 'col'. Modify other theme elements according to taste
  8. Create x labels (xlab) dynamically: grab current 'grp' and calculate sample size (nrow(dat))
  9. Assign the plot to its list element (l[[i]] <- p)
  10. Use gridExtra::grid.arrange to render and arrange the plots in the list
  11. Voilà!
Henrik
  • 65,555
  • 14
  • 143
  • 159
1

This is the best I have been able to come up with. I had to approximate the four corners of each rectangle by trial-and-error. I commented out the three white rectangles without sizing them properly, but retained the code to show they could be included with a desired color.

setwd('C:/Users/general1/Documents/simple R programs/')

jpeg(filename = "boxplot_background_color_with_layout.jpeg")

set.seed(1223)
par(xpd = NA, mar = c(2,4,1,1), bg = 'white')
layout(matrix(c(1,2,3,4,5), 1, 5, byrow = TRUE))

boxplot(rnorm(20), ylab = "A")
title(xlab="n = 54", line=0)
#rect(-1, -2.375, 1.585, 2, col = rgb(0,0,0,alpha=0.5), border=FALSE) 

boxplot(rnorm(20), ylab = "B")
title(xlab="n = 54", line=0)
rect(-0.4, -2.229, 1.6, 2.0, col = rgb(0.5,0.5,0.5,alpha=0.5), border=FALSE) 

boxplot(rnorm(20), ylab = "C")
title(xlab="n = 54", line=0)
#rect(-1, -2.375, 1.585, 2, col = rgb(0,0,0,alpha=0.5), border=FALSE)

boxplot(rnorm(20), ylab = "D")
title(xlab="n = 54", line=0)
rect(-0.4, -2.5, 1.6, 2.5, col = rgb(0.5,0.5,0.5,alpha=0.5), border=FALSE) 

boxplot(rnorm(20), ylab = "E")
title(xlab="n = 54", line=0)
#rect(-1, -2.375, 1.585, 2, col = rgb(0,0,0,alpha=0.5), border=FALSE)

dev.off()

enter image description here

Mark Miller
  • 12,483
  • 23
  • 78
  • 132