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:
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:
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.
CodePudding user response:
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")