22

I have the same problem as this user: I'd like to make a facet_grid plot with a discrete x-axis, and I'd like to have the x-axis labels be written under each facet rather than only underneath the bottom row of facets. For instance:

# Drop some factor levels to make the plot smaller 
diamondSub <- subset(diamonds, (cut=="Ideal" | cut=="Premium") & 
                     (color=="E" | color=="I"))

# Note that scales="free_x" has no practical effect here
ggplot(diamondSub, aes(x=clarity, y=price)) + 
  geom_blank()+ 
  geom_boxplot() +
  facet_grid(cut~color, scales="free_x")

enter image description here

However, I'd prefer not to use the solution from that post, which was just to use facet_wrap instead of facet_grid, because I prefer the way facet_grid labels the strip text with one variable on top of the columns, and the other variable on the sides of the rows.

Is there a way to get x-axis labels under each facet, when all the x-axes are actually the same, using facet_grid?

Community
  • 1
  • 1
Drew Steen
  • 16,045
  • 12
  • 62
  • 90

2 Answers2

19

You can insert a copy of the axes inside the gtable,

library(gtable)
g <- ggplotGrob(p)
# locate the panels
panels <- grep("panel", g$layout$name)
top <- unique(g$layout$t[panels])
# intersperse a copy of the bottom axes
all <- gtable:::rbind_gtable(gtable:::rbind_gtable(g[seq.int(min(top)), ], 
                                                   g[max(top)+1,], "first"), 
                             g[seq(min(top)+1, nrow(g)),], "first")
grid.newpage()
grid.draw(all)

enter image description here

baptiste
  • 75,767
  • 19
  • 198
  • 294
  • I get error while running the line `all <- gtable:::rbind_gtable(gtable:::rbind_gtable(g[1:4],g[7,]), g[5:9,])`. The error I got is `Error in UseMethod("grid.draw") : no applicable method for 'grid.draw' applied to an object of class "function"`. I believe `p` refers to ggplot object, is that true ? – Jd Baba Jul 15 '13 at 18:37
  • yes, p is your ggplot. What do you get with `print(all)`? It should be a `TableGrob (10 x 8) "layout": 16 grobs` etc. – baptiste Jul 15 '13 at 18:38
  • The error I got now is as follows: `> all <- gtable:::rbind_gtable(gtable:::rbind_gtable(g[1:4],g[7,]), g[5:7,]) Error in mmm < each : comparison of these types is not implemented` – Jd Baba Jul 15 '13 at 18:39
  • I see. That's because I grew tired of this and fixed it in my own version of gtable. Try the updated code. – baptiste Jul 15 '13 at 18:43
  • It seems to work but the final figure doesn't look like the figure you posted. On my machine the y-axis get overlapped. The final figure looks like this: [1]: http://i.stack.imgur.com/2wzE8.png – Jd Baba Jul 15 '13 at 18:46
  • strange,; make sure you don't forget to issue `grid.newpage()` between new plots, otherwise they get drawn on top of each other. – baptiste Jul 15 '13 at 18:47
  • +1 `grid.newpage()` seems to solve the problem. Thank you. May you you can add `grid.newpage()` on your code. – Jd Baba Jul 15 '13 at 18:50
  • Great way to add axes to every facet, however I seem to have lost the y-axis label. Any thought on how to recover that? – mattek Nov 25 '15 at 15:10
  • 7
    Is this "workaround" still the best solution for this question? Why does not ggplot support the x-axis in all subplots? @mattek – Dan Aug 03 '16 at 05:17
  • 3
    worked, but only for 2 x 2, what about other arranges... 3x1 3x2 3x3 3x4 3x5 – Ferroao Mar 04 '17 at 16:15
1

Script can be much simpler by using cbind.gtable:

library(gtable)
g <- ggplotGrob(p)
# locate the panels
panels <- grep("panel", g$layout$name)
top <- unique(g$layout$t[panels])

# intersperse a copy of the bottom axes
all <- gtable:::cbind.gtable(
    g[seq.int(min(top)), ], 
    g[max(top)+1,],
    g[seq(min(top)+1, nrow(g)),], 
    size = "first")
grid.newpage()
grid.draw(all)
Dongdong Kong
  • 361
  • 2
  • 13