stat_summary ggplot2 中的破坏因子排序

stat_summary breaking factor ordering in ggplot2

我有一个奇怪的问题,可能是 lubridateggplot 的错误,堆积条形图中的因子排序(一周中的每一天都有一个因子)有时会中断当我添加 stat_summary 行时。当第一周的数据只有一天显示时似乎会中断,但是当有更多数据时就可以正常工作。

假设我们有这个包含十天数据的数据框。我希望每周从星期一开始。

library(tidyverse); library(lubridate)
df <- structure(list(perf_dt = structure(c(18032, 18033, 18034, 18035, 18036, 
                                     18037, 18039, 18040, 18041, 18042), class = "Date"), 
               n = c(32, 14, 55, 73, 39, 41, 44, 36, 71, 80), 
               week = structure(c(18035, 18035, 18035, 18035, 18042,
                                  18042, 18042, 18042, 18042, 18042), class = "Date")), 
          class = c("tbl_df", "tbl", "data.frame"), row.names = c(NA, -10L)) %>%
  group_by(week) %>%
  mutate(cuml = cumsum(n),
         day_num = lubridate::wday(perf_dt, week_start = 1),
         day = lubridate::wday(perf_dt, label = T, week_start = 1)) %>%
  ungroup()

df
# A tibble: 10 x 6
   perf_dt        n week        cuml day_num day  
   <date>     <dbl> <date>     <dbl>   <dbl> <ord>
 1 2019-05-16    32 2019-05-19    32       4 Thu  
 2 2019-05-17    14 2019-05-19    46       5 Fri  
 3 2019-05-18    55 2019-05-19   101       6 Sat  
 4 2019-05-19    73 2019-05-19   174       7 Sun  
 5 2019-05-20    39 2019-05-26    39       1 Mon  
 6 2019-05-21    41 2019-05-26    80       2 Tue  
 7 2019-05-23    44 2019-05-26   124       4 Thu  
 8 2019-05-24    36 2019-05-26   160       5 Fri  
 9 2019-05-25    71 2019-05-26   231       6 Sat  
10 2019-05-26    80 2019-05-26   311       7 Sun

我可以将这些绘制在堆积条中,使用 stat_summary 获得每周总数。这就是我想要的。

ggplot(df,
       aes(week, n, fill = day)) +
  geom_col(position = position_stack(reverse = T)) +
  geom_text(aes(label = scales::dollar(n), color = day), size = 3.5,
            position = position_stack(reverse = T, vjust = 0.5)) +
  stat_summary(fun.y = sum, aes(label = scales::comma(..y..), group = week),
               vjust = -0.5, fontface = "bold", geom = "text") +
  scale_color_viridis_d(direction = -1) +
  scale_fill_viridis_d(guide = guide_legend(reverse=TRUE)) +
  guides(color = F)

但是如果我给它提供从星期日开始的数据,比如 5 月 19 日,并且我包含了 stat_summary 层,那么在堆叠和图例中的顺序都会变得混乱。如果我删除 stat_summary 层,它工作正常,甚至从星期天开始。

我是否遗漏了一些可以使其更好地工作的设置方式?这是 lubridateggplot 中的已知错误吗?有没有办法做到这一点并保持方便和优雅的 stat_summary 公式?

# Same as above, but limited to dates starting May 19 and later
ggplot(df %>% filter(perf_dt >= ymd(20190519)),
       aes(week, n, fill = day)) +
  geom_col(position = position_stack(reverse = T)) +
  geom_text(aes(label = scales::dollar(n), color = day), size = 3.5,
            position = position_stack(reverse = T, vjust = 0.5)) +
  stat_summary(fun.y = sum, aes(label = scales::comma(..y..), group = week),
               vjust = -0.5, fontface = "bold", geom = "text") +
  scale_color_viridis_d(direction = -1) +
  scale_fill_viridis_d(guide = guide_legend(reverse=TRUE)) +
  guides(color = F)

解决方案

fill = dayggplot(aes(...)) 移动到 geom_col(aes(...)),因为无论如何其他层都不需要继承它。

或者,通过将 limits = levels(df$day) 添加到 scale_fill_viridis_d(...) 来指定中断顺序也可以。

说明

fill = day作为顶级美学映射之一包含在ggplot()中时,它被stat_summary层继承。这意味着虽然图层选择的 geom (geom_text) 不需要填充美学,但映射包含在图层数据的计算中。

当整个数据集 df 用于绘图时,这不是问题,因为按周汇总(指定的 group 变量)returns 只有 NA 值日。然后,在完成任何到填充比例的映射之前,天列将从图层数据中完全删除。

然而,当使用子集 df 时,按周汇总 returns 第二周的 NA 值,但第一周的 "Sun",因为现在只有一个与第一周相关的数据行。因此,层数据保留了一个包含两个值的填充列:"Sun" 和 NA.

在第一种情况下,填充比例是根据与前两层关联的数据帧构建的,它们只有 df$day 中的值,因此保留了原始因子顺序。

在第二种情况下,填充比例由与所有三层相关联的数据帧构成,其值来自df$day加上NA。这搞砸了因子顺序,因此比例默认为字母顺序。