R散点图:符号颜色表示重叠点的数量。

22
散点图在许多点重叠时很难解释,因为这种重叠会掩盖特定区域内数据的密度。一种解决方案是使用半透明颜色来绘制数据点,以便不透明区域指示在这些坐标中存在许多观测值。
下面是我在R中提出的黑白解决方案的示例:
MyGray <- rgb(t(col2rgb("black")), alpha=50, maxColorValue=255)
x1 <- rnorm(n=1E3, sd=2)
x2 <- x1*1.2 + rnorm(n=1E3, sd=2)
dev.new(width=3.5, height=5)
par(mfrow=c(2,1), mar=c(2.5,2.5,0.5,0.5), ps=10, cex=1.15)
plot(x1, x2, ylab="", xlab="", pch=20, col=MyGray)
plot(x1, x2, ylab="", xlab="", pch=20, col="black")

The advantages of using opacity to indicate point density

然而,最近我看到了PNAS上的这篇文章,采用了类似的方法,但使用热图颜色而不是透明度来指示有多少点重叠。该文章是开放获取的,因此任何人都可以下载pdf并查看第1图,其中包含我想创建的图表的相关示例。该论文的方法部分表明分析是在Matlab中完成的。
为了方便起见,这里是上述文章中图1的一小部分:

Figure 1 from Flombaum et al. 2013, PNAS

如何在R中创建散点图,使用颜色而不是透明度作为点密度的指标?

首先,R用户可以在install.packages("fields")库中使用tim.colors()函数访问此Matlab颜色方案。

是否有一种简单的方法在R中制作与上述文章中图1类似的图形?谢谢!

3个回答

38

一种选择是使用densCols()函数在每个点提取核密度。将这些密度映射到所需的色带,并按照局部密度递增的顺序绘制点,就可以得到类似于链接文章中的图形。

## Data in a data.frame
x1 <- rnorm(n=1E3, sd=2)
x2 <- x1*1.2 + rnorm(n=1E3, sd=2)
df <- data.frame(x1,x2)

## Use densCols() output to get density at each point
x <- densCols(x1,x2, colramp=colorRampPalette(c("black", "white")))
df$dens <- col2rgb(x)[1,] + 1L

## Map densities to colors
cols <-  colorRampPalette(c("#000099", "#00FEFF", "#45FE4F", 
                            "#FCFF00", "#FF9400", "#FF3100"))(256)
df$col <- cols[df$dens]

## Plot it, reordering rows so that densest points are plotted on top
plot(x2~x1, data=df[order(df$dens),], pch=20, col=col, cex=2)

在此输入图像描述


这似乎正是我所期望的答案...谢谢! - rbatt
@JoshOBrien:太棒了!有两个问题: 1)你是如何在回答中添加图片的? 2)如何在这里添加图例? - Shambho
@Shambho --(1)你可能需要至少100的声望才能在你的标记组合框上获得一个图像图标。(2) 据我所知,没有预打包的方法。我会使用类似layout(matrix(1:2,ncol=2),width=c(75,25))的东西将绘图设备分成两个绘图区域,将第一部分中的图形放在上方,颜色条形放在第二部分中。对于颜色条形,我可能会首先使用此处 给出的 color.bar() 函数,然后删除其中对 dev.new() 的调用。 - Josh O'Brien
@JoshO'Brien 你是怎样选择cols <- colorRampPalette(c("#000099", "#00FEFF", "#45FE4F","#FCFF00", "#FF9400", "#FF3100"))(256)里的颜色的?好像colors()中没有任何一种颜色匹配这些。 - rbatt
@Basilique 这是一个好问题。为了追寻答案,我认为需要跟随 densCols() 所使用的计算方式来确定其返回的颜色,这似乎是由 grDevices:::.smoothScatterCalcDensity()KernSmooth::bkde2D()完成的。 - Josh O'Brien
显示剩余3条评论

5

通过六边形网格化可以获得类似的效果,将区域分成六边形,根据六边形内点的数量着色。Hexbin包中有函数可实现此功能,ggplot2包中也有相关函数。


1
ggplot2 中有哪个函数可以实现这个功能? - rbatt
@rbatt,请看一下 stat_binhex - Greg Snow

3
您可以使用smoothScatter来实现此功能。
colramp = colorRampPalette(c('white', 'blue', 'green', 'yellow', 'red'))
smoothScatter(x1, x2, colramp=colramp)

谢谢您的回复--这大致是正确的想法,但我想避免点的平滑处理。我尝试过调整带宽等参数,但似乎这个函数无法保留每个点的独立性。 - rbatt
不错的发现!我之前不知道这个函数或者相关的 densCols() 函数,但是我在我的回答中使用了它。 - Josh O'Brien

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