跟着iMeta学做图|分面箱线图展示alpha多样性并用标注差异分析结果

本教程相关代码已经上传至 https://github.com/iMetaScience/iMetaPlot/tree/main/230107FacetsBoxplot 如果你使用本代码,请引用:Yu-Xi Zhu. 2022. Gut microbiota composition in the sympatric and diet-sharing Drosophila simulans and Dicranocephalus wallichii bowringi shaped largely by community assembly processes rather than regional species pool. iMeta 1: e57. https://doi.org/10.1002/imt2.57

代码编写及注释:农心生信工作室

写在前面

箱线图 (boxplot) 是一种基于五位数摘要(“最小”,第一四分位数(Q1),中位数,第三四分位数(Q3)和“最大”)显示数据分布的标准化方法, 可以表示微生物群落的alpha多样性。本期我们挑选2022年10月13日刊登在iMeta上的Gut microbiota composition in the sympatric and diet-sharing Drosophila simulans and Dicranocephalus wallichii bowringi shaped largely by community assembly processes rather than regional species pool - iMeta | 扬州大学杜予州团队揭示同域内同食物的两种昆虫肠道微生物群落装配机制,选择文章的Figure 1A进行复现,基于vegan包和ggplot2包,讲解和探讨alpha多样性的计算、箱线图的可视化以及用ANOVA进行差异分析并用字母标注显著性,先上原图:

d7961b78236a6256cee40813ddb632ba.gif

26686d2182690ae7d5ff098697753050.jpeg

接下来,我们将通过详尽的代码逐步拆解原图,最终实现对原图的复现。

R包检测和安装

01

安装核心R包vegan、ggplot2以及一些功能辅助性R包,并载入所有R包。

# 下载包
if (!require("vegan"))
  install.packages('vegan') 
if (!require("ggplot2"))
  install.packages('ggplot2')
if (!require("tidyverse"))
  install.packages('tidyverse')
if (!require("agricolae"))
  install.packages('agricolae')
# 加载包
library(vegan)
library(ggplot2)
library(tidyverse)
library(agricolae)

生成测试数据

02

由于缺少原始数据,因此本例使用vegan包自带的dune数据集进行测试。dune数据集的格式是otu表转置后的格式,包含了20个样品,每个样品有30个物种丰度,每一行是一个样品,每一列是一个物种。

# 载入dune数据集
data(dune)
#载入dune包含分组信息等的元数据(即metadata),分组信息为Management列
data(dune.env)

03

计算alpha多样性,包括均匀度、丰富度和香农指数。

#计算丰富度richness,即群落中丰度大于0的otu数量之和
richness <- rowSums(dune>0)
#计算香农指数Shannon diversity index,以e作为底数
shannon <- diversity(dune, index = 'shannon', base = exp(1))
#计算均匀度Pielou evenness,即香农指数与ln(Richness)的比值
pielo <- shannon/log(richness, base = exp(1))

04

创建函数一步计算alpha多样性。

calculate_alpha <- function(otu){
  data_richness <- rowSums(otu>0)
  data_shannon <- diversity(otu, index = 'shannon', base = exp(1))
  data_pielou <- data_shannon/log(data_richness, base = exp(1))
  alpha_matrix <- cbind(data_pielou, data_richness, data_shannon)
  alpha_df <- as.data.frame(alpha_matrix)
  return(alpha_df)
}

05

利用函数calculate_alpha(),创建绘图所需数据框并重命名其中的列:

plot_df <- calculate_alpha(dune)%>%
  cbind(dune.env$Management)%>%
  rename_with(~"Group", 4)

作图预览

06

接下来,逐一预览不同alpha多样性的箱线图:

#绘制Pielou evenness的箱线图
p_pielou <- ggplot(plot_df, aes(Group, data_pielou))+
  geom_boxplot(aes(fill = Group))+ 
  geom_jitter(aes(Group, data_pielou), size = 0.8) #添加散点

