【问题标题】:Controlling the order of points in ggplot2?控制ggplot2中点的顺序?
【发布时间】:2013-03-20 08:00:41
【问题描述】:

我正在 ggplot2 中绘制一个密集的散点图,其中每个点都可能用不同的颜色标记:

df <- data.frame(x=rnorm(500))
df$y = rnorm(500)*0.1 + df$x
df$label <- c("a")
df$label[50] <- "point"
df$size <- 2

ggplot(df) + geom_point(aes(x=x, y=y, color=label, size=size))

当我这样做时,标记为“点”(绿色)的散点被绘制在标记为“a”的红色点之上。是什么控制了 ggplot 中的 z 顺序,即什么控制了哪个点在哪个之上?

例如,如果我希望所有“a”点都位于所有标记为“点”的点之上(这意味着它们有时会部分或完全隐藏该点)?这是否取决于标签的字母数字顺序?

我想找到一个可以轻松翻译为 rpy2 的解决方案。

【问题讨论】:

  • last answer 是最好的。 @user248237dfsf,也许你可以选择一个接受的答案?

标签: r ggplot2 rpy2


【解决方案1】:

ggplot2 将逐层创建绘图,并且在每一层内,绘图顺序由geom 类型定义。默认是按照它们在data 中出现的顺序进行绘制。

如果有不同,请注明。例如

geom_line

连接观察,按 x 值排序。

geom_path

按数据顺序连接观察结果


还有known issues regarding the ordering of factors,注意包作者Hadley的回复很有意思

绘图的显示应该与数据框的顺序保持不变 - 其他任何东西都是错误。


记住这句话,图层是按指定的顺序绘制的,所以过度绘制可能是个问题,尤其是在创建密集散点图时。因此,如果您想要一个一致的图(而不是依赖于数据框中的顺序的图),您需要多考虑一下。


创建第二层

如果您希望某些值出现在其他值之上,您可以使用subset 参数来创建第二层,以便之后确定绘制。您需要显式加载 plyr 包,以便 .() 可以工作。

set.seed(1234)
df <- data.frame(x=rnorm(500))
df$y = rnorm(500)*0.1 + df$x
df$label <- c("a")
df$label[50] <- "point"
df$size <- 2
library(plyr)
ggplot(df) + geom_point(aes(x = x, y = y, color = label, size = size)) +
  geom_point(aes(x = x, y = y, color = label, size = size), 
             subset = .(label == 'point'))

更新

ggplot2_2.0.0 中,不推荐使用subset 参数。使用例如base::subset 选择在 data 参数中指定的相关数据。并且无需加载plyr

ggplot(df) +
  geom_point(aes(x = x, y = y, color = label,  size = size)) +
  geom_point(data = subset(df, label == 'point'),
             aes(x = x, y = y, color = label, size = size))

或者使用alpha

另一种避免过度绘制问题的方法是设置点的alpha(透明度)。这不会像上面显式的第二层方法那样有效,但是,如果明智地使用scale_alpha_manual,您应该能够得到一些工作。

例如

# set alpha = 1 (no transparency) for your point(s) of interest
# and a low value otherwise
ggplot(df) + geom_point(aes(x=x, y=y, color=label, size=size,alpha = label)) + 
  scale_alpha_manual(guide='none', values = list(a = 0.2, point = 1))

【讨论】:

【解决方案2】:

2016 年更新:

订单美学has been deprecated,所以此时最简单的方法是对data.frame进行排序,使绿点位于底部,最后绘制。如果您不想更改原始 data.frame,您可以在 ggplot 调用期间对其进行排序 - 这是一个使用 dplyr 包中的 %&gt;%arrange 进行动态排序的示例:

library(dplyr)
ggplot(df %>%
         arrange(label),
       aes(x = x, y = y, color = label, size = size)) +
  geom_point()

ggplot2 版本

的 2015 年原始答案

在 ggplot2 中,您可以使用 order aesthetic 指定点的绘制顺序。最后绘制的将出现在顶部。要应用这一点,您可以创建一个变量来保存您希望绘制点的顺序。

将绿点绘制在其他点之后:

df$order <- ifelse(df$label=="a", 1, 2)
ggplot(df) + geom_point(aes(x=x, y=y, color=label, size=size, order=order))

或者先绘制绿点并把它埋起来,以相反的顺序绘制点:

ggplot(df) + geom_point(aes(x=x, y=y, color=label, size=size, order=-order))

对于这个简单的示例,您可以跳过创建新的排序变量,只需将 label 变量强制转换为一个因子,然后是一个数字:

ggplot(df) +
  geom_point(aes(x=x, y=y, color=label, size=size, order=as.numeric(factor(df$label))))

