基于geom_segment()的排序日历图优化:分段排序与刻度修复
ggplot2日历图调整方案
问题需求
用ggplot2制作日历图时,需完成两项调整:
- 每个
year与num_months分组的分面内,geom_segment按start_month从小到大排序,分面中第一个分段对应最小的start_month,依次排列; - 强制每个年份的x轴刻度范围固定为当年1月至12月,即使该时间段无观测数据。
修改后的完整代码
library(tidyverse) library(lubridate) data <- read_csv("num_months,start_month_year,end_month_year,B1,B1_p,year,start_month,end_month 1,6,6,3.3571016788482666,0.007681768853217363,2021,5,5 1,8,8,2.548985481262207,0.007373321335762739,2021,7,7 1,10,10,2.139772415161133,0.03452971577644348,2021,9,9 1,12,12,2.165775775909424,0.07796278595924377,2021,11,11 1,13,13,1.9506219625473022,0.09215697646141052,2021,12,12 1,23,23,2.7839596271514893,0.011407249607145786,2022,10,10 1,25,25,2.220555543899536,0.06181173026561737,2022,12,12 6,6,11,0.9881601333618164,0.08719704300165176,2021,5,10 6,8,13,1.438501238822937,0.032221969217061996,2021,7,12 6,9,14,1.16400945186615,0.09187468141317368,2021,8,1 6,10,15,1.5834165811538696,0.03494146466255188,2021,9,2 6,11,16,1.294316291809082,0.09792502969503403,2021,10,3 6,12,17,1.4204859733581543,0.0546354204416275,2021,11,4 6,20,25,1.07038414478302,0.0722803920507431,2022,7,12") %>% mutate( start_dt = ymd(paste(year, start_month, "01", sep = "-")), end_dt = case_when( # 处理跨年份的结束日期 start_month > end_month ~ ceiling_date(ymd(paste(year + 1, end_month, "01", sep = "-")), unit = "month") - 1, TRUE ~ ceiling_date(ymd(paste(year, end_month, "01", sep = "-")), unit = "month") - 1 ) ) %>% # 分组内按start_month升序排序,确保y轴位置正确 group_by(year, num_months) %>% arrange(start_month, .by_group = TRUE) %>% mutate(yy = row_number()) %>% ungroup() # 绘制日历图 ggplot(data) + geom_segment(aes(x = start_dt, xend = end_dt, y = yy, yend = yy, color = factor(num_months)), size = 1) + scale_x_date( date_labels = "%b", date_breaks = "1 month", expand = expansion(0, 0), # 强制每个分面x轴为当年1月1日至12月31日 limits = function(x) { current_year = year(x)[1] ymd(c(paste0(current_year, "-01-01"), paste0(current_year, "-12-31"))) } ) + scale_y_continuous(labels = NULL) + # x轴不使用自由刻度,只放开y轴 facet_grid(rows = vars(num_months), cols = vars(year), space = "free_y", scales = "free_y") + labs(x = "月份", y = "月份数量", color = "月份数量") + theme_bw() + theme( panel.spacing = unit(1, "lines"), panel.grid.major.y = element_blank(), axis.ticks.y = element_blank() )
调整说明
1. 分面内segment排序修正
- 改为分组内再次按
start_month升序排序(arrange(start_month, .by_group = TRUE)),确保每个分面内的yy严格对应start_month从小到大的顺序,避免全局排序被后续操作干扰。 - 简化了
start_dt的生成逻辑,无需用case_when区分年份,直接拼接即可。
2. 固定x轴范围为全年
- 将
facet_grid的scales参数从"free"改为"free_y",保留y轴自由刻度的同时,固定x轴规则。 - 在
scale_x_date中添加limits函数,自动识别每个分面对应的年份,将x轴范围强制设为当年1月1日至12月31日,确保无数据的月份也会显示刻度。 - 修正了跨年份的
end_dt计算逻辑,当start_month > end_month时(比如起始月为8月、结束月为1月),自动对应到下一年的结束日期,避免日期计算错误。
内容的提问来源于stack exchange,提问作者Paula
相关产品推荐
相关产品推荐

