如何在R中叠加密度图?

90
我想在R中叠加两个密度图到同一设备上,应该怎么操作?我在网络上搜索了但没有找到明显的解决方案。
我的想法是从文本文件(列)中读取数据,然后使用:
plot(density(MyData$Column1))
plot(density(MyData$Column2), add=T)

或者类似这样的内容。

1
对于ggplot2家族,现在有一个名为"ggridges"的包可以实现这一功能。 - Liang Zhang
8个回答

107

使用lines来表示第二个:

plot(density(MyData$Column1))
lines(density(MyData$Column2))

确保第一个图的范围合适。


12
当两个密度曲线的范围不同时,第二条曲线不适合在图形限制内显示时,你可能需要使用稍微复杂一些的方法。然后,你可以在绘图之前计算密度值,并使用range(dens1$y, dens2$y)计算出适当的 ylim,其中 dens1dens2 是包含两个密度估计对象的变量。在调用 plot() 时使用这个 ylim - Gavin Simpson
3
您可能还希望区分这两条线。设置线宽(lwd)、线型(lty)或线条颜色(col)可以帮助实现。此时,您还可以考虑使用 legend() 添加图例。 - nullglob
如果OP正在从文件中读取数据,我会构建一个复杂的函数来读取数据(sapply,lapply),找到所有数据集的范围,将默认范围设置为所有范围的最大值,然后绘制(lines)密度。@Gavin - Roman Luštrik

52

ggplot2 是另一个图形包,可以相当巧妙地处理像Gavin提到的范围问题。它还可以自动生成适当的图例,并且在我看来,从开箱即用的角度来看,它的整体感觉更加 polished,需要较少的手动操作。

library(ggplot2)

#Sample data
dat <- data.frame(dens = c(rnorm(100), rnorm(100, 10, 5))
                   , lines = rep(c("a", "b"), each = 100))
#Plot.
ggplot(dat, aes(x = dens, fill = lines)) + geom_density(alpha = 0.5)

这里输入图片描述


9
首先需要将OP的数据框转换成长格式:ggplot(melt(MyData), mapping=aes(fill=variable, x=value)) + geom_density(alpha=.5)。然后可以使用这个语句绘制密度图。 - cbeleites unhappy with SX
1
好的图表。"dat2"是什么?"melt"是什么(命令未找到)? - Erik Aronesty
@ErikAronesty - 在这一点上,你的猜测和我的一样好,我在两年前回答了这个问题!我猜想我在环境中有另一个名为dat的对象,所以将其命名为dat2...我提供的模拟数据按照预期工作。melt()命令来自reshape2包。早在2011年,当加载ggplot2时,reshape2会自动加载,但现在不再是这样,所以您需要单独执行library(reshape2) - Chase

24

添加基本图形版本,可以处理y轴限制,添加颜色,并适用于任意列数:

如果我们有一个数据集:

myData <- data.frame(std.nromal=rnorm(1000, m=0, sd=1),
                     wide.normal=rnorm(1000, m=0, sd=2),
                     exponent=rexp(1000, rate=1),
                     uniform=runif(1000, min=-3, max=3)
                     )

接下来绘制密度图:

dens <- apply(myData, 2, density)

plot(NA, xlim=range(sapply(dens, "[", "x")), ylim=range(sapply(dens, "[", "y")))
mapply(lines, dens, col=1:length(dens))

legend("topright", legend=names(dens), fill=1:length(dens))

这将会得到:

输入图片说明


我喜欢这个例子,但如果您的数据列包含NA值,则它无法正常工作。我不确定如何修改代码,但这将非常有用。 - daisy
1
@daisy 将这行代码 dens <- apply(myData, 2, density) 改为 dens <- apply(myData, 2, density, na.rm=TRUE),然后它就可以正常工作了。 - Karolis Koncevičius

13

为了提供完整的解决方案,这里是使用 lattice 的 Chase 答案版本:

dat <- data.frame(dens = c(rnorm(100), rnorm(100, 10, 5))
                   , lines = rep(c("a", "b"), each = 100))

