1

I'm looking for a way to produce a diagonal slash from the bottom left the to top right corner of a cell within a plot made using geom_tile.

The input is a melted data frame with two categorical factor columns, sample and gene. I'd like to use something like geom_segment, but I'm not able to specify fractional increments. Any ideas on the best way to accomplish this?

edit: Here is a reproducible example, I can't share one from my own data, as it's protected patient information.

df <- data_frame( gene     = c('TP53','TP53','MTOR','BRACA1'),
                  sample   = c('A','B','A','B'),
                  diagonal = c(FALSE,TRUE,TRUE,FALSE),
                  effect   = c('missense', 'nonsense', 'missense', 'silent') )

 ggplot(df, aes(sample, gene)) + geom_tile(aes(fill = effect))

example no diagonal

what I'm looking for:

example no diagonal

Sam Hart
  • 109
  • 1
  • 5
  • This is an interesting question, I'd upvote if you'd share a little data via simulation or `dput()` to make [a nice reproducible example](http://stackoverflow.com/q/5963269/903061). – Gregor Thomas May 11 '16 at 22:36

3 Answers3

1

One way to do it:

library(ggplot2)
df <- data.frame(
  x = rep(c(2, 5, 7, 9, 12), 2),
  y = rep(c(1, 2), each = 5),
  z = factor(1:10),
  w = rep(diff(c(0, 4, 6, 8, 10, 14)), 2)
)
p <- ggplot(df, aes(x, y)) + geom_tile(aes(fill = z))
gb <- ggplot_build(p)
p + geom_segment(data=gb$data[[1]][1:2, ], 
                 aes(x=xmin, xend=xmax, y=ymin, yend=ymax), 
                 color="white")

enter image description here


In your example, could also rely on the indices of the factor levels like this:

library(ggplot2)
df <- data.frame( gene     = c('TP53','TP53','MTOR','BRACA1'),
                  sample   = c('A','B','A','B'),
                  diagonal = c(FALSE,TRUE,TRUE,FALSE),
                  effect   = c('missense', 'nonsense', 'missense', 'silent') )
df$cross <- c(F,T,T,F)
ggplot(df, aes(sample, gene)) + 
  geom_tile(aes(fill = effect)) + 
  geom_segment(data=transform(subset(df, !!cross), sample=as.numeric(sample), gene=as.numeric(gene)), 
               aes(x=sample-.49, xend=sample+.49, y=gene-.49, yend=gene+.49), 
               color="white", size=2)

(Note that I used data.frame and not dplyr::data_frame, so that both columns become factors.)

enter image description here

If you want a legend:

ggplot(df, aes(sample, gene)) + 
  geom_tile(aes(fill = effect)) + 
  geom_segment(data=transform(subset(df, !!cross), sample=as.numeric(sample), gene=as.numeric(gene)), 
               aes(x=sample-.49, xend=sample+.49, y=gene-.49, yend=gene+.49, color=cross), 
               size=2) + 
  scale_color_manual(values=c("TRUE"="white", "FALSE"=NA))

enter image description here

lukeA
  • 53,097
  • 5
  • 97
  • 100
  • Thank you very much for your response. It's not quite as robust as I'd like, since the grob object is subject to change based on the plot context. I've upvoted, but I'd like to see if I can solicit something a bit more straightforward if possible. – Sam Hart May 13 '16 at 03:16
  • You're welcome. I the example, I just read from the grob object, where each tile starts and ends. I agree it's not very elegant. In your case, you could also use the indices of the factor levels. See my edit. – lukeA May 13 '16 at 08:47
  • That's perfect, thank you so much! I was trying to do this with factor levels and couldn't quite get it. Great solution. – Sam Hart May 13 '16 at 16:17
1

You can use geom_abline. You can tweak intercept and slope to get what you want. More info and examples here.

ggplot(df, aes(sample, gene)) + 
  geom_tile(aes(fill = effect)) +
  geom_abline(intercept = 1, slope = 1, color="white", size=2)

enter image description here

rafa.pereira
  • 13,251
  • 6
  • 71
  • 109
0

If you don't actually want specific lines, but just want to highlight, you can simply draw dots:

ggplot(df, aes(sample, gene)) + geom_tile(aes(fill = effect)) +
    geom_point(aes(sample, gene))

You can make it look like a line: geom_point(aes(sample, gene), shape='/', size=10, color='white')

To have the lines be only on some tiles, simply pass only the rows with those coordinates to geom_point: geom_point(data=filter(df, diagonal), aes(sample, gene))

Alternatively, you can hack it with a manual shape scale: geom_point(aes(sample, gene, shape=diagonal)) + scale_shape_manual(values=c(' ', '/'))

Wassinger
  • 347
  • 2
  • 16