使用alpha通道叠加两个ggplot2 stat_density2d绘图。

22

我希望能够叠加两个带有 alpha 通道的 ggplot2 图表,使得生成的图像能够同时显示两个数据集。这是我的测试数据:

data = read.table(text="P1 -1 0 4\nP2 0 0 2\nP3 2 1 8\nP4 -2 -2 6\nP5 0.5 2 12")
data2 = read.table(text="Q1 1 1 3\nQ2 1 -1 2\nQ3 -1 1 8")
colnames(data) = c("name","x","y","score")
colnames(data2) = c("name","x","y","score")

这是我绘制这些数据的方法:

ggplot(data, aes(x=x,y=y)) + 
  stat_density2d(data=data,geom="tile", aes(fill = ..density..,alpha=..density..), contour=FALSE) + 
  theme(legend.position="none") + scale_fill_gradient (low = "#FFFFFF", high = "#FF0000") + 
  xlim(-3,3) + ylim(-3,3) + 
  geom_point()

ggplot(data2, aes(x=x,y=y)) + 
  stat_density2d(data=data2,geom="tile", aes(fill = ..density..,alpha=..density..), contour=FALSE) + 
  theme(legend.position="none") + 
  scale_fill_gradient (low = "#FFFFFF", high = "#00FF00") + 
  xlim(-3,3) + ylim(-3,3) + 
  geom_point()

第一个图显示data,第二个图显示data2:

数据集*data*的绘图 数据集*data2*的绘图

现在我想要结合这两个图。下面的图片就是我想得到的效果。我使用桌面上的图像编辑程序将两个图像相乘作为图层来生成它。

同时包含两个数据集的图

我尝试将一个数据集放在另一个数据集之上,但这样并不能将两个图层相乘,而是第二个颜色覆盖了第一个颜色。

ggplot(data, aes(x=x,y=y)) + 
  stat_density2d(data=data,geom="tile", aes(fill = ..density..,alpha=..density..), contour=FALSE) + 
  theme(legend.position="none") + scale_fill_gradient (low = "#FFFFFF", high = "#FF0000") + 
  xlim(-3,3) + ylim(-3,3) + 
  stat_density2d(data=data2,geom="tile", aes(fill = ..density..,alpha=..density..), contour=FALSE) + 
  scale_fill_gradient (low = "#FFFFFF", high = "#00FF00")

在此输入图像描述

此外,我收到了这个警告:'fill'的比例已经存在。添加另一个'fill'的比例,它将替换现有的比例。

在R中是否有一种方法可以实现这一点?或者是否有其他方法(如使用smoothScatter等其他函数)可以获得类似的结果?作为一种解决方法,我认为我可以在服务器上使用ImageMagick获得类似的结果,但我更喜欢在R中完成所有操作。

更新1

在ImageMagick中执行两个图层的乘法是这样的;

composite -compose multiply data-red.png data-green.png im-multiply.png

这与上面显示的结果相同。

更新2

@Roland 在他的答案中教我如何在同一图中绘制两个数据集。虽然这很方便,但仍存在一个问题:图像取决于您将数据提供给绘图的顺序。

ggplot(rbind(data.frame(data, group="a"), data.frame(data2, group="b")), aes(x=x,y=y)) + 
  stat_density2d(geom="tile", aes(fill = group, alpha=..density..), contour=FALSE) + 
  scale_fill_manual(values=c("a"="#FF0000", "b"="#00FF00")) + 
  geom_point() + 
  theme_minimal() + 
  xlim(-3.3, 3.3) + ylim(-3.3, 3.3) +
  coord_cartesian(xlim = c(-3.2, 3.2), ylim = c(-3.2, 3.2))

得到以下结果:

先绘制数据集"a",然后绘制数据集"b2"的第一张图。

当交换这两个数据集的顺序(现在数据集“b”也称为data2放在前面,然后是数据集data也称为“a”),您会得到一个类似的结果,但现在红色占主导地位,因为它后来被绘制,从而覆盖了绿色数据。

ggplot(rbind(data.frame(data2, group="a"), data.frame(data, group="b")), aes(x=x,y=y)) + 
  stat_density2d(geom="tile", aes(fill = group, alpha=..density..), contour=FALSE) + 
  scale_fill_manual(values=c("b"="#FF0000", "a"="#00FF00")) +
  geom_point() + theme_minimal() + 
  xlim(-3.3, 3.3) + ylim(-3.3, 3.3) + 
  coord_cartesian(xlim = c(-3.2, 3.2), ylim = c(-3.2, 3.2))

