Jen
Jen

Reputation: 355

Plotting multiple plots with two discrete variables - how to include all discrete variables in both axes

I have a dataset that looks like this:

test<-data.frame("M"=c("a","b","c","a","b","b","c","a","b","c"), 
                 "N"=c(1,3,4,6,6,7,7,8,8,8), 
                 "X"=c(0,1,0,1,1,0,1,0,1,1), 
                 "Y"=c(1,1,0,0,1,0,1,1,1,0))

I'm making a simple plot where I want X and Y on the y axis, M on the x axis, each grid colored if the value of X or Y is 1 and empty if the value of X or Y is 0. I'm repeating this for each categories in N (the categories of N are 1 to 5, 6, 7, 8), then stacking all plots together. Right now, I'm doing this with the following code.

test <- test[order(test$N),]
test1 <- test[c(1:3),]
test2 <- test[c(4:5),]
test3 <- test[c(6:7),]
test4 <- test[c(8:10),]   # I'm doing this to "separate" categories of `N` manually

p1 <- test1[,c(1,3:4)] %>%
  gather(col_name, value, -M) %>%
  ggplot(aes(factor(M), col_name, fill = value == 1))+
  geom_tile(colour = 'black')+
  scale_fill_manual(values = c('FALSE' = 'white', 'TRUE' = 'red'))
p2 <- test2[,c(1,3:4)] %>%
  gather(col_name, value, -M) %>%
  ggplot(aes(factor(M), col_name, fill = value == 1))+
  geom_tile(colour = 'black')+
  scale_fill_manual(values = c('FALSE' = 'white', 'TRUE' = 'yellow'))
p3 <- test3[,c(1,3:4)] %>%
  gather(col_name, value, -M) %>%
  ggplot(aes(factor(M), col_name, fill = value == 1))+
  geom_tile(colour = 'black')+
  scale_fill_manual(values = c('FALSE' = 'white', 'TRUE' = 'green'))
p4 <- test4[,c(1,3:4)] %>%
  gather(col_name, value, -M) %>%
  ggplot(aes(factor(M), col_name, fill = value == 1))+
  geom_tile(colour = 'black')+
  scale_fill_manual(values = c('FALSE' = 'white', 'TRUE' = 'blue'))

grid.arrange(p1, p2, p3, p4, ncol = 1)

the plot I have after running the code above

I'm attaching an image of what I have right now. I want to fix these plots so that I would have the same factors of M for all four plots (right now, only p1 and p4 have all three factors (a, b and c) in the x axis but I want to add factor c to p2 and a to p3 so that all x axes are identical to each other. Can anyone give me suggestions on how to do this?

(Also, I'm suspecting that the current way I'm plotting things is probably not the most quickest/easiest way to go, if anyone has suggestions on how to improve things it'd be really helpful!)

Upvotes: 3

Views: 304

Answers (3)

Duck
Duck

Reputation: 39613

Maybe one approach I can suggest you is using facets after applying a smart trick to group your values and avoid splitting in different dataframes. Here the code as an option for you (The colors will be the same across the facets in base of TRUE/FALSE values):

library(tidyverse)
#Code
test %>% mutate(Var=lead(N)) %>%
  mutate(Diff=Var-N,Diff=ifelse(row_number()==1,0,Diff)) %>%
  mutate(Group=ifelse(Diff==0,N,NA)) %>%
  fill(Group) %>% select(-c(N,Var,Diff)) %>%
  group_by(Group) %>% mutate(NG=paste0('p',cur_group_id())) %>% ungroup() %>%
  select(-Group) %>%
  pivot_longer(cols = -c(NG,M)) %>%
  ggplot(aes(factor(M), name, fill = value == 1,group=value))+
  geom_tile(colour = 'black')+
  facet_wrap(.~NG,ncol = 1)+
  scale_fill_manual('value',values=c('tomato','cyan3'))+
  xlab('M')

Output:

enter image description here

The othe option would be patchwork with a customized function:

library(tidyverse)
library(patchwork)
#Code
data <- test %>% mutate(Var=lead(N)) %>%
  mutate(Diff=Var-N,Diff=ifelse(row_number()==1,0,Diff)) %>%
  mutate(Group=ifelse(Diff==0,N,NA)) %>%
  fill(Group) %>% select(-c(N,Var,Diff)) %>%
  group_by(Group) %>% mutate(NG=paste0('p',cur_group_id())) %>% ungroup() %>%
  select(-Group) %>%
  mutate(M=factor(M,levels = unique(M),ordered = T)) %>%
  pivot_longer(cols = -c(NG,M))
#List
List <- split(data,data$NG)
#Function
myfun <- function(x)
{
  #Test for color
  val <- unique(x$NG)
  #Conditioning for color
  if(val=='p1') {vcolor=c('FALSE' = 'white', 'TRUE' = 'red')} else
    if(val=='p2') {vcolor=c('FALSE' = 'white', 'TRUE' = 'yellow')} else
      if(val=='p3') {vcolor=c('FALSE' = 'white', 'TRUE' = 'green')} else
      {vcolor=c('FALSE' = 'white', 'TRUE' = 'blue')}
  #Update data
  x <- x %>% mutate(M=factor(M,levels = c('a','b','c'),ordered = T)) %>% complete(M=M)
  #Plot
  G <- ggplot(x,aes(factor(M), name, fill = (value == 1 & !is.na(value))))+
    geom_tile(colour = 'black')+
    scale_fill_manual('value',values=vcolor)+
    xlab('M')+
    scale_y_discrete(limits=c('X','Y'))+
    theme_bw()+
    ggtitle(val)
  return(G)
}
#Apply
Lplot <- lapply(List,myfun)
#Wrap
GF <- wrap_plots(Lplot,ncol = 1)

Output:

enter image description here

Upvotes: 0

Johan
Johan

Reputation: 828

Something like this?

test<-data.frame("M"=c("a","b","c","a","b","b","c","a","b","c"), 
                 "N"=c(1,3,4,6,6,7,7,8,8,8), 
                 "X"=c(0,1,0,1,1,0,1,0,1,1), 
                 "Y"=c(1,1,0,0,1,0,1,1,1,0))

library(tidyverse)

test = mutate(test, N2 = cut(N, breaks = c(0,5:100)))    
m = pivot_longer(test, c(X, Y))

ggplot(m, aes(M, name,fill=factor(value))) +
    geom_tile(colour = 'black') +
    facet_wrap(~N2, scales = 'free') +
    scale_fill_manual(values = c(`0` = 'white', `1` = 'red'))

Upvotes: 0

Ben Norris
Ben Norris

Reputation: 5747

To continue using grid.arrange(), instead of facet_wrap(), do the following:

Make M a factor:

test$M <- factor(test$M)

Add the following to each of your plots:

scale_x_discrete(limits = levels(test$M))

enter image description here

Upvotes: 1

Related Questions