dbf752fef4630db93ade9c218a381205.png

#绘制Shannon的箱线图
p_richness <- ggplot(plot_df, aes(Group, data_richness))+
  geom_boxplot(aes(fill = Group))+
  geom_jitter(aes(Group, data_richness), size = 0.8)

7c829e23f6c4601de7de2ecd932a8575.png

#绘制Richness的箱线图
p_shannon <- ggplot(plot_df, aes(Group, data_shannon))+
  geom_boxplot(aes(fill = Group))+
  geom_jitter(aes(Group, data_shannon), size = 0.8)

3b5b49a5fd7c335a1bcb0cfb607abd0a.png

07

现在,需要绘制分面箱线图,以在同一张图片中表示三种不同的alpha多样性,为此,我们需要将plot_df的宽表转化为长表:

#宽表转化为长表
df_long <- pivot_longer(plot_df, cols = -Group, names_to = "type", values_to = "alpha_index")
#根据不同的alpha多样性绘制分面箱线图
p <- ggplot(df_long, aes(Group, alpha_index))+
  geom_boxplot(aes(fill = Group))+
  geom_jitter(aes(Group, alpha_index), size = 0.8)+
  facet_wrap(.~type, #type列作为变量,分面为一行多列
             scales = "free_y")+  #scales = "free_y"可以使各个分面有自己的y轴刻度
  theme(panel.grid = element_blank(), 
        panel.background = element_rect(fill = 'white'), 
        panel.border = element_rect(fill = NA, color = "black", size = 0.5, linetype = "solid"), 
        axis.title = element_blank(), 
        axis.text.x = element_blank())

ef3d3145741b6815a21cec2d47093d75.png

08

到这一步,基本的分面箱线图已经完成,但我们注意到原图做了差异分析,并用字母标记了差异分析结果。这里我们以参数检验中的one-way ANOVA为例进行差异分析(默认总体符合正态分布和方差齐性,所以在这里没有做正态检验和方差齐性检验):

#先选择Shannon进行one-way ANOVA分析
shannon_anova <- aov(data_shannon~Group, data = plot_df)
#查看ANOVA结果,其中Pr(>F)是p值,p<0.05时,认为不同组的Shannon具有显著差异
summary(shannon_anova)
#>             Df Sum Sq Mean Sq F value  Pr(>F)   
#> Group        3 0.7171 0.23905   5.676 0.00763 **
#> Residuals   16 0.6739 0.04212                   
#> ---
#> Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
#进一步得到更详细的两两比较,用TukeyHSD()函数
pair_comparison <- TukeyHSD(shannon_anova)
pair_comparison <- as.data.frame(pair_comparison$Group)
pair_comparison

e51912a7e28644ef3a4404ceb0f1e686.jpeg

09

如何用abc字母标注差异分析的结果,是本文的难点。为此,我们利用agricolae包的orderPvalue()函数来得到显著性标记。这个函数需要四个参数,因此要对数据提前处理:

#计算分组平均数
group_mean <- aggregate(x = plot_df$data_shannon, by = list(plot_df$Group), FUN = mean)%>%
  rename_with(~c("Group", "mean_val"), 1:2)


#创建一个pvalue矩阵
ntr <- nrow(group_mean)
mat <- matrix(1, ncol = ntr, nrow = ntr)
p <- pair_comparison$`p adj`
k <- 0
for (i in 1:(ntr - 1)) {
  for (j in (i + 1):ntr) {
    k <- k + 1
    mat[i, j] <- p[k]
    mat[j, i] <- p[k]
  }
}


treatments <- as.vector(group_mean$Group)
means <- as.vector(group_mean$mean_val)
alpha <- 0.05
pvalue <- mat
out <- orderPvalue(treatments, means, alpha, pvalue, console = TRUE)
out

d1d6458be11abc27138e10a0b3d3dee5.jpeg

10

