gosia
gosia

Reputation: 131

R: Scatter plot matrix using ggplot2 with themes that vary by facet panel

I want to create Scatter Plot Matrix using ggplot2. Partially I coped with my problem. I managed to create three-part graph using ggplot2: the lower triangle - Scatterplot, diagonally - variable names and the upper triangle - correlation coefficient (R^2). Below I give piece of my data + code generating my chart. My data:

f = 
C   xval    V   yval    corr    V1
1   1622    1   1622    1       2ng
1   1622    2   1639    0.997   2ng
1   1622    3   1584    0.992   2ng
1   1622    4   1549    0.99    2ng
1   1622    5   1541    0.993   2ng
1   1622    6   1543    0.994   2ng
1   1622    7   1530    0.988   2ng
2   1639    1   1622    0.997   5ng
2   1639    2   1639    1       5ng
2   1639    3   1584    0.997   5ng
2   1639    4   1549    0.997   5ng
2   1639    5   1541    0.998   5ng
2   1639    6   1543    0.998   5ng
2   1639    7   1530    0.995   5ng
3   1584    1   1622    0.992   10ng
3   1584    2   1639    0.997   10ng
3   1584    3   1584    1       10ng
3   1584    4   1549    0.997   10ng
3   1584    5   1541    0.995   10ng
3   1584    6   1543    0.999   10ng
3   1584    7   1530    0.999   10ng
4   1549    1   1622    0.99    15ng
4   1549    2   1639    0.997   15ng
4   1549    3   1584    0.997   15ng 
4   1549    4   1549    1       15ng
4   1549    5   1541    0.998   15ng
4   1549    6   1543    0.998   15ng
4   1549    7   1530    0.998   15ng
5   1541    1   1622    0.993   30ng
5   1541    2   1639    0.998   30ng
5   1541    3   1584    0.995   30ng
5   1541    4   1549    0.998   30ng
5   1541    5   1541    1       30ng
5   1541    6   1543    0.998   30ng
5   1541    7   1530    0.995   30ng
6   1543    1   1622    0.994   60ng
6   1543    2   1639    0.998   60ng
6   1543    3   1584    0.999   60ng
6   1543    4   1549    0.998   60ng
6   1543    5   1541    0.998   60ng
6   1543    6   1543    1       60ng
6   1543    7   1530    0.998   60ng
7   1530    1   1622    0.988   100ng
7   1530    2   1639    0.995   100ng
7   1530    3   1584    0.999   100ng
7   1530    4   1549    0.998   100ng
7   1530    5   1541    0.995   100ng
7   1530    6   1543    0.998   100ng
7   1530    7   1530    1       100ng

And code:

g <- ggplot(data = f, aes(x=xval, y=yval))+ 
  geom_point(data = f[(xtfrm(f$C)<xtfrm(f$V)),], colour = "darkblue", size = 1.5)+
  geom_smooth(data = f[(xtfrm(f$C)<xtfrm(f$V)),], aes(colour = "red"), method="lm", size = 0.1)+
  geom_text(data = f[(xtfrm(f$C)==xtfrm(f$V)),], aes(x = 4000, y = 4000, label = paste(V1)), size = 10, colour="red")+
  geom_tile(aes(fill=corr))+
  geom_text(data = f[(xtfrm(f$C)>xtfrm(f$V)), ], aes(x = 4000, y = 4000, label = corr), size = 10)+
  coord_cartesian(xlim=c(0,8000), ylim=c(0,8000))+
  facet_grid(V~C, space = "fixed") + 
  theme(panel.grid.major = element_blank(), strip.background = element_blank(), strip.text.y = element_blank(), strip.text.x = element_blank(), legend.position = "none")

g

enter image description here However, I have got a problem for improving the appearance of the graph. I want to separate part of the graph with different background colour for example: white background for scatters, gray for variable names and blue for correlation coeff. Does anyone know how to do it? Is it possible or I have to create each part of graph separately?

Upvotes: 4

Views: 2067

Answers (1)

eipi10
eipi10

Reputation: 93771

One way to do this is to create each plot separately and then lay them out together. This allows you to set all the plot elements independently for each plot, including theme elements like the background fill color.

The function below uses mapply to create a separate plot for each combination of V and C, and uses if statements to assign the desired background color for each plot.

library(gridExtra)

p.list = mapply(FUN=function(v,c) {

    fvc = f[f$V==v & f$C==c, ]

    g <- ggplot(data=fvc, aes(x=xval, y=yval))+ 
      coord_cartesian(xlim=c(0,8000), ylim=c(0,8000))+
      theme(axis.title=element_blank(),
            axis.text=element_text(size=8))

    if (c == v) {
      g = g + geom_text(aes(x = 4000, y = 4000, label=V1),
                        size = 6, colour="red")
    }

    if (c < v) {
      g = g + geom_text(aes(x = 4000, y = 4000, label=corr), size = 6) +
        theme(panel.background=element_rect(fill=hcl(180,100,60, alpha=0.3)))
    }

    if (c > v) {
      g = g + geom_point(colour = "darkblue", size = 1.5) +
              geom_smooth(aes(colour = "red"), method="lm", size = 0.1) +
        theme(panel.background=element_blank(),
              panel.grid.major=element_line(colour="grey80", size=0.3))
    }

    if(v != 1) {
      g = g + theme(axis.text.y=element_blank(),
                    axis.ticks.y=element_blank())
    }

    if(c != max(f$C)) {
      g = g + theme(axis.text.x=element_blank(),
                    axis.ticks.x=element_blank())
    }

    return(g) }, 
    expand.grid(V=unique(f$V), C=unique(f$C))[[1]], 
    expand.grid(V=unique(f$V), C=unique(f$C))[[2]], SIMPLIFY=FALSE)

Now lay out all the plots together and add x-axis and y-axis labels:

grid.arrange(
  arrangeGrob(
    arrangeGrob(textGrob("Y vals", rot=90),
                do.call(arrangeGrob, c(p.list, ncol=7)), widths=c(0.05,0.95)),
    textGrob("X vals"), heights=c(0.95,0.05)))

enter image description here

As you can see in the above plot, there's one remaining issue: The panels in the first column and last row have a smaller plot area, due to the axis labels. This SO answer shows how to equalize the sizes of the plot areas, but you have to list each plot object separately.

Fortunately, we don't have to roll our own function to equalize the size of all the plot areas in a large grid of plots, as plot_grid from the cowplot package, can do this. However, I thought the margins between each graph were too large after running plot_grid. You can tweak this by changing the plot margins when you create the graphs. To do this, you can adjust the plot margins in the return line of the plotting function as follows:

return(g + theme(plot.margin=unit(c(0,-0.15,0,-0.15), "lines"))) },

Then plot using plot_grid:

library(cowplot)

grid.arrange(
  arrangeGrob(
    arrangeGrob(textGrob("Y vals", rot=90),
                do.call(plot_grid, c(p.list, align="hv")), widths=c(0.05,0.95)),
    textGrob("X vals"), heights=c(0.95,0.05)))

enter image description here

Upvotes: 7

Related Questions