向 ggplot 热图添加噪声,其中噪声量基于值?

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

我正在尝试向 ggplot 热图添加噪声或抖动,其中每个图块中的噪声量由一个值决定。

例如,如果我像这样制作热图:

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)

结果如下:

但是,我想根据特定值向热图的每个图块添加噪声。例如,如果我在数据框中添加另一列来表示噪声:

df$noise <- runif(25)

我正在尝试做类似的事情:

我用photoshop做了上面的图。但我想知道是否有可能在 ggplot 中制作这样的东西?因此,例如,如果一个图块的噪声值为 0,则该图块上将没有 noise/dithering...如果该图块的 noise/dithering 值为 1,则将有一个那个瓷砖上有很多噪音。

这是一种使用 tidyr::uncount 复制每个单元格的方法,然后根据 noise 变量分配一定程度的噪音。

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")