rggplot2plotfiguremirroring

Mirror two PheWAS plots with ggplot2


I have two PheWAS plots, and the number of categories (x axis, 20 categories) is the same in case of both. I would like to put them on the same plot, mirroring one of them on the y axis, but leaving the x axis titles in the middle.

Example data:

dataset1 <- data.frame(
  chr = c(1, 3, 5, 6, 7, 2, 8, 3, 6, 4, 6, 3),
  pos = c(445578, 659990, 789689, 678599, 97890, 67899, 9867647, 675890, 799030, 8609000, 789900, 90907878),
  p = c(0.05, 0.34, 0.55, 0.05, 0.67, 0.01, 0.34, 0.55, 0.76, 0.88, 0.12, 0.22),
  description = factor(c("Metabolic", "Metabolic", "Immunological", "BodyStructures", "Cardiovascular", "Hematological", "Nutritional", "Environment", "Psychiatric", "Cognitive", "Musculoskeletal", "Opthalmological"))
)

dataset2 <- data.frame(
  chr = c(1, 3, 5, 6, 7, 2, 8, 3, 6, 4, 6, 3),
  pos = c(444358, 647389, 76379, 64789, 1456378, 5647839, 452678, 65789, 657839, 3562789, 15367384, 2647489),
  p = c(5e-05, 0.4554, 0.003, 0.6789, 0.6783, 0.00568, 0.789, 0.7799, 0.00457, 0.7899, 0.35678, 0.3678),
  description = factor(c("Metabolic", "Metabolic", "Immunological", "BodyStructures", "Cardiovascular", "Hematological", "Nutritional", "Environment", "Psychiatric", "Cognitive", "Musculoskeletal", "Opthalmological"))
)

To create my two plots I use the following script:

Plot 1:

library(ggplot2)
library(RColorBrewer)

colourCount <- length(unique(dataset1$description))
getPalette <- colorRampPalette(brewer.pal(9, "Set1"))

PheWAS_1 <- ggplot(dataset1, aes(x=description, y=-log(p), colour = description)) + 
  geom_jitter(mapping=aes(x=as.factor(description), y=-log10(p))) +
  theme_classic() + 
  scale_colour_manual(values = getPalette(colourCount)) +
  theme(axis.text.x=element_text(angle = 75, vjust = 0.5, hjust=1, size = 10, margin=margin(-30,0,0,0))) + 
  labs(color="description", size="Effect size", x="Phenotype Group", y="-log10(p-value)") +
  geom_hline(yintercept=-log10(7.45E-07), color="gray32", linetype="dashed", size=1, alpha=0.5)+
  theme(legend.position = "none") +
  theme(axis.title.x = element_text(margin = margin(40, 0, 0, 0)))

Plot 2:

colourCount <- length(unique(dataset2$description))
getPalette <- colorRampPalette(brewer.pal(9, "Set1"))

PheWAS_2 <- ggplot(dataset2, aes(x=description, y=-log(p), colour = description)) + 
  geom_jitter(mapping=aes(x=as.factor(description), y=-log10(p))) +
  theme_classic() + 
  scale_colour_manual(values = getPalette(colourCount)) +
  theme(axis.text.x=element_text(angle = 75, vjust = 0.5, hjust=1, size = 10, margin=margin(-30,0,0,0))) + 
  labs(color="description", size="Effect size", x="Phenotype Group", y="-log10(p-value)") +
  geom_hline(yintercept=-log10(2.83E-06), color="gray32", linetype="dashed", size=1, alpha=0.5)+
  theme(legend.position = "none") +
  theme(axis.title.x = element_text(margin = margin(40, 0, 0, 0)))

I added an example image, I would like to make a similar one, but with my colours and my titles in between of the two figures.

Example image


Solution

  • Flipping the 2nd plot

    To achieve this, we need to add two functions:

    Fixing the y-axis limits

    It would be best to keep the same y-axis limits for both plots, to make them comparable. As such, we have to supply ylim() to the first plot. For the second plot, we already have scale_y_reverse, so we can supply our limits there.

    Fixing the x labels

    Since you only want the labels to appear once, you'd have to use element_blank() for theme(axis.text.x) and theme(axis.title.x) in the 2nd plot. Similarly, I would remove the x-axis title in the first plot to keep it balanced.

    Combining the plots

    Now, you want to combine the plots. However, the first plot has a lot of information on the x-axis, while the second plot doesn't. This means they have different heights. I like to use cowplot::plot_grid for combining plots, because it allows you to set the relative height of the plots. In this case, we can use it to account for the height difference between the two plots.

    Final code

    PheWAS_1 <- ggplot(dataset1, aes(x = description, y = -log(p), colour = description)) + 
      geom_jitter() +
      theme_classic() + 
      scale_colour_manual(values = getPalette(colourCount)) +
      theme(axis.text.x = element_text(angle = 90, vjust = 0.5, hjust = 0, size = 10),
            axis.title.x = element_blank(),
            legend.position = "none") + 
      labs(color = "description", size = "Effect size", x = "", y = "-log10(p-value)") +
      ylim(c(0, 10)) +
      geom_hline(yintercept = -log10(7.45E-07), color = "gray32", linetype = "dashed", size = 1, alpha = 0.5)
    
    
    PheWAS_2 <- ggplot(dataset2, aes(x = description, y = -log(p), colour = description)) + 
      geom_jitter() +
      theme_classic() + 
      scale_colour_manual(values = getPalette(colourCount)) +
      theme(axis.text.x = element_blank(),
            axis.title.x = element_blank(),
            legend.position = "none") + 
      labs(color = "description", size = "Effect size", x = "Phenotype Group", y = "-log10(p-value)") +
      scale_y_reverse(limits = c(10, 0)) +
      scale_x_discrete(position = "top") +
      geom_hline(yintercept = -log10(2.83E-06), color = "gray32", linetype = "dashed", size = 1, alpha = 0.5)
    
    cowplot::plot_grid(PheWAS_1, PheWAS_2, ncol = 1, rel_heights = c(1, 0.75))
    

    enter image description here

    Final note

    The way that you set up your code is that you introduce jitter. This is not a good approach, since ideally the peaks would match between the two plots. You may be better off assigning every row a position on the x-axis.