library(tidyverse)
datasets::ChickWeight # from Base R
ggplot(ChickWeight, aes(Time, weight, group = Chick)) + geom_line()

Спор здесь подсчитывает, сколько показаний в каждом интервале времени / веса, и нормализуется до «доли наиболее распространенных показаний» для каждого времени.
ChickWeight %>%
count(Time, weight = 10*floor(weight/10)) %>%
complete(Time, weight = 10*0:30, fill = list(n = 0)) %>%
group_by(Time) %>%
mutate(share = n / max(n)) %>% # weighted for num as % of max for that Time
ungroup() %>%
ggplot(aes(Time, weight, fill = share)) +
geom_tile(width = 2) +
scale_fill_viridis_c(direction = -1)

Если ваши данные имеют разреженные показания времени, может быть полезно интерполировать ваши строки, чтобы получить большее разрешение для биннинга:
ChickWeight %>%
group_by(Chick) %>%
arrange(Time) %>%
padr::pad_int("Time", step = 0.5) %>%
mutate(weight_approx = approx(Time, weight, Time)$y) %>%
ungroup() %>%
count(Time, weight_approx = 10*floor(weight_approx/10)) %>%
complete(Time, weight_approx = 10*0:60, fill = list(n = 0)) %>%
group_by(Time) %>%
mutate(share = n / sum(n)) %>% # Different weighting option
ungroup() %>%
ggplot(aes(Time, weight_approx, fill = share)) +
geom_tile() +
scale_fill_viridis_c(direction = -1)
