我用R,我有两个数据帧:胡萝卜和黄瓜。每个数据帧都有一个数字列,列出了所有测量的胡萝卜(总共:100k胡萝卜)和黄瓜(总共:50k黄瓜)的长度。
我希望在同一个图上绘制两个直方图——胡萝卜长度和黄瓜长度。它们重叠了,所以我想我也需要一些透明度。我还需要使用相对频率,而不是绝对频率,因为每个组中的实例数量是不同的。
这样的东西会很好,但我不明白如何从我的两个表创建它:
我用R,我有两个数据帧:胡萝卜和黄瓜。每个数据帧都有一个数字列,列出了所有测量的胡萝卜(总共:100k胡萝卜)和黄瓜(总共:50k黄瓜)的长度。
我希望在同一个图上绘制两个直方图——胡萝卜长度和黄瓜长度。它们重叠了,所以我想我也需要一些透明度。我还需要使用相对频率,而不是绝对频率,因为每个组中的实例数量是不同的。
这样的东西会很好,但我不明白如何从我的两个表创建它:
当前回答
下面是一个在“经典”R图形中如何做到这一点的例子:
## generate some random data
carrotLengths <- rnorm(1000,15,5)
cucumberLengths <- rnorm(200,20,7)
## calculate the histograms - don't plot yet
histCarrot <- hist(carrotLengths,plot = FALSE)
histCucumber <- hist(cucumberLengths,plot = FALSE)
## calculate the range of the graph
xlim <- range(histCucumber$breaks,histCarrot$breaks)
ylim <- range(0,histCucumber$density,
histCarrot$density)
## plot the first graph
plot(histCarrot,xlim = xlim, ylim = ylim,
col = rgb(1,0,0,0.4),xlab = 'Lengths',
freq = FALSE, ## relative, not absolute frequency
main = 'Distribution of carrots and cucumbers')
## plot the second graph on top of this
opar <- par(new = FALSE)
plot(histCucumber,xlim = xlim, ylim = ylim,
xaxt = 'n', yaxt = 'n', ## don't add axes
col = rgb(0,0,1,0.4), add = TRUE,
freq = FALSE) ## relative, not absolute frequency
## add a legend in the corner
legend('topleft',c('Carrots','Cucumbers'),
fill = rgb(1:0,0,0:1,0.4), bty = 'n',
border = NA)
par(opar)
唯一的问题是,如果直方图断点是对齐的,它看起来会更好,这可能需要手动完成(在传递给hist的参数中)。
其他回答
下面是一个更简单的解决方案,使用基本图形和alpha混合(并不适用于所有图形设备):
set.seed(42)
p1 <- hist(rnorm(500,4)) # centered at 4
p2 <- hist(rnorm(500,6)) # centered at 6
plot( p1, col=rgb(0,0,1,1/4), xlim=c(0,10)) # first histogram
plot( p2, col=rgb(1,0,0,1/4), xlim=c(0,10), add=T) # second
关键是颜色是半透明的。
编辑,两年多后:由于这篇文章刚刚获得了好评,我想我不妨添加一个可视化的代码,因为alpha混合是如此有用:
基本想法很好,但代码可以改进。[需要很长时间解释,因此需要单独回答,而不是评论。]
hist()函数默认绘制图形,因此需要添加plot=FALSE选项。此外,通过plot(0,0,type="n",…)调用可以更清晰地建立plot区域,您可以在其中添加轴标签、plot标题等。最后,我想提一下,还可以使用阴影来区分两个直方图。代码如下:
set.seed(42)
p1 <- hist(rnorm(500,4),plot=FALSE)
p2 <- hist(rnorm(500,6),plot=FALSE)
plot(0,0,type="n",xlim=c(0,10),ylim=c(0,100),xlab="x",ylab="freq",main="Two histograms")
plot(p1,col="green",density=10,angle=135,add=TRUE)
plot(p2,col="blue",density=10,angle=45,add=TRUE)
这里是结果(有点太宽,因为RStudio:-)):
下面是一个在“经典”R图形中如何做到这一点的例子:
## generate some random data
carrotLengths <- rnorm(1000,15,5)
cucumberLengths <- rnorm(200,20,7)
## calculate the histograms - don't plot yet
histCarrot <- hist(carrotLengths,plot = FALSE)
histCucumber <- hist(cucumberLengths,plot = FALSE)
## calculate the range of the graph
xlim <- range(histCucumber$breaks,histCarrot$breaks)
ylim <- range(0,histCucumber$density,
histCarrot$density)
## plot the first graph
plot(histCarrot,xlim = xlim, ylim = ylim,
col = rgb(1,0,0,0.4),xlab = 'Lengths',
freq = FALSE, ## relative, not absolute frequency
main = 'Distribution of carrots and cucumbers')
## plot the second graph on top of this
opar <- par(new = FALSE)
plot(histCucumber,xlim = xlim, ylim = ylim,
xaxt = 'n', yaxt = 'n', ## don't add axes
col = rgb(0,0,1,0.4), add = TRUE,
freq = FALSE) ## relative, not absolute frequency
## add a legend in the corner
legend('topleft',c('Carrots','Cucumbers'),
fill = rgb(1:0,0,0:1,0.4), bty = 'n',
border = NA)
par(opar)
唯一的问题是,如果直方图断点是对齐的,它看起来会更好,这可能需要手动完成(在传递给hist的参数中)。
这里是类似于我只以r为基数给出的ggplot2的版本。我从@nullglob复制了一些。
生成数据
carrots <- rnorm(100000,5,2)
cukes <- rnorm(50000,7,2.5)
您不需要像使用ggplot2那样将其放入数据帧中。这种方法的缺点是你必须写出更多的情节细节。这样做的好处是你可以控制更多的情节细节。
## calculate the density - don't plot yet
densCarrot <- density(carrots)
densCuke <- density(cukes)
## calculate the range of the graph
xlim <- range(densCuke$x,densCarrot$x)
ylim <- range(0,densCuke$y, densCarrot$y)
#pick the colours
carrotCol <- rgb(1,0,0,0.2)
cukeCol <- rgb(0,0,1,0.2)
## plot the carrots and set up most of the plot parameters
plot(densCarrot, xlim = xlim, ylim = ylim, xlab = 'Lengths',
main = 'Distribution of carrots and cucumbers',
panel.first = grid())
#put our density plots in
polygon(densCarrot, density = -1, col = carrotCol)
polygon(densCuke, density = -1, col = cukeCol)
## add a legend in the corner
legend('topleft',c('Carrots','Cucumbers'),
fill = c(carrotCol, cukeCol), bty = 'n',
border = NA)
下面是我写的一个函数,它使用伪透明来表示重叠的直方图
plotOverlappingHist <- function(a, b, colors=c("white","gray20","gray50"),
breaks=NULL, xlim=NULL, ylim=NULL){
ahist=NULL
bhist=NULL
if(!(is.null(breaks))){
ahist=hist(a,breaks=breaks,plot=F)
bhist=hist(b,breaks=breaks,plot=F)
} else {
ahist=hist(a,plot=F)
bhist=hist(b,plot=F)
dist = ahist$breaks[2]-ahist$breaks[1]
breaks = seq(min(ahist$breaks,bhist$breaks),max(ahist$breaks,bhist$breaks),dist)
ahist=hist(a,breaks=breaks,plot=F)
bhist=hist(b,breaks=breaks,plot=F)
}
if(is.null(xlim)){
xlim = c(min(ahist$breaks,bhist$breaks),max(ahist$breaks,bhist$breaks))
}
if(is.null(ylim)){
ylim = c(0,max(ahist$counts,bhist$counts))
}
overlap = ahist
for(i in 1:length(overlap$counts)){
if(ahist$counts[i] > 0 & bhist$counts[i] > 0){
overlap$counts[i] = min(ahist$counts[i],bhist$counts[i])
} else {
overlap$counts[i] = 0
}
}
plot(ahist, xlim=xlim, ylim=ylim, col=colors[1])
plot(bhist, xlim=xlim, ylim=ylim, col=colors[2], add=T)
plot(overlap, xlim=xlim, ylim=ylim, col=colors[3], add=T)
}
下面是使用R对透明颜色的支持的另一种方法
a=rnorm(1000, 3, 1)
b=rnorm(1000, 6, 1)
hist(a, xlim=c(0,10), col="red")
hist(b, add=T, col=rgb(0, 1, 0, 0.5) )
最终的结果是这样的: