【问题标题】:Shading a kernel density plot between two points.对两点之间的核密度图进行着色。
【发布时间】:2011-03-30 12:07:12
【问题描述】:

我经常使用核密度图来说明分布。像这样在 R 中轻松快速地创建它们:

set.seed(1)
draws <- rnorm(100)^2
dens <- density(draws)
plot(dens)
#or in one line like this: plot(density(rnorm(100)^2))

这给了我这个漂亮的小 PDF:

我想在 PDF 下的第 75 到 95 个百分位数之间涂上阴影。使用quantile 函数很容易计算点数:

q75 <- quantile(draws, .75)
q95 <- quantile(draws, .95)

但是我如何为q75q95 之间的区域设置阴影?

【问题讨论】:

  • 你能提供一个例子来说明你的范围外和范围内的阴影吗?谢谢。

标签: r plot


【解决方案1】:

另一种解决方案:

dd <- with(dens,data.frame(x,y))

library(ggplot2)

qplot(x,y,data=dd,geom="line")+
  geom_ribbon(data=subset(dd,x>q75 & x<q95),aes(ymax=y),ymin=0,
              fill="red",colour=NA,alpha=0.5)

结果:

【讨论】:

    【解决方案2】:

    这是另一个ggplot2 变体,它基于一个函数,该函数在原始数据值处近似核密度:

    approxdens <- function(x) {
        dens <- density(x)
        f <- with(dens, approxfun(x, y))
        f(x)
    }
    

    使用原始数据(而不是生成具有密度估计的 x 和 y 值的新数据框)还具有在分面图中工作的好处,其中分位数值取决于数据分组所依据的变量:

    使用的代码

    library(tidyverse)
    library(RColorBrewer)
    
    # dummy data
    set.seed(1)
    n <- 1e2
    dt <- tibble(value = rnorm(n)^2)
    
    # function that approximates the density at the provided values
    approxdens <- function(x) {
        dens <- density(x)
        f <- with(dens, approxfun(x, y))
        f(x)
    }
    
    probs <- c(0.75, 0.95)
    
    dt <- dt %>%
        mutate(dy = approxdens(value),                         # calculate density
               p = percent_rank(value),                        # percentile rank 
               pcat = as.factor(cut(p, breaks = probs,         # percentile category based on probs
                                    include.lowest = TRUE)))
    
    ggplot(dt, aes(value, dy)) +
        geom_ribbon(aes(ymin = 0, ymax = dy, fill = pcat)) +
        geom_line() +
        scale_fill_brewer(guide = "none") +
        theme_bw()
    
    
    
    # dummy data with 2 groups
    dt2 <- tibble(category = c(rep("A", n), rep("B", n)),
                  value = c(rnorm(n)^2, rnorm(n, mean = 2)))
    
    dt2 <- dt2 %>%
        group_by(category) %>% 
        mutate(dy = approxdens(value),    
               p = percent_rank(value),
               pcat = as.factor(cut(p, breaks = probs,
                                    include.lowest = TRUE)))
    
    # faceted plot
    ggplot(dt2, aes(value, dy)) +
        geom_ribbon(aes(ymin = 0, ymax = dy, fill = pcat)) +
        geom_line() +
        facet_wrap(~ category, nrow = 2, scales = "fixed") +
        scale_fill_brewer(guide = "none") +
        theme_bw()
    

    reprex package (v0.2.0) 于 2018 年 7 月 13 日创建。

    【讨论】:

      【解决方案3】:

      使用polygon() 功能,请参阅它的帮助页面,我相信我们在这里也有类似的问题。

      您需要找到分位数值的索引才能获得实际的(x,y) 对。

      编辑:给你:

      x1 <- min(which(dens$x >= q75))  
      x2 <- max(which(dens$x <  q95))
      with(dens, polygon(x=c(x[c(x1,x1:x2,x2)]), y= c(0, y[x1:x2], 0), col="gray"))
      

      输出(由 JDL 添加)

      【讨论】:

      • 如果你没有提供结构,我永远不会让它工作。谢谢!
      • 这是其中之一……从黎明前就已经在demo(graphics) 中,因此时不时会遇到。 NBER 回归着色等的想法相同。
      • 哦。我知道我在某个地方看到过它,但无法从我看到它的心理索引中拉出来。我很高兴你的心理指数比我的好。
      【解决方案4】:

      扩展解决方案:

      如果您想遮蔽两条尾巴(复制并粘贴 Dirk 的代码)并使用已知的 x 值:

      set.seed(1)
      draws <- rnorm(100)^2
      dens <- density(draws)
      plot(dens)
      
      q2     <- 2
      q65    <- 6.5
      qn08   <- -0.8
      qn02   <- -0.2
      
      x1 <- min(which(dens$x >= q2))  
      x2 <- max(which(dens$x <  q65))
      x3 <- min(which(dens$x >= qn08))  
      x4 <- max(which(dens$x <  qn02))
      
      with(dens, polygon(x=c(x[c(x1,x1:x2,x2)]), y= c(0, y[x1:x2], 0), col="gray"))
      with(dens, polygon(x=c(x[c(x3,x3:x4,x4)]), y= c(0, y[x3:x4], 0), col="gray"))
      

      结果:

      【讨论】:

      • 我有 png 文件并将其托管在 freeimagehosting 上,它可能无法加载,因为......我不确定。
      • 非常模糊的文件。您能否重新创建它并直接在此处上传 SO 有自己的服务器服务?
      • 对不起,我看不到如何直接上传到 SO。
      【解决方案5】:

      这个问题需要lattice 的答案。这是一个非常基本的方法,只是改编了 Dirk 和其他人使用的方法:

      #Set up the data
      set.seed(1)
      draws <- rnorm(100)^2
      dens <- density(draws)
      
      #Put in a simple data frame   
      d <- data.frame(x = dens$x, y = dens$y)
      
      #Define a custom panel function;
      # Options like color don't need to be hard coded    
      shadePanel <- function(x,y,shadeLims){
          panel.lines(x,y)
          m1 <- min(which(x >= shadeLims[1]))
          m2 <- max(which(x <= shadeLims[2]))
          tmp <- data.frame(x1 = x[c(m1,m1:m2,m2)], y1 = c(0,y[m1:m2],0))
          panel.polygon(tmp$x1,tmp$y1,col = "blue")
      }
      
      #Plot
      xyplot(y~x,data = d, panel = shadePanel, shadeLims = c(1,3))
      

      【讨论】:

        猜你喜欢
        • 2011-04-10
        • 1970-01-01
        • 2021-05-13
        • 1970-01-01
        • 2012-12-12
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多