【问题标题】:How to change x axis from years to months with ggplot2如何使用ggplot2将x轴从年更改为月
【发布时间】:2017-06-23 13:52:16
【问题描述】:

我有一个随时间变化的网络访问量图表,它绘制了从 2014 年到现在的每日流量,看起来像这样:

 ggplot(subset(APRA, Post_Day > "2013-12-31"), aes(x = Post_Day, y = Page_Views))+
   geom_line()+
   scale_y_continuous(labels = comma)+
   ylim(0,50000)

正如您所见,这不是一个很好的图表,更有意义的是按月而不是按天细分它。但是,当我尝试此代码时:

 ggplot(subset(APRA, Post_Day > "2013-12-31"), aes(x = Post_Day, y = Page_Views))+
   geom_line()+
   scale_y_continuous(labels = comma)+
   ylim(0,50000)+
   scale_x_date(date_breaks = "1 month", minor_breaks = "1 week", labels = date_format("%B"))

我收到此错误:

错误:输入无效:date_trans 仅适用于 Date 类的对象

日期字段Post_DayPOSIXctPage_Views 是数字。数据如下:

Post_Title  Post_Day    Page_Views
Title 1     2016-05-15  139
Title 2     2016-05-15  61
Title 3     2016-05-15  79
Title 4     2016-05-16  125
Title 5     2016-05-17  374
Title 6     2016-05-17  39
Title 7     2016-05-17  464
Title 8     2016-05-17  319
Title 9     2016-05-18  84
Title 10    2016-05-18  64
Title 11    2016-05-19  433
Title 12    2016-05-19  418
Title 13    2016-05-19  124
Title 14    2016-05-19  422

我希望将 X 轴从每日粒度更改为每月。

【问题讨论】:

  • 这真的不是一个关于如何将日期聚合为月份的问题,而不是如何更改 x 轴吗?
  • @C8H10N4O2 是的,我想是的。我以为这就是我对 scale_x_date() 所做的事情,但它似乎不起作用。
  • 使用Post_Day > "2013-12-31"表示Post_Day是一个字符变量。您应该使用as.Date 将此变量转换为日期类,然后使用Post_Day > as.Date("2013-12-31")
  • 您可以为year(post_day)month(post_day) 创建列,或者您可以使用these approaches 之一来获取日期的“月底”
  • @lmo R 足够聪明,可以在Post_DayDate 时处理Post_Day > "2013-12-31" 的比较

标签: r ggplot2


【解决方案1】:

问题中显示的样本数据集每天有多个数据点。因此,无论如何都需要按天汇总。对于按天或按月的聚合,使用data.tablelubridate

创建示例数据

由于没有提供可重现的示例,因此创建了一个示例数据集:

library(data.table)
n_rows <- 5000L
n_days <- 365L*3L
set.seed(123L)
DT <- data.table(Post_Title = paste("Title", 1:n_rows),
                 Post_Day = as.Date("2014-01-01") + sample(0:n_days, n_rows, replace = TRUE),
                 Page_Views = round(abs(rnorm(n_rows, 500, 200))))[order(Post_Day)]
DT
      Post_Title   Post_Day Page_Views
   1:   Title 74 2014-01-01        536
   2:  Title 478 2014-01-01        465
   3: Title 3934 2014-01-01        289
   4: Title 4136 2014-01-01        555
   5:  Title 740 2014-01-02        442
  ---                                 
4996: Title 1478 2016-12-31        586
4997: Title 2251 2016-12-31        467
4998: Title 2647 2016-12-31        468
4999: Title 3243 2016-12-31        498
5000: Title 4302 2016-12-31        309

绘制原始数据

无需聚合,数据可以通过以下方式绘制

library(ggplot2)
ggplot(DT) + aes(Post_Day, Page_Views) + geom_line()

按天汇总

ggplot(DT[, .(Page_Views = sum(Page_Views)), by = Post_Day]) + 
  aes(Post_Day, Page_Views) + geom_line()

为了按天聚合,使用data.table 的分组参数bysum() 作为聚合函数。聚合将数据点的数量从 5000 个减少到 1087 个。因此,该图看起来不那么复杂。

按月汇总

ggplot(DT[, .(Page_Views = sum(Page_Views)), 
          by = .(Post_Month = lubridate::floor_date(Post_Day, "month"))]) + 
  aes(Post_Month, Page_Views) + geom_line()

为了按月聚合,使用了分组参数by,但这次Post_Day 映射到各个月份的第一天。所以,2014-03-26 变成了2014-03-01Post_Month,它仍然属于POSIXct。这样,x 轴与日期刻度保持连续。这避免了将Post_Day 转换为因子时的麻烦,例如,使用format(Post_Day, ""%Y-%m")"2014-03" 转换为x 轴将变得离散。

【讨论】:

  • 我不确定这是解决问题的正确方法。听起来问题是关于更改轴上的标签,而不是聚合数据。 ggplot2::scale_x_date 也有 scale_x_datetime 选项 - 将 posixct 日期作为日期时间而不是日期会给出显示的错误,并且可以通过将 scale_x_date 更改为 scale_x_datetime 来轻松修复
  • @LucieCBurgess 使用scale_x_datetime() 而不是scale_x_date() 将使错误消息消失,但不会解决根本问题。误解是,将比例更改为月也会自动按月汇总数据 - 但事实并非如此。用 OP 的话 你可以看到它不是一个很好的图表,更有意义的是按月而不是按天分解它。 OP 的数据每天包含多个条目,需要无论如何,按天汇总。显然,OP 对我的回答很满意并接受了它。
【解决方案2】:
APRA$month <- as.factor(stftime(APRA$Post_Day, "%m")
APRA       <- APRA[order(as.numeric(APRA$month)),]

这将为您的数据创建一个月份列

z <- apply(split(APRA, APRA$month), function(x) {sum(as.numeric(APRA$Page_Views))})
z <- do.call(rbind, z)
z$month <- unique(APRA$month)
colnames(Z) <- c("Page_Views", "month")

这将创建一个 z dataframe ,每个月都有月份和页面浏览量

现在画出来

ggplot(z, aes(x = month, y = Page_Views)) + geom_line()

如果这是您要找的,请告诉我。另外我还没有编译它,请告诉它是否会引发一些错误。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-08-15
    • 2021-12-04
    • 2015-02-23
    • 2019-07-07
    • 1970-01-01
    • 1970-01-01
    • 2016-01-16
    • 2019-09-09
    相关资源
    最近更新 更多