densityplot(~dens,data=dat,groups = lines,
            plot.points = FALSE, ref = TRUE, 
            auto.key = list(space = "right"))

这会产生一个像这样的图表: 输入图像说明


不创建新的 data.framedensityplot(~rnorm(100)+rnorm(100, 10, 5), plot.points=FALSE, ref=TRUE, auto.key = list(space = "right"))。或者对于 OP 数据 densityplot(~Column1+Column2, data=myData) - Marek

9
这是我在基础中的做法(实际上在第一个答案的评论中提到了,但我会在这里展示完整的代码,包括图例,因为我还不能发表评论...)
首先,您需要从密度图中获取有关 y 轴最大值的信息。因此,您需要先单独计算密度。
dta_A <- density(VarA, na.rm = TRUE)
dta_B <- density(VarB, na.rm = TRUE)

根据第一个答案绘制它们,并为您刚获得的y轴定义最小和最大值。(我将最小值设置为0)

plot(dta_A, col = "blue", main = "2 densities on one plot"), 
     ylim = c(0, max(dta_A$y,dta_B$y)))  
lines(dta_B, col = "red")

然后将图例添加到右上角。
legend("topright", c("VarA","VarB"), lty = c(1,1), col = c("blue","red"))

4
您可以使用 ggjoy 软件包。 假设我们有三个不同的 beta 分布,例如:
set.seed(5)
b1<-data.frame(Variant= "Variant 1", Values = rbeta(1000, 101, 1001))
b2<-data.frame(Variant= "Variant 2", Values = rbeta(1000, 111, 1011))
b3<-data.frame(Variant= "Variant 3", Values = rbeta(1000, 11, 101))


df<-rbind(b1,b2,b3)

您可以按以下方式获取三种不同的分发版本:
library(tidyverse)
library(ggjoy)


ggplot(df, aes(x=Values, y=Variant))+
    geom_joy(scale = 2, alpha=0.5) +
    scale_y_discrete(expand=c(0.01, 0)) +
    scale_x_continuous(expand=c(0.01, 0)) +
    theme_joy()

enter image description here


3

我拿上面的格子例子做了一个很棒的函数。可能有更好的方法可以通过melt/cast重塑来完成这个任务。(如果您看到改进的地方,请评论或编辑。)

multi.density.plot=function(data,main=paste(names(data),collapse = ' vs '),...){
  ##combines multiple density plots together when given a list
  df=data.frame();
  for(n in names(data)){
    idf=data.frame(x=data[[n]],label=rep(n,length(data[[n]])))
    df=rbind(df,idf)
  }
  densityplot(~x,data=df,groups = label,plot.points = F, ref = T, auto.key = list(space = "right"),main=main,...)
}

使用示例:

multi.density.plot(list(BN1=bn1$V1,BN2=bn2$V1),main='BN1 vs BN2')

multi.density.plot(list(BN1=bn1$V1,BN2=bn2$V1))

2

每当出现轴限不匹配的问题时,base图形中正确的工具是使用matplot。关键在于利用density.default中的fromto参数。这有点hackish,但相当容易实现:

set.seed(102349)
x1 = rnorm(1000, mean = 5, sd = 3)
x2 = rnorm(5000, mean = 2, sd = 8)

xrng = range(x1, x2)

#force the x values at which density is
#  evaluated to be the same between 'density'
#  calls by specifying 'from' and 'to'
#  (and possibly 'n', if you'd like)
kde1 = density(x1, from = xrng[1L], to = xrng[2L])
kde2 = density(x2, from = xrng[1L], to = xrng[2L])

matplot(kde1$x, cbind(kde1$y, kde2$y))

这是一个绘制matplot函数输出的图表。观察到两条曲线,一条是红色的,另一条是黑色的;黑色曲线比红色曲线更高,而红色曲线则“更胖”。</br>

根据需要添加各种功能(matplot接受所有标准的plot/par参数,例如ltytypecollwd等)。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接