Shaded area under density curve in ggplot2

2019-07-13 03:22发布

I have plotted a distribution and I want to shade the area>95 percentile. However when I try to use the different techniques documented here:ggplot2 shade area under density curve by group It does not work as the length of my dataset differ.

AGG[,1]=seq(1:1000)
AGG[,2]=rnorm(1000,mean=150,sd=10)
Z<-data.frame(AGG) 
library(ggplot2)
ggplot(Z,aes(x=Z[,2]))+stat_density(geom="line",colour="lightblue",size=1.1)+xlim(0,350)+ylim(0,0.05)+geom_vline(xintercept=quantile(Z[,2],prob=0.95),colour="red")+geom_text(aes(x=quantile(Z[,2],prob=0.95)),label="VaR 95%",y=0.0225, colour="red")
#I want to add a shaded area right of the VaR in this chart

2条回答
放荡不羁爱自由
2楼-- · 2019-07-13 04:07

This is a case where ggplot's helper functions and built-in summaries can end up being more troublesome than helpful. In your situation, it's probably best to calculate your summary statistics directly, and then plot those. In the example below, I use density and quantile from the base stats library to compute what will be plotted. Feeding this to ggplot directly ends up being much simpler than trying to manipulate ggplot's summary functions. This way, shading is accomplished using geom_ribbon and ggplot's intended aesthetic system; no need to go digging through the plot object.

rm(list = ls())
library(magrittr)
library(ggplot2)

y <- rnorm(1000, 150, 10)

cutoff <- quantile(y, probs = 0.95)

hist.y <- density(y, from = 100, to = 200) %$% 
  data.frame(x = x, y = y) %>% 
  mutate(area = x >= cutoff)

the.plot <- ggplot(data = hist.y, aes(x = x, ymin = 0, ymax = y, fill = area)) +
  geom_ribbon() +
  geom_line(aes(y = y)) +
  geom_vline(xintercept = cutoff, color = 'red') +
  annotate(geom = 'text', x = cutoff, y = 0.025, color = 'red', label = 'VaR 95%', hjust = -0.1)
print(the.plot)

enter image description here

查看更多
forever°为你锁心
3楼-- · 2019-07-13 04:08

Here is a solution using the function WVPlots::ShadedDensity. I will use this function because its arguments are self-explanatory and therefore the plot can be created very easily. On the downside, the customization is a bit tricky. But once you worked your head around a ggplot object, you'll see that it is not that mysterious.

library(WVPlots)

# create the data
set.seed(1)
V1 = seq(1:1000)
V2 = rnorm(1000, mean = 150, sd = 10)
Z <- data.frame(V1, V2)

Now you can create your plot.

threshold <- quantile(Z[, 2], prob = 0.95)[[1]]
p <- WVPlots::ShadedDensity(frame = Z, 
                            xvar = "V2",
                            threshold = threshold,
                            title = "Your title",
                            tail = "right")
p

enter image description here

But since you want the colour of the line to be lightblue etc, you need to manipulate the object p. In this regard, see also this and this question.

The object p contains four layers: geom_line, geom_ribbon, geom_vline and geom_text. You'll find them here: p$layers.

Now you need to change their aesthetic mappings. For geom_line there is only one, the colour

p$layers[[1]]$aes_params
$colour
[1] "darkgray"

If you now want to change the line colour to be lightblue simply overwrite the existing colour like so

p$layers[[1]]$aes_params$colour <- "lightblue"

Once you figured how to do that for one layer, the rest is easy.

p$layers[[2]]$aes_params$fill <- "grey"     #geom_ribbon
p$layers[[3]]$aes_params$colour <- "red"    #geom_vline
p$layers[[4]]$aes_params$label <- "VaR 95%" #geom_text

p

And the plot now looks like this

enter image description here

查看更多
登录 后发表回答