将整个ANOVA分析和显著性标记过程打包成一个函数anova_sig()便于后续绘图,在这个函数里我们还添加了分组最大值和sd值的计算:

anova_sig <- function(df, alpha_diversity, group){
  anova <- aov(alpha_diversity~group, data = plot_df)
  pair_comparison <- TukeyHSD(anova)
  pair_comparison_df <- pair_comparison$group
  pair_comparison_df <- as.data.frame(pair_comparison_df)
  group_mean <- aggregate(x = alpha_diversity, by = list(group), FUN = mean)%>%
    rename_with(~c("Group", "mean_val"), 1:2)
  group_max <- aggregate(x = alpha_diversity, by = list(group), FUN = max)%>%
    rename_with(~c("Group", "max"), 1:2)
  group_sd <- aggregate(x = alpha_diversity, by = list(group), FUN = sd)%>%
    rename_with(~c("Group", "sd"), 1:2)
  ntr <- nrow(group_mean)
  mat <- matrix(1, ncol = ntr, nrow = ntr)
  p <- pair_comparison_df$`p adj`
  k <- 0
  for (i in 1:(ntr - 1)) {
    for (j in (i + 1):ntr) {
      k <- k + 1
      mat[i, j] <- p[k]
      mat[j, i] <- p[k]
    }
  }
  treatments <- as.vector(group_mean$Group)
  means <- as.vector(group_mean$mean_val)
  alpha <- 0.05
  pvalue <- mat
  output <- orderPvalue(treatments, means, alpha, pvalue, console = TRUE)
  output$Group <- rownames(output)
  output <- left_join(output, group_max, by = "Group")
  output <- left_join(output, group_sd, by = "Group")
  return(output)
}


#丰富度的ANOVA检验及结果
data_richness <- plot_df$data_richness
Group = plot_df$Group
richness_out <- anova_sig(plot_df, data_richness, Group)
richness_out$type <- "data_richness" #添加一列alpha多样性类别


#均匀度的ANOVA检验及结果
data_pielou <- plot_df$data_pielou
Group = plot_df$Group
pielou_out <- anova_sig(plot_df, data_pielou, Group)
pielou_out$type <- "data_pielou"


#香农指数的的ANOVA检验及结果
data_shannon <- plot_df$data_shannon
Group = plot_df$Group
shannon_out <- anova_sig(plot_df, data_shannon, Group)
shannon_out$type <- "data_shannon"


#合并三者结果
alpha_out <- rbind(pielou_out, shannon_out, richness_out)%>%rename_with(~"marker", 2)
#将长表与差异分析结果合并
df_long_all <- left_join(df_long, alpha_out, by = c("type", "Group"))

11

最后,用geom_text()来添加abc标记,成品图可以根据个人喜好用AI微调:

p <- ggplot(df_long_all, aes(Group, alpha_index))+
  geom_boxplot(aes(fill = Group))+
  geom_jitter(aes(Group, alpha_index), size = 0.8)+
  geom_text(aes(x = Group, y = max+sd, label = marker), size = 4, position =  position_dodge(0.6))+
  facet_wrap(.~type, #type列作为变量,分面为一行多列
             scales = "free_y")+  #scales = "free_y"可以使各个分面有自己的y轴刻度
  theme(panel.grid = element_blank(), 
        panel.background = element_rect(fill = 'white'), 
        panel.border = element_rect(fill = NA, color = "black", size = 0.8, linetype = "solid"), 
        axis.title = element_blank(), 
        axis.text.x = element_blank())

b084b7668ddd8d68a2bb9871f33ad1f3.png

完整代码

# 下载包
if (!require("vegan"))
  install.packages('vegan') 
if (!require("ggplot2"))
  install.packages('ggplot2')
if (!require("tidyverse"))
  install.packages('tidyverse')
if (!require("agricolae"))
  install.packages('agricolae')
