1
votes

I am trying to assign different colour scales to my dataset based on the column variable. The dummy code is

df1 <- data.frame(ID = c('a1', 'b1', 'c1', 'd1', 'e1', 'f1'),
                  var1 = c('a', 'b', 'c', 'a', 'b', 'c'),
                  var2 = c(0.006, 0.04, .005, 0, 0.02, 0.05))

Instead of an overall colour scale, I want 'a' from var1 to be red to white, 'b'blue to white, and 'c' as purple to white. I have 4000 rows in my actual data, I tried to nest each on top of each other, but failed.. the running is below. Please suggest where do I need to make the changes to get my desired output.

P.S.I know, the var2 will have different high's and lows, if legend is available, great, otherwise I just need to show color differences.

ggplot(df1,aes(y = var1, x = ID, fill = var2)) +
  geom_tile(color = "white") +
  coord_equal() +
  scale_fill_gradient(low = "steelblue", high = "white") +
  ylab("var1") +
  xlab("ID") +
  theme(legend.title = element_text(size = 10),
        legend.text = element_text(size = 12),
        plot.title = element_text(size = 16),
        axis.title = element_text(size = 14, face = "bold"),
        axis.text.x = element_text(angle = 90, hjust = 1)) +
  labs(fill = "ABC association") 
1
ggplot2 does not permit multiple scales of a single type (i.e. multiple colour or fill scales). If you really want the desired behavior you will need to play with grobs, grids etc.missuse

1 Answers

2
votes

If you want each colour scale to take on a gradient between a specific colour and white, you can fake it by assigning a different colour to each var1 value, and vary the transparency based on var2. Here's an illustration, though of course you can vary the details depending on how you want the results to appear:

Step 1. Define the colour for each var1 value.

color.scale <- c("a" = "red", "b" = "blue", "c" = "purple")

Step 2. Scale the range of var2 values within each var1 category to a common range.

library(dplyr)

df2 <- df1 %>%
  group_by(var1) %>%
  mutate(var2.alpha = scale(var2)) %>%
  ungroup() %>%
  arrange(var1)

> df2
# A tibble: 6 x 4
  ID     var1      var2 var2.alpha
  <fctr> <fctr>   <dbl>      <dbl>
1 a1     a      0.00600      0.707
2 d1     a      0           -0.707
3 b1     b      0.0400       0.707
4 e1     b      0.0200      -0.707
5 c1     c      0.00500     -0.707
6 f1     c      0.0500       0.707

Step 3. Create your plot. The first white geom_tile() provides a "backing" for the coloured tile layer, so that background elements (panel colour, grid lines, etc) don't show up within the tiles.

p.plot <- ggplot(df2,
       aes(x = ID, y = var1, fill = var1, alpha = var2.alpha)) +
  geom_tile(fill = "white", alpha = 1) +
  geom_tile() +
  scale_fill_manual(values = color.scale) +
  scale_alpha(range = c(0.1, 0.9)) +
  coord_equal() +
  theme_light() +
  theme(legend.position = "none")

p.plot

Step 4. Create a separate plot to serve as the legend.

df3 <- df2 %>% group_by(var1) %>% 
  summarise(min = min(var2), max = max(var2)) %>%
  mutate(tile.1 = 0.1, tile.3 = 0.3, tile.5 = 0.5, tile.7 = 0.7, tile.9 = 0.9) %>%
  tidyr::gather(tile, value, -var1, -min, -max)
p.legend <- ggplot(df3, aes(x = value, y = var1, fill = var1, alpha = value)) +
  geom_tile() +
  geom_text(aes(label = var1), x = -0.1) +
  geom_text(aes(label = min), x = 0.1) +
  geom_text(aes(label = max), x = 0.9, color = "white") +
  ggtitle("ABC association") +
  coord_cartesian(xlim = c(-0.2, 1.1)) +
  scale_fill_manual(values = color.scale) +
  scale_alpha_identity() +
  theme_void() +
  theme(legend.position = "none")

p.legend

Step 5. Combine the two, allocating more space to the main plot.

cowplot::plot_grid(p.plot, p.legend, 
                   ncol = 1, align = "v", 
                   rel_heights = c(5, 1))

combined plot