1

Hi suppose I have a plot as such,

library (ggplot2)
# txhousing is part of ggplot2 and should load

dt <- ggplot2::txhousing[ggplot2::txhousing$year %in% 2000:2002 & ggplot2::txhousing$month %in% 1:3,]
    
ggplot(dt, aes(median, sales)) +
  geom_point() +
  facet_wrap( year ~ month, 
              labeller = labeller( year=label_both, month=label_value), 
             scales = "free")

What I want is to avoid facet_grid because it does not provide a seperate free y-axis for each cell even when scales='free' ( if you know how then this might work as well), however in facet_wrap I feel like the the labels for the rows are redundant, what I want is the following mockup shown in red, is this possible? Basically each month would be label outside the facet or stack on top somehow with a different color or font. thanks.

enter image description here

Ahdee
  • 4,679
  • 4
  • 34
  • 58
  • @MrFlick txhousing is part of ggplot2. I edited and load the ggplot2 so that txhousing is available. – Ahdee Sep 02 '21 at 01:32
  • I see your issue. You want the individual scales that are given in y-axis for `facet_wrap()`, but need the strip labelling you get in `facet_grid()`. The problem is `facet_grid(...scales="free")` only allows adjustment of scales *per row* and *per column*... but not individual facets. – chemdork123 Sep 02 '21 at 01:39
  • I guess you could build the plot row by row and arrange with `grid` or `cowplot`, but then you'd still have to build the strip labels for each row manually. Blah. Interesting question, OP. – chemdork123 Sep 02 '21 at 01:43
  • @chemdork123 yes that is the issue. – Ahdee Sep 02 '21 at 01:44

2 Answers2

2

I found a pretty simple solution, which is to use the lemon package. This cool little extension to ggplot gives you functions facet_rep_grid() and facet_rep_wrap() are the same as facet_grid() and facet_wrap(), respectively, but preserve axis lines and labels on all panels. This seems pretty much what you want, right OP?

library(lemon)

ggplot(dt, aes(median, sales)) +
  geom_point() +
  facet_rep_grid( month ~ year,
              labeller = labeller( year=label_both, month=label_value),
              repeat.tick.labels = TRUE,
              scales = "free_y") +

  # I recommend increasing panel spacing to account for axis labels
  theme(panel.spacing = unit(20, units="pt"))

enter image description here

As for the coloring each facet according to some scheme... you can always use the trick to draw a geom_rect() behind your data points with some alpha applied. The key here is that if you use geom_rect() and your original data, you'll get tons of overplotting, so your panels never match the keys in the legend. The idea is to create a data frame used for geom_rect() that includes only one observation per facet (per combination of year and month in this case. You also need to include median and sales, since they are designated as x and y in the mapping, but it doesn't really matter the value here.

library(dplyr)
library(tidyr)

ggplot(dt, aes(median, sales)) +
  geom_rect(
    data=expand_grid(month=1:3, year=2000:2002) %>% mutate(sales=0, median=0),
    xmin=-Inf, xmax=Inf, ymin=-Inf, ymax=Inf,
    aes(fill=factor(month)), alpha=0.2
  ) +
  geom_point() +
  facet_rep_grid( month ~ year,
              labeller = labeller( year=label_both, month=label_value),
              repeat.tick.labels = TRUE,
              scales = "free_y") +
  theme(panel.spacing = unit(20, units="pt"))

enter image description here

chemdork123
  • 12,369
  • 2
  • 16
  • 32
  • This is very close, however unfortunately the y-axis is not really scaling per se. It looks like its just repeating. Its not very distinctive here but if the y-axis were vastly different this method will not work well. Is there anyway to force it to scale? – Ahdee Sep 02 '21 at 02:38
  • I know what you mean - this still uses `facet_grid()` under the hood, which scales by *row* and by *column*, not by individual panel when you set `scales="free"`. – chemdork123 Sep 02 '21 at 02:44
1

found similar one in How to position strip labels in facet_wrap like in facet_grid

library(grid)
library(gtable)

g1 = ggplot(dt, aes(median, sales)) +
  geom_point() +
  facet_wrap(c("year", "month"), scales = "free") +
  theme(strip.background = element_blank(),
        strip.text = element_blank())

g2 = ggplot(dt, aes(median, sales)) +
  geom_point() +
  facet_grid(c("year", "month"), scales = "free")

gt1 = ggplot_gtable(ggplot_build(g1))
gt2 = ggplot_gtable(ggplot_build(g2))
gt1$grobs[grep('strip-t.+1$', gt1$layout$name)] = gt2$grobs[grep('strip-t', gt2$layout$name)]
grid.draw(gt1)

gt.side1 = gtable_filter(gt2, 'strip-r-1')
gt.side2 = gtable_filter(gt2, 'strip-r-2')
gt.side3 = gtable_filter(gt2, 'strip-r-3')

gt1 = gtable_add_cols(gt1, widths=gt.side1$widths[1], pos = -1)
gt1 = gtable_add_grob(gt1, zeroGrob(), t = 1, l = ncol(gt1), b=nrow(gt1))

panel_id <- gt1$layout[grep('panel-.+1$', gt1$layout$name),]
gt1 = gtable_add_grob(gt1, gt.side1, t = panel_id$t[1], l = ncol(gt1))
gt1 = gtable_add_grob(gt1, gt.side2, t = panel_id$t[2], l = ncol(gt1))
gt1 = gtable_add_grob(gt1, gt.side3, t = panel_id$t[3], l = ncol(gt1))

grid.newpage()
grid.draw(gt1)

enter image description here

Park
  • 14,771
  • 6
  • 10
  • 29