Jakeeln
Jakeeln

Reputation: 353

R ggplot heatmap with multiple rows having separate legends on the same graph

I'm trying to make one heatmap using ggplot2 that contains 3 types of variables where each need their own independent legend/scale.

I am able to plot them all in one heatmap (pictured below), but I am having trouble separating them to have their own legend. My three categories are the row "Score", "samp1" and the rest of the data. I would like each of these to have their own independent legends with their respective ranges.

My only addition would be to have the row score have a green,yellow,red (low, mid,high) color scheme, if that is possible to include in this question.

an image of what I have so far

This is the code I am using to create that graph

library(ggplot2)
test_data <- read.csv("test_table.csv", row.names = 1)

ggplot(test_data, aes(x=sample, y=id, fill = value)) + 
  geom_raster() + 
  theme(axis.text.x = element_text(angle = 90, vjust = 0.5, hjust=1), # lables vertical
        strip.text.y = element_blank()) +  #remove facet bar on y 
  scale_fill_gradient(low = "darkblue", high = "lightblue") +
  ggtitle("test table") +
  facet_grid(rows = vars(test_data$category), 
             cols = vars(test_data$group), scales = "free", space="free_y") #facets to add gaps 

I have used facets to separate the data by sample and by the 3 categories I described above. I was hoping to use this grouping to create their own legends as well, but I am not sure if this is possible.

Click here to download the data (pre-melted).

Thank you in advance.

Upvotes: 8

Views: 6712

Answers (3)

Allan Cameron
Allan Cameron

Reputation: 174641

It's certainly possible to make 3 plots and stick them together, but given the facets are different shapes, this isn't ideal. You could use the ggnewscale package as per Stefan, which is easier now it is on CRAN, but if you want to do it in a single ggplot without add-ons it is possible. You just need to plot a geom_point that is made of large solid squares. This allows you to use a colour scale as well as a fill scale.

ggplot(test_data, aes(x=sample, y=id, fill = value)) + 
  geom_raster() + 
  geom_point(aes(alpha = id, colour = value), size = 12, shape = 15) +
  theme(axis.text.x = element_text(angle = 90, vjust = 0.5, hjust=1),
        strip.text.y = element_blank()) + 
  scale_fill_gradient(low = "darkblue", high = "lightblue") +
  ggtitle("test table") +
  facet_grid(rows = vars(test_data$category), 
             cols = vars(test_data$group),  scales = "free", space = "free_y") +
  scale_alpha_manual(values = c(rep(0, 19), 1, 0, 0), guide = guide_none()) +
  scale_color_gradientn(colours = c("red", "orange", "gold", "yellow"))

enter image description here

Upvotes: 1

Duck
Duck

Reputation: 39623

I would suggest next approach. Split data by groups and then build a separate plot for each group with a function. Finally use purrr and patchwork to join all plots with the diferent legends. Here the code:

library(purrr)
library(ggplot2)
library(patchwork)
#Load data
test_data <- read.csv("test_table.csv", row.names = 1)
#Split into list
List <- split(test_data,test_data$group)
#Function for plots
myfun <- function(x)
{
  G <- ggplot(x, aes(x=sample, y=id, fill = value)) + 
    geom_raster() + 
    theme(axis.text.x = element_text(angle = 90, vjust = 0.5, hjust=1), # lables vertical
          strip.text.y = element_blank()) +  #remove facet bar on y 
    scale_fill_gradient(low = "darkblue", high = "lightblue") +
    facet_grid(rows = vars(x$category), 
               cols = vars(x$group), scales = "free", space="free_y")
  return(G)
}
#Apply
List2 <- lapply(List,myfun)
#Plot
reduce(List2, `+`)+plot_annotation(title = 'My plot')

The output:

enter image description here

You can explore further about patchwork and how to join multiple plots.

Upvotes: 3

stefan
stefan

Reputation: 125897

This could be achieved via the ggnewscale package like so:

library(ggplot2)
library(dplyr)
library(ggnewscale)

ggplot() +
  geom_raster(data = filter(test_data, category == "1 score"), aes(x = sample, y = id, fill = value)) +
  scale_fill_gradient2(low = "green", mid = "yellow", high = "red", midpoint = 4, name = "Score") +
  new_scale_fill() +
  geom_raster(data = filter(test_data, category == "2 samp1"), aes(x = sample, y = id, fill = value)) +
  scale_fill_gradient(low = "darkblue", high = "lightblue", name = "Sample1") +
  new_scale_fill() +
  geom_raster(data = filter(test_data, category == "3 samp2"), aes(x = sample, y = id, fill = value)) +
  scale_fill_gradient(low = "darkblue", high = "lightblue", name = "Sample2") +
  ggtitle("test table") +
  facet_grid(
    rows = vars(category),
    cols = vars(group), scales = "free", space = "free_y"
  ) +
  theme(
    axis.text.x = element_text(angle = 90, vjust = 0.5, hjust = 1),
    strip.text.y = element_blank()
  )

Upvotes: 6

Related Questions