Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Vary the fill scale when using facet_wrap and geom_tile together

When using function geom_tile and facet_wrap together in ggplot2, how to set different limits of the aesthetic fill, as the option scales which can be set to be free/free_y/free_x in facet_wrap?

The following is an example to show the problem. For different type in data.frame df, the range of z could be so different. If we use the same limits of aesthetic fill, some panle, which one the z part have very small value, would be hard to see the details.

pp <- function (n,r=4) {
    x <- seq(-r*pi, r*pi, len=n)
    df <- expand.grid(x=x, y=x)
    df$r <- sqrt(df$x^2 + df$y^2)
    df$z <- cos(df$r^2)*exp(-df$r/6)
    df
}
tmp <- pp(20)
tmp$type <- rep(1:4,each=nrow(tmp)/4)
tmp$z <- tmp$z*(10^(tmp$type))
ggplot(tmp,aes(x,y))+geom_tile(aes(fill=z))+facet_wrap(~type,scales="free")
like image 753
nicolas.wong Avatar asked Jun 09 '13 03:06

nicolas.wong


2 Answers

I know this is an old issue, but I recently had the same problem and came up with this solution that I wanted to share. The trick is to collect the datasets needed for the individual geom_tile() plots in a nested dataframe using nest() from tidyr and then use map2() function from the purrr package and a wrapper function to create the individual plots:

library(tidyverse)

pp <- function (n,r=4) {
  x <- seq(-r*pi, r*pi, len=n)
  df <- expand.grid(x=x, y=x)
  df$r <- sqrt(df$x^2 + df$y^2)
  df$z <- cos(df$r^2)*exp(-df$r/6)
  df
}
tmp <- pp(20)
tmp$type <- rep(1:4,each=nrow(tmp)/4)
tmp$z <- tmp$z*(10^(tmp$type))

plot_func <- function(df, name) {
  ggplot(data = df, aes(x = x, y = y, fill = z)) +
    geom_tile() +
    scale_fill_continuous(name = name)
}

nested_tmp <- tmp %>% 
  group_by(type) %>% 
  nest() %>% 
  mutate(plots = map2(data, type, plot_func)) 

gridExtra::grid.arrange(grobs = nested_tmp$plots)

Grid-plot of maps with different color scale

The nested dataframe contains two list-columns, which contain the datasets and plots:

> nested_tmp
# A tibble: 4 × 3
     type               data    plots
    <int>             <list>   <list>
  1     1 <tibble [100 × 4]> <S3: gg>
  2     2 <tibble [100 × 4]> <S3: gg>
  3     3 <tibble [100 × 4]> <S3: gg>
  4     4 <tibble [100 × 4]> <S3: gg>    

From here it is very easy to modify plot_func() to fine-tune the plots.

like image 178
emiltb Avatar answered Oct 19 '22 22:10

emiltb


One way to solve this problem is to standardize the fill variable, so that the scale is similar for all facets.

library(dplyr)
tmp1 <- group_by(tmp,type) # grouping the data by type
tmp2 <- mutate(tmp1, z1 = (z-mean(z))/sd(z)) #groupwise standardization 
ggplot(tmp2,aes(x,y))+geom_tile(aes(fill=z1))+facet_wrap(~type,scales="free")

I wish there were anything like fill=std(z) so that I don't have to manually standardize.

like image 21
Mahbubul Majumder Avatar answered Oct 20 '22 00:10

Mahbubul Majumder