Search code examples
rggplot2heatmapdendrogram

How to export properly scaled Heatmap and Dendogram Plot in R ggplot2


I was trying this (https://jcoliver.github.io/learn-r/008-ggplot-dendrograms-and-heatmaps.html) tutorial for making heatmap and dendrogram using ggplot2. Data can be found here: https://jcoliver.github.io/learn-r/data/otter-mandible-data.csv .

However, when I try to export high-resolution image,

jpeg(file="HeatDendoTest02.jpeg", units="mm", width=775, height=638, res=300)
grid.newpage()
print(heatmap_plot, 
      vp = viewport(x = 0.4, y = 0.5, width = 0.8, height = 1.0))
print(dendro_plot, 
      vp = viewport(x = 0.90, y = 0.43, width = 0.2, height = 0.92))
dev.off()

The arrangement of Dendogram is not properly fitting with the Heatmap, I'm wondering how can I fix this issue.

# Cluster & heatmap on otter data
# Jeff Oliver
# [email protected]
# 2017-08-15

################################################################################

# Load dependencies
library("ggplot2")
library("ggdendro")
library("tidyr")
library("grid")

# Read in data
otter <- read.csv(file = "data/otter-mandible-data.csv",
                  stringsAsFactors = TRUE)

# Restrict the data to only two species, A. cinerea & L. canadensis
two_species <- c("A. cinerea", "L. canadensis")
otter <- otter[otter$species %in% two_species, ]

# Force re-numbering of the rows after subsetting
rownames(otter) <- NULL

# Scale each measurement (independently) to have a mean of 0 and variance of 1
otter_scaled <- otter
otter_scaled[, c(4:9)] <- scale(otter_scaled[, 4:9])

# Run clustering
otter_matrix <- as.matrix(otter_scaled[, -c(1:3)])
rownames(otter_matrix) <- otter_scaled$accession
otter_dendro <- as.dendrogram(hclust(d = dist(x = otter_matrix)))

# Create dendrogram plot
dendro_plot <- ggdendrogram(data = otter_dendro, rotate = TRUE) + 
  theme(axis.text.y = element_text(size = 6))

# Heatmap

# Data wrangling
otter_long <- pivot_longer(data = otter_scaled,
                           cols = -c(species, museum, accession),
                           names_to = "measurement",
                           values_to = "value")
# Extract the order of the tips in the dendrogram
otter_order <- order.dendrogram(otter_dendro)
# Order the levels according to their position in the cluster
otter_long$accession <- factor(x = otter_long$accession,
                               levels = otter_scaled$accession[otter_order], 
                               ordered = TRUE)

# Create heatmap plot
heatmap_plot <- ggplot(data = otter_long, aes(x = measurement, y = accession)) +
  geom_tile(aes(fill = value)) +
  scale_fill_gradient2() +
  theme(axis.text.y = element_blank(),
        axis.title.y = element_blank(),
        axis.ticks.y = element_blank(),
        legend.position = "top")

# All together
grid.newpage()
print(heatmap_plot, 
      vp = viewport(x = 0.4, y = 0.5, width = 0.8, height = 1.0))
print(dendro_plot, 
      vp = viewport(x = 0.90, y = 0.43, width = 0.2, height = 0.92))

After exporting the plot, the dendrogram does not match with the heatmap. enter image description here


Solution

  • Here is an option using patchwork to glue your plots together before exporting. Nonetheless, to align the dendrogram with the heat map still requires some additional effort, i.e. we need the same expansion for the y scale using scale_x_continuous (x because of rotate=TRUE). Additionally, when doing so we also have to set the breaks= and labels= .

    Note: I use ggsave for exporting and set scale=.33 to make the text readable.

    library(ggplot2)
    library(patchwork)
    
    dendro_plot <- dendro_plot +
      scale_x_continuous(
        breaks = seq_along(levels(otter_long$accession)),
        labels = levels(otter_long$accession),
        # Set the same expansion as for the heatmap
        expand = c(0, .6)
      )
    
    heatmap_plot + dendro_plot +
      plot_layout(widths = c(.8, .2))
    
    ggsave(
      "HeatDendoTest02.jpeg",
      units = "mm", width = 775,
      height = 638, dpi = 300,
      scale = .33
    )
    

    enter image description here