Wednesday, August 16, 2017

In a `facet_wrap`ed grid, center subplots at 0 while keeping `free_x`

Leave a Comment

In the plot below, I have a faceted grid.

Is there any way to center both subplots at 0, while keeping different min/max values for the x axis?

In the case below that would be xlim=c(-1,1) for left and xlim=c(-2,2) for right, but it should be generally applicable.

(in a real life example, those are faceted volcano plots and I want to center at 0 effect size but keep the different x scales for different plots)

library(ggplot2) df = data.frame(x=c(1,2), y=c(0,0), group=c(1,2)) ggplot(df, aes(x=x, y=y)) + geom_point() + facet_wrap(~group, scale="free_x") 

enter image description here

5 Answers

Answers 1

I've also needed something like this to display asymmetric spectra side-by-side,

enter image description here

Try this function,

symmetrise_scale <- function(p, axis = "x"){   gb <- ggplot_build(p)   type <- switch(axis, "x" = "x.range", "y" = "y.range")   lims <- sapply(gb$panel$ranges, "[[", type)   fname <- as.character(p$facet$facets)   facets <- gb$panel$layout[[fname]]   lims2 <- as.vector(t(tcrossprod(apply(abs(lims), 2, max), c(-1,1))))   dummy <- setNames(data.frame(rep(facets, each=2), lims2), c(fname, axis))   switch(axis,           "x" = p + geom_blank(data=dummy, aes(x=x, y=Inf), inherit.aes = FALSE),           "y" = p + geom_blank(data=dummy, aes(x=Inf, y=y), inherit.aes = FALSE)) }   library(ggplot2) df = data.frame(x=c(1,2), y=c(5,0.2), group=c(1,2)) p <- ggplot(df, aes(x=x, y=y)) + geom_point() + facet_wrap(~group, scale="free") symmetrise_scale(p, "x") 

enter image description here

symmetrise_scale(p, "y") 

enter image description here

Answers 2

with version ggplot2_2.2.1.9000

symmetrise_scale <- function(p, axis = "x"){   gb <- ggplot_build(p)   type <- switch(axis, "x" = "x.range", "y" = "y.range")    fname <- setdiff(names(gb$layout$layout), c("PANEL", "ROW", "COL",  "SCALE_X", "SCALE_Y"))     facets <- gb$layout$layout[ ,fname, drop=FALSE]    lims <- do.call(cbind, lapply(gb$layout$panel_params, "[[", type))   lims2 <- as.vector(t(tcrossprod(apply(abs(lims), 2, max), c(-1,1))))    dummy <- setNames(data.frame(facets[rep(seq_len(nrow(facets)), each=2),], lims2), c(fname, axis))      switch(axis,           "x" = p + geom_blank(data=dummy, aes(x=x, y=Inf), inherit.aes = FALSE),           "y" = p + geom_blank(data=dummy, aes(x=Inf, y=y), inherit.aes = FALSE)) } 

Answers 3

A simpler, perhaps more robust solution, would be the following. In a more complex plot using several dataframes you would need a similar geom_blank term for each one.

df = data.frame(x=c(1,2,3,4,5,6), y=c(5,-3,2,-0.2,0.3,-0.1), group=c(1,1,1,2,2,2))  ggplot(df, aes(x=x, y=y)) +        geom_blank(aes(y=-y)) + #plot mirror image points invisibly (can do same with x)       geom_line() + facet_wrap(~group, scale="free") 

enter image description here

Answers 4

library(ggplot2) library(tidyverse)  df = data.frame(x=c(1,2), y=c(0,0), group=c(1,2))  # determine the maximum range df_xr <- df %>%    group_by(group) %>%   summarize(xr = max(abs(x))) %>%   ungroup()  # join the mximum range ot original df df_plot <- df %>%    inner_join(df_xr)  # plot using geom_blank to force the extents without plotting anything ggplot(df_plot, aes(x=x, y=y)) +    geom_blank(aes(x = xr)) +   geom_blank(aes(x = -xr)) +   geom_point() +    facet_wrap(~group, scale="free_x") 

enter image description here

Answers 5

This seems to do the trick - for now (this is ggplot2 2.2.1). The main edits to the previous answer are to reflect changes in the names/structure of the ggplot_build object.

symmetrise_scale <- function(p, axis = "x"){   gb <- ggplot_build(p)   type <- switch(axis, "x" = "x.range", "y" = "y.range")    fname <- setdiff(names(gb$layout$panel_layout), c("PANEL", "ROW", "COL",  "SCALE_X", "SCALE_Y"))     facets <- gb$layout$panel_layout[ ,fname, drop=FALSE]    lims <- do.call(cbind, lapply(gb$layout$panel_ranges, "[[", type))   lims2 <- as.vector(t(tcrossprod(apply(abs(lims), 2, max), c(-1,1))))    dummy <- setNames(data.frame(facets[rep(seq_len(nrow(facets)), each=2),], lims2), c(fname, axis))    switch(axis,           "x" = p + geom_blank(data=dummy, aes(x=x, y=Inf), inherit.aes = FALSE),           "y" = p + geom_blank(data=dummy, aes(x=Inf, y=y), inherit.aes = FALSE)) }   library(ggplot2) df <- data.frame(x=c(1,2,3,4,5,6), y=c(5,-3,2,-0.2,0.3,-0.1), group=c(1,1,1,2,2,2)) p <- ggplot(df, aes(x=x, y=y)) + geom_line() + facet_wrap(~group, scale="free") symmetrise_scale(p, "y") 

enter image description here

If You Enjoyed This, Take 5 Seconds To Share It

0 comments:

Post a Comment