1 写在前面
Part.1
在数据可视化领域,柱状图(bar chart)是最基础、最直观的图形之一;而当我们的数据存在“一个分类变量 + 一个分组变量”的双重结构时,分组柱状图(grouped bar chart,亦叫簇状柱形图)便成为展示“组内差异”与“组间差异”的首选。
本期我们挑选刊登在iMeta上的HLF and PPARα axis regulates metabolic-associated fatty liver disease through extracellular vesicles derived from the intestinal microbiota论文的Figure 2L进行复现
原文链接:https://onlinelibrary.wiley.com/doi/full/10.1002/imt2.70022
DOI:https://doi.org/10.1002/imt2.70022
中文链接:iMeta | 周磊/李一星组-解析HLF在代谢相关脂肪性肝病中的作用
引文格式:
Xingzhen Yang, Jiale Wang, Xinyu Qi, Menglong Hou, Mengkuan Liu, Yixing Li, Lei Zhou, et al. 2025. HLF and PPARα axis regulates metabolic-associated fatty liver disease through extracellular vesicles derived from the intestinal microbiota. iMeta 4: e70022. https://doi.org/10.1002/imt2.70022.
文中Figure 2L:
接下来,我们将通过详尽的代码逐步拆解原图,最终实现对原图的复现。
2 数据整理
Part.2
整理原文中的数据成如下格式:
分组信息整理如下:
3 代码复现
Part.3
3.1 R包检测和安装
✦
加载使用到的R包openxlsx、dplyr、tidyr、agricolae、ggplot2
library(openxlsx)library(dplyr)library(tidyr)library(agricolae)library(ggplot2)# 如果没有安装R包可以使用下面的命令安装install.packages("openxlsx")install.packages("vegan")install.packages("dplyr")install.packages("ggplot2")
3.2 读取数据及数据处理
✦
设置工作路径,读取先前整理好的数据
setwd('C:/Users/law/Desktop/') # 设置工作路径data = read.xlsx("imeta分组柱状图数据.xlsx", sheet = 1) # 读取数据names(data)[1] <- "sampleid" # 修改第一列的列名为 sampleid,减少后面代码需要改动的地方group_data = read.xlsx("imeta分组柱状图数据.xlsx", sheet = 2) # 读取分组数据names(group_data)[1] <- "sampleid"names(group_data)[2] <- "group"
读取数据之后的数据框如下:
转换数据成长格式并合并分组信息
idx_col <- names(data)[-1] # 读取除了sampleid一列,其余列的列名,作为后续转换的临时变量# 将数据从宽格式转换为长格式data_long <- data %>%pivot_longer(cols = all_of(idx_col), # 选择要转换的列名names_to = "Group", # 原列名变成新的一列列values_to = "value" # 原数值变成新列)%>%drop_na(value) # 删除na的行,如果有的话# 合并分组信息到长格式数据中data_long <- merge(data_long, group_data, by = "sampleid")
分组设置为因子类型并按默认顺序排列
data_long <- data_long %>%mutate(sampleid = factor(sampleid, levels = unique(data$sampleid)),Group = factor(Group, levels = idx_col)) %>%arrange(sampleid, Group)
计算均值并添加显著性检验的结果
# 计算均值和标准差data_mean <- data_long %>%group_by(Group, group) %>%dplyr::summarize(mean_data = mean(value, na.rm = T),sd = sd(value, na.rm = T),n=sum(!is.na(value)),se = sd/sqrt(n),max_data = max(value, na.rm = TRUE), # 最大值min_data = min(value, na.rm = TRUE), # 最小值.groups = "drop" # 计算完毕之后,取消分组)#给均值添加显著性检验结果Group <- unique(data_long$Group) # 获取所有的 Group 水平mark_result <- data.frame() # 初始化一个空的数据框,用于存储每个 Group 的显著性标记结果for (i in Group){# 设置临时变量temp_data <- filter( data_long, Group == i)# 进行 LSD 检验,这里可以根据自己的需求选择不同的多重比较方法比如:HSD、Duncan 等LSD_test <- LSD.test( lm(value ~ group, temp_data), 'group',p.adj = 'BH', alpha = 0.05)# 合并检验数据mark_result <- rbind(mark_result,data.frame(LSD_test$groups,Group = i,group = rownames(LSD_test$groups)),make.row.names = FALSE # 不保留原始行名,让新行名自动变成 1、2、3…,防止行名混乱)}# 将字母标记的信息和均值数据合并data_mean <- merge(data_mean, mark_result, by = c("Group", "group"))
添加显著性标记之后的数据如下:
设置作图时的因子类型,保证顺序不乱
data_mean$Group <- factor(data_mean$Group, levels = unique(data_long$Group) ) # 这里的顺序可以根据实际情况调整data_mean$group <- factor(data_mean$group, levels = unique(data_long$group) ) # 这里的顺序可以根据实际情况调整data_long$group <- factor(data_long$group, levels = unique(data_long$group) )
3.3 分组柱状图的绘制
✦
构建柱状图、散点、误差棒、显著性标记
p = ggplot(data_mean, aes(x = Group, y = mean_data, color = group)) +geom_bar(position = position_dodge(width = 0.8), stat = "identity",width = 0.6, linewidth = 1.5, fill = 'white') +# 添加样本点并按照group映射颜色geom_point(data = data_long, aes(y = value, color = group),position = position_jitterdodge(jitter.width = 0.2, dodge.width = 0.8),alpha = 1, size = 3, shape = 16, show.legend = FALSE) +# 添加误差棒geom_errorbar(aes(ymin = mean_data - sd, ymax = mean_data + sd),position = position_dodge(0.8), width = 0.2,linewidth = 1, show.legend = FALSE) +# 添加整理好的标记字母geom_text(data = data_mean,aes(x = Group, y = max_data, group = group, label = groups),color = 'black', position = position_dodge(0.8),size = 8, vjust = -0.5, show.legend = FALSE)p
设置颜色 + 坐标轴 + 主题样式
p = p +scale_color_manual( values = c('#D1166D', '#0F99B1', '#FF7900', '#028102'), name = '' ) + # 使用 RColorBrewer 的调色板labs(x = NULL, y = "Fat weight/BW (%)") +theme_classic() +scale_y_continuous(breaks = c(0,2,4,6,8), # 指定刻度位置expand = expansion(mult = c(0, 0.11)) # 设置y轴的范围扩展)+scale_x_discrete(expand = c(0.05,0.05) ) +theme(axis.text.x = element_text(size = 20,face = 'bold'),axis.text.y = element_text(size = 20),axis.title.y = element_text(size = 20,face = 'bold'),legend.title = element_text(size = 15),legend.text = element_text(size = 20),legend.position = 'top', # 图例位置设置到上方legend.direction = 'horizontal', # 图例水平展示axis.ticks = element_line(size = 1.5), # x轴刻度线axis.ticks.length = unit(0.4, "cm"), # 刻度线的长度axis.line = element_line(linewidth = 1.5) # xy轴的粗细) +guides(color = guide_legend(ncol = 2)) # 图例“一行 2 个”p
导出文件
#可以选择导出pdf、jpg、png等格式ggsave("分组柱状图.pdf", plot = p, width = 7, height = 6)
4 完整代码
Part.4
library(openxlsx)library(dplyr)library(tidyr)library(agricolae)library(ggplot2)setwd('C:/Users/law/Desktop/') # 设置工作路径data = read.xlsx("imeta分组柱状图.xlsx", sheet = 1) # 读取数据names(data)[1] <- "sampleid"# 修改第一列的列名为 sampleid,有利于后面代码统一减少需要改动的地方group_data = read.xlsx("imeta分组柱状图.xlsx", sheet = 2)names(group_data)[1] <- "sampleid"names(group_data)[2] <- "group"idx_col <- names(data)[-1] # 读取除了sampleid一列,其余列的列名,作为后续转换的依据# 将数据从宽格式转换为长格式data_long <- data %>%pivot_longer(cols = all_of(idx_col), # 选择要转换的列,就是一簇一簇的名称,通俗一些就是分组组装图的x轴名称names_to = "Group", # 原列名变成新的一列列values_to = "value"# 原数值变成新列)%>%drop_na(value)# 合并分组信息到长格式数据中data_long <- merge(data_long, group_data, by = "sampleid")# 设置为因子类型并按默认顺序排列data_long <- data_long %>%mutate(sampleid = factor(sampleid, levels = unique(data$sampleid)),Group = factor(Group, levels = idx_col)) %>%arrange(sampleid, Group)# 计算均值和标准差data_mean <- data_long %>%group_by(Group, group) %>%dplyr::summarize(mean_data = mean(value, na.rm = T),sd = sd(value, na.rm = T),n=sum(!is.na(value)),se = sd/sqrt(n),max_data = max(value, na.rm = TRUE), # 最大值min_data = min(value, na.rm = TRUE), # 最小值.groups = "drop"# 计算完毕之后,取消分组)##给均值添加显著性检验结果Group <- unique(data_long$Group) # 获取所有的 Group 水平mark_result <- data.frame() # 初始化一个空的数据框,用于存储每个 Group 的显著性标记结果for (i in Group){# 设置临时变量temp_data <- filter( data_long, Group == i)# 进行 LSD 检验,这里可以根据自己的需求选择不同的多重比较方法比如:HSD、Duncan 等LSD_test <- LSD.test( lm(value ~ group, temp_data), 'group',p.adj = 'BH', alpha = 0.05)mark_result <- rbind(mark_result,data.frame(LSD_test$groups,Group = i,group = rownames(LSD_test$groups)),make.row.names = FALSE# 不保留原始行名,让新行名自动变成 1、2、3…,防止行名混乱)}data_mean <- merge(data_mean, mark_result, by = c("Group", "group"))# 设置因子类型,保持绘图顺序和读取数据顺序一致data_mean$Group <- factor(data_mean$Group, levels = unique(data_long$Group) ) # 这里的顺序可以根据实际情况调整data_mean$group <- factor(data_mean$group, levels = unique(data_long$group) ) # 这里的顺序可以根据实际情况调整data_long$group <- factor(data_long$group, levels = unique(data_long$group) )p = ggplot(data_mean, aes(x = Group, y = mean_data, color = group)) +geom_bar(position = position_dodge(width = 0.8),stat = "identity",width = 0.6,linewidth = 1.5,fill = 'white') +geom_point(data = data_long,aes(y = value, color = group),position = position_jitterdodge(jitter.width = 0.2, dodge.width = 0.8),alpha = 1,size = 3,shape = 16,show.legend = F) +geom_errorbar(aes(ymin = mean_data - sd, ymax = mean_data + sd),position = position_dodge(width = 0.8), width = 0.2, linewidth = 1, show.legend = FALSE) +geom_text(data = data_mean,aes(x = Group,y = max_data,group = group,label = groups),color = 'black',position = position_dodge(0.8),size = 8,show.legend = FALSE,vjust = -0.5)# 配置颜色、调整字体p = p +scale_color_manual( values = c('#D1166D', '#0F99B1', '#FF7900', '#028102'), name = '' ) + # 使用 RColorBrewer 的调色板labs(x = NULL, y = "Fat weight/BW (%)") +theme_classic() +scale_y_continuous(breaks = c(0,2,4,6,8), # 指定刻度位置expand = expansion(mult = c(0, 0.11)) # 设置y轴的范围扩展)+scale_x_discrete(expand = c(0.05,0.05) ) +theme(axis.text.x = element_text(size = 20,face = 'bold'),axis.text.y = element_text(size = 20),axis.title.y = element_text(size = 20,face = 'bold'),legend.title = element_text(size = 15),legend.text = element_text(size = 20),legend.position = 'top',legend.direction = 'horizontal',axis.ticks = element_line(size = 1.5), # x轴刻度线axis.ticks.length = unit(0.4, "cm"), # 刻度线的长度axis.line = element_line(linewidth = 1.5) # xy轴的粗细) +guides(color = guide_legend(ncol = 2)) # 图例“一行 2 个”pggsave("分组柱状图.pdf", plot = p, width = 7, height = 6)
(▼ 点击跳转)
1卷1期
1卷2期
1卷3期
1卷4期
2卷1期
2卷2期
2卷3期
2卷4期
3卷1期
3卷2期
3卷3期
3卷4期
3卷5期
3卷6期
4卷1期
4卷2期
4卷3期
4卷4期
4卷5期
1卷1期
1卷2期
2卷1期
2卷2期
2卷3期
1卷1期
1卷2期
“iMeta” 是由威立、宏科学和本领域数千名华人科学家合作出版的开放获取期刊,主编由中科院微生物所刘双江研究员和荷兰格罗宁根大学傅静远教授担任。目的是发表所有领域高影响力的研究、方法和综述,重点关注微生物组、生物信息、大数据和多组学等前沿交叉学科。目标是发表前10%(IF > 20)的高影响力论文。期刊特色包括中英双语图文、双语视频、可重复分析、图片打磨、60万用户的社交媒体宣传等。2022年2月正式创刊!相继被Google Scholar、PubMed、SCIE、ESI、DOAJ、Scopus等数据库收录!2025年6月影响因子33.2,中科院分区生物学1区Top,位列全球SCI期刊前千分之三(65/22249),微生物学科2/163,仅低于Nature Reviews,学科研究类期刊全球第一,中国大陆5/585!
“iMetaOmics” 是“iMeta” 子刊,主编由中国科学院北京生命科学研究院赵方庆研究员和香港中文大学于君教授担任,目标是成为影响因子大于10的高水平综合期刊,欢迎投稿!
"iMetaMed" 是“iMeta” 子刊,专注于医学、健康和生物技术领域,目标是成为影响因子大于15的医学综合类期刊,欢迎投稿!
iMeta主页:
http://www.imeta.science
姊妹刊iMetaOmics主页:
http://www.imeta.science/imetaomics/
出版社iMeta主页:
https://onlinelibrary.wiley.com/journal/2770596x
出版社iMetaOmics主页:
https://onlinelibrary.wiley.com/journal/29969514
出版社iMetaMed主页:
https://onlinelibrary.wiley.com/journal/3066988x
iMeta投稿:
https://wiley.atyponrex.com/journal/IMT2
iMetaOmics投稿:
https://wiley.atyponrex.com/journal/IMO2
iMetaMed投稿:
https://wiley.atyponrex.com/submission/dashboard?siteName=IMM3
邮箱:
office@imeta.science



