1
votes

I have two factors and two continuous variables, and I use this to create a two-way facet plot using ggplot2. However, not all of my factor combinations have data, so I end up with dummy facets. Here's some dummy code to produce an equivalent output:

library(ggplot2)
dummy<-data.frame(x=rnorm(60),y=rnorm(60),
                  col=rep(c("A","B","C","B","C","C"),each=10),
                  row=rep(c("a","a","a","b","b","c"),each=10))
ggplot(data=dummy,aes(x=x,y=y))+
       geom_point()+
       facet_grid(row~col)

This produces this figure

Is there any way to remove the facets that don't plot any data? And, ideally, move the x and y axis labels up or right to the remaining plots? As shown in this GIMPed version

I've searched here and elsewhere and unless my search terms just aren't good enough, I can't find the same problem anywhere. Similar issues are often with unused factor levels, but here no factor level is unused, just factor level combinations. So facet_grid(drop=TRUE) or ggplot(data=droplevel(dummy)) doesn't help here. Combining the factors into a single factor and dropping unused levels of the new factor can only produce a 1-dimensional facet grid, which isn't what I want.

Note: my actual data has a third factor level which I represent by different point colours. Thus a single-plot solution allowing me to retain a legend would be ideal.

3

3 Answers

5
votes

It's not too difficult to rearrange the graphical objects (grobs) manually to achieve what you're after.

  1. Load the necessary libraries.

    library(grid);
    library(gtable);
    
  2. Turn your ggplot2 plot into a grob.

    gg <- ggplot(data = dummy, aes(x = x,y = y)) +
            geom_point() +
            facet_grid(row ~ col);
    grob <- ggplotGrob(gg);
    

    Working out which facets to remove, and which axes to move where depends on the grid-structure of your grob. gtable_show_layout(grob) gives a visual representation of your grid structure, where numbers like (7, 4) denote a panel in row 7 and column 4.

  3. Remove the empty facets.

    # Remove facets
    idx <- which(grob$layout$name %in% c("panel-2-1", "panel-3-1", "panel-3-2"));
    for (i in idx) grob$grobs[[i]] <- nullGrob();
    
  4. Move the x axes up.

    # Move x axes up
    # axis-b-1 needs to move up 4 rows
    # axis-b-2 needs to move up 2 rows
    idx <- which(grob$layout$name %in% c("axis-b-1", "axis-b-2"));
    grob$layout[idx, c("t", "b")] <- grob$layout[idx, c("t", "b")] - c(4, 2);
    
  5. Move the y axes to the right.

    # Move y axes right
    # axis-l-2 needs to move 2 columns to the right
    # axis-l-3 needs ot move 4 columns to the right
    idx <- which(grob$layout$name %in% c("axis-l-2", "axis-l-3"));
    grob$layout[idx, c("l", "r")] <- grob$layout[idx, c("l", "r")] + c(2, 4);
    
  6. Plot.

    # Plot
    grid.newpage();
    grid.draw(grob);
    

enter image description here

Extending this to more facets is straightforward.

0
votes

One possible solution, of course, would be to create a plot for each factor combination separately and then combine them using grid.arrange() from gridExtra. This would probably lose my legend and would be an all around pain, would love to hear if anyone has any better suggestions.

0
votes

This particular case looks like a job for ggpairs (link to a SO example). I haven't used it myself, but for paired plots this seems like the best tool for the job.

In a more general case, where you're not looking for pairs, you could try creating a column with a composite (pasted) factor and facet_grid or facet_wrap by that variable (example)