R ggplot2 geom_rect堆叠式展示

3

我想在时间轴上叠加一个图表。以下是我的数据:

 Flight_No Dest      Date  Time STD.60 STD.45      Date2          start       end
1    ab0729  KP 14-Oct-13 00:05      1      0 2013-10-14 2013-10-14 00:05:00 2013-10-14 00:20:00
2    ab8063  KI 14-Oct-13 00:20      0      3 2013-10-14 2013-10-14 00:20:00 2013-10-14 00:35:00
3    ab0337  ST 14-Oct-13 00:30      1      0 2013-10-14 2013-10-14 00:30:00 2013-10-14 00:45:00

以下是绘制图形的代码示例:
data$Total<-data$STD.60+data$STD.45    
ggplot(data,aes(x=start,y=Total,xmin=start,xmax=end,ymin=0,ymax=Total,alpha=0,fill=factor(Dest)))+geom_rect()

上面的代码生成了这个图表: enter image description here 但是,我想在有重叠的情况下将这些矩形堆叠起来。 例如,在00:30到00:35之间,y轴的值应该显示为4而不是3。
请帮忙解决。

我认为没有一种“自动”完成这个任务的方法。你可能注定要自己编写代码。但我希望有人能够证明我是错的。 - Roman Luštrik
@RomanLuštrik 确实... - agstudy
2个回答

3

日期排序后,计算重叠范围变得容易。 对于每个区间,我检查是否有任何重叠(开始时间 > 结束时间),如果是,则将下一个总数添加到当前总数中。

## choose just relevant columns
d <- dat[,c('start','end','Dest','Total')]
# Make sure the data is sorted
d <- d[ order(d$start), ]
h <- d
## here all the main stuff
for (i in head(seq_len(nrow(d)),-1)){
  if(d[i+1,'start'] < d[i,'end']){
    xx <- d[i,]
    xx$start <- d[i+1,'start'] 
    xx$Total <- d[i,'Total'] +d[i+1,'Total']
    h <- rbind(h,xx)   
  }
}

library(ggplot2)
ggplot(h,aes(x=start,y=Total,xmin=start,xmax=end,ymin=0,ymax=Total,
             ,fill=factor(Dest),alpha=0))+
  geom_rect()

编辑

我使用scale_x_datetime手动添加了x轴标签。同时,我还使用scales包来格式化日期。

library(scales)
last_plot()
scale_x_datetime(breaks=unique(c(h$start,h$end)),
               labels = date_format("%H:%M"))

enter image description here


@Chandra,你想保留重叠吗?因为在这里我已经将其删除了。 - agstudy
谢谢您的帮助。我想保持重叠。 - Chandra
1
有趣的解决方案,我在思考这带来了什么(额外)信息。如果箱子宽度不相同,则条之间的区域不能直接比较。此时,这不再是一个条形图。我想知道JS人是否有类似的东西?我发现他们的一些可视化方式在统计上是非正确的,但很有创意。 :) - Roman Luštrik
@Chandra 我认为目前没有任何软件包能够很好地处理重叠的时间序列...但是我添加了一些比例尺,也许这可以回答你的问题! - agstudy
@agstudy,上面的问题还有一个复杂的方面... 如果我想在特定的时间间隔内绘制最大值,例如每15分钟一个区间(0000-0015、0015-0030等),应该如何操作? - Chandra
显示剩余3条评论

2
这里有一个解决方案,它依赖于:(1)将时间轴分成5分钟宽的区间,(2)重建长格式数据,以及(3)利用geom_bar(position="stack")的堆叠能力。
dat = structure(list(Dest = c("KP", "KI", "ST"), Total = c(1L, 3L, 1L), 
    start = structure(c(1381730700, 1381731600, 1381732200), 
    class = c("POSIXct", "POSIXt"), tzone = ""), 
    end = structure(c(1381731600, 1381732500, 1381733100), 
    class = c("POSIXct", "POSIXt"), tzone = "")), 
    .Names = c("Dest", "Total", "start", "end"), 
    class = "data.frame", row.names = c(NA, -3L))

# Use loop to split each row of data into bins.
Time = as.POSIXct(vector())
Dest = vector("character", length=0)
Total = vector("integer", length=0)

for (i in seq(nrow(dat))) {
    times = seq(from=dat[i, "start"], to=dat[i, "end"], by="5 min")
    times = head(times, -1) # Remove last element.
    Time = c(Time, times)
    Dest = c(Dest,  rep(dat[i, "Dest"],  length(times)))
    Total= c(Total, rep(dat[i, "Total"], length(times)))
}

dat2 = data.frame(Time, Total, Dest)

library(ggplot2)
p = ggplot(dat2, aes(x=Time, y=Total, fill=Dest)) + 
    geom_bar(stat="identity", position="stack", width=300, color="grey30")

ggsave("plot.png", plot=p, width=10, height=4.5, dpi=120)

注意事项:

  1. 您可以通过更改seq(..., by=参数来改变bin的宽度。请参阅?seq.POSIXt
  2. 您可能希望将startend时间四舍五入到最接近x分钟,以便简化分箱过程。
  3. geom_bar(..., width=300)之所以有效是因为5分钟内有300秒。根据需要进行调整。
  4. x轴上的刻度标记位于条形图的中心,但实际上应用于条形图的左边缘。请像@agstudy所示使用scale_x_datetime(breaks=进行调整。

@bdemarest-- 感谢您提供的出色解决方案。 - Chandra

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