如何用R(ggplot2)或SAS绘制双独立轴游泳图:主轴随访时长,次轴日历时间
双独立轴游泳图的实现方案
R(ggplot2)实现
ggplot2原生对双独立轴支持有限,可通过将日期转换为数值变量,手动映射次轴刻度来实现需求,以下是完整流程:
数据预处理
扩展数据,增加日历时间的数值映射(以1950年为基准计算年份差):
library(dplyr) library(ggplot2) # 示例数据 data <- data.frame( ID = 1:10, start_date = as.Date(c('1950-01-01', '1960-02-01', '1970-03-01', '1980-04-01', '1990-05-01', '1955-06-01', '1965-07-01', '1975-08-01', '1985-09-01', '1995-10-01')), end_date = as.Date(c('2000-01-01', '2010-02-01', '2020-03-01', '2015-04-01', '2025-05-01', '1995-06-01', '2005-07-01', '2015-08-01', '2020-09-01', '2030-10-01')) ) # 计算随访时长(年)和日历时间的数值映射 data <- data %>% mutate( follow_up_years = as.numeric(difftime(end_date, start_date, units = "weeks")) / 52.25, start_year = as.numeric(start_date - as.Date("1950-01-01")) / 365.25, end_year = as.numeric(end_date - as.Date("1950-01-01")) / 365.25 )
绘图代码
# 定义日历轴的刻度与对应日期标签 calib_breaks <- seq(0, 80, 10) calib_labels <- as.character(as.Date("1950-01-01") + calib_breaks*365.25) ggplot(data, aes(y = factor(ID, levels = rev(1:10)))) + # 主轴:随访时长条形图(以x=0为起点) geom_bar(aes(x = follow_up_years), stat = "identity", fill = "#6366F1", width = 0.7) + # 次轴:日历时间起止线段 geom_segment(aes(x = start_year, xend = end_year, yend = factor(ID, levels = rev(1:10))), color = "#EF4444", size = 1.2) + # 添加起止点标记 geom_point(aes(x = start_year), color = "#EF4444", size = 3) + geom_point(aes(x = end_year), color = "#EF4444", size = 3) + # 设置双轴 scale_x_continuous( name = "随访时长(年)", sec.axis = sec_axis( trans = ~., name = "日历时间", breaks = calib_breaks, labels = calib_labels ) ) + ylab("研究对象ID") + theme_minimal() + theme( axis.title.x.bottom = element_text(color = "#6366F1"), axis.title.x.top = element_text(color = "#EF4444"), axis.text.x.top = element_text(angle = 45, hjust = 0) )
核心逻辑是将日期转换为与基准年的年份差,让日历时间数值与随访时长在同一x轴空间展示,再手动替换次轴刻度为日期格式,实现双独立轴效果。
SAS实现
SAS的PROC SGPLOT支持X2AXIS,同样通过日期转数值的方式实现需求:
数据预处理
/* 创建示例数据 */ data data; input ID start_date : date9. end_date : date9.; format start_date end_date date9.; /* 计算随访时长(年) */ follow_up_years = (end_date - start_date) / 365.25; /* 计算日历时间的数值映射(以1950年1月1日为基准的年份) */ start_year = (start_date - '01JAN1950'd) / 365.25; end_year = (end_date - '01JAN1950'd) / 365.25; datalines; 1 01JAN1950 01JAN2000 2 01FEB1960 01FEB2010 3 01MAR1970 01MAR2020 4 01APR1980 01APR2015 5 01MAY1990 01MAY2025 6 01JUN1955 01JUN1995 7 01JUL1965 01JUL2005 8 01AUG1975 01AUG2015 9 01SEP1985 01SEP2020 10 01OCT1995 01OCT2030 ; run;
绘图代码
proc sgplot data=data noautolegend; /* 主轴:随访时长条形图 */ hbarparm category=ID response=follow_up_years / fillattrs=(color=#6366F1) barwidth=0.7; /* 次轴:日历时间线段和点 */ highlow y=ID low=start_year high=end_year / type=bar lineattrs=(color=#EF4444 thickness=2); scatter y=ID x=start_year / markerattrs=(color=#EF4444 size=12); scatter y=ID x=end_year / markerattrs=(color=#EF4444 size=12); /* 设置X轴和X2轴 */ xaxis label="随访时长(年)" valueattrs=(color=#6366F1); x2axis label="日历时间" values=(0 to 80 by 10) valueattrs=(color=#EF4444) tickvalueformat=(strip(put('01JAN1950'd + _VALUE_*365.25, date9.))); yaxis label="研究对象ID" reverse; styleattrs datacolors=(#6366F1 #EF4444); run;
通过X2AXIS的tickvalueformat参数自定义刻度标签,将数值转换为日期格式,完成独立次轴的配置。
内容的提问来源于stack exchange,提问作者W. Fan
相关产品推荐
相关产品推荐

