get scales/range of facets (scales='free')

2019-05-22 20:19发布

问题:

I have a faceted ggplot with free scales. Now I want to annotate this plot at the same RELATIVE Position at each facet. This would be easy to do, if I knew how to get the range/limits of the scale of each facet. QUESTION: Is there any way to get the scales of each facet in ggplot?

In the following example, I did it manually. The question would be how to construct facet_scales by a function which uses a2 (which would also be more exact). If i call str(a2), it gives me an explanation of a2$scales. It also states that a useful function could be get_scales(). Lamentably, i don't know how to call this function.

library(ggplot2)
a <- ggplot(data = msleep, aes(x = bodywt, y = sleep_total))+ geom_point()
a2 <- a + facet_wrap(~vore, scales="free") 
a2

facet_scales = data.frame(vore=c(levels(msleep$vore), NA),
                           x_min = c(0,0,0,0,0),
                           x_max = c(800,7000,60,90,4),
                           y_min = c(0,0,5,7.5,5),
                           y_max = c(20,18,21,19,15)
                           )
a2 + geom_rect(data=facet_scales, mapping =aes(xmin=x_min, xmax=x_max, ymin=y_min, 
                ymax=(y_max+y_min)/3, x=NULL, y=NULL ), color='yellow', alpha=0.2)

回答1:

You can get the range of each facet axis by converting a2 with function ggplot_build(). Then axis ranges are stored in list element panel sublist ranges, and then for each panel x axis range is in element x.range

a3<-ggplot_build(a2)

a3$panel$ranges[[1]]$x.range
[1] -39.9706 839.9986

a3$panel$ranges[[2]]$x.range
[1] -332.6769 6986.6989


回答2:

Building on Didzis answer I built a function to extract the ranges:

get_facet_ranges <- function (x){
  ret <- x$panel$layout
  for (i in 1:nrow(ret)){
    print(i)
    x_range <- x$panel$ranges[[i]]$x.range
    y_range <- x$panel$ranges[[i]]$y.range

    ret[i, "x_min"] <- x_range[1]
    ret[i, "x_max"] <- x_range[2]
    ret[i, "y_min"] <- y_range[1]
    ret[i, "y_max"] <- y_range[2]
  }

  return(ret)
}

Now I can easily annotate each facet as described in my question:

library(ggplot2)
a <- ggplot(data = msleep, aes(x = bodywt, y = sleep_total))+ geom_point()
a2 <- a + facet_wrap(~vore, scales="free") 
a2

facet_scales = get_facet_ranges(ggplot_build(a2) )
a2 + geom_rect(data=facet_scales, mapping =aes(xmin=x_min, xmax=x_max, ymin=y_min, 
                                               ymax=(y_max-y_min)/3 +y_min, 
                                               x=NULL, y=NULL ), 
               color='yellow', alpha=0.2)

The function should work with both facet_grid() and facet_wrap(), but is hardly tested ;)



标签: r ggplot2