R语言ggplot坐标轴断点设置及图例合并方法求助
住院时长数据可视化优化方案
问题背景与数据
我用R处理患者住院时长数据,其中9999-12-31代表患者仍在住院(用三角形标识),每个患者有多条住院记录,数据如下:
df = structure(list(var1 = structure(c(1L, 1L, 1L, 1L, 2L, 2L, 2L, 2L, 3L, 3L, 3L, 3L, 2L), .Label = c("A", "B", "C"), class = "factor"), start_date = structure(c(18169, 18217, 17933, 16232, 15901, 18692, 17548, 16848, 19077, 16959, 16974, 16744, 19358), class = "Date"), end_date = structure(c(19189, 18217, 18392, 17372, 18501, 18692, 17548, 16848, 19077, 16959, 17777, 17126, 2932896), class = "Date")), row.names = c(NA, -13L), class = "data.frame")
现有可视化代码
我尝试绘制每条住院记录的时长图表,代码如下:
# 补充原代码缺失的列定义 df$row <- seq(nrow(df)) df$hospital_patient <- df$var1 palette <- c("A" = "red", "B" = "blue", "C" = "green") p <- ggplot(df, aes(x = start_date, xend = end_date, y = row, yend = row, color = hospital_patient)) + geom_segment(size = 1.5, lineend = "round") + geom_point(aes(x = start_date), size = 3) + geom_point(data = df[df$end_date != as.Date('9999-12-31'),], aes(x = end_date), size = 3) + geom_point(data = df[df$end_date == as.Date('9999-12-31'),], aes(x = end_date), size = 3, shape = 17) + scale_color_manual(values = palette) + labs(x = "Time", y = "Row") + theme_minimal() p <- p + geom_vline(aes(xintercept = as.numeric(Sys.Date()), linetype = "Today"), color = "black", size = 1.5) p + scale_linetype_manual(values = c("Today" = "dotted"))
待解决问题
- 目前只能手动将
9999-12-31替换为未来日期(如2030-12-31)再修改轴标签,否则图表会因日期范围过大变形,能否用坐标轴断点实现需求? - 如何将患者(颜色)图例与“今日”竖线(线型)图例合并为一个统一图例?
解决方案
1. 用坐标轴断点处理9999-12-31日期
ggplot2本身不支持坐标轴断点,可借助ggbreak包实现。核心思路是把x轴拆分为两段:一段是实际住院日期的正常范围,另一段单独放置9999-12-31的标记,无需修改原始日期。
示例代码:
library(ggbreak) # 确定实际日期的最大范围(排除9999-12-31) max_real_date <- max(df$end_date[df$end_date != as.Date("9999-12-31")]) # 设置断点位置,在实际最大日期后留两年间隔 break_pos <- max_real_date + 365*2 p_break <- ggplot(df, aes(x = start_date, xend = end_date, y = row, yend = row, color = hospital_patient)) + geom_segment(size = 1.5, lineend = "round") + geom_point(aes(x = start_date), size = 3) + geom_point(data = df[df$end_date != as.Date('9999-12-31'),], aes(x = end_date), size = 3) + geom_point(data = df[df$end_date == as.Date('9999-12-31'),], aes(x = end_date), size = 3, shape = 17) + scale_color_manual(values = palette) + geom_vline(aes(xintercept = as.numeric(Sys.Date()), linetype = "Today"), color = "black", size = 1.5) + scale_linetype_manual(values = c("Today" = "dotted")) + # 设置x轴断点,自定义标签 scale_x_date_break(breaks = break_pos, labels = function(x) { ifelse(x == as.Date("9999-12-31"), "9999", format(x, "%Y")) }, expand = c(0, 0)) + labs(x = "Time", y = "Row") + theme_minimal() p_break
2. 合并患者与“今日”竖线图例
要合并两个不同美学(颜色、线型)的图例,需要统一图例名称,并通过guide_legend()手动调整图例元素,让两个类别在同一个图例中展示。
示例代码:
p_combined <- ggplot(df, aes(x = start_date, xend = end_date, y = row, yend = row, color = hospital_patient)) + geom_segment(size = 1.5, lineend = "round") + geom_point(aes(x = start_date), size = 3) + geom_point(data = df[df$end_date != as.Date('9999-12-31'),], aes(x = end_date), size = 3) + geom_point(data = df[df$end_date == as.Date('9999-12-31'),], aes(x = end_date), size = 3, shape = 17) + # 把"Today"加入颜色映射,设置颜色为黑色 scale_color_manual(values = c(palette, "Today" = "black"), labels = c("A", "B", "C", "Today")) + # 竖线同时映射color和linetype为"Today" geom_vline(aes(xintercept = as.numeric(Sys.Date()), color = "Today", linetype = "Today"), size = 1.5) + scale_linetype_manual(values = c("Today" = "dotted")) + # 合并图例,自定义每个条目的显示样式 guides(color = guide_legend(override.aes = list( linetype = c("solid", "solid", "solid", "dotted"), shape = c(19, 19, 19, NA), size = c(1.5, 1.5, 1.5, 1.5) )), linetype = "none") + # 隐藏单独的线型图例 labs(x = "Time", y = "Row", color = "Legend") + theme_minimal() p_combined
内容的提问来源于stack exchange,提问作者stats_noob
相关产品推荐
相关产品推荐

