使用ggplot2在多个面板中划分长时间序列

时间:2017-03-24 18:21:23

标签: r ggplot2

我有一个相当长的时间序列,我想在ggplot中绘制,但它足够长,即使使用页面的全宽度,它几乎不可读。

one time series in one panel

我想要做的是将绘图分成2个(或更多,在一般情况下)面板,彼此叠加。

我可以手动完成,但不仅麻烦,而且很难让轴具有相同的比例。理想情况下,我希望有这样的东西:

ggplot(data, aes(time, y)) + 
  geom_line() +
  facet_time(time, n = 2)

然后得到这样的东西:

one time series in multiple panesl

(此图是使用facet_wrap(~(year(as.Date(time)) > 2000), ncol = 1, scales = "free_x")制作的,它会混淆x轴刻度,它仅适用于2个面板,并且不适用于geom_smooth()

另外,理想情况下,它也会正确处理摘要统计信息。例如,使用geom_smooth()的正确数据(因此,facetting不会这样做,因为在每个方面的开头它不会使用前一个方块的最后一个块中的数据)。

有办法做到这一点吗?

谢谢!

2 个答案:

答案 0 :(得分:2)

您可以通过存储绘图对象,然后将其打印两次来完成此操作。每次添加选项coord_cartesian

orig_plot <- ggplot(data, aes(time, y)) + 
  geom_line() 

early <-  orig_plot + coord_cartesian(xlim = c(1982, 2000))
late  <-  orig_plot + coord_cartesian(xlim = c(2000, 2016))

确保两个图都使用所有数据。

要在同一页面上绘制它们,请使用网格(我从ggplot2书中得到了这个,这可能是某个地方的pdf):

library(grid)
vp1 <- viewport(width = 1, height = .5, just = c("center", "bottom"))
vp2 <- viewport(width = 1, height = .5, just = c("center", "top"))
print(early, vp = vp1)
print(late, vp = vp2)

答案 1 :(得分:2)

下面我创建两个单独的图,一个用于1982-1999期间,一个用于1999-2016,然后使用grid.arrange包中的gridExtra进行布局。水平轴在两个图中等效缩放。

我还使用loess函数在ggplot之外生成回归线,以便可以使用geom_line添加它(当然,您可以使用任何回归函数,例如lmgam,样条等)。通过这种方法,回归可以在整个时间序列上运行,确保两个面板上的回归线的连续性,即使我们将时间序列分成两半进行绘图。

library(dplyr)      # For the chaining (%>%) operator
library(purrr)      # For the map function
library(gridExtra)  # For the grid.arrange function

从ggplot中提取图例的功能。我们将使用它来在两个单独的图中获得一个图例。

# http://stackoverflow.com/questions/12539348/ggplot-separate-legend-and-plot
g_legend<-function(a.gplot){
  tmp <- ggplot_gtable(ggplot_build(a.gplot))
  leg <- which(sapply(tmp$grobs, function(x) x$name) == "guide-box")
  legend <- tmp$grobs[[leg]]
  legend
}

# Fake data
set.seed(255)
dat = data.frame(time=rep(seq(1982,2016,length.out=500),2),
                 value= c(arima.sim(list(ar=c(0.4, 0.05, 0.5)), n=500), 
                          arima.sim(list(ar=c(0.3, -0.3, 0.6)), n=500)),
                 group=rep(c("A","B"), each=500))

使用loess生成更平滑的行:我们需要为group的每个级别设置单独的回归线,因此我们将group_by与来自dplyr的链接运算符一起使用:

dat = dat %>% group_by(group) %>%
        mutate(smooth = predict(loess(value ~ time, span=0.1)))

创建两个图表的列表,每个时间段一个:我们使用map为每个时间段创建单独的图并返回一个列表,其中两个图对象作为元素(您也可以使用base {{ 1}}代替lapply):

map

最后,我们列出了两个图(删除图例后)以及提取的图例:

pl = map(list(c(1982,1999), c(1999,2016)), 
         ~ ggplot(dat %>% filter(time >= .x[1], time <= .x[2]), 
                  aes(colour=group)) +
             geom_line(aes(time, value), alpha=0.5) +
             geom_line(aes(time, smooth), size=1) + 
             scale_x_continuous(breaks=1982:2016, expand=c(0.01,0)) +
             scale_y_continuous(limits=range(dat$value)) +
             theme_bw() +
             labs(x="", y="", colour="") +
             theme(strip.background=element_blank(),
                   strip.text=element_blank(),
                   axis.title=element_blank()))


# Extract legend as a separate graphics object
leg = g_legend(pl[[1]])

enter image description here