Different breaks per facet in ggplot2 histogram

A ggplot2-challenged latticist needs help: What's the syntax to request variable per-facet breaks in a histogram?

library(ggplot2)
d = data.frame(x=c(rnorm(100,10,0.1),rnorm(100,20,0.1)),par=rep(letters[1:2],each=100))
# Note: breaks have different length by par
breaks = list(a=seq(9,11,by=0.1),b=seq(19,21,by=0.2))
ggplot(d, aes(x=x) ) + 
  geom_histogram() + ### Here the ~breaks should be added
  facet_wrap(~ par,  scales="free")

As pointed out by jucor, here some more solutions.

On special request, and to show why I am not a great ggplot fan, the lattice version

library(lattice)
d = data.frame(x=c(rnorm(100,10,0.1),rnorm(100,20,0.1)),par=rep(letters[1:2],each=100))
# Note: breaks have different length by par
myBreaks = list(a=seq(8,12,by=0.1),b=seq(18,22,by=0.2))
histogram(~x|par,data=d,
          panel = function(x,breaks,...){
            # I don't know of a generic way to get the 
            # grouping variable with histogram, so 
            # this is not very generic
            par = levels(d$par)[which.packet()]
            breaks = myBreaks[[par]]
            panel.histogram(x,breaks=breaks,...)
          },
          breaks=NULL, # important to force per-panel compute
          scales=list(x=list(relation="free")))

enter image description here


Solution 1:

Here is one alternative:

hls <- mapply(function(x, b) geom_histogram(data = x, breaks = b), 
              dlply(d, .(par)), myBreaks)
ggplot(d, aes(x=x)) + hls + facet_wrap(~par, scales = "free_x")

enter image description here

If you need to shrink the range of x, then

hls <- mapply(function(x, b) {
  rng <- range(x$x)
  bb <- c(rng[1], b[rng[1] <= b & b <= rng[2]], rng[2])
  geom_histogram(data = x, breaks = bb, colour = "white")
}, dlply(d, .(par)), myBreaks)

ggplot(d, aes(x=x)) + hls + facet_wrap(~par, scales = "free_x")

enter image description here

Solution 2:

I don't think that it is possible to give different break points in each facet.

As workaround you can make two plots and then with grid.arrange() function from library gridExtra put them together. To set break points in geom_histogram() use binwidth= and set one value for width of bin.

p1<-ggplot(subset(d,par=="a"), aes(x=x) ) + 
  geom_histogram(binwidth=0.1) +
  facet_wrap(~ par)

p2<-ggplot(subset(d,par=="b"), aes(x=x) ) + 
  geom_histogram(binwidth=0.2) +
  facet_wrap(~ par)
library(gridExtra)
grid.arrange(p1,p2,ncol=2)

enter image description here