enter image description here

我需要一种不依赖数据集顺序的解决方案。


1
不幸的是,根据Hadley在StackOverflow上的回答,每个图表只能有一个比例尺(除了x和y轴)。因此,您最有可能只能生成两张图表并使用ImageMagick进行转换。 - hrbrmstr
谢谢您指出这个声明。那我就用ImageMagick的方式去做。 - z80crew
关于堆叠顺序影响最终颜色的问题,这里还有一个相关的讨论:http://www.mail-archive.com/r-help@r-project.org/msg84014.html 最好的解决方案是自己计算堆叠的颜色并绘制出来 - 这里有一个例子,虽然不是在ggplot2中:http://stackoverflow.com/questions/13867782/superimpose-red-green-images-in-r-using-image-or-rasterimage - Tom Wenseleers
根据顺序得到的不同结果可能也与背景的白色混合有关。 - Tom Wenseleers
你也可以尝试使用MASS::kde2d自行计算密度,当堆叠时计算适当的RGB值,并使用类似qplot(x, y, data=mydata, fill=rgb, geom="raster") + scale_fill_identity()的方法绘制它们。 - Tom Wenseleers
2个回答

16

这里提供与 @Roland 完全相同的解决方案,除了我建议使用等高线。这样可以让您欣赏到重叠部分。 我不知道 geom_tile 和你所谓的“乘法”如何让您欣赏到这一点。也许如果您在非重叠区域使用蓝色和红色,并在重叠区域使用“加权”的紫色。但我想在绘图之前你需要在前面的步骤中计算它。

contour_line

ggplot(rbind(data.frame(data, group="a"), data.frame(data2, group="b")), 
       aes(x=x,y=y)) + 
  stat_density2d(geom="density2d", aes(color = group,alpha=..level..),
                 size=2,
                 contour=TRUE) + 
  #scale_color_manual(values=c("a"="#FF0000", "b"="#00FF00")) +
  geom_point() +
  theme_minimal() +
  xlim(-3.3, 3.3) + ylim(-3.3, 3.3) +
  coord_cartesian(xlim = c(-3.2, 3.2), ylim = c(-3.2, 3.2))

我猜你是想用 scale_color_manual 而不是 scale_fill_manual - William Zhang
@WilliamZhang。是的,谢谢。实际上我复制/粘贴了Roland的解决方案,并进行了最小的更改。我现在已经纠正了我的帖子。 - Pierre
谢谢,这是一种有趣的视觉方法。虽然它对我展示的测试数据效果很好,但我不确定它是否适用于我的真实数据。尽管如此,还是加一分。 - z80crew

7

您应该在相同的比例尺上绘制两个密度图:

ggplot(rbind(data.frame(data, group="a"), data.frame(data2, group="b")), 
       aes(x=x,y=y)) + 
  stat_density2d(geom="tile", aes(fill = group, alpha=..density..), 
                 contour=FALSE) + 
  scale_fill_manual(values=c("a"="#FF0000", "b"="#00FF00")) +
  geom_point() +
  theme_minimal() +
  xlim(-3.3, 3.3) + ylim(-3.3, 3.3) +
  coord_cartesian(xlim = c(-3.2, 3.2), ylim = c(-3.2, 3.2))

否则,您会展示一张失真的数据图片。

这是我尝试过的巨大改进。谢谢你。两个图层有可能相乘吗?使用您的代码,后面的数据集在视觉上占主导地位,因此绿色比红色更亮。如果我交换datadata2,红色会变得更亮。 - z80crew
组a的局部密度极大值高于组b。 图表反映了这一点。 我不知道你所说的“乘以”是什么意思。 - Roland
但是当组 a 的最大值(以红色绘制)更高时,为什么绿色(组 b)更亮呢?如果您在代码中更改 datadata2rbind(data.frame(data2, group="a"), data.frame(data, group="b")values=c("b"="#FF0000", "a"="#00FF00") - 那么红色比绿色更亮。在“乘法”的概念中,我指的是图像编辑中两个图层的混合模式。该模式是对称的,因此执行顺序并不重要。 - z80crew
抱歉,在写作过程中我混淆了。B组的最大值更高。 - Roland
为什么B组的最大值应该更高?事实是,您的解决方案取决于将数据提供给ggplot的顺序。稍后打印的数据会在某种程度上覆盖先前的数据。 - z80crew

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