使用ggplot绘制具有不同起点和终点的时间序列数据时的阴影月间隔

时间:2016-10-30 17:28:21

标签: r ggplot2 lubridate

我试图在geom_rect()中使用ggplot2来遮蔽冬季,并且有许多不同的时间序列数据,其中包含不同的起点和终点。对于每个时间序列,我希望每年的11月到3月期间都要加上阴影(剩下的几个月不应该着色)。

例如,使用以下时间序列

library(ggplot2)
library(lubridate)

now <- Sys.time()
set.seed(123)
datOne <- data.frame(IndID = "One",
                      DateTime = seq(from = now - dyears(0.2), length.out = 50, by = "months"),
                      Value = rnorm(50))

我可以定义一个新的数据框对象,每个着色部分的起点和终点(即每年的11月 - 3月)

temp <- data.frame(
  start = as.Date(c('2016-11-1', '2017-11-01', '2018-11-01', '2019-11-01')), 
  end   = as.Date(c('2017-03-01', '2018-03-01', '2019-03-01', '2020-03-01')))

dateRanges <- data.frame(
  start = as.POSIXct(temp [,1], "%Y-%m-%d")+ hours(6),
  end   = as.POSIXct(temp [,2], "%Y-%m-%d")+ hours(6))

然后制作一个情节。

ggplot(datOne) + 
  geom_rect(data = dateRanges, aes(xmin = start , xmax = end, ymin = -Inf, ymax = Inf),
            inherit.aes=FALSE, alpha = 0.4, fill = c("lightblue"))+
  geom_line(aes(x=  DateTime, y = Value), size = 1.5)

enter image description here

虽然这适用于单个时间序列,但我为每个单独的时间序列制作一个单独的数字,每个时间序列都有不同的起点和终点,并且需要一个独特的数据框来创建着色区域。 例如,如下图所示,应用于不同时间序列的相同dateRanges数据框显然不起作用。

datTwo <- data.frame(IndID = "Two",
                      DateTime = seq(from = now , length.out = 100, by = "months"),
                      Value = rnorm(100)) 

ggplot(datTwo) + 
  geom_rect(data = dateRanges, aes(xmin = start , xmax = end, ymin = -Inf, ymax = Inf),
            inherit.aes=FALSE, alpha = 0.4, fill = c("lightblue"))+
  geom_line(aes(x=  DateTime, y = Value), size = 1.5)

是否有不同的方式来遮蔽两个时间序列,以便每个时间我可以自动创建dateRanges或一起使用不同的方法(即注释...)。换句话说,鉴于需要在不同的时期内制作大约100个不同的数字和100个不同的时间序列,那么从11月到3月对任何一年的时间进行着色的最佳方法是什么?

提前致谢。

enter image description here

2 个答案:

答案 0 :(得分:2)

我不知道这是否是“最好的”方法,但这很容易:展开dateRanges框架并重置轴的限制:

# let's make it past & future proof for the next few years: 
dateRanges <- data.frame(
  start = seq(as.POSIXct("1900-11-01 07:00:00"), as.POSIXct("2100-11-01 07:00:00"), "1 year"),
  end = seq(as.POSIXct("1901-03-01 07:00:00"), as.POSIXct("2101-03-01 07:00:00"), "1 year")
)
ggplot(datTwo) + 
  geom_rect(data = dateRanges, aes(xmin = start , xmax = end, ymin = -Inf, ymax = Inf),
            inherit.aes=FALSE, alpha = 0.4, fill = c("lightblue"))+
  geom_line(aes(x=  DateTime, y = Value), size = 1.5) + 
  coord_cartesian(xlim = range(datTwo$DateTime))

enter image description here

答案 1 :(得分:2)

试试这个:

# make it a function
get.date.ranges <- function(data) {
  range.df <- NULL
  for (year in seq(min(year(data$DateTime)), year(max(data$DateTime)), 1)) {
    cur <- data.frame(
          start = as.POSIXct(as.Date(paste(year, '-11-1',sep='')), "%Y-%m-%d")+ hours(6),
          end   = as.POSIXct(as.Date(paste(year+1, '-03-1',sep='')), "%Y-%m-%d")+ hours(6)
        )
    if (cur$start <= max(data$DateTime)) {
      range.df <- rbind(range.df, cur)
    }
  }
  if (nrow(range.df) > 0) {
    range.df[1,]$start <- max(range.df[1,]$start, min(data$DateTime))
    range.df[nrow(range.df),]$end <- min(range.df[nrow(range.df),]$end, max(data$DateTime))
  }
  return(range.df)
}

# plot function
plot.data <- function(data) {
  ggplot(data) + 
    geom_rect(data = get.date.ranges(data), aes(xmin = start , xmax = end, ymin = -Inf, ymax = Inf),
              inherit.aes=FALSE, alpha = 0.4, fill = c("lightblue"))+
    geom_line(aes(x=  DateTime, y = Value), size = 1.5)
}

plot.data(datOne)

enter image description here

plot.data(datTwo)

enter image description here