如何将循环与 geom_vline 和 facet_wrap 一起使用?

Posted

技术标签:

【中文标题】如何将循环与 geom_vline 和 facet_wrap 一起使用?【英文标题】:How to use loop with geom_vline and facet_wrap? 【发布时间】:2021-12-21 08:50:48 【问题描述】:

我的数据类似于我在下面创建的数据:

set.seed(42)
dates <- seq.Date(as.Date("2012-08-01"), as.Date("2014-08-30"), "day")
n <- length(dates)
dat <- data.frame(date = dates,
                  category = rep(LETTERS[1:4], n/2),
                  daily_count = sample(18:100, n, replace=TRUE))

#following to be used for creating dotted lines; highlighting a certain point for each category
point_dates <- sample(seq.Date(as.Date("2012-08-01"), as.Date("2014-08-30"), "month"),4)
category_name <- list("A", "B", "C", "D")

我正在使用facet_wrap 为每个类别创建一个箱线图,point_dates 对我来说很重要,因为它们显示了每个箱线图中的兴趣点。这就是我创建情节的方式:

ggplot(dat) +
  geom_boxplot(aes(y = daily_count,
                   x = yearmonth(date),
                   group = paste(yearmonth(date), category),
                   fill = category)) +
  labs(x = 'Month & Year',
       y = 'Count',
       fill = "Category") +
  theme_bw() +
  theme(axis.text=element_text(size=10),
        axis.title=element_text(size=10),
        legend.position="none") +
  geom_vline(xintercept =  lubridate::ymd("2013-08-23"), linetype=1, colour="red", size = 0.5)+
  
  sapply(point_dates[[1]], function(xint) geom_vline(data=filter(dat, 
  category==category_name[[1]]),aes(xintercept = xint),
  linetype=3, colour="black", size = 1))+
  
  sapply(point_dates[[2]], function(xint) geom_vline(data=filter(dat, 
  category==category_name[[2]]),aes(xintercept = xint),
  linetype=3, colour="black", size = 1))+
  
  sapply(point_dates[[3]], function(xint) geom_vline(data=filter(dat, 
  category==category_name[[3]]),aes(xintercept = xint),
  linetype=3, colour="black", size = 1))+
  
  sapply(point_dates[[4]], function(xint) geom_vline(data=filter(dat, 
  category==category_name[[4]]),aes(xintercept = xint),
  linetype=3, colour="black", size = 1))+
  
  facet_wrap(~category, nrow = 2)

这是代码的输出: 情节正在被创造得很好。我的问题是,有没有更好的方法(可能是循环?)可以帮助我摆脱多次写sapply。因为类别的数量可能会发生变化(增加/减少),那就是每次都更改代码。

请问有什么指导吗?

【问题讨论】:

【参考方案1】:

您可以使用map() 来迭代对sapply() 的调用:

ggplot(dat) +
  geom_boxplot(aes(y = daily_count,
                   x = yearmonth(date),
                   group = paste(yearmonth(date), category),
                   fill = category)) +
  labs(x = 'Month & Year',
       y = 'Count',
       fill = "Category") +
  theme_bw() +
  theme(axis.text=element_text(size=10),
        axis.title=element_text(size=10),
        legend.position="none") +
  geom_vline(xintercept =  lubridate::ymd("2013-08-23"), linetype=1, colour="red", size = 0.5)+
  
  map(seq_along(unique(dat$category)), ~sapply(point_dates[[.]], function(xint) geom_vline(data=filter(dat, 
  category==category_name[[.]]),aes(xintercept = xint),
  linetype=3, colour="black", size = 1))) +

  facet_wrap(~category, nrow = 2)

【讨论】:

【参考方案2】:

我不确定这是不是最好的方法,但您可以使用来自tidyrmap2 一次性完成所有这些。这样可以节省您写出单个 sapply 的时间。

library(tidyverse)

ggplot(dat) +
  geom_boxplot(aes(y = daily_count,
                   x = yearmonth(date),
                   group = paste(yearmonth(date), category),
                   fill = category)) +
  labs(x = 'Month & Year',
       y = 'Count',
       fill = "Category") +
  theme_bw() +
  theme(axis.text=element_text(size=10),
        axis.title=element_text(size=10),
        legend.position="none") +
  geom_vline(xintercept =  lubridate::ymd("2013-08-23"), 
             linetype=1, colour="red", size = 0.5)+
  map2(point_dates, category_name, 
       ~geom_vline(data=filter(dat, category==.y),
                   aes(xintercept = .x),
                   linetype=3, colour="black", size = 1))+
  facet_wrap(~category, nrow = 2)

【讨论】:

非常感谢大家。我喜欢 SO,总能找到解决方案和最优秀的人。所有答案都是正确的,我希望我能全部选择。【参考方案3】:

如果我没看错,您已经为每个组定义了日期。所以制作第一个情节:

library(ggplot2)
library(tsibble)

g = ggplot(dat) +
  geom_boxplot(aes(y = daily_count,
                   x = yearmonth(date),
                   group = paste(yearmonth(date), category),
                   fill = category)) +
  labs(x = 'Month & Year',
       y = 'Count',
       fill = "Category") +
  theme_bw() +
  theme(axis.text=element_text(size=10),
        axis.title=element_text(size=10),
        legend.position="none") +
  geom_vline(xintercept =  lubridate::ymd("2013-08-23"), linetype=1, colour="red", size = 0.5)+ 
  facet_wrap(~category, nrow = 2)

你只需要提供一个新的数据框并调用geom_vline:

tmp = data.frame(category=unlist(category_name),date=point_dates)

g + geom_vline(data=tmp,aes(xintercept = date),
linetype=3, colour="black", size = 1)

【讨论】:

以上是关于如何将循环与 geom_vline 和 facet_wrap 一起使用?的主要内容,如果未能解决你的问题,请参考以下文章

使用因式分解变量和 geom_hline / geom_vline 进行刻面

如何将垂直 geom_vline 获取到课程日期的 x 轴?

将 geom_vline 扩展到绘图之外

如何在同一个散点图上使用 geom_vline() 和 geom_hline 避免图例中的交叉效应?

If else in ggplot +在geom_vline的字符和数字之间切换值

具有二进制变量和 x 轴日期和长数据格式的 ggplot geom_vline