【问题标题】:Subset/filter in dplyr chain with ggplot2使用 ggplot2 在 dplyr 链中进行子集/过滤
【发布时间】:2017-10-15 22:06:38
【问题描述】:

我想按照this 的线条(没有双关语)制作一个斜率图。理想情况下,我想在 dplyr 样式的链中完成所有操作,但是当我尝试对数据进行子集化以添加特定的 geom_text 标签时遇到了障碍。这是一个玩具示例:

# make tbl:

df <- tibble(
  area = rep(c("Health", "Education"), 6),
  sub_area = rep(c("Staff", "Projects", "Activities"), 4),
  year = c(rep(2016, 6), rep(2017, 6)),
  value = rep(c(15000, 12000, 18000), 4)
) %>% arrange(area)


# plot: 

df %>% filter(area == "Health") %>% 
  ggplot() + 
  geom_line(aes(x = as.factor(year), y = value, 
            group = sub_area, color = sub_area), size = 2) + 
  geom_point(aes(x = as.factor(year), y = value, 
            group = sub_area, color = sub_area), size = 2) +
  theme_minimal(base_size = 18) + 
  geom_text(data = dplyr::filter(., year == 2016 & sub_area == "Activities"), 
  aes(x = as.factor(year), y = value, 
  color = sub_area, label = area), size = 6, hjust = 1)

但这给了我Error in filter_(.data, .dots = lazyeval::lazy_dots(...)) : object '.' not found。使用子集而不是 dplyr::filter 会给我一个类似的错误。我在 SO/Google 上找到的是this question,它解决了一个稍微不同的问题。

像这样对链中的数据进行子集化的正确方法是什么?

编辑:我的reprex 是一个简化的例子,在实际工作中我有一个长链。 Mike 在下面的评论适用于第一种情况,但不适用于第二种情况。

【问题讨论】:

  • df替换.怎么样?
  • 您可以通过使用大括号明确指定您希望传入 data.frame 的管道位置来破解它:df %&gt;% filter(area == "Health") %&gt;% { ggplot(.) + geom_line(aes(x = as.factor(year), y = value, group = sub_area, color = sub_area), size = 2) + geom_point(aes(x = as.factor(year), y = value, group = sub_area, color = sub_area), size = 2) + geom_text(data = dplyr::filter(., year == 2016 &amp; sub_area == "Activities"), aes(x = as.factor(year), y = value, color = sub_area, label = area), size = 6, hjust = 1) } 我不确定它是否能满足您的需求,但这是一个情节,至少。
  • @MikeH。谢谢,这行得通!但是,它需要aes()中的变量前面的数据框名称(我的真实示例是一个长管道,数据框不是首先创建的)。但是,谢谢,当数据在全球环境中时,这是有效的。
  • @alistaire 哇,这是一种非常有趣的方式。您介意解释一下在这种情况下括号是如何工作的吗?
  • ?magrittr::`%&gt;%`。通常管道将左侧的结果传递给右侧的第一个参数,但如果您将 RHS 包裹在大括号中,它只会将结果发送到您放置 . 的任何位置,这样您就可以使用它重复或跨子管道中的多个调用。

标签: r ggplot2 dplyr subset


【解决方案1】:

如果将绘图代码包装在{...} 中,则可以使用. 来指定先前计算结果的准确插入位置:

library(tidyverse)

df <- tibble(
  area = rep(c("Health", "Education"), 6),
  sub_area = rep(c("Staff", "Projects", "Activities"), 4),
  year = c(rep(2016, 6), rep(2017, 6)),
  value = rep(c(15000, 12000, 18000), 4)
) %>% arrange(area)

df %>% filter(area == "Health") %>% {
    ggplot(.) +    # add . to specify to insert results here
        geom_line(aes(x = as.factor(year), y = value, 
                      group = sub_area, color = sub_area), size = 2) + 
        geom_point(aes(x = as.factor(year), y = value, 
                       group = sub_area, color = sub_area), size = 2) +
        theme_minimal(base_size = 18) + 
        geom_text(data = dplyr::filter(., year == 2016 & sub_area == "Activities"),    # and here
                  aes(x = as.factor(year), y = value, 
                      color = sub_area, label = area), size = 6, hjust = 1)
}

虽然该情节可能不是您真正想要的,但至少它可以运行,以便您可以对其进行编辑。

发生了什么:通常%&gt;% 将左侧 (LHS) 的结果传递给右侧 (RHS) 的第一个参数。但是,如果您将 RHS 包裹在大括号中,%&gt;% 只会将结果传递到您明确放置 . 的任何位置。这个公式对于嵌套的子管道或其他复杂的调用(如 ggplot 链)很有用,这些调用无法通过. 重定向来解决。有关更多详细信息和选项,请参阅help('%&gt;%', 'magrittr')

【讨论】:

    【解决方案2】:

    写作:

    geom_text(data = df[df$year == 2016 & df$sub_area == "Activities",],...
    

    而不是

    geom_text(data = dplyr::filter(., year == 2016 & sub_area == "Activities"),...
    

    使它工作,但您仍然对文本的位置有疑问(您应该能够轻松找到关于该问题的 SO 帮助)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-08
      • 2018-06-22
      相关资源
      最近更新 更多