代码之家  ›  专栏  ›  技术社区  ›  DaveM

ggplot:防止年末数据显示为下一年

  •  1
  • DaveM  · 技术社区  · 7 年前

    这似乎是一个简单的问题,但我找不到一个简单的方法,类似的问题似乎没有解决我的问题。

    我正在绘制年终数据,希望它在x轴上显示为当年,而不是次年。例如,2015年12月31日的数据反映的是2015年发生的情况,而不是2016年,但曲线图将显示为2016年。

    我可以对数据进行变异,并在变异列中添加年份值(2015年12月31日变为2015年),并使用该值绘制数据集,但我希望有更简单的方法来绘制其他时间段(季度、月份等)。

    So 2问题:

    1) 是否有一种简单的方法可以自动绘制年终数据,以表示发生数据的年份,而不是下一年?

    2) 当我试图调整x轴比例时,为什么ggplot删除了2行,导致绘制更差(test\u p2)?

    可复制示例

    library(ggplot2)
    library(lubridate)
    
    # Sample data
    mydates   <- as.Date(c( "2015-12-31", "2016-12-31", "2017-12-23", "2015-12-31", "2016-12-31", "2017-12-23"))
    variables <- c(rep("A", 3), rep("B", 3))
    values    <- c(2, 4, -4, -5, -10, 5)
    test_df   <- data.frame(mydates, variables, values)
    
    # plot
    test_p <- ggplot(test_df, aes(x = mydates, y = values, fill = variables)) + geom_col(position = "dodge")
    test_p
    

    enter image description here

    调整x轴比例:

    BeginPlotDate   = "2015-12-31"
    EndPlotDate     = "2017-12-23"
    
    test_p2 <- test_p + scale_x_date(date_breaks = "1 year",
                                     date_labels = "%Y",
                                     limits      = as.Date(c(BeginPlotDate, EndPlotDate))
                                     )
    test_p2
    

    enter image description here

    2 回复  |  直到 7 年前
        1
  •  1
  •   Claus Wilke    7 年前

    通常情况下,你不能同时问两个问题,但无论如何,这里有两个答案:

    问题1

    所发生的是,ggplot2将日期四舍五入到最接近的年份,即下一年。我认为解决这个问题最简单的方法就是在 aes() 声明:

    test_p <- ggplot(test_df,
                     aes(x = mydates %m-% months(12),
                         y = values, fill = variables)) + 
              geom_col(position = "dodge")
    test_p
    

    enter image description here

    唯一的缺点是,现在需要手动调整x轴的标题,但这很简单,例如 xlab() :

    test_p + xlab("my dates")
    

    enter image description here

    问题2

    您正在将x轴的起点设置为“2015-12-31”,而这正是ggplot所做的。您需要将起点设置为更早的日期(大约提前6个月),以便有足够的空间放置要在此处绘制的条形图。(在这里,我实际上必须提前18个月设置,因为我还从日期中减去12个月,见上文。)

    BeginPlotDate   = "2014-06-01"
    EndPlotDate     = "2017-08-01"
    
    test_p2 <- test_p + scale_x_date(date_breaks = "1 year",
                                     date_labels = "%Y",
                                     limits      = as.Date(c(BeginPlotDate, EndPlotDate))
    )
    test_p2
    

    enter image description here

        2
  •  1
  •   Community CDub    4 年前

    这个问题有一个非常简单的解决方案:只需使用 year(mydates) :

    library(ggplot2)
    library(lubridate)
    
    ggplot(test_df, aes(x = year(mydates), y = values, fill = variables)) + 
      geom_col(position = "dodge")
    

    enter image description here

    打印时 Date POSIXct , ggplot2 假设一个连续的刻度,通过在适当的位置放置贴有良好标签的记号来适当形成,例如,2016-01-01上会有标有“2016”的记号。因此,如果数据点的x值为2015-12-31,则将在2016-01-01记号附近绘制。这对于每日或每周的数据很有用,但在您的用例中并不有用。

    编辑

    OP指出,他需要一个日期轴,因为他也想绘制月度和季度数据。

    如果OP想要 覆盖的步骤 中的月度、季度和年度数据 一个绘图 如果使用连续的日期轴,那么我强烈建议不要使用条形图,尤其是在避开的情况下。

    条形图通常用于离散数据。条的高度传递信息。通常,宽度没有任何意义,可以任意选择,也可以美观。

    如果OP坚持使用日期轴,则宽度 应该 有意义。例如,水平扩展可以传递每个值分配给哪个时间段的信息,例如。,

    ggplot(test_df, aes(x = floor_date(mydates, "year"), xend = mydates, 
                        y = values, yend = values, colour = variables)) + 
      geom_segment(size = 1) +
      theme_bw()
    

    enter image description here

    在这里,线段从年初开始,一直延伸到给定的结束日期。这将可视化 values 表示年度值。回避对她没有任何意义,所以颜色代码是唯一的区别 variables .

    一个更复杂的例子(使用特别是合成的数据)是在一个图表中显示月度值、季度和年度平均值:

    ggplot(month_df) + 
      aes(x = mydates, xend = floor_date(mydates, first(period)), 
          xmin = floor_date(mydates, first(period)), xmax = mydates,
          y = values, yend = values, ymin = 0, ymax = values, 
          fill = variables, shape = variables) + 
      geom_rect(data = year_df, alpha = 0.5)  +
      geom_segment(aes(colour = variables), data = quarter_df, size = 1) + 
      geom_point() +
      theme_bw()
    

    enter image description here

    然而,图表相当复杂,图表的信息很难解释和感知。

    数据

    library(data.table)
    # create monthly dummy data
    month_df <- data.table(
      # last day of month
      mydates = rep(seq(as.Date("2015-02-01"), length.out = 36L, by = "month") - days(1L), 2L),
      variables = rep(LETTERS[1:2], each = 36L),
      values = c(sinpi((1:36) / 18), cospi((1:36) / 12)),
      period = "month"
    )
    # aggregate by quarter
    quarter_df <- month_df[, .(values = mean(values), period = "quarter"), 
         by = .(mydates = ceiling_date(mydates, "quarter") - days(1L), variables)]
    # aggregate by year
    year_df <- month_df[, .(values = mean(values), period = "year"), 
         by = .(mydates = ceiling_date(mydates, "year") - days(1L), variables)]