如何在ggplot2中为堆叠时序图添加上下双日期坐标轴?
在ggplot2的堆叠时序分面图中同时显示上下日期刻度
你遇到的这个场景太典型了——当分面堆叠出多个时序图后,用户得滚动到底部才能看时间刻度,体验确实不好。虽然scale_x_date()支持调整刻度位置,但没法直接生成顶部的次坐标轴,不过我们可以通过把日期转换为数值,再结合scale_x_continuous()的sec.axis参数来实现这个需求,下面是具体的解决方案:
完整实现代码
library(data.table) library(ggplot2) set.seed(123) foo <- data.table( day = rep(seq(as.Date("2018-01-01"), as.Date("2018-01-30"), by="days"), 3), var = c(rep("v1", 30), rep("v2", 30), rep("v3", 30)), value = round(rnorm(90)*90) ) # 定义日期与数值的转换函数 date_to_num <- function(x) as.numeric(x) num_to_date <- function(x) as.Date(x, origin = "1970-01-01") ggplot(data = foo, aes(x = day, y = value, color = var)) + geom_line() + ggtitle("Demo example", subtitle = "random values") + # 用scale_x_continuous替代scale_x_date,同时设置主副坐标轴 scale_x_continuous( # 主坐标轴(底部):把数值转回日期,设置标签格式和刻度 breaks = date_to_num(seq(from = min(foo$day), to = max(foo$day), length.out = 5)), labels = function(x) format(num_to_date(x), "%Y%m%d"), position = "bottom", # 次坐标轴(顶部):和主坐标轴完全一致的刻度与标签 sec.axis = dup_axis( breaks = date_to_num(seq(from = min(foo$day), to = max(foo$day), length.out = 5)), labels = function(x) format(num_to_date(x), "%Y%m%d"), name = "" # 顶部不需要轴标题,留空 ) ) + facet_grid(var ~ ., scales = "free") + theme( legend.position = "top", legend.title = element_blank(), legend.direction = "horizontal", plot.title = element_text(hjust = 0.5), plot.subtitle = element_text(hjust = 0.5), # 可以调整顶部坐标轴的样式,和底部保持一致 axis.text.x.top = element_text(color = "black"), axis.ticks.x.top = element_line(color = "black") )
关键思路解释
- 日期转数值:因为
scale_x_continuous()只处理数值型数据,所以我们先把Date类型的日期转成对应的数值(从1970-01-01开始的天数),用as.numeric()就能实现。 - 自定义刻度与标签:在
scale_x_continuous()的breaks里传入转换后的数值刻度,再用自定义的标签函数把数值转回日期格式,保证显示的是我们需要的%Y%m%d样式。 - 复制主坐标轴到顶部:用
dup_axis()快速生成和主坐标轴完全一致的次坐标轴,只需要把位置设为顶部,并且去掉轴标题即可。
这样就能实现上下都显示相同的日期刻度,用户不用滚动就能随时看到时间范围啦!
内容的提问来源于stack exchange,提问作者abhiieor
相关产品推荐
相关产品推荐

