Konrad
Konrad

Reputation: 18655

How to add a border around a chart created via arrange.grid in gridExtra encompassing a set ggplot2 scatter plots

I'm using the code below:

# Libs
require(ggplot2); require(gridExtra); require(grid)

# Generate separate charts
chrts_list_scts <- list()

# Data
data("mtcars")

# A
chrts_list_scts$a <- ggplot(mtcars) +
  geom_point(size = 2, aes(x = mpg, y = disp,
                           colour = as.factor(cyl))) +
  geom_smooth(aes(x = mpg, y = disp),
              method = "auto") +
  xlab("MPG") +
  ylab("Disp") +
  theme_bw() +
  theme(panel.grid.major = element_blank(),
        panel.grid.minor = element_blank(),
        legend.position = "none")

# B
chrts_list_scts$b <- ggplot(mtcars) +
  geom_point(size = 2, aes(x = mpg, y = drat,
                           colour = as.factor(cyl))) +
  geom_smooth(aes(x = mpg, y = drat),
              method = "auto") +
  xlab("MPG") +
  ylab("Drat") +
  theme_bw() +
  theme(panel.grid.major = element_blank(),
        panel.grid.minor = element_blank(),
        legend.position = "none")

# C
chrts_list_scts$c <- ggplot(mtcars) +
  geom_point(size = 2, aes(x = mpg, y = qsec,
                           colour = as.factor(cyl))) +
  geom_smooth(aes(x = mpg, y = qsec),
              method = "auto") +
  xlab("MPG") +
  ylab("QSEC") +
  guides(colour = guide_legend(title = "cyl")) +
  theme_bw() +
  theme(panel.grid.major = element_blank(),
        panel.grid.minor = element_blank(),
        legend.position = "bottom",
        legend.key = element_rect(colour = NA))

# Arrange grid
png(filename = "chrts.PNG", width = 6,
    height = 10, units = 'in', res = 300)
title_text <- c("mtcars")
chrts_list_scts$all_scts <- grid.arrange(chrts_list_scts$a,
                                         chrts_list_scts$b,
                                         chrts_list_scts$c,
                                         top =
                                           textGrob(label = title_text,
                                                    gp = gpar(
                                                      fontsize = 14,
                                                      font = 2)))
dev.off()
rm(title_text)

To generate the following chart:

first chart

I'm interested in adding border around that chart, as in the picture below:

with border

Attempts

I tried to address this request via adding polygonGrob in the code:

chrts_list_scts$all_scts <- grid.arrange(chrts_list_scts$dep_work,
                                         chrts_list_scts$chld_work,
                                         chrts_list_scts$pens,
                                         polygonGrob(x = c(0,0.5,1.05),
                                                     y = c(0,0.5,1.05)
                                                     ),
                                         top =
                                           textGrob(label = title_text,
                                                    gp = gpar(
                                                      fontsize = 14,
                                                      font = 2)))

but this generates a pointless chart with one line across in the bottom. I had a look at the seeming similar discussion on SO but it wasn't clear to me how to arrive at a working solution.

Side requirements

In addition to generating the border, I would like to:

  1. Be able to exercise some control over the border aesthetics, like changing size and colour of the border.
  2. Ideally, I would like to encapsulate this solution within the arrange.grid call. So at the object chrts_list_scts$all_scts has all elements including charts and neat border around all of them.

I will be happy to accept solutions that address the major requirements with respect to the border only, if there is a suggested solution that matches the remaining two points it will be even nicer.

Upvotes: 16

Views: 8642

Answers (2)

G. Grothendieck
G. Grothendieck

Reputation: 270075

1) Using the iris example (but further simplified) from the link provided in the question just add the last line. Modify the gpar(...) components (and possibly the width and height) to get different aesthetics. (This is not encapsulated in the grid.arrange call.)

library(ggplot2)
library(grid)
library(gridExtra)

g <- ggplot(iris, aes(Sepal.Width, Sepal.Length)) + geom_point()
grid.arrange(g, g, ncol=2)


# next line adds border
grid.rect(width = .98, height = .98, gp = gpar(lwd = 2, col = "blue", fill = NA))

(continued after plot)

screenshot

2) This is a variation of solution (1) in which on the plus side encapsulates both the graphics and border in the gt gTree by creating grobs to hold each. On the other hand it does involve some additional complexity:

grid.newpage()
ga <- arrangeGrob(g, g, ncol = 2)
gb <- rectGrob(height = .98, width = .98, gp = gpar(lwd = 2, col = "blue", fill = NA)) # border, no fill
gt <- gTree(children = gList(ga, gb))
grid.draw(gt)

Upvotes: 12

baptiste
baptiste

Reputation: 77116

you can add a rectGrob to the gtable

grid.draw(gtable::gtable_add_grob(arrangeGrob(g, g, ncol=2),
             rectGrob(gp=gpar(lwd=5, fill=NA)), 1, 1, 1, 2))

NOTE: fill=NA or fill='transparent' is required otherwise the rectangle can mask the objects below it.

Upvotes: 2

Related Questions