R学习|基于ggplot2,使用金字塔图可视化临床研究中的不良事件(AE)

对于临床研究而言,疗效和安全性是大家最关心的问题。那么,如何在一个临床研究中将读者们最关心的问题有效的展示出来至关重要。这期我们选择临床研究中的不良事件(AE)。通常来讲,在绝大多数文章中作者一般会使用表格来呈现不同干预组参与者不同AE的构成比。

John, Thomas et al. “Three-Year Safety, Tolerability, and Health-Related Quality of Life Outcomes of Adjuvant Osimertinib in Patients With Resected Stage IB to IIIA EGFR-Mutated NSCLC: Updated Analysis From the Phase 3 ADAURA Trial.” Journal of thoracic oncology : official publication of the International Association for the Study of Lung Cancer vol. 18,9 (2023): 1209-1221. doi:10.1016/j.jtho.2023.05.015

例如上面提到的文章,作者在表格中展示了不同治疗组参与者任何级别和3级及以上AE的构成比。

图片

此外,作者也通过类似于金字塔图的形式来展示一些AE在不同组中的发生情况。

图片

上图貌似是从Prism中绘制得到的。那么,如何用R来达到上面的效果呢,确切的来说,是通过ggplot2。

要实现上一目标,我们得将目光转向金字塔图。那什么是金字塔图?金字塔图又有什么作用呢?

金字塔图是一种图形表达方式,其形状类似金字塔,从顶部开始逐渐向底部扩展。它通常用于展示层次关系、分层结构或者逐级递减的数据。金字塔图在商业、统计学、人口学和市场营销等领域中被广泛应用。

金字塔图的基本特征包括:

  1. 层次结构: 金字塔图的形状呈金字塔状,从上到下逐渐变宽,表示数据的逐级递减或者逐级分层。

  2. 比例表达: 金字塔图的每个层次都代表了不同的数值或者占比,并且可以通过宽度或高度的变化来表示相对的数量。

金字塔图的作用包括:

  1. 展示层次结构: 金字塔图适用于展示具有明显层次结构的数据,例如组织层级、人口金字塔等。

  2. 比较占比:通过金字塔图,可以清晰地看到每个层次的占比情况,便于比较不同级别或群体之间的相对大小。

  3. 传达逐渐减少的趋势:当数据呈现逐级递减的趋势时,金字塔图能够生动地表达这种递减关系。

  4. 人口金字塔:金字塔图在人口学中被广泛用于展示不同年龄层次和性别的人口分布,形成人口金字塔,用于分析人口结构和趋势。

在R中,可以通过apyramid包来绘制金字塔图。相关内容有很多推送,不再赘述。小编选择使用ggplot2来实现金字塔图的可视化,是因为后者具有更强的可编辑性。

以下是小编使用ggplot2绘制的金字塔图,来展示上面提到的表格中不同治疗组任意级别AE的发生构成比。

需要注意的是,里面的数据为小编随意生成,并不是原始表格中的数据。但值得肯定的是,下图可以更加清晰的来展示AE。也推荐大家用在自己的文章中,提升一点儿逼格。

图片


下面我们看下具体是如何实现的吧。

加载包

1
2
3
4
5
# 加载包
library(ggplot2)#可视化
library(ggsci)#配色
library(tidyverse)#数据操纵
library(ggrepel)#文本注释

数据处理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

# 读入数据
data<-read.delim("pyramid.txt",header = T)
# 数据处理-宽数据格式转变为长数据格式
data%>%
pivot_longer(cols = 2:3,
names_to = "Arm",
values_to = "Count")->data2

# 计算不同干预组不同AE的构成比
data2%>%
mutate(Percent=
ifelse(Arm=="Osimertinib",Count/337,Count/343))->data2

# 产生标签,将构成比转换为百分数
data2%>%
mutate(label=sprintf("%.0f%%", Percent * 100),
Count=ifelse(Arm=="Osimertinib",Count,-1*Count))->Label

绘图

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
# 绘图
ggplot(mapping = aes(x=reorder(AE,Count),y=Count,fill=Arm)) +#绘制图层
geom_col(data = data2 %>% filter(Arm == "Osimertinib"),alpha=0.8) +#奥希替尼组条形图
geom_col(data = data2 %>% filter(Arm == "Placebo"),#安慰剂组条形图,绘制到坐标轴左半部分
mapping = aes(y =Count* (-1)),alpha=0.8) +
coord_flip()+#坐标轴翻转
# 设置坐标轴范围
scale_y_continuous(limits = c(-250,350),
breaks = seq(-250,350,100),
labels = abs(seq(-250,350,100)))+
scale_fill_jco(name="Treatment Arm",#设置主题及图例标题和标签
labels=c("Osimertinib (n=337)","Placebo (n=343)"))+
labs(x="",y="Count of patients with AE",
caption = "Most Common Investigator-Assessed Possibly Causally Related AEs Reported in More Than or Equal to 5% of Patients
Treated With Osimertinib or Placebo, by Maximum CTCAE Grade")+
ggtitle("Pyramid plot to visualize the AEs in clinical study")+
theme_classic()+
theme(axis.line.y = element_blank(),
axis.ticks.y = element_blank(),
axis.line.x = element_line(linewidth = 1),
axis.text = element_text(color = "black",face = "bold.italic"),
plot.title = element_text(size = 12,color = "red",
face = "bold.italic",hjust = 0),
plot.caption = element_text(size = 8,color = "grey",
face = "italic",hjust =0.5))+
geom_hline(yintercept = 0,linewidth=1)+#添加辅助线
geom_text_repel(data = Label %>% filter(Arm == "Osimertinib"),#添加奥希替尼组AE构成比的文本注释
aes(label = label),
force = 0.5,
nudge_y =15,
direction = "x",
hjust = 0) +
geom_text_repel(data = Label %>% filter(Arm == "Placebo"),#安慰剂组注释
aes(label = label),
force = 0.5,
nudge_y =-15,
direction = "x",
hjust =1)

生成图片

本次的分享就到这里了!

-------- 本文结束 感谢阅读 --------