【问题标题】:Stacked histogram from already summarized counts using ggplot2使用ggplot2从已经汇总的计数中堆叠直方图
【发布时间】:2013-02-20 06:51:04
【问题描述】:

我需要一些帮助来着色从已经汇总的计数数据生成的 ggplot2 直方图。

这些数据类似于生活在多个不同地区的 # 名男性和 # 名女性的数量。绘制总计数(即男性 + 女性)的直方图很容易:

set.seed(1)
N=100;
X=data.frame(C1=rnbinom(N,15,0.1), C2=rnbinom(N,15,0.1),C=rep(0,N)); 
X$C=X$C1+X$C2;
ggplot(X,aes(x=C)) + geom_histogram()

但是,我想根据 C1 和 C2 的相对贡献为每个条形图着色,以便获得与上述示例相同的直方图(即整体条形图高度),另外我还可以看到类型“ C1" 和 "C2" 个体在堆积条形图中。

关于使用 ggplot2 执行此操作的干净方法的建议,在示例中使用“X”之类的数据?

【问题讨论】:

    标签: r graphics ggplot2 histogram


    【解决方案1】:

    怎么样:

    library("reshape2")
    mm <- melt(X[,1:2])
    ggplot(mm,aes(x=value,fill=variable))+geom_histogram(position="stack")
    

    【讨论】:

    • 不幸的是,我认为这行不通。总体分布不同。我想保留例如 100 个垃圾箱中的 100 个人的数量,但要为该垃圾箱中 M 和 F 的整体分类着色。
    • @PaulJHurtado 我认为您误解了 Ben 的代码。每个箱的总计数将完全相同,因为它们将被堆叠。 'melt' 函数只是压缩数据,然后直方图选项position="stack" 将变量放在一起。总高度将相同。我会在 Ben 的回答中添加一些细节,希望能更清楚。
    • 感谢@Dinre 的努力。请务必运行我发布的代码示例并进行比较。 Ben 的示例给出了不同的总体分布。
    • 啊……找到了。这是一个缩放问题,而不是价值观不同的问题。在原始帖子中,您通过使用总数来分散数据,这很好,但是一旦分成组,它就会不准确。将数据分成组,Ben 的方法是更准确的方法,因为它会分别显示两个组的分布,然后叠加。您是否有某些原因试图避免这种情况?
    • @PaulJHurtado 如果您真的想保留原始堆栈,请说出来,我会为您编写一个不同的函数。我们将不得不自己计算堆栈并使用stat="identity" 来执行类似的操作。
    【解决方案2】:

    很快,您可以使用stat="identity" 选项和plyr 包手动计算直方图,像这样:

    library(plyr)
    
    X$mid <- floor(X$C/20)*20+10
    X_plot <- ddply(X, .(mid), summarize, total=length(C), split=sum(C1)/sum(C)*length(C))
    
    ggplot(data=X_plot) + geom_histogram(aes(x=mid, y=total), fill="blue", stat="identity") + geom_histogram(aes(x=mid, y=split), fill="deeppink", stat="identity")
    

    我们基本上只是为如何定位列制作一个“中间”列,然后制作两个图:一个是总数 (C) 的计数,另一个是调整到其中一列的计数 (C1) 的列)。您应该可以从这里进行自定义。

    更新 1:我意识到我在计算中频时犯了一个小错误。现在修好了。另外,我不知道为什么我使用“ddply”语句来计算中间值。那很愚蠢。新代码更加清晰简洁。

    更新 2:我返回查看评论并注意到一些有点可怕的事情:我使用总和作为直方图频率。我已经对代码进行了一些清理,还添加了 cmets 关于着色语法的建议。

    【讨论】:

    • 这很好,只是你的传说很古怪。以geom_histogram(aes(x=mid, y=total), fill="blue") 开头(即将fill 规范放在映射之外);那么你需要弄清楚如何手动添加指南(图例)。
    • @BenBolker 是的,这只是让数据正确显示的快速解决方案。现在,OP 只需要从这里进行自定义。
    【解决方案3】:

    这是一个使用 ggplot_build 的 hack。我们的想法是首先获取您的旧/原始情节:

    p <- ggplot(data = X, aes(x=C)) + geom_histogram()
    

    存储在p。然后,使用ggplot_build(p)$data[[1]] 提取数据,特别是xminxmax 列(以获得相同的直方图中断/binwidths)和count 列(通过count 标准化百分比。这是代码:

    # get old plot
    p <- ggplot(data = X, aes(x=C)) + geom_histogram()
    # get data of old plot: cols = count, xmin and xmax
    d <- ggplot_build(p)$data[[1]][c("count", "xmin", "xmax")]
    # add a id colum for ddply
    d$id <- seq(nrow(d))
    

    现在如何生成数据?我从你的帖子中了解到的是这样的。以情节中的第一个栏为例。它的计数为 2,从 xmin = 147 延伸到 xmax = 156.8。当我们检查X 的这些值时:

    X[X$C >= 147 & X$C <= 156.8, ] # count = 2 as shown below
    #    C1 C2   C
    # 19 91 63 154
    # 75 86 70 156
    

    在这里,我将 (91+86)/(154+156)*(count=2) = 1.141935(63+70)/(154+156) * (count=2) = 0.8580645 计算为我们将生成的每个柱的两个标准化值。

    require(plyr)
    dd <- ddply(d, .(id), function(x) {
        t <- X[X$C >= x$xmin & X$C <= x$xmax, ]
        if(nrow(t) == 0) return(c(0,0))
        p <- colSums(t)[1:2]/colSums(t)[3] * x$count
    })
    
    # then, it just normal plotting
    require(reshape2)
    dd <- melt(dd, id.var="id")
    ggplot(data = dd, aes(x=id, y=value)) + 
          geom_bar(aes(fill=variable), stat="identity", group=1)
    

    这是原来的情节:

    这就是我得到的:

    编辑:如果您还想获得正确的休息,那么,您可以从旧图中获取相应的x 坐标并在此处使用它而不是id

    p <- ggplot(data = X, aes(x=C)) + geom_histogram()
    d <- ggplot_build(p)$data[[1]][c("count", "x", "xmin", "xmax")]
    d$id <- seq(nrow(d))
    
    require(plyr)
    dd <- ddply(d, .(id), function(x) {
        t <- X[X$C >= x$xmin & X$C <= x$xmax, ]
        if(nrow(t) == 0) return(c(x$x,0,0))
        p <- c(x=x$x, colSums(t)[1:2]/colSums(t)[3] * x$count)
    })
    
    require(reshape2)
    dd.m <- melt(dd, id.var="V1", measure.var=c("V2", "V3"))
    ggplot(data = dd.m, aes(x=V1, y=value)) + 
          geom_bar(aes(fill=variable), stat="identity", group=1)
    

    【讨论】:

    • require(reshape2);ggplot(melt(X,id.vars="C"),aes(x=C,fill=variable)) + geom_histogram() 不具备的解决方案是什么?
    • 由于这些天很少有人使用plyrreshape2,我在this answer 中使用tidyrlapply 创建了@Arun 的答案版本
    猜你喜欢
    • 2019-02-18
    • 2020-07-14
    • 1970-01-01
    • 2016-08-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-04-14
    相关资源
    最近更新 更多