Data
dat <- structure(list(Date = structure(c(19913, 19913, 19913, 19913,
19914, 19914, 19914, 19914, 19915, 19915, 19915, 19915, 19916,
19916, 19916, 19916), class = "Date"), meal = structure(c(1L,
2L, 3L, 4L, 1L, 2L, 3L, 4L, 1L, 2L, 3L, 4L, 1L, 2L, 3L, 4L), levels = c("Fasting",
"Breakfast", "Lunch", "Dinner"), class = "factor"), value = c(NA,
NA, 121, 136, 75, 82, 86, 114, 80, 81, 78, 90, 75, 91, NA, NA
), threshold = c(NA, NA, FALSE, FALSE, TRUE, TRUE, TRUE, TRUE,
TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, NA, NA)), row.names = c(NA,
-16L), class = "data.frame")
Date meal value threshold
<date> <fct> <dbl> <lgl>
1 2024-07-09 Fasting NA NA
2 2024-07-09 Breakfast NA NA
3 2024-07-09 Lunch 121 FALSE
4 2024-07-09 Dinner 136 FALSE
5 2024-07-10 Fasting 75 TRUE
6 2024-07-10 Breakfast 82 TRUE
7 2024-07-10 Lunch 86 TRUE
8 2024-07-10 Dinner 114 TRUE
9 2024-07-11 Fasting 80 TRUE
10 2024-07-11 Breakfast 81 TRUE
11 2024-07-11 Lunch 78 TRUE
12 2024-07-11 Dinner 90 TRUE
13 2024-07-12 Fasting 75 TRUE
14 2024-07-12 Breakfast 91 TRUE
15 2024-07-12 Lunch NA NA
16 2024-07-12 Dinner NA NA
Problem
I want to create a tile plot with two different gradients based on a threshold:
- Where
thresholdisFALSEthe higher the value the more red - Where
thresholdisTRUEthe lower the value the more green - Where
thresholdisNAgrey is fine (this is the default anyway).
Attempt
library(ggplot2)
ggplot(dat, aes(x = meal, y = Date, fill = threshold)) +
geom_tile() +
geom_text(aes(label = value), color = "white", fontface = "bold") +
scale_fill_manual(values = c("#ef5350", "#48bf53")) +
scale_x_discrete(expand = c(0, 0)) +
scale_y_date(expand = c(0, 0), date_breaks = "1 day", date_labels = "%B %d") +
theme(legend.position = "none") +
labs(x = element_blank(), y = element_blank())
This output is what I would like but I cannot get the gradient to work within threshold.
>Solution :
The usual trick to do this, is to map value to the alpha transparency. In your case, you just need to flip the direction for the green case first:
library(ggplot2)
dat |>
mutate(
alpha_scale = ifelse(threshold, scales::rescale(-value), scales::rescale(value)),
.by = threshold
) |>
ggplot(aes(x = meal, y = Date, fill = threshold)) +
geom_tile(aes(alpha = alpha_scale)) +
geom_text(aes(label = value), color = "white", fontface = "bold") +
scale_fill_manual(values = c("#ef5350", "#48bf53")) +
scale_x_discrete(expand = c(0, 0)) +
scale_y_date(expand = c(0, 0), date_breaks = "1 day", date_labels = "%B %d") +
theme(legend.position = "none") +
labs(x = element_blank(), y = element_blank())