【讨论】:

  • 我猜这很新?这是一个比其他所有答案都好得多的答案。
  • @naught101 很高兴您向下滚动以找到此答案,因为可能需要一段时间才能在列表中冒泡。根据各种博客文章,order 美学似乎至少从 2009 年或 2010 年就已经存在。
  • @SamFrike 我无法使用完全相同的代码复制您的解决方案,似乎忽略了订单美学。我正在使用 R 版本 3.3.1 (2016-06-21) 和 x86_64-apple-darwin13.4.0 平台。关于这个问题的任何想法?谢谢
  • @ChriiSchee 感谢您注意到这一点。我看到 order 美学不幸已从 ggplot2 中弃用,因此我更新了答案以反映我认为是下一个最佳选择。
【解决方案3】:

这里的基本问题可以改写如下:

如何控制绘图的层级?

在“ggplot2”包中,您可以通过将每个不同的层拆分为不同的命令来快速完成此操作。考虑层次需要一些练习,但它本质上归结为你想要在其他事物之上绘制的内容。您从后台向上构建。

准备:准备样本数据。此步骤仅在本示例中是必需的,因为我们没有要处理的真实数据。

# Establish random seed to make data reproducible.
set.seed(1)

# Generate sample data.
df <- data.frame(x=rnorm(500))
df$y = rnorm(500)*0.1 + df$x

# Initialize 'label' and 'size' default values.
df$label <- "a"
df$size <- 2

# Label and size our "special" point.
df$label[50] <- "point"
df$size[50] <- 4

您可能会注意到,我在示例中添加了不同的大小,只是为了使图层差异更加清晰。

第 1 步:将数据分层。在使用“ggplot”功能之前,请务必执行此操作。太多人因为试图使用“ggplot”函数进行数据操作而陷入困境。在这里,我们要创建两层:一层带有“a”标签,一层带有“点”标签。

df_layer_1 <- df[df$label=="a",]
df_layer_2 <- df[df$label=="point",]

您可以使用其他函数来执行此操作,但我只是快速使用数据框匹配逻辑来提取数据。

第 2 步:将数据绘制为图层。我们要先绘制所有“a”数据,然后再绘制所有“点”数据。

ggplot() + 
    geom_point(
        data=df_layer_1,
        aes(x=x, y=y), 
        colour="orange", 
        size=df_layer_1$size) +
    geom_point(
        data=df_layer_2, 
        aes(x=x, y=y), 
        colour="blue", 
        size=df_layer_2$size)

请注意,基本绘图层ggplot() 没有分配数据。这很重要,因为我们将覆盖每一层的数据。然后,我们有两个独立的点几何层geom_point(...),它们使用自己的规范。 x 和 y 轴将共享,但我们将使用不同的数据、颜色和大小。

将颜色和尺寸规格移到aes(...) 函数之外很重要,因此我们可以按字面意思指定这些值。否则,“ggplot”函数通常会根据数据中的级别分配颜色和大小。例如,如果您在数据中有大小值 2 和 5,它将为任何出现的值 2 分配一个默认大小,并为任何出现的值 5 分配一些更大的大小。一个“aes”函数规范不会使用值 2 和 5 作为尺寸。 颜色也是如此。我有想要使用的确切尺寸和颜色,所以我将这些参数移到“geom_plot”函数本身。另外,'aes'函数中的任何规格都会被放入图例中,这真的没用。

最后说明:在此示例中,您可以通过多种方式获得想要的结果,但重要的是要了解“ggplot2”图层的工作原理,以便充分利用“ggplot” '图表。只要在调用 'ggplot' 函数之前将数据分成不同的层,您就可以很好地控制屏幕上的图形显示方式。

【讨论】:

  • 你的第二个图层解决方案很好,但不幸的是没有关于彩色点的传说
【解决方案4】:

它是按 data.frame 中的行顺序绘制的。试试这个:

df2 <- rbind(df[-50,],df[50,])
ggplot(df2) + geom_point(aes(x=x, y=y, color=label, size=size))

如您所见,绿点是最后绘制的,因为它代表 data.frame 的最后一行。

这是一种命令 data.frame 先绘制绿点的方法:

df2 <- df[order(-as.numeric(factor(df$label))),]

【讨论】:

  • 当我尝试你的代码时,绿点仍然在所有红色的顶部。有没有办法在不改变数据框的情况下改变 z 顺序?我只是希望某些点在非常密集的分散中位于其他点之上
  • 您应该设置随机种子以使您的问题可重现。只需通过label 对data.frame 进行排序,然后再将其传递给ggplot。如果要先绘制绿点,请对 data.frame 进行排序,以便标签为 point 的行位于 data.frame 的顶部。
  • 不幸的是,我不知道如何将这个 df[order(-as.numeric(factor(df$label))),] 翻译成 Rpy2 语法(我使用的是 rpy2,而不是直接使用 R)。
  • 对不起,我对rpy2一无所知。你可以使用df[order(df$label,decreasing=TRUE),],它也应该这样做。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-11-13
  • 2013-05-28
  • 2021-10-09
相关资源
最近更新 更多