1

I would like to generate a heatmap with specific cells having an overlaid strikethrough, or some other simple pattern on the cell. I would like to achieve the same results as in this question (ggplot2 geom_tile diagonal line overlay) however I am not able to reproduce this solution, as I am very much struggling to follow the solution's code after geom_segment().

Here's some example data for a data frame:

GN  a   b
willy   -1.58215    -2.53036
wee 0.611129    0.485053
waffy   1.580719    0.857198

and the code for the heatmap:

library(tidyr)
library(ggplot2)
legend_title <- "log(z/w)"
pivot_longer(df, 2:3) %>%
    ggplot(aes(name, GN, fill=value)) +
    geom_tile(color = 'black') +
    scale_x_discrete(expand = c(0, 0)) +
    scale_y_discrete(expand = c(0, 0)) + 
    coord_equal() +
    theme(axis.title.x = element_blank(),
          axis.title.y = element_blank(),
          axis.ticks.x = element_blank(),
          axis.text.x = element_blank(),
          axis.text.y = element_text(color = 'black', face = 'bold')) +
    scale_fill_gradient2(legend_title, low = "blue", mid = "white", high = "red")

This should produce the following heatmap:

enter image description here

I would like to be able to specify, for example, the left cell of row waffy and the right cell of wee to be stricken through. It would be even better if there are design options for this, for example having three colored diagonal strikethroughs.

Many thanks for any help.

Z.Lin
  • 28,055
  • 6
  • 54
  • 94

1 Answers1

1

Starting with the original plot, p.

library(tidyverse)

df <- tibble(
  GN = c("willy", "wee", "waffy"),
  a = c(-1.58215, 0.611129, 1.580719),
  b = c(-2.53036, 0.485053, 0.857198)
)


p <-
  ggplot(pivot_longer(df, 2:3), aes(name, GN, fill=value)) +
  geom_tile(color = 'black') +
  scale_x_discrete(expand = c(0, 0)) +
  scale_y_discrete(expand = c(0, 0)) + 
  coord_equal() +
  theme(axis.title.x = element_blank(),
        axis.title.y = element_blank(),
        axis.ticks.x = element_blank(),
        axis.text.x = element_blank(),
        axis.text.y = element_text(color = 'black', face = 'bold')) +
  scale_fill_gradient2("log(z/w)", low = "blue", mid = "white", high = "red")

add_strikes takes a plot and adds strikes to the specified cells.

add_strikes <- function(p, cell, color, n_lines, thickness) {
  strike_df <- tibble(cell, color, n_lines, thickness)
  
  data <-
    ggplot_build(p)$data[[1]] %>%
    rownames_to_column("cell") %>%
    inner_join(uncount(strike_df, n_lines)) %>%
    group_by(cell) %>%
    mutate(
      x = pmax(xmin - (xmax - xmin) + row_number() * 2 * (xmax - xmin) / (n() + 1), xmin),
      y = pmax(ymax - row_number() * 2 * (ymax - ymin) / (n() + 1), ymin),
      xend = pmin(xmin + row_number() * 2 * (xmax - xmin) / (n() + 1), xmax),
      yend = pmin(ymax + (ymax - ymin) - row_number() * 2 * (ymax - ymin) / (n() + 1), ymax)
    )
  p + geom_segment(
    data = data, 
    aes(x, y, xend = xend, yend = yend, color = I(color), size = I(thickness)), 
    inherit.aes = FALSE,
    show.legend = FALSE
  )
}

Specify how you want the strikes to look.

add_strikes(
  p,
  cell = c("4", "5"),
  color = c("black", "#ebb734"),
  n_lines = c(3, 6),
  thickness = c(0.8, 0.2)
)

strikes

Paul
  • 8,734
  • 1
  • 26
  • 36