在使用ggplot2的dplyr链中进行子集/筛选

7

我想制作一个类似于这个的斜坡图。理想情况下,我希望能够在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上找到的是这个问题,它解决了一个略微不同的问题。

在这样的链中,正确的数据子集是什么?

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


2
. 替换成 df 怎么样? - Mike H.
4
您可以使用大括号来明确指定数据框应该被导入到哪里: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) + 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) }我不确定它是否能给您想要的结果,但至少这是一张图表。 - alistaire
@MikeH。谢谢,有效!但是,在aes()中的变量前面需要数据框的名称(我的真实示例是一个长管道,数据框不是首先创建的)。但是感谢您,在全局环境中使用时有效。 - RobertMyles
@alistaire 哇,这是一种非常有趣的方法。你介意解释一下在这种情况下括号是如何起作用的吗? - RobertMyles
3
请参阅?magrittr::\%>%`。通常,管道将左侧操作的结果传递给右侧第一个参数,但如果您将 RHS 包装在大括号中,则只会将结果发送到您放置 . `的位置,这使您可以在子管道内重复使用它或跨多个调用使用它。 - alistaire
@alistaire 谢谢你的解释。如果你想写下来,我会把它作为答案接受的。无论如何,感谢你的帮助,这很完美,正是我想要的。 - RobertMyles
2个回答

12

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

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)
}

虽然这个图形可能不是你真正想要的,但至少它能运行,以便你可以编辑它。

正在发生的事情:通常 %>% 将左侧结果(LHS)传递给右侧第一个参数(RHS)。但是,如果你在 RHS 中用大括号包裹,%>% 仅会将结果传递到你明确放置 . 的位置。这种形式对于嵌套的子管道或其他复杂的调用(如 ggplot 链)非常有用,否则无法通过重定向 . 来解决。有关详细信息和选项,请参见 help('%>%', 'magrittr')


3

写作:

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

替代

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

这使得它能够工作,但您仍然有关于文本位置的问题(您应该能够在SO上轻松找到解决此问题的帮助)。


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