Conditional or arbitrary fill in density plots?

I've tried googling this but can't find anything, so apologies if there's an obvious solution, but so far it's eluded me.

I ultimately want to create a geom_density_ridges plot using the ggridges package, and fill in the parts of the density plots where values are, for example, >= -2 & =< 0 with some colour, and the part of the plot where >=0.2 & <= 1 with another.

Below is the closest I've got whereby I create another variable which is conditional on the values of x. This sort of works for a histogram but obviously fails for geom_density() since ggplot treats each fill as a group. I basically just need to 'overlay' my arbitrary fills. Does that make sense?

library(tidyverse)

data <- 
  tibble(
    x = rnorm(1000, mean = 0, sd = 1)
  ) %>%
  mutate(
    variable = case_when(
      (x >= -2 & x <= 0) ~ "On",
      (x >= 0.2 & x <= 1) ~ "Off",
      TRUE ~ NA_character_
    )
  )


ggplot(data, aes(x, fill = variable)) +
  geom_histogram(binwidth = 0.1, alpha = 0.7)


ggplot(data, aes(x, fill = variable)) +
  geom_density()

Created on 2018-11-12 by the reprex package (v0.2.1)

This might be a good start for you - based on r - How to shade specific region under ggplot2 density curve? - Stack Overflow and r - Shaded area under density curve in ggplot2 - Stack Overflow

library(tidyverse)
z <-  rnorm(1000, mean = 0, sd = 1)

dens <- density(z)

data <- tibble(x = dens$x, y = dens$y) %>% 
    mutate(variable = case_when(
      (x >= -2 & x <= 0) ~ "On",
      (x >= 0.2 & x <= 1) ~ "Off",
      TRUE ~ NA_character_))
#> Warning: package 'bindrcpp' was built under R version 3.4.4

ggplot(data, aes(x, y)) + geom_line() +
  geom_area(data = filter(data, variable == 'On'), fill = 'grey') + 
  geom_area(data = filter(data, variable == 'Off'), fill = 'light blue')

Created on 2018-11-12 by the reprex package (v0.2.1)

3 Likes

Thanks @jrlewi, this does exactly what I described. Since your solution finds the density estimates outside of ggplot2, I had to have a play about because I have another factor which I use in facet_grid() (my fault for not mentioning it earlier :roll_eyes:). Combined with what you wrote, I managed to find a solution, although not at all elegant:

library(tidyverse)

data <- data.frame(
  x = c(rnorm(1000, mean = 1, sd = 1), rnorm(1000, mean = 0, sd = 1), rnorm(1000,mean = -1, sd = 0)),
  group = c(rep('a', 1000), rep('b', 1000), rep('c', 1000))
)

# Get density information for each group
densities <- data %>%
  group_by(group) %>%
  do(., dens = density(.$x))

# Bind these into a data frame in order to plot them using ggplot2
densities_df <-
  data.frame(
    group = c(rep('a', 512),
              rep('b', 512),
              rep('c', 512)),
    x = c(densities$dens[[1]]$x, 
          densities$dens[[2]]$x,
          densities$dens[[3]]$x),
    y = c(densities$dens[[1]]$y,
          densities$dens[[2]]$y,
          densities$dens[[3]]$y)
  ) %>%
  mutate(
    group = factor(group),
    variable = case_when(
      (x >= -2 & x <= 0) ~ "On",
      (x >= 0.2 & x <= 1) ~ "Off",
      TRUE ~ NA_character_
    )
  )
  
# Plot data
ggplot(densities_df, aes(x = x, y = y)) + 
  geom_area(data = filter(densities_df, variable == 'On'), fill = '#8ad5ae') +
  geom_area(data = filter(densities_df, variable == 'Off'), fill = '#f8d0d2') +
  geom_line(size = 1) +
  facet_grid(.~group)

Created on 2018-11-13 by the reprex package (v0.2.1)

Now I need to figure out how to crowbar this into ggridges... think I'll grab some lunch first.

1 Like

This topic was automatically closed 7 days after the last reply. New replies are no longer allowed.