用R中的ggplot2覆盖直方图

Blo*_*omy 114 r ggplot2

我是R的新手,我试图将3个直方图绘制在同一个图表上.一切都很好,但我的问题是你没有看到2个直方图重叠的位置 - 它们看起来相当截止:直方图

当我制作密度图时,它看起来很完美:每条曲线都被黑色框线包围,颜色在曲线重叠的地方看起来不同:密度图

有人可以告诉我,如果第一张照片中的直方图可以实现类似的东西吗?这是我正在使用的代码:

lowf0 <-read.csv (....)
mediumf0 <-read.csv (....)
highf0 <-read.csv(....)
lowf0$utt<-'low f0'
mediumf0$utt<-'medium f0'
highf0$utt<-'high f0'
histogram<-rbind(lowf0,mediumf0,highf0)
ggplot(histogram, aes(f0, fill = utt)) + geom_histogram(alpha = 0.2)
Run Code Online (Sandbox Code Playgroud)

提前感谢任何有用的提示!

koh*_*ske 221

使用@joran的样本数据,

ggplot(dat, aes(x=xx, fill=yy)) + geom_histogram(alpha=0.2, position="identity")
Run Code Online (Sandbox Code Playgroud)

请注意,默认位置geom_histogram是"堆栈".

看这个页面的"位置调整":

docs.ggplot2.org/current/geom_histogram.html

  • 我认为这应该是最好的答案,因为它避免重复代码 (21认同)
  • 就个人而言,我认为stackoverflow应该首先列出最受欢迎的答案."正确答案"仅代表一个人的意见. (7认同)
  • 另外,请确保在 `fill` 中使用的变量是一个因素。 (6认同)
  • `position ='identity'`不仅仅是一个更易读的答案,它更适合于更复杂的图,例如对`aes()`和`aes_string()`的混合调用. (5认同)
  • 此答案还将自动显示颜色的图例,而@joran 的答案则不会。然后可以使用例如`scale_fill_manual()`来修改图例。此函数还可用于修改直方图中的颜色。 (2认同)
  • 是否可以使用此方法缩放 y 轴以匹配?我相信使用其他方法,您可以使用 `aes(y=..count../sum(..count..)` 来执行此操作。当我使用相同的代码时,分母似乎是数据的总数填充总数的 (2认同)

jor*_*ran 110

您当前的代码:

ggplot(histogram, aes(f0, fill = utt)) + geom_histogram(alpha = 0.2)
Run Code Online (Sandbox Code Playgroud)

告诉我使用所有值ggplot构建一个直方图f0,然后根据变量为该单个直方图的条形着色utt.

你想要的是创建三个单独的直方图,使用alpha混合使它们彼此可见.所以你可能想要使用三个单独的调用geom_histogram,每个调用都有自己的数据框并填充:

ggplot(histogram, aes(f0)) + 
    geom_histogram(data = lowf0, fill = "red", alpha = 0.2) + 
    geom_histogram(data = mediumf0, fill = "blue", alpha = 0.2) +
    geom_histogram(data = highf0, fill = "green", alpha = 0.2) +
Run Code Online (Sandbox Code Playgroud)

这是一个输出的具体示例:

dat <- data.frame(xx = c(runif(100,20,50),runif(100,40,80),runif(100,0,30)),yy = rep(letters[1:3],each = 100))

ggplot(dat,aes(x=xx)) + 
    geom_histogram(data=subset(dat,yy == 'a'),fill = "red", alpha = 0.2) +
    geom_histogram(data=subset(dat,yy == 'b'),fill = "blue", alpha = 0.2) +
    geom_histogram(data=subset(dat,yy == 'c'),fill = "green", alpha = 0.2)
Run Code Online (Sandbox Code Playgroud)

产生这样的东西:

在此输入图像描述

编辑修复错别字; 你想要填充,而不是颜色.

  • 当子集具有不同的大小时,这不起作用.知道怎么解决这个问题?(例如,在"a"上使用100点数据,在"b"上使用50点数据). (4认同)
  • 这种方法的一个缺点是我很难让它显示一个传奇(尽管这可能只是因为我缺乏知识).@kohske下面的另一个答案将默认显示一个图例,然后可以修改该图例(以及直方图上显示的特定颜色),例如`scale_fill_manual()`. (2认同)
  • @shenglih 对于传奇,下面 kohske 的回答更好。他的回答通常也更好。 (2认同)

Cyb*_*tic 10

尽管仅需几行即可在ggplot2中绘制多个/重叠的直方图,但结果并不总是令人满意。需要适当使用边框和颜色以确保眼睛可以区分直方图

以下功能平衡了边框的颜色,不透明度和叠加的密度图,以使观看者能够区分分布

单个直方图

plot_histogram <- function(df, feature) {
    plt <- ggplot(df, aes(x=eval(parse(text=feature)))) +
    geom_histogram(aes(y = ..density..), alpha=0.7, fill="#33AADE", color="black") +
    geom_density(alpha=0.3, fill="red") +
    geom_vline(aes(xintercept=mean(eval(parse(text=feature)))), color="black", linetype="dashed", size=1) +
    labs(x=feature, y = "Density")
    print(plt)
}
Run Code Online (Sandbox Code Playgroud)

多个直方图

plot_multi_histogram <- function(df, feature, label_column) {
    plt <- ggplot(df, aes(x=eval(parse(text=feature)), fill=eval(parse(text=label_column)))) +
    geom_histogram(alpha=0.7, position="identity", aes(y = ..density..), color="black") +
    geom_density(alpha=0.7) +
    geom_vline(aes(xintercept=mean(eval(parse(text=feature)))), color="black", linetype="dashed", size=1) +
    labs(x=feature, y = "Density")
    plt + guides(fill=guide_legend(title=label_column))
}
Run Code Online (Sandbox Code Playgroud)

用法

只需将数据框以及所需的参数传递给上述函数即可

plot_histogram(iris, 'Sepal.Width')
Run Code Online (Sandbox Code Playgroud)

在此处输入图片说明

plot_multi_histogram(iris, 'Sepal.Width', 'Species')
Run Code Online (Sandbox Code Playgroud)

在此处输入图片说明

plot_multi_histogram中的额外参数是包含类别标签的列的名称。

通过创建具有许多不同分布方式的数据框,我们可以更加生动地看到这一点:

a <-data.frame(n=rnorm(1000, mean = 1), category=rep('A', 1000))
b <-data.frame(n=rnorm(1000, mean = 2), category=rep('B', 1000))
c <-data.frame(n=rnorm(1000, mean = 3), category=rep('C', 1000))
d <-data.frame(n=rnorm(1000, mean = 4), category=rep('D', 1000))
e <-data.frame(n=rnorm(1000, mean = 5), category=rep('E', 1000))
f <-data.frame(n=rnorm(1000, mean = 6), category=rep('F', 1000))
many_distros <- do.call('rbind', list(a,b,c,d,e,f))
Run Code Online (Sandbox Code Playgroud)

像以前一样传递数据框(并使用选项扩展图表):

options(repr.plot.width = 20, repr.plot.height = 8)
plot_multi_histogram(many_distros, 'n', 'category')
Run Code Online (Sandbox Code Playgroud)

在此处输入图片说明

  • @EdwardTyler 非常正确。我希望我能不止一次地对此投赞成票! (3认同)
  • 这非常有用,希望得到更多关注。 (2认同)
  • @Julien 该答案在发表评论时已有 51 票。更不用说其他评论认为我的回答非常有帮助。编程并不是要知道确切的答案,而是要了解可以普遍应用的一般概念/模式。我的回答很靠谱。 (2认同)