Ggplot: color areas between density lines according to relative position

I have this plot

set.seed(28100) df <- data.frame(value = sample(1:10000,1000,replace=TRUE), gender = sample(c("male","female"),1000,replace=TRUE)) ggplot(df, aes(value)) + geom_density() + geom_density(data=subset(df, gender=='male'), aes(value), colour="blue") + geom_density(data=subset(df, gender=='female'), aes(value), colour="red") 

I wonder if it is possible to fill the areas between the red and blue density lines with two colors: one color when the blue line is above the red line and the other color when the blue line is lower.

+3
r ggplot2
source share
2 answers

There is no easy way to color in different overlapping areas unless you explicitly calculate the regions themselves. Here's a feature that can help calculate regions where density is swapping

 densitysplit <- function(val, grp, N=200, x=seq(min(val), max(val), length.out=N)) { grp <- factor(grp) den <- Map(function(z) { dx<-density(val[grp==z]) approxfun(dx$x, dx$y)(x) }, levels(grp)) maxcat <- apply(do.call("cbind",den), 1, which.max) data.frame(x=x, ymin=do.call("pmin", den), ymax=do.call("pmax", den), top = levels(grp)[maxcat], group = cumsum(c(1,diff(maxcat)!=0)) ) } 

For your data, you would do something like this

 head(densitysplit(df$value, df$gender)) # x ymin ymax top group # 1 8.00000 4.214081e-05 5.198326e-05 male 1 # 2 58.17085 4.485596e-05 5.433638e-05 male 1 # 3 108.34171 4.760983e-05 5.665547e-05 male 1 # 4 158.51256 5.039037e-05 5.893143e-05 male 1 # 5 208.68342 5.318724e-05 6.115595e-05 male 1 # 6 258.85427 5.598707e-05 6.332672e-05 male 1 

This gives you the data that geom_ribbon needs to use to build the data. You can do

 ggplot(df, aes(value)) + geom_ribbon(data=densitysplit(df$value, df$gender), aes(x, ymin=ymin, ymax=ymax, fill=top, group=group)) + geom_density() + geom_density(data=subset(df, gender=='male'), aes(value), colour="blue") + geom_density(data=subset(df, gender=='female'), aes(value), colour="red") 

enter image description here

+3
source share

You can use fill and alpha to create the desired effect (possibly).

 set.seed(28100) df <- data.frame(value = sample(1:10000,1000,replace=TRUE), gender = sample(c("male","female"),1000,replace=TRUE)) ggplot(df, aes(value, colour=gender, fill=gender, alpha=0.5)) + geom_density() +theme(legend.position="none") 

Hope this helps. Greetings

0
source share

All Articles