Nature 复现 | 患者泳道图 Swimmer’s plot
Nature 复现 | 患者泳道图 Swimmer’s plot by MsTt笔记
请尊重原创劳动成果🙏
未经允许,不可抄袭,转载请注明出处!
今天复现的图是 Swimmer's plot,其在医学/临床研究领域通常叫做 "游泳图" 或 "泳道图"。
这是一种用于可视化临床试验中个体患者治疗历程的图表,横轴通常表示时间,纵轴表示每个患者,用不同颜色的条形(泳道)表示不同的治疗阶段,并用符号标记响应事件、疾病进展、治疗终止等关键时间点。 它在肿瘤学临床试验报告中尤为常见,用于展示患者层面的治疗暴露时间、响应持续时间和结局。
Nature 文章中 (Safonov, A., Lee, M., Brown, D.N. et al. Homologous recombination deficiency and hemizygosity drive resistance in breast cancer. Nature (2026). https://doi.org/10.1038/s41586-026-10197-0) 的 Fig 2.d
原图
这张图清晰地展示了 41 名 患者在接受了 CDK4/6抑制剂 + 内分泌治疗(红色长条) 之后,序贯接受 PARP抑制剂(蓝色长条) 的治疗历程、响应情况及生存结局。
1. 治疗顺序与持续时间
每个患者用两条水平“泳道”表示:红色代表 CDK4/6i+ET 治疗阶段,蓝色代表后续的 PARPi 治疗阶段。 横轴为时间(单位:月),泳道的长度直观反映每位患者接受各方案治疗的持续时间。 通过对比同一患者红蓝两条的长度,可以看出部分患者从 PARPi 中获得了比前线治疗更长的治疗获益。
2. 响应标记
图中使用不同符号标记每位患者在两种治疗下的最佳响应: CR(完全缓解)/ PR(部分缓解)/ SD(疾病稳定)/ PD(疾病进展) 可以直观地看到:许多患者在红色条(CDK4/6i+ET)上标记为 SD 或 PD,但在蓝色条(PARPi)上转为 PR 或 CR,体现了 PARPi 的后线治疗价值
3. 治疗终止原因
泳道末端的符号或箭头表示终止原因(如疾病进展、毒性、仍在治疗中等) MD(physician)可能表示医生决策终止
4. 患者排序
患者通常按某种临床特征(如响应类型、生物标志物状态或前线治疗时长)排序,便于发现模式
复现图
游泳图的独特价值:
个体化呈现:不仅展示群体统计结果,还能看到每个患者的具体治疗轨迹 异质性可视化:直观显示不同患者对同一治疗方案的响应差异 时间维度清晰:同时展示治疗顺序、持续时间和事件发生时间点 前后对比:同一患者红蓝条并排,便于比较两种方案的个体获益
加载包,读入数据
# 加载必要的包library(tidyverse)# 读入数据data <- readr::read_csv("data_1.csv")# 泳道颜色(按不同治疗方案分组)main_colors <- c("cdk" = "#f06b6c", "parp" = "#6c90c9", "other" = "#dbdada")# 最佳响应颜色(圆形点)response_colors <- c("bet" = "#F4F4F4", "SD" = "#6b8590", "PR" = "#9cc0cd", "CR" = "#FFFDEC")# 治疗终止原因颜色(菱形点和箭头)status_colors <- c("Toxicity" = "#b9b9ba","Disease Progression" = "black","Ongoing" = "black")# 元数据 - Treatment_linemeta_colors_1 <- c("1" = "#dfebf3", "2" = "#8eb8d0", ">2" = "#1f7386")# 元数据 - LOH_statusmeta_colors_2 <- c("AI_LOH_ALT" = "#ef75ad", "No_LOH" = "#FAC1E3", "Non_evaluable" = "#FFFFFF")# 元数据 - CDKmeta_colors_3 <- c("Palbociclib" = "#f8ae82", "Abemaciclib" = "#f06b6c", "Ribociclib" = "#ce5455")# 元数据 - AI.SERDmeta_colors_4 <- c("SERD" = "#a060a7", "AI" = "#e4c9e0")# 元数据 - Interim.Platinummeta_colors_5 <- c("Yes" = "#08b06e", "No" = "#b3dcc2")
此数据为模拟数据,无实际意义,如需文末可以自助获取。
绘图
ggplot() +# ------------------- A. 泳道主体(长矩形) -------------------# 每个治疗阶段用一个矩形条表示geom_rect(data = data,aes(xmin = Start.Date.norm, xmax = End.Date.norm,ymin = index - 0.3, ymax = index + 0.3, fill = Treatment),linewidth = 0.2, alpha = 1) +# 填充颜色映射到治疗方案,并添加图例(order=1表示图例排在最前)scale_fill_manual(name = "Treatment\n", values = main_colors,guide = guide_legend(order = 1,override.aes = list(alpha = 1))) +# ------------------- B. 基线到最末时间的连线 -------------------# 为每个患者(index)画一条从时间0到最晚治疗结束时间的灰色线段,表示观察总时长geom_segment(data = data %>%group_by(index) %>%summarise(Max_End = max(End.Date.norm, na.rm = TRUE)),aes(x = 0, xend = Max_End, y = index, yend = index),color = "grey30", linewidth = 0.4) +# ------------------- C. 最佳响应(圆形点) -------------------# 使用新的填充标度(不影响之前的fill标度)ggnewscale::new_scale_fill() +geom_point(data = filter(data, Rapid.Prog == 0 & Best.Response %in% c("CR", "PR", "SD")),aes(x = Scan.Date.Norm, y = index, fill = Best.Response),shape = 21, size = 3.5, color = "black", stroke = 0.3) +# 响应颜色映射,添加图例(order=2)scale_fill_manual(name = "Best\nresponse", values = response_colors,guide = guide_legend(order = 2,override.aes = list(size = 6))) +# ------------------- D. 终止原因标记 -------------------# 新的颜色标度ggnewscale::new_scale_color() +# 菱形(shape=18)表示因毒性或疾病进展而停止治疗的患者geom_point(data = filter(data, Treatment %in% c("cdk", "parp") &Reason.Stop %in% names(status_colors) &Reason.Stop != "Ongoing"),aes(x = End.Date.norm, y = index, color = Reason.Stop),shape = 18, size = 3) +# ------------------- E. 仍在治疗中的箭头 -------------------# 对于Reason.Stop为"Ongoing"的患者,在治疗结束时间点绘制向右的箭头,表示治疗仍在继续geom_segment(data = filter(data, Reason.Stop == "Ongoing"),aes(x = End.Date.norm, y = index, xend = End.Date.norm + 2, yend = index,color = Reason.Stop),arrow = arrow(length = unit(0.15, "cm")), linewidth = 0.5) +# 终止原因颜色映射,添加图例(order=3)scale_color_manual(name = "Reason\nfor stop", values = status_colors,guide = guide_legend(order = 3,override.aes = list(size = 6))) +# ------------------- F. 左侧元数据方块(5个分类变量) -------------------# F1. 治疗线数 (Treatment_line)ggnewscale::new_scale_fill() +geom_point(data = filter(meta_data, category == "Treatment_line"),aes(x = x_pos, y = index, fill = value), shape = 22, size = 4.5, alpha = 0.8) +scale_fill_manual(name = "Treatment line\nCDK4/6i", values = meta_colors_1,guide = guide_legend(order = 8,override.aes = list(size = 6))) +# F2. LOH状态 (LOH_status)ggnewscale::new_scale_fill() +geom_point(data = filter(meta_data, category == "LOH_status"),aes(x = x_pos, y = index, fill = value), shape = 22, size = 4.5, alpha = 0.8) +scale_fill_manual(name = "BRCA2\nzygosity", values = meta_colors_2,guide = guide_legend(order = 7,override.aes = list(size = 6))) +# F3. CDK4/6抑制剂具体药物 (CDK)ggnewscale::new_scale_fill() +geom_point(data = filter(meta_data, category == "CDK"),aes(x = x_pos, y = index, fill = value), shape = 22, size = 4.5, alpha = 0.8) +scale_fill_manual(name = "CDK4/6i\nagent", values = meta_colors_3,guide = guide_legend(order = 6,override.aes = list(size = 6))) +# F4. 内分泌治疗药物类型 (AI.SERD)ggnewscale::new_scale_fill() +geom_point(data = filter(meta_data, category == "AI.SERD"),aes(x = x_pos, y = index, fill = value), shape = 22, size = 4.5, alpha = 0.8) +scale_fill_manual(name = "Endocrine\nagent", values = meta_colors_4,guide = guide_legend(order = 5,override.aes = list(size = 6))) +# F5. 既往铂类化疗 (Interim.Platinum)ggnewscale::new_scale_fill() +geom_point(data = filter(meta_data, category == "Interim.Platinum"),aes(x = x_pos, y = index, fill = value), shape = 22, size = 4.5, alpha = 0.8) +scale_fill_manual(name = "Previous\nplatinum", values = meta_colors_5,guide = guide_legend(order = 4,override.aes = list(size = 6))) +# ------------------- G. 坐标轴与视图范围设置 -------------------coord_cartesian(xlim = c(0, max(data$End.Date.norm, na.rm = TRUE) + 5), clip = "off") +# 设置 X 轴刻度,只显示正数部分scale_x_continuous(breaks = seq(0, 80, by = 20), expand = c(0, 0)) +# Y轴:上下各扩展0.5个单位,避免图形紧贴边缘scale_y_continuous(expand = c(0, 0.5)) +# ------------------- H. 主题与标签设置 -------------------theme_classic()
更多可视化案例,复现思路大同小异,大家可以参考样式:
https://link.springer.com/article/10.1186/s12916-022-02696-4
https://www.nature.com/articles/s41586-025-09580-0
https://www.nature.com/articles/s41586-025-09203-8
https://www.nature.com/articles/s41586-025-10004-2
https://link.springer.com/article/10.1186/s13045-020-01019-5
获取以 RProject 形式保存的绘图代码+注释+数据模板,后台回复关键词: 260409_swimmer_plot
原文链接