Search code examples
rggplot2plotstacked-bar-chart

How can I combine two plots that share the same x-axis seamlessly, one is stacked bar plot and the other is line+point plot


This is an R-related question about plotting, I hope to be received some helps, I have the following data

library(ggplot2)
library(ggpubr)
library(egg)

minor_count_vec <- c(6, 95, 57, 22, 6, 0)
major_count_vec <- c(4, 147, 65, 34, 2, 2)
time_vec_temp <- c(2500, 5000, 7500, 10000, 12500, 15000)
maf_vec <- c(0.6, 0.4, 0.5, 0.4, 0.7, 0)

# First data for stacked bar plot
plot_data_bar <- data.frame(minor_count_vec,major_count_vec,time_vec_temp)
colnames(plot_data_bar) <- c("C","T","Year")

# Reshape the above data to produce the stacked bar plot:
plot_data_bar_long <- reshape2::melt(plot_data_bar, id.vars= "Year", variable.name = "Allele", value.name = "Count")

# Second data for line plot
plot_data_line <- data.frame(maf_vec,time_vec_temp)
colnames(plot_data_line) <- c("MAF","Year")

I want to use those data to produce a plot that look similar to this picture (sorry for the quality)

Sample plot

As you can see the plot has two separated plot, the line (and point) plot on the top (ignoring the blue, green square and their lines) and the stacked bar plot at the bottom.

Two plots are seamlessly connected because they share the same x-axis, and here is attempt to produce a some what similar plot.

plot1 <- ggplot()+
  geom_point(data=plot_data_line, aes(x = Year, y = MAF))+
  geom_line(data=plot_data_line, aes(x = Year, y = MAF))+
  theme_classic()+
  scale_x_reverse() + theme(axis.title.x = element_blank(), axis.text.x = element_blank())

plot2 <- ggplot()+
  geom_bar(data=plot_data_bar_long,stat = "identity", aes(x=Year,y=Count,fill=Allele)) + 
  scale_fill_manual(values = c("C"="green","T"="blue")) +
  scale_x_reverse() +
  scale_y_reverse() +
  theme_classic() + theme(legend.position = "none") 

# Attempt 1 
plot3 <- ggarrange(plot2,plot1,nrow=2,ncol=1)

# Attempt 2
egg::ggarrange(plot2, plot1, heights = c(0.25, 0.4))

Attempt 1

The problem with this one is the x-axis is not connected between two plots, and each points are not in the middle of the bar that corresponded to their value. (You can see that the x-axis between two plots are also kinda off.

Attempt 2

In attempt 2 is basically the same but the ratio between two plot is kinda similar to the sample plot.


# Modify the plot_data_line
plot_data_line_modify <- plot_data_line
plot_data_line_modify$MAF <- -100*plot_data_line_modify$MAF

# Attempt 3
plot4 <- ggplot()+
  geom_bar(data=plot_data_bar_long,stat = "identity", aes(x=Year,y=Count,fill=Allele)) + 
  scale_fill_manual(values = c("C"="green","T"="blue")) +
  scale_x_reverse() +
  scale_y_reverse() +
  theme_classic() + theme(legend.position = "none") +
  geom_point(data=plot_data_line_modify, aes(x = Year, y = MAF))+
  geom_line(data=plot_data_line_modify, aes(x = Year, y = MAF))

Attempt 3

In attempt 3 the line + point plot is now in the middle but there is no axis value on the top one. And also have to add the missing MAF label on the y axis.

My final question is : is there some kind of modification/method/addition of code/ect that I should use/do in order to mimic the sample plot.

Thank you in advance!

I've made three attempt as I described above, try 3 types of plotting.


Solution

  • plot1 <- ggplot()+
      geom_point(data=plot_data_line, aes(x = Year, y = MAF))+
      geom_line(data=plot_data_line, aes(x = Year, y = MAF))+
      theme_classic()+
      scale_x_reverse(expand = expansion(add = c(1625, 1625))) +
      scale_y_continuous(expand = expansion(mult = c(0, 0.05))) +
      theme(axis.title.x = element_blank(), axis.text.x = element_blank()) +
      theme(axis.ticks.length.x = unit(0, "cm")) +
      theme(plot.margin = unit(c(0,0,0,0), "cm"))
    
    # Part of the trickiness here is that padding works differently 
    # for points/lines vs. bars, which have width around the data point. 
    # So if we want our points to be aligned with our bars, we need to tweak that.
    # To estimate what this should be, I note that the Year resolution is 2500, the
    # bars will be 90% of that width (2,250), so each side of the bar extends 1,125 
    # beyond the range that the points need. So I add 1,125 to the point padding.
    
    plot2 <- ggplot()+
      geom_bar(data=plot_data_bar_long,stat = "identity", aes(x=Year,y=Count,fill=Allele)) + 
      scale_fill_manual(values = c("C"="green","T"="blue")) +
      scale_x_reverse(expand = expansion(add = c(500, 500))) +
      scale_y_reverse(expand = expansion(mult = c(0.05, 0))) +
      theme_classic() + theme(legend.position = "none") +
      theme(plot.margin = unit(c(0,0,0,0), "cm"))
    
    
    ggarrange(plot1, plot2, nrow = 2)
    

    enter image description here