ggplot2 geom_density2d 停止正常工作

问题描述

请参阅下面的示例代码,它输出链接的图像 (link to image)。

在这个包含 3 组的数据集中,当我一次绘制一组时,一切正常。但是当我将所有 3 个组绘制在一起(右下图)时,绿色和蓝色组的密度线不正确,正如您通过比较右上图与右下图以及左下图与右下图所见情节(分别)。

这个问题最近开始出现,因为过去一切正常。我不确定是什么导致了这个问题,所以我从我的 MacBook Pro(macOS Catalina 10.15.6)中卸载了 R,然后重新安装了 R(4.0.5)和 ggplot2,但问题仍然存在。你能帮忙吗?谢谢。

library(gridExtra); library(ggplot2)
dat <- read.csv(url("https://github.com/tidyverse/ggplot2/files/6426291/test.csv"))
p1 <- ggplot(dat[dat$Type=="type1",],aes(x=dim1,y=dim2,col=Type))+geom_density2d()+scale_color_manual(values="#F8766D")+theme_classic()+theme(legend.position="top")+scale_x_continuous(limits=c(-50,50))+scale_y_continuous(limits=c(-50,50))
p2 <- ggplot(dat[dat$Type=="type2",col=Type))+geom_density2d()+scale_color_manual(values="#00BA38")+theme_classic()+theme(legend.position="top")+scale_x_continuous(limits=c(-50,50))
p3 <- ggplot(dat[dat$Type=="type3",col=Type))+geom_density2d()+scale_color_manual(values="#619CFF")+theme_classic()+theme(legend.position="top")+scale_x_continuous(limits=c(-50,50))
p4 <- ggplot(dat,col=Type))+geom_density2d()+theme_classic()+theme(legend.position="top")+scale_x_continuous(limits=c(-50,50))
grid.arrange(p1,p2,p3,p4,nrow=2)

解决方法

来自 Claus Wilke (GitHub) 的解决方案:用 geom_density2d(contour_var="ndensity") 替换 geom_density2d()

,

geom_density2d 工作正常。它只是没有按照你想要的方式工作。您的问题是由于您允许 geom_density2d 自动计算轮廓的位置,并且您的数据在按 Type 分组时具有不同的范围。您可以通过以下方式查看:

dat %>% 
  group_by(Type) %>% 
  summarise(across(everything(),.fns=list(min=min,max=max,mean=mean)),.groups="drop")
# A tibble: 3 x 7
  Type  dim1_min dim1_max dim1_mean dim2_min dim2_max dim2_mean
* <fct>    <dbl>    <dbl>     <dbl>    <dbl>    <dbl>     <dbl>
1 type1    -16.2     35.0      7.31    -23.8     41.1     29.2 
2 type2    -30.2     43.6     23.5     -11.3     43.3      8.43
3 type3    -39.2     39.6    -15.4     -41.4     30.8    -15.6 

这意味着由 geom_density2d() 标记的密度级别在类型级别(在单个图中)和整个数据集之间是不同的。解决方案是强制 geom_density2d() 使用您想要的轮廓。一旦您知道要使用的轮廓,就可以使用 breaks 参数完成此操作。

找出原始图中使用的轮廓有点难看,但可以做到:

unique(ggplot_build(p1)$data[[1]]$level)
[1] 0.0005 0.0010 0.0015 0.0020 0.0025 0.0030 0.0035 0.0040 0.0045
unique(ggplot_build(p2)$data[[1]]$level)
[1] 0.0002 0.0004 0.0006 0.0008 0.0010 0.0012 0.0014
unique(ggplot_build(p3)$data[[1]]$level)
[1] 1e-04 2e-04 3e-04 4e-04 5e-04 6e-04 7e-04 8e-04
unique(ggplot_build(p4)$data[[1]]$level)
[1] 0.0005 0.0010 0.0015 0.0020 0.0025 0.0030 0.0035 0.0040 0.0045

简而言之,ggplot_build 允许您检查 ggplot 对象下的数据。在这里,我打印了四个绘图中每一个的独特轮廓级别。

我们可以通过将每个图中使用的轮廓整理成单个向量来强制 geom_density2d() 在整个图中使用我们想要的轮廓。假设 b1b2b3 是上述前三个调用的结果。然后设置

b <- c(b1,b2,b3)

并使用例如

p1 <- dat %>% 
        filter(Type == "type1") %>%
        ggplot(Type=="type1",aes(x=dim1,y=dim2,col=Type)) +
        geom_density2d(breaks=b) +
        scale_color_manual(values="#F8766D") +
        theme_classic() +
        theme(legend.position="top") +
        coord_cartesian(xlim=c(-50,50),ylim=c(-50,50))

p4 <- data %>% 
        ggplot(dat,col=Type)) +
        geom_density2d(breaks=b) +
        theme_classic() +
        theme(legend.position="top") +
        coord_cartesian(xlim=c(-50,50))

这样你的最终组合图就变成了:

enter image description here

一些额外的评论:

  1. 这些新图与您的原图不同的原因是您现在在每个图中使用了不同的等高线级别。
  2. 我已经使用您的原始图来定义等高线级别。显然,您不会在最终的工作代码中这样做 - 您可以使用任何您喜欢的级别:只需使用 breaks 参数将它们传递给每个绘图。
  3. 我已经修改了您创建 p1 的代码,以使用更常用的语法,但它的作用与原始语法完全相同。就我个人而言,我发现标准语法更易于阅读。
  4. 我认为您应该在调用 coord_cartesian() 函数时使用 limits 来设置轴限制,而不是 scale_xxxx。原因是 coord_cartesian 使用整个数据集来创建绘图,然后将输出“缩放”到请求的视口。 limits 另一方面,在仅使用视口中的点创建绘图之前过滤数据集。当绘图涉及插值或创建汇总统计时,这可能会产生意想不到的后果。根据我的经验,coord-cartesian 几乎总是给出“正确”的输出。
  5. 以后,请格式化您的代码,以便于阅读。除非查看者向右滚动,否则您的代码的重要功能在这篇文章中是不可见的。帮助我们为您提供帮助。

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...