stat_summary ggplot2 中的破坏因子排序
stat_summary breaking factor ordering in ggplot2
我有一个奇怪的问题,可能是 lubridate
或 ggplot
的错误,堆积条形图中的因子排序(一周中的每一天都有一个因子)有时会中断当我添加 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
层,它工作正常,甚至从星期天开始。
我是否遗漏了一些可以使其更好地工作的设置方式?这是 lubridate
或 ggplot
中的已知错误吗?有没有办法做到这一点并保持方便和优雅的 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 = day
从 ggplot(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。这搞砸了因子顺序,因此比例默认为字母顺序。
我有一个奇怪的问题,可能是 lubridate
或 ggplot
的错误,堆积条形图中的因子排序(一周中的每一天都有一个因子)有时会中断当我添加 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
层,它工作正常,甚至从星期天开始。
我是否遗漏了一些可以使其更好地工作的设置方式?这是 lubridate
或 ggplot
中的已知错误吗?有没有办法做到这一点并保持方便和优雅的 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 = day
从 ggplot(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。这搞砸了因子顺序,因此比例默认为字母顺序。