ggplot:按月在同一个图上的多个时间段

Posted

技术标签:

【中文标题】ggplot:按月在同一个图上的多个时间段【英文标题】:ggplot: multiple time periods on same plot by month 【发布时间】:2022-01-12 21:52:49 【问题描述】:

我试图在同一个时间序列图上按月绘制多个时间段。这是我的数据:https://pastebin.com/458t2YLg。我试图避免使用dput() 示例,但我认为减少样本并仍保留原始数据的结构会造成混乱。这里基本上是它的外观:

    date        fl_all_cumsum
671 2015-11-02  0.785000
672 2015-11-03  1.046667
673 2015-11-04  1.046667
674 2015-11-05  1.099000
675 2015-11-06  1.099000
676 2015-11-07  1.099000
677 2015-11-08  1.151333

基本上,它是跨越数年的每日数据。我的目标是比较几个冬季的累积雪滑翔(fl_all_cumsum)( 与此非常相似:ggplot: Multiple years on same plot by month 但是,有一些区别,例如:1)时间段不是年份而是冬季(1.10.xxxx - 6.30.xxxx+1); 2)因为我只关心冬季,所以我希望 x 轴只从 10 月到次年 6 月底; 3) 数据不一致(几个月内有很多 NA 差距)。

我设法制作了这个:

library(zoo)
library(lubridate)
library(ggplot2)
library(scales)
library(patchwork)
library(dplyr)
library(data.table)

startTime <- as.Date("2016-10-01")
endTime <- as.Date("2017-06-30")
start_end <- c(startTime,endTime)

ggplot(data = master_dataset, aes(x = date, y = fl_all_cumsum))+
  geom_line(size = 1, na.rm=TRUE)+
  ggtitle("Cumulative Seasonal Gliding Distance")+
  labs(color = "")+
  xlab("Month")+
  ylab("Accumulated Distance [mm]")+
  scale_x_date(limits=start_end,breaks=date_breaks("1 month"),labels=date_format("%d %b"))+
  theme(axis.text.x = element_text(angle = 50, size = 10 , vjust = 0.5),
        axis.text.y = element_text(size = 10, vjust = 0.5), 
        panel.background = element_rect(fill = "gray100"),
        plot.background = element_rect(fill = "gray100"),
        panel.grid.major = element_line(colour = "lightblue"),
        plot.margin = unit(c(1, 1, 1, 1), "cm"),
        plot.title = element_text(hjust = 0.5, size = 22))

这实际上在视觉上效果很好,因为 x 轴根据需要从 10 月到 6 月;但是,我通过设置限制来做到这一点,

startTime <- as.Date("2016-10-01")
endTime <- as.Date("2017-06-30")
start_end <- c(startTime,endTime)

然后设置 1 个月的休息时间。

scale_x_date(limits=start_end,breaks=date_breaks("1 month"),labels=date_format("%d %b"))+

不用说,如果我想包括其他冬季和传奇,这种技术将不起作用。

我还尝试将季节分配给某些时间段,然后将它们用作一个因素:

master_dataset <- master_dataset %>%
  mutate(season = case_when(date>=as.Date('2015-11-02')&date<=as.Date('2016-06-30')~"season 2015-16",
                            date>=as.Date('2016-11-02')&date<=as.Date('2017-06-30')~"season 2016-17",
                            date>=as.Date('2017-10-13')&date<=as.Date('2018-06-30')~"season 2017-18",
                            date>=as.Date('2018-10-18')&date<=as.Date('2019-06-30')~"season 2018-19"))

ggplot(master_dataset, aes(month(date, label=TRUE, abbr=TRUE), fl_all_cumsum, group=factor(season),colour=factor(season)))+
  geom_line()+
  labs(x="Month", colour="Season")+
  theme_classic()

如您所见,我设法将其他季节包括在图表中,但现在有几个问题:

    按月分组,它汇总了每日值,我在图表中丢失了每日动态(看看它是如何基于每月步骤的) x 轴按时间顺序排列,这弄乱了我的可视化(请记住,我关心冬季的发展,所以我需要 x 轴从 10 月到 6 月底;请参阅我制作的第一张图表)李> 问题不大,但由于数据存在 NA 差距,因此图例还显示了“NA”因子

我不是程序员,所以我无法思考如何为此类问题编写代码。在一个完美的世界里,我想要像我制作的第一张图表一样,但包括所有冬季和一个传奇。有人对此有解决方案吗?提前致谢。

佐林

【问题讨论】:

【参考方案1】:

这确实有点痛苦,而且相当繁琐。我创建了与您的 date 列相同的“假日期”,但年份设置为 2015/2016(使用 2016 作为 2 月份的日期,因此不会丢失闰日)。然后我们绘制所有数据,告诉 ggplot 都是 2015-2016,所以它被绘制在同一轴上,但我们没有标注年份。 (使用季节标签,并非“假”。)

## Configure some constants:
start_month = 10  # first month on x-axis
end_month = 6     # last month on x-axis
fake_year_start = 2015  # year we'll use for start_month-December
fake_year_end = fake_year_start + 1 # year we'll use for January-end_month
fake_limits = c(   # x-axis limits for plot
  ymd(paste(fake_year_start, start_month, "01", sep = "-")),
  ceiling_date(ymd(paste(fake_year_end, end_month, "01", sep = "-")), unit = "month")
)

df = df %>%
  mutate(
    ## add (real) year and month columns
    year = year(date),  
    month = month(date),
    ## add the year for the season start and end
    season_start = ifelse(month >= start_month, year, year - 1),
    season_end = season_start + 1,
    ## create season label 
    season = paste(season_start, substr(season_end, 3, 4), sep = "-"),
    ## add the appropriate fake year
    fake_year = ifelse(month >= start_month, fake_year_start, fake_year_end),
    ## make a fake_date that is the same as the real date
    ## except set all the years to the fake_year
    fake_date = date, 
    fake_date = "year<-"(fake_date, fake_year)
  ) %>% 
  filter(
    ## drop irrelevant data
    month >= start_month | month <= end_month,
    !is.na(fl_all_cumsum)
  )


ggplot(df, aes(x = fake_date, y = fl_all_cumsum, group = season,colour= season))+
  geom_line()+
  labs(x="Month", colour = "Season")+
  scale_x_date(
    limits = fake_limits,
    breaks = scales::date_breaks("1 month"),
    labels = scales::date_format("%d %b")
  ) +
  theme_classic()

【讨论】:

谢谢。它完美无缺。不幸的是,我不得不花一些时间研究代码,因为乍一看我并不清楚你在这里做了什么类型的 wizzardy。 我会添加一些cmets。

以上是关于ggplot:按月在同一个图上的多个时间段的主要内容,如果未能解决你的问题,请参考以下文章

修改顶部ggplot百分比条形图上的文本标签

android重复警报,应按月重复,每个月在同一天重复,依此类推

如何在ggplot2中并排条形图上居中标签

如何在 ggplot 的多面饼图上正确放置标签?

R语言ggplot2可视化时间序列数据:ggplot2可视化在时间轴上添加按月的箱图(boxplot)

ggplot条形图中的恒定宽度