泳道图可以展示不同患者在一定时间内接受不同治疗(或者处于不同时期)的情况,在肿瘤治疗领域的文献中很常见,但是竟然百度不到它的具体含义。。。
泳道图
上面这张图横坐标表示月数,纵坐标表示病人ID,一个条形就是一个病人,条形的颜色表示疾病的不同阶段,不同的形状表示肿瘤治疗中的起止,这张图是用SAS画出来的~
复习下肿瘤领域的几个术语:
- 完全缓解(CR, complete response):所有靶病灶消失,无新病灶出现,且肿瘤标志物正常,至少维持4周。
- 部分缓解(PR, partial response):靶病灶最大径之和减少≥30%,至少维持4周。
- 疾病进展(PD, progressive disease):靶病灶最大径之和至少增加≥20%,或出现新病灶。
- 疾病稳定(SD, stable disease):靶病灶最大径之和缩小未达PR,或增大未达PD。
“数就是图,图就是数
这个图形其实不复杂,主体部分就是我们常见的条形图,再加上几个形状,无非就是不同的坐标进行映射即可。
一般我们在收集病人信息的时候都是宽数据,一行表示一个病人,每一列表示不同的信息,数据结构大概像下面这样:
代码语言:javascript复制suppressMessages(library(tidyverse))
set.seed(200)
df <- data.frame(Patient = 1:12,
Months = sample(6:30, 12, replace=TRUE),
Stage = sample(1:4, 12, replace=TRUE),
Continued = sample(0:1, 12, replace=TRUE))
df <- df |>
mutate(Patient = fct_reorder(factor(Patient), Months)) |> # 画图时保证顺序
group_by(Patient) |>
mutate('Complete Response Start'=sample(c(6:(max(Months)-1),NA), 1,
prob=c(rep(1, length(6:(max(Months)-1))),5), replace=TRUE),
'Partial Response Start'=sample(c(6:(max(Months)-1),NA), 1,
prob=c(rep(1, length(6:(max(Months)-1))),5), replace=TRUE),
'Durable'=sample(c(-0.5,NA), 1, replace=TRUE),
'Response End'=sample(c(6:(max(Months)-1),NA), 1,
prob=c(rep(1, length(6:(max(Months)-1))),5), replace=TRUE)
)
# 数据大概这样
head(df)
## # A tibble: 6 × 8
## # Groups: Patient [6]
## Patient Months Stage Continued Complete Response Sta…¹ Parti…² Durable Respo…³
## <fct> <int> <int> <int> <int> <int> <dbl> <int>
## 1 1 11 1 1 10 8 -0.5 NA
## 2 2 23 4 1 NA 15 NA 17
## 3 3 20 2 0 16 NA NA 17
## 4 4 13 3 0 11 9 -0.5 10
## 5 5 28 4 0 NA 23 NA 15
## 6 6 17 4 0 NA NA -0.5 NA
## # … with abbreviated variable names ¹`Complete Response Start`,
## # ²`Partial Response Start`, ³`Response End`
由于手里没有此类研究的信息,只能自己构建一个,可能有错误,但是不影响画图。
有了这个数据,我们其实就可以开始画图了。先画一个简单的条形图:
代码语言:javascript复制p <- ggplot(df, aes(Months, Patient))
geom_bar(stat = "identity", aes(fill=factor(Stage)),width = 0.7)
p
plot of chunk unnamed-chunk-2
这个图出来之后,我们只要再把不同的形状加上去就好了。形状代表不同的信息,因此这些信息需要在一列里才行,所以我们需要一个长数据。
下面就把不同的信息变成一个长数据,长宽数据转换真的是太重要了,尤其是临床收集的数据大部分都是宽数据,长宽转换非常频繁,如果你还不会,赶紧翻看之前的推文:
宽数据变为长数据的5种情况! 长数据变为宽数据的7种情况! 长宽数据转换的特殊情况
宽数据转为长数据:
代码语言:javascript复制df_long <- df |>
pivot_longer(5:8,names_to = "type",values_to = "value") |>
mutate(type=factor(type, # 顺便给type排个序,画图保证顺序
levels = c("Complete Response Start","Partial Response Start","Response End","Durable")))
head(df_long)
## # A tibble: 6 × 6
## # Groups: Patient [2]
## Patient Months Stage Continued type value
## <fct> <int> <int> <int> <fct> <dbl>
## 1 1 11 1 1 Complete Response Start 10
## 2 1 11 1 1 Partial Response Start 8
## 3 1 11 1 1 Durable -0.5
## 4 1 11 1 1 Response End NA
## 5 2 23 4 1 Complete Response Start NA
## 6 2 23 4 1 Partial Response Start 15
你看这样用来映射形状的不同信息就都在type
这一列了!
然后就可以添加形状了。
代码语言:javascript复制p1 <- p
geom_point(data = df_long, aes(value, Patient, shape=type, color=type), size=5)
p1
这是这个图已经具有雏形了,但是还少一个箭头,由于R默认的形状(pch)中并没有箭头,所以一开始并没有把箭头表示的信息也加入到type
这一列中。。
我们可以通过geom_segment()
函数添加箭头信息。
p2 <- p1
geom_segment(data = df |> dplyr::filter(Continued == 1),
aes(x=Months 0.1, xend=Months 1.5, y=Patient, yend=Patient),
size = 2,
arrow = arrow(length = unit(0.3,"cm"))
)
p2
plot of chunk unnamed-chunk-5
非常棒!其实到这里就已经基本成功了,该有的东西都有了,剩下的就是各种scale_xxxx/theme(xxx)
进行修改颜色、形状、大小等细节问题。在ggplot2
中一旦你掌握了规律,修改这些东西真的非常简单!
ggplot2修改坐标轴详细介绍 超详细教程:修改ggplot2图例
下面就是修改细节。
- 调整大小
- 修改图例形状
- 修改图例标题
- 修改横纵坐标
- 修改整体背景
- ......
p3 <- p2
scale_shape_manual(values = c(16:18,15))
scale_color_manual(values = c("red","blue","grey","black"))
scale_x_continuous(limits = c(-1,32), breaks = -1:30,expand = c(0,0.6))
labs(fill = "Disease Stage", shape = NULL, color = NULL)
theme_bw()
theme(panel.grid.minor=element_blank(),
panel.grid.major=element_blank(),
axis.text.y=element_blank(),
axis.ticks.y=element_blank(),
legend.position = c(0.9,0.3)
)
p3
plot of chunk unnamed-chunk-6
这样一幅泳道图就画好了!是不是很简单呢?
画图1分钟,准备数据10分钟!
难的还是准备符合要求的数据,这其中长款数据转换就是必备的技能!以后还会分享一些中药数据挖掘方面的内容,长款数据转换将会是其中的核心技能~
最后给大家看看怎么用Excel画泳道图:https://peltiertech.com/swimmer-plots-excel/