# 加载包
library(vegan)
library(ggplot2)
library(tidyverse)
library(agricolae)


# 载入dune数据集
data(dune)
#载入dune包含分组信息等的元数据(即metadata),分组信息为Management列
data(dune.env)


#计算丰富度Richness,即群落中丰度大于0的otu数量之和
richness <- rowSums(dune>0)
#计算香农指数Shannon diversity index,以e作为底数
shannon <- diversity(dune , index = 'shannon' , base = exp(1))
#计算均匀度Pielou evenness,即香农指数与ln(Richness)的比值
pielo <- shannon/log(richness , base = exp(1))


#创建函数一步计算alpha多样性
calculate_alpha <- function(otu){
  data_richness <- rowSums(otu>0)
  data_shannon <- diversity(otu , index = 'shannon' , base = exp(1))
  data_pielou <- data_shannon/log(data_richness , base = exp(1))
  alpha_matrix <- cbind(data_pielou , data_richness , data_shannon)
  alpha_df <- as.data.frame(alpha_matrix)
  return(alpha_df)
}
plot_df <- calculate_alpha(dune)%>%
  cbind(dune.env$Management)%>%
  rename_with(~"Group" , 4)


#绘制Pielou evenness的箱线图
p_pielou <- ggplot(plot_df , aes(Group , data_pielou))+
  geom_boxplot(aes(fill = Group))+ 
  geom_jitter(aes(Group , data_pielou) , size = 0.8) #添加散点


#绘制Shannon的箱线图
p_richness <- ggplot(plot_df , aes(Group , data_richness))+
  geom_boxplot(aes(fill = Group))+
  geom_jitter(aes(Group , data_richness) , size = 0.8)


#绘制Richness的箱线图
p_shannon <- ggplot(plot_df , aes(Group , data_shannon))+
  geom_boxplot(aes(fill = Group))+
  geom_jitter(aes(Group , data_shannon) , size = 0.8)


#宽表转化为长表
df_long <- pivot_longer(plot_df , cols = -Group , names_to = "type" , values_to = "alpha_index")
#根据不同的alpha多样性绘制分面箱线图
p <- ggplot(df_long , aes(Group , alpha_index))+
  geom_boxplot(aes(fill = Group))+
  geom_jitter(aes(Group , alpha_index) , size = 0.8)+
  facet_wrap(.~type ,  #type列作为变量,分面为一行多列
             scales = "free_y")+  #scales = "free_y"可以使各个分面有自己的y轴刻度
  theme(panel.grid = element_blank() , 
        panel.background = element_rect(fill = 'white') , 
        panel.border = element_rect(fill = NA , color = "black" ,  size = 0.5 ,  linetype = "solid") , 
        axis.title = element_blank() , 
        axis.text.x = element_blank())


#先选择Shannon进行one-way ANOVA分析
shannon_anova <- aov(data_shannon~Group , data = plot_df)
#查看ANOVA结果,其中Pr(>F)是p值,p<0.05时,认为不同组的Shannon具有显著差异
summary(shannon_anova)
#>             Df Sum Sq Mean Sq F value  Pr(>F)   
#> Group        3 0.7171 0.23905   5.676 0.00763 **
#> Residuals   16 0.6739 0.04212                   
#> ---
#> Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
#进一步得到更详细的两两比较,用TukeyHSD()函数
pair_comparison <- TukeyHSD(shannon_anova)
pair_comparison <- as.data.frame(pair_comparison$Group)


#计算分组平均数
group_mean <- aggregate(x = plot_df$data_shannon , by = list(plot_df$Group) , FUN = mean)%>%
  rename_with(~c("Group" , "mean_val") , 1:2)


#创建一个pvalue矩阵
ntr <- nrow(group_mean)
mat <- matrix(1 ,  ncol = ntr ,  nrow = ntr)
p <- pair_comparison$`p adj`
k <- 0
for (i in 1:(ntr - 1)) {
  for (j in (i + 1):ntr) {
    k <- k + 1
    mat[i ,  j] <- p[k]
    mat[j ,  i] <- p[k]
  }
}


