44

It is often desirable to minimize ink in a plot. I have a faceted plot (facet_wrap) and would like to remove as much ink as possible yet maintain readability. I have set it up as I'd like except the x and y axis is not present for the facets (subplots) unless on the far left or bottom. With so much ink removed I believe the eye needs these cues and am asking how to put the x and y axis in all plots within a facet_wrap. Below is my code thus far, the current output and the desired output (red lines are the desired add in):

library(ggplot); library(grid)

ggplot(mtcars, aes(mpg, hp)) + 
    geom_point() + 
    facet_wrap(~carb) +
    theme(panel.grid = element_blank(),
        panel.background = element_rect(fill = "white", colour = "black"), 
        panel.border = element_rect(fill = NA, colour = "white"), 
        axis.line = element_line(),
        strip.background = element_blank(),
        panel.margin = unit(2, "lines"))

Current Plot enter image description here

Desired Plot enter image description here

andschar
  • 3,504
  • 2
  • 27
  • 35
Tyler Rinker
  • 108,132
  • 65
  • 322
  • 519
  • I got a `could not find function "unit"` error on your example. – Thomas Mar 01 '14 at 16:11
  • @Thomas my apologies. let me add the libraries used. – Tyler Rinker Mar 01 '14 at 16:28
  • You can't do this easily, because the `axis.line` theme element will not be displayed on each panel unless `scales = "free"`, and the `panel.border` theme element is a rectangle, and you can't specify different values for the different sides of a rectangle element. You can sort of fake it with `geom_vline` and `geom_hline`, but it will be hard to get it to look right. – Ista Mar 01 '14 at 16:29
  • You may get some ideas from @baptiste's answers [**here**](http://stackoverflow.com/questions/17661052/force-x-axis-text-on-for-all-facets-of-a-facet-grid-plot) and [**here**](http://stackoverflow.com/questions/21987834/display-y-axis-for-each-subplot-when-faceting). – Henrik Mar 01 '14 at 16:40
  • `gridExtra::borderGrob(type=9)` could help, [if ggplot2 had allowed some flexibility in theme elements](https://github.com/hadley/ggplot2/issues/808). – baptiste Mar 01 '14 at 16:42
  • @baptise can you undelete your answer? – Tyler Rinker Mar 01 '14 at 17:03
  • I don't think they're very useful examples for future use, I mostly put them up for discussion as they don't fit in comments – baptiste Mar 01 '14 at 17:11

6 Answers6

44

This should simplify things considerably:

library('ggthemes')
ggplot(mtcars, aes(mpg, hp)) + geom_point() + facet_wrap(~carb, scales='free') + 
    theme_tufte() + theme(axis.line=element_line()) + 
    scale_x_continuous(limits=c(10,35)) + scale_y_continuous(limits=c(0,400))

enter image description here

Thomas
  • 43,637
  • 12
  • 109
  • 140
37

easiest way would be to add segments in each plot panel,

ggplot(mtcars, aes(mpg, hp)) + 
  geom_point() + 
  facet_wrap(~carb) +
  theme_minimal() +
  annotate("segment", x=-Inf, xend=Inf, y=-Inf, yend=-Inf)+
  annotate("segment", x=-Inf, xend=-Inf, y=-Inf, yend=Inf)

example

Thomas
  • 43,637
  • 12
  • 109
  • 140
baptiste
  • 75,767
  • 19
  • 198
  • 294
  • For me it ends up in different width of the additional lines, which is quite annoying... – JelenaČuklina Aug 20 '19 at 15:01
  • 1
    I hoped to use this simple answer for my graphs as well, but my x-axis uses dates, which gives the error: "Error: Invalid input: date_trans works with objects of class Date only". Any ideas? – Tingolfin Jun 27 '20 at 14:20
  • @JelenaČuklina try adding a `size` argument, e.g., `annotate("segment", x=-Inf, xend=Inf, y=-Inf, yend=-Inf, size = 1) +`. It worked for me. – Øystein S Jul 10 '20 at 17:47
19

Following Thomas answer from above -

You just need to set scales='free' in facet_wrap and make sure to set the limits in scale_x_continuous and scale_y_continuous

ggplot(mtcars, aes(mpg, hp)) + geom_point() + facet_wrap(~carb, scales='free') + 
    scale_x_continuous(limits=c(10,35)) + scale_y_continuous(limits=c(0,400))
Tal Galili
  • 24,605
  • 44
  • 129
  • 187
16

The lemon package adds this functionality; see this vignette. (Example code and plot from there.)

library(lemon)
p + facet_rep_grid(drv ~ cyl) + coord_capped_cart(bottom='both', left='both') +
  theme_bw() + theme(panel.border=element_blank(), axis.line=element_line())

From the lemon documentation:

Aaron left Stack Overflow
  • 36,704
  • 7
  • 77
  • 142
4

Here is long workaround.

First, store your original plot as object and then create another plot that doesn't have axis ticks and axis texts.

p1<-ggplot(mtcars, aes(mpg, hp)) + 
  geom_point() + 
  facet_wrap(~carb) +
  theme(panel.grid = element_blank(),
        panel.background = element_blank(), 
        panel.border = element_blank(), 
        axis.line = element_line(),
        strip.background = element_blank(),
        panel.margin = unit(2, "lines"))

p2<-ggplot(mtcars, aes(mpg, hp)) + 
  geom_point() + 
  facet_wrap(~carb) +
  theme(panel.grid = element_blank(),
        panel.background = element_blank(), 
        panel.border = element_blank(), 
        axis.line = element_line(),
        strip.background = element_blank(),
        panel.margin = unit(2, "lines"),
        axis.ticks=element_blank(),
        axis.text=element_blank())

Now use function ggplotGrob() to convert both plots to grobs. If we look on structure of those grobs you will see that visible y axis is grob 14 and 17 (others are zero grobs), and x axis are grobs 23 to 25.

g1<-ggplotGrob(p1)
g2<-ggplotGrob(p2)
g2
TableGrob (12 x 12) "layout": 28 grobs
    z         cells       name                                     grob
1   0 ( 1-12, 1-12) background          rect[plot.background.rect.3481]
2   1 ( 4- 4, 4- 4)    panel-1                gTree[panel-1.gTree.3356]
3   2 ( 4- 4, 7- 7)    panel-2                gTree[panel-2.gTree.3366]
4   3 ( 4- 4,10-10)    panel-3                gTree[panel-3.gTree.3376]
5   4 ( 8- 8, 4- 4)    panel-4                gTree[panel-4.gTree.3386]
6   5 ( 8- 8, 7- 7)    panel-5                gTree[panel-5.gTree.3396]
7   6 ( 8- 8,10-10)    panel-6                gTree[panel-6.gTree.3406]
8   7 ( 3- 3, 4- 4)  strip_t-1    absoluteGrob[strip.absoluteGrob.3448]
9   8 ( 3- 3, 7- 7)  strip_t-2    absoluteGrob[strip.absoluteGrob.3453]
10  9 ( 3- 3,10-10)  strip_t-3    absoluteGrob[strip.absoluteGrob.3458]
11 10 ( 7- 7, 4- 4)  strip_t-4    absoluteGrob[strip.absoluteGrob.3463]
12 11 ( 7- 7, 7- 7)  strip_t-5    absoluteGrob[strip.absoluteGrob.3468]
13 12 ( 7- 7,10-10)  strip_t-6    absoluteGrob[strip.absoluteGrob.3473]
14 13 ( 4- 4, 3- 3)   axis_l-1 absoluteGrob[axis-l-1.absoluteGrob.3433]
15 14 ( 4- 4, 6- 6)   axis_l-2         zeroGrob[axis-l-2.zeroGrob.3434]
16 15 ( 4- 4, 9- 9)   axis_l-3         zeroGrob[axis-l-3.zeroGrob.3435]
17 16 ( 8- 8, 3- 3)   axis_l-4 absoluteGrob[axis-l-4.absoluteGrob.3441]
18 17 ( 8- 8, 6- 6)   axis_l-5         zeroGrob[axis-l-5.zeroGrob.3442]
19 18 ( 8- 8, 9- 9)   axis_l-6         zeroGrob[axis-l-6.zeroGrob.3443]
20 19 ( 5- 5, 4- 4)   axis_b-1         zeroGrob[axis-b-1.zeroGrob.3407]
21 20 ( 5- 5, 7- 7)   axis_b-2         zeroGrob[axis-b-2.zeroGrob.3408]
22 21 ( 5- 5,10-10)   axis_b-3         zeroGrob[axis-b-3.zeroGrob.3409]
23 22 ( 9- 9, 4- 4)   axis_b-4 absoluteGrob[axis-b-4.absoluteGrob.3415]
24 23 ( 9- 9, 7- 7)   axis_b-5 absoluteGrob[axis-b-5.absoluteGrob.3421]
25 24 ( 9- 9,10-10)   axis_b-6 absoluteGrob[axis-b-6.absoluteGrob.3427]
26 25 (11-11, 4-10)       xlab             text[axis.title.x.text.3475]
27 26 ( 4- 8, 2- 2)       ylab             text[axis.title.y.text.3477]
28 27 ( 2- 2, 4-10)      title               text[plot.title.text.3479]

So, use corresponding grobs of plot 2 to replace zero grobs in plot 1 and you will get axis lines.

g1[[1]][[15]]<-g2[[1]][[14]]
g1[[1]][[16]]<-g2[[1]][[14]]
g1[[1]][[18]]<-g2[[1]][[14]]
g1[[1]][[19]]<-g2[[1]][[14]]
g1[[1]][[20]]<-g2[[1]][[23]]
g1[[1]][[21]]<-g2[[1]][[23]]
g1[[1]][[22]]<-g2[[1]][[23]]

grid.draw(g1)

enter image description here

Didzis Elferts
  • 95,661
  • 14
  • 264
  • 201
4

Just found a simple solution for this myself - functionality can be found in the ggh4x package under facet_wrap2(~carb, axes = "all", remove_labels = "all").

library(ggplot2)
library(ggh4x)

ggplot(mtcars, aes(mpg, hp)) + 
    geom_point() + 
    facet_wrap2(~carb, axes = "all", remove_labels = "all") + # this can also just by "x" or "y" to remove axis labels
    theme(panel.grid = element_blank(),
        panel.background = element_rect(fill = "white", colour = "black"), 
        panel.border = element_rect(fill = NA, colour = "white"), 
        axis.line = element_line(),
        strip.background = element_blank(),
        panel.margin = unit(2, "lines"))

enter image description here

Timmo83
  • 119
  • 5