'Add noise to ggplot heatmap where the amount of noise is based on a value?

I am trying to add noise or dithering to a ggplot heatmap, where the amount of noise in each tile is determined by a value.

for example, If I make a heatmap like so:

library(tidyr)
library(tibble)
library(ggplot2)

set.seed(100)
s<-matrix(runif(25,0,1),5)
s[lower.tri(s)] = t(s)[lower.tri(s)]
diag(s) <- 0
colnames(s) <- rownames(s) <- paste0('x', 1:5)

df <- reshape2::melt(s) 

ggplot(df, aes(x = Var1, y = Var2, fill = value)) +
  geom_tile() +
  scale_fill_viridis_c() +
  theme_bw() +
  theme(aspect.ratio = 1)

This results in something like: example heatmap

However, I would like to add noise to each tile of the heatmap based on a certain value. For example, if I add another column to my data frame to represent the noise:

df$noise <- runif(25)

I am trying to make something like: heatmap with noise

I made the above plot in photoshop. But I was wondering if it is possible to make something like this in ggplot? So, for example, if one tile had a noise value of 0, then there would be no noise/dithering on that tile... and if the tile had a noise/dithering value of 1, there would be a lot of noise on that tile.



Solution 1:[1]

Here's an approach using tidyr::uncount to make copies of each cell, and then assigning a degree of noise based on the noise variable.

library(tidyverse)
df %>%
  uncount(25, .id = "id") %>%
  mutate(value2 = value + rnorm(n(), sd = noise),
         Var1_offset = (id - 1) %% 5,
         Var2_offset = (id - 1) %/% 5) %>%
  ggplot(aes(as.numeric(Var1) + Var1_offset/5, 
             as.numeric(Var2) + Var2_offset/5, 
             fill = value2)) +
    geom_tile() +
    scale_fill_viridis_c() +
    theme_bw() +
    theme(aspect.ratio = 1) +
  scale_x_continuous(breaks = 0.5 + (1:5),
                     labels = paste0("x", 1:5), name = "Var1") +
  scale_y_continuous(breaks = 0.5 + (1:5),
                     labels = paste0("x", 1:5), name = "Var2")

enter image description here

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Jon Spring