treatments <- as.vector(group_mean$Group)
means <- as.vector(group_mean$mean_val)
alpha <- 0.05
pvalue <- mat
out <- orderPvalue(treatments , means , alpha , pvalue , console = TRUE)


anova_sig <- function(df , alpha_diversity , group){
  anova <- aov(alpha_diversity~group , data = plot_df)
  pair_comparison <- TukeyHSD(anova)
  pair_comparison_df <- pair_comparison$group
  pair_comparison_df <- as.data.frame(pair_comparison_df)
  group_mean <- aggregate(x = alpha_diversity , by = list(group) , FUN = mean)%>%
    rename_with(~c("Group" , "mean_val") , 1:2)
  group_max <- aggregate(x = alpha_diversity , by = list(group) , FUN = max)%>%
    rename_with(~c("Group" , "max") , 1:2)
  group_sd <- aggregate(x = alpha_diversity , by = list(group) , FUN = sd)%>%
    rename_with(~c("Group" , "sd") , 1:2)
  ntr <- nrow(group_mean)
  mat <- matrix(1 ,  ncol = ntr ,  nrow = ntr)
  p <- pair_comparison_df$`p adj`
  k <- 0
  for (i in 1:(ntr - 1)) {
    for (j in (i + 1):ntr) {
      k <- k + 1
      mat[i ,  j] <- p[k]
      mat[j ,  i] <- p[k]
    }
  }
  treatments <- as.vector(group_mean$Group)
  means <- as.vector(group_mean$mean_val)
  alpha <- 0.05
  pvalue <- mat
  output <- orderPvalue(treatments , means , alpha , pvalue , console = TRUE)
  output$Group <- rownames(output)
  output <- left_join(output , group_max , by = "Group")
  output <- left_join(output , group_sd , by = "Group")
  return(output)
}


#丰富度的ANOVA检验及结果
data_richness <- plot_df$data_richness
Group = plot_df$Group
richness_out <- anova_sig(plot_df , data_richness , Group)
richness_out$type <- "data_richness" #添加一列alpha多样性类别


#均匀度的ANOVA检验及结果
data_pielou <- plot_df$data_pielou
Group = plot_df$Group
pielou_out <- anova_sig(plot_df , data_pielou , Group)
pielou_out$type <- "data_pielou"


#香农指数的的ANOVA检验及结果
data_shannon <- plot_df$data_shannon
Group = plot_df$Group
shannon_out <- anova_sig(plot_df , data_shannon , Group)
shannon_out$type <- "data_shannon"


#合并三者结果
alpha_out <- rbind(pielou_out , shannon_out , richness_out)%>%rename_with(~"marker" , 2)
#将长表与差异分析结果合并
df_long_all <- left_join(df_long , alpha_out , by = c("type" , "Group"))


pdf("Figure 1A.pdf" , width = 8 ,  height = 6)
ggplot(df_long_all , aes(Group , alpha_index))+
  geom_boxplot(aes(fill = Group))+
  geom_jitter(aes(Group , alpha_index) , size = 0.8)+
  geom_text(aes(x = Group , y = max+sd , label = marker) , size = 4 , position =  position_dodge(0.6))+
  facet_wrap(.~type ,  #type列作为变量,分面为一行多列
             scales = "free_y")+  #scales = "free_y"可以使各个分面有自己的y轴刻度
  theme(panel.grid = element_blank() , 
        panel.background = element_rect(fill = 'white') , 
        panel.border = element_rect(fill = NA , color = "black" ,  size = 0.8 ,  linetype = "solid") , 
        axis.title = element_blank() , 
        axis.text.x = element_blank())
dev.off()

以上数据和代码仅供大家参考,如有不完善之处,欢迎大家指正!

更多推荐

