Search code examples
rheatmapcorrelationgeom-raster

Why geom_raster() is not displaying the good columns orders in my heatmap?


I'm using a double triangular matrix (10x10) representing 2 types of correlations between these variables. The dataset is like this one (4x4).

ff <- data.frame(Var1=as.factor(c("V1", "V2", "V3","V4", "V1", "V2", "V3","V4", "V1", "V2", "V3","V4", "V1", "V2","V3","V4")),
                 Var2=as.factor(c("V1", "V1", "V1", "V1", "V2", "V2", "V2", "V2", "V3", "V3","V3","V3", "V4", "V4", "V4","V4")),
                 value=c(NA, 0.1, 0.2, 0.2, 
                         0.4, NA, 0.3, 0.4, 
                         0.5, 0.5, NA, 0.3,
                         0.2, 0.3, 0.3, NA))

I then used the geom_raster function from ggplot2 to get 2 colors scales (1 for each triangular matrix) + color for the identity diagonal in grey (ie correlation btw the same variable which does not exist (NA)). I used the same code than in a previous post (Single heatmap on two symetric matrices with different colours and scales R)

ggplot(ff, aes(Var1, Var2)) +
  # The first layer, with its own fill scale
  geom_raster(
    data = ~ subset(.x, as.numeric(Var1) > as.numeric(Var2)),
    aes(fill = value)
  ) +
  scale_fill_distiller(palette = "Blues") +
  # Declare new fill scale for the second layer
  new_scale_fill() +
  geom_raster(
    data = ~ subset(.x, as.numeric(Var1) < as.numeric(Var2)),
    aes(fill = value)
  ) +
  scale_fill_distiller(palette = "Reds", direction=-1) +
  # I'm not sure what to do with the diagonal. Make it grey?
  new_scale_fill() +
  geom_raster(
    data = ~ subset(.x, as.numeric(Var1) == as.numeric(Var2)),
    aes(fill = value)
  ) +
  scale_fill_distiller(palette = "Greys", guide = "none")

However, I'm a little disappointed because as you can see in the output I have (below) there is a problem in the final display of the graph I get :

heatmap obtained where the last column appearing should be the 1st one I would expect

As you can see what I expected to be the 1st column is now the last one and I don't know what to do. I tried to reorder the levels of the factor variable but it did not solve the problem. I would be very grateful if someone could help me for this challenge (for me !)

Many thanks in advance!


Solution

  • The problem comes from when you plot the first part of the heatmap (Var1 > Var2). In that case, Var1 (x-axis) starts at V2. And then when you plot the second, because the x-axis is discrete it goes to the right and V1 goes to the right.

    First a hacky way would be to plot a grey (or whatever color you want) heatmap as a background and then plot the triangular heatmaps:

    ggplot(ff, aes(Var1, Var2)) +
        geom_raster(fill = "darkgrey") +
        # The first layer, with its own fill scale
        geom_raster(
            data = ~ subset(.x, as.numeric(Var1) > as.numeric(Var2)),
            aes(fill = value)
        ) +
        scale_fill_distiller(palette = "Blues") +
        # Declare new fill scale for the second layer
        new_scale_fill() +
        geom_raster(
            data = ~ subset(.x, as.numeric(Var1) < as.numeric(Var2)),
            aes(fill = value)
        ) +
        scale_fill_distiller(palette = "Reds", direction=-1)
    

    The second way would be to reorder your x-axis with scale_x_discrete:

    ggplot(ff, aes(Var1, Var2)) +
        # The first layer, with its own fill scale
        geom_raster(
            data = ~ subset(.x, as.numeric(Var1) > as.numeric(Var2)),
            aes(fill = value)
        ) +
        scale_fill_distiller(palette = "Blues") +
        # Declare new fill scale for the second layer
        new_scale_fill() +
        geom_raster(
            data = ~ subset(.x, as.numeric(Var1) < as.numeric(Var2)),
            aes(fill = value)
        ) +
        scale_fill_distiller(palette = "Reds", direction=-1) +
        scale_x_discrete(limits = c("V1", "V2", "V3", "V4"))
    

    Sorry I lost the diagonal part, it didn't work on my computer, but with first example you can customize the color of the background that will end on the diagonal.

    I hope this answers your problem.