(▼ 点击跳转)

高引文章 ▸▸▸▸

iMeta | 德国国家肿瘤中心顾祖光发表复杂热图(ComplexHeatmap)可视化方法

819fc382d6c82157ea04972381e9f4fd.png

▸▸▸▸

iMeta | 浙大倪艳组MetOrigin实现代谢物溯源和肠道微生物组与代谢组整合分析

8db7d078f7d47a6b401d2ac9385468a3.png

▸▸▸▸

iMeta | 高颜值绘图网站imageGP+视频教程合集                                             

a092e7722522547dfc592be6bf63f17b.png

9d86aafff6d8dc4d4ccd46defe6f24a2.jpeg

第1卷第1期

08b605fa44de3a2cc4d2338e19b13271.jpeg

第1卷第2期

a4ac38e0d6fda94317b259addeb25289.jpeg

第1卷第3期

a4f83b0ca378c9241eb4ea4667f31d8d.jpeg

第1卷第4期

期刊简介

“iMeta” 是由威立、肠菌分会和本领域数百位华人科学家合作出版的开放获取期刊,主编由中科院微生物所刘双江研究员和荷兰格罗宁根大学傅静远教授担任。目的是发表原创研究、方法和综述以促进宏基因组学、微生物组和生物信息学发展。目标是发表前10%(IF > 15)的高影响力论文。期刊特色包括视频投稿、可重复分析、图片打磨、青年编委、前3年免出版费、50万用户的社交媒体宣传等。2022年2月正式创刊发行!

联系我们

iMeta主页:http://www.imeta.science

出版社:https://onlinelibrary.wiley.com/journal/2770596x
投稿:https://mc.manuscriptcentral.com/imeta
邮箱:office@imeta.science

往期精品(点击图片直达文字对应教程)

07a0f52f5a0a04b547e5378b176c1fb6.jpeg

baf594ebf1831f91cdf8364a1f0b2906.jpeg

b1fb2f7e8d7e9d27f6fe3161f38e7ac8.jpeg

6c154dd8eea289e70d4b654e21c43090.jpeg

9650b6997c3b0bdd4d1f36b4e04efcfa.jpeg

cbe2b61db7eb3f905716d9ea8f713748.jpeg

2fa5e0c64ebfb1d89f9c64650c4cd89e.jpeg

caab1338b8021931077323367fe97595.jpeg

88479cfcd43617fa6cbd285f22a0aee0.jpeg

1872bb042a557b9e5aab54ed13a53d8b.jpeg

37566c291a595f6e3d769b866a0ac7ba.jpeg

17f12b743d1867238d58309f0ab78fad.jpeg

294632630aa90e27f525205902e774ca.png

9027bea12c72ca0f137abbc492713232.png

f2e382f8c794c4a68597171dd8e47ba1.png

abc6596fed9529be848e37a631d0007e.png

cc4d6d66540818501214d3b0718901b7.jpeg

03cc6b9e6e6161912ddefc9556b39a2c.jpeg

a515eec8e2902a5d66e859d9923724f3.jpeg

87acd1aeba76ddb0994df3a073e61851.jpeg

e0ad94e55ca586de0c64eb62919d7fb1.png

130efebb912e04d041b741cf58cd565c.png

0f838d166a0160a7faf8abb9f6682c12.jpeg

c57bac3e6e33a790d55ab60683f8235d.png

ab3ecf47133bd718a51cd348802558ea.png

28719df39e7096401f648b30bf263f3e.jpeg

4d924bc95849846a210b146e5a1f9978.png

ef1d68f54ae7649a69509951d3e07352.png

机器学习

后台回复“生信宝典福利第一波”或点击阅读原文获取教程合集

e2ee817d3e303c5e01f670dddcaaf4f3.jpeg

bedcb91489719bbf3e493237d030daee.jpeg

5bed0d4e0f36c0698b2927bcd2a3fc84.png

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值