【错误于split.default(seq_len(nrow(mat)), split): 组的长度为零但数据的长度大于零】

  • ComplexHeatmap的最突出特点就在于其强大的注释功能,通常来说ComplexHeatmap的可视化结果包含heamap,body,titles dendrograms, row/column names/labels和heatmap annotations,并且其具有足够的自由度,能够完成各类数据的组合可视化,经典的ComplexHeatmap的可视化结果如下,heamap body中的矩阵也可以由用户自行分割:

  • 这里再给大家介绍一个热图绘制的终极答案: ComplexHeatmap,这个包最初由Zuguang Gu博士于2016年被发布在《Bioinformatics》上,最初的灵感也来自于我们之前介绍过的pheatmap,甚至作者最初写的包就叫pheatmap2,因此ComplexHeatmap当中的许多函数名称也与pheatmap相同或类似。目前ComplexHeatmap已经经历了诸多的版本更新,具有强大的可视化功能,基本与ggplot2一样被广泛的内嵌于各类R包的可视化功能之中,例如我们之前的Cellchat教程中便有涉及。这里先放一个我做的笔记(Rmarkdow编译好的html文件),链接会持续更新:

  • https://pan.baidu.com/s/1VkWbfLAZzAnm_eC7GkYD4g?pwd=gs5n 

  • ComplexHeatmap

    慢慢我们会发现pheatmap逐渐不能满足复杂热图作图的需求,需要运用到complexheatmap包,功能更加多样和强大。复杂热图可以有效地直观显示不同数据集来源之间的关联,并揭示潜在的模式。ComplexHeatmap 软件包提供了一种高度灵活的方式来排列多个热图,并支持各种注释图形。

    Circlize

    Circlize 圆形布局由 sectors(扇形)和 tracks(轨迹)组成。对于数据中的不同分类,会作为不同的 sectors,在圆形布局上看起来就是将圆切割为一个个扇形;而同一个类别的不同维度的观测值,会作为从圆外向圆内不断堆叠的图形轨迹 tracks,即展示的各种数据图形。

R包检测和安装

01 安装核心R包circlize以及一些功能辅助性R包,并载入所有R包

# 检查开发者工具devtools,如没有则安装if (!require("devtools"))  install.packages("devtools")# 加载开发者工具devtoolslibrary(devtools)# 检查circlize包,没有则通过github安装最新版if (!require("circlize"))  install_github("jokergoo/circlize")if (!require("tidyverse"))  install.packages('tidyverse') if (!require("ComplexHeatmap"))  install.packages('ComplexHeatmap') if (!require("tidyverse"))  install.packages('tidyverse') # 加载包library(circlize)library(tidyverse)library(ComplexHeatmap)library(gridBase)

生成测试数据

02

由于没有在补充文件里找到原文相关数据,在这里我们通过生成随机数据来替代。


#生成KEGG数据矩阵(矩阵1)
data1<-matrix(rnorm(670,mean=0.5),nrow=67)
rownames(data1)<-c("K01446","K01971","K01142","K01151","K01246","K00784","K02031","K01644","K02037","K02065","K01448",
  "K01890","K00266","K01725","K00806","K00231","K01737","K00858","K00019","K01715","K01692","K00249",
  "K00023","K00626","K00101","K00803","K01710","K01791","K01176","K00799","K00800","K01667","K01668",
  "K01712","K00053","K01696","K01697","K00108","K00639","K01489","K00226","K01488","K02339","K01428",
  "K01438","K02124","K02275","K01796","K00632","K00648","K00849","K01805","K01685","K00065","K00090",
  "K01619","K01834","K00121","K02182","K02082","K02005","K01266","K01990","K01463","K02217","K01174","K02003")
colnames(data1)<-c(paste('H',seq(1:5),sep = ""),paste("PS",seq(1:5),sep = ""))
#生成EC数据矩阵(矩阵2)
data2<-matrix(rnorm(130,mean=1),nrow = 13)
rownames(data2)<-c("2.1.1.165","1.1.5.-","4.2.99.20","1.1.1.86","1.1.99.1","1.1.2.3","4.2.1.28","4.2.1.82","5.4.1.3","1.13.12.16","5.1.99.4","1.17.4.1","1.8.4.-")
colnames(data2)<-c(paste('H',seq(1:5),sep = ""),paste("PS",seq(1:5),sep = ""))
#生成细菌数据矩阵(矩阵3)
data3<-matrix(rnorm(20,mean=1),nrow = 10)
supdata<-matrix(0,nrow = 10,ncol = 8)
#由于该矩阵为10×2矩阵,需补充10×8全为0的矩阵,使得矩阵123均为m×10的矩阵
data3<-cbind(data3,supdata)
rownames(data3)<-c("Proteobacteria","Actinobacteria","Acidobacteria","Bacteroidetes","Gemmatimonadetes","Chloroflexi","Planctomycetes","Firmicutes","Verrucomicrobia","unidentified_Acidobacteria")
#将三个矩阵按行合并
mat_data<-rbind(data1,data2,data3)
#按行将矩阵反转,这样矩阵3的非零数据会出现在内圈
mat_dataR<-mat_data%>% as.data.frame() %>% rowwise() %>% rev() %>% as.matrix() 
rownames(mat_dataR)<-rownames(mat_data)

环形热图预览

03

开始作图,首先画一个最基本的环形热图:


pdf("plot1.pdf",width = 8, height = 6)
#设置热图颜色范围:
colpattern = colorRamp2(c(-1, 0, 1), c("#2574AA", "white", "#ED7B79"))
#设置扇区,这里划分了三个扇区,KEGG,EC和细菌种类。
level_test<-c(rep("KEGG",67),rep("EC",13),rep("SP",10)) %>% factor()

#画图
circos.heatmap(mat_dataR, col = colpattern, rownames.side = "outside", cluster = TRUE)
circos.clear()

dev.off()

04

添加扇区分化,单元格边框,轨道高度,扇区间间隔:


pdf("plot2.pdf",width = 8, height = 6)
circos.par(gap.after = c(10, 10, 12))
circos.heatmap(mat_dataR, split = level_test, 
               col = colpattern, rownames.side = "outside", 
               cluster = TRUE,cell.lwd=0.8,
               cell.border="white",track.height = 0.2)
circos.clear()

dev.off()

05

添加矩阵的列名。circos.heatmap()不直接支持矩阵的列名,可以通过自定义panel.fun函数轻松添加:


pdf("plot3.pdf",width = 8, height = 6)
circos.par(gap.after = c(10, 10, 12))
circos.heatmap(mat_dataR, split = level_test, 
               col = colpattern, rownames.side = "outside", 
               cluster = TRUE,cell.lwd=0.8,
               cell.border="white",track.height = 0.2) 
circos.track(track.index = get.current.track.index(), panel.fun = function(x, y) {
  if(CELL_META$sector.numeric.index == 1) { # the last sector
    cn = colnames(mat_dataR)
    n = length(cn)
    circos.text(rep(CELL_META$cell.xlim[2], n) + convert_x(1, "mm"), 
                1:n - 0.5, cn, 
                cex = 0.3, adj = c(0, 0.5), facing = "inside")
  }
}, bg.border = NA)


circos.track(track.index = get.current.track.index(), panel.fun = function(x, y) {
  if(CELL_META$sector.numeric.index == 3) { # the last sector
    cn = colnames(mat_dataR)
    n = length(cn)
    circos.text(rep(CELL_META$cell.xlim[2], n) + convert_x(1, "mm"), 
                1:n - 0.5, cn, 
                cex = 0.3, adj = c(0, 0.5), facing = "inside")
  }
}, bg.border = NA)
circos.clear()

dev.off()

06

接下来添加连接线,连接线表示位置和位置的对应关系。首先生成数据:


#灰色连接线数据
df_link = data.frame(
  from_index = sample(nrow(mat_dataR), 30),
  to_index = sample(nrow(mat_dataR), 30)
)
#红色连接线数据
red_df_link<-data.frame(from_index = c(86,87,82),
                        to_index = c(2,15,36))
#蓝色连接线数据
blue_df_link<-data.frame(from_index = c(84,86,90),
                         to_index = c(72,76,69))

07

接下来开始添加link:


pdf("plot4.pdf",width = 8, height = 6)
circos.par(gap.after = c(10, 10, 12))
circos.heatmap(mat_dataR, split = level_test, 
               col = colpattern, rownames.side = "outside", 
               cluster = TRUE,cell.lwd=0.8,
               cell.border="white",track.height = 0.2) 
circos.track(track.index = get.current.track.index(), panel.fun = function(x, y) {
  if(CELL_META$sector.numeric.index == 1) { # the last sector
    cn = colnames(mat_dataR)
    n = length(cn)
    circos.text(rep(CELL_META$cell.xlim[2], n) + convert_x(1, "mm"), 
                1:n - 0.5, cn, 
                cex = 0.3, adj = c(0, 0.5), facing = "inside")
  }
}, bg.border = NA)


circos.track(track.index = get.current.track.index(), panel.fun = function(x, y) {
  if(CELL_META$sector.numeric.index == 3) { # the last sector
    cn = colnames(mat_dataR)
    n = length(cn)
    circos.text(rep(CELL_META$cell.xlim[2], n) + convert_x(1, "mm"), 
                1:n - 0.5, cn, 
                cex = 0.3, adj = c(0, 0.5), facing = "inside")
  }
}, bg.border = NA)

for(i in seq_len(nrow(df_link))) {
  circos.heatmap.link(df_link$from_index[i],
                      df_link$to_index[i],
                      col = "grey")
}

for(i in seq_len(nrow(red_df_link))) {
  circos.heatmap.link(red_df_link$from_index[i],
                      red_df_link$to_index[i],
                      col = "red")
}

for(i in seq_len(nrow(blue_df_link))) {
  circos.heatmap.link(blue_df_link$from_index[i],
                      blue_df_link$to_index[i],
                      col = "blue")
}
circos.clear()


dev.off()

08

添加图例,circos.heatmap()本身是不支持添加图例的,但我们可以利用gridBase和ComplexHeatmap包添加图例:

pdf("plot5.pdf",width = 8, height = 6)
plot.new()
circle_size = unit(1, "snpc") # snpc unit gives you a square region

pushViewport(viewport(x = 0, y = 0.5, width = circle_size, height = circle_size,
                      just = c("left", "center")))
par(omi = gridOMI(), new = TRUE)
circos.par(gap.after = c(10, 10, 12))
circos.heatmap(mat_dataR, split = level_test, 
               col = colpattern, rownames.side = "outside", 
               cluster = TRUE,cell.lwd=0.8,
               cell.border="white",track.height = 0.2) 
circos.track(track.index = get.current.track.index(), panel.fun = function(x, y) {
  if(CELL_META$sector.numeric.index == 1) { # the last sector
    cn = colnames(mat_dataR)
    n = length(cn)
    circos.text(rep(CELL_META$cell.xlim[2], n) + convert_x(1, "mm"), 
                1:n - 0.5, cn, 
                cex = 0.3, adj = c(0, 0.5), facing = "inside")
  }
}, bg.border = NA)


circos.track(track.index = get.current.track.index(), panel.fun = function(x, y) {
  if(CELL_META$sector.numeric.index == 3) { # the last sector
    cn = colnames(mat_dataR)
    n = length(cn)
    circos.text(rep(CELL_META$cell.xlim[2], n) + convert_x(1, "mm"), 
                1:n - 0.5, cn, 
                cex = 0.3, adj = c(0, 0.5), facing = "inside")
  }
}, bg.border = NA)

for(i in seq_len(nrow(df_link))) {
  circos.heatmap.link(df_link$from_index[i],
                      df_link$to_index[i],
                      col = "grey")
}

for(i in seq_len(nrow(red_df_link))) {
  circos.heatmap.link(red_df_link$from_index[i],
                      red_df_link$to_index[i],
                      col = "red")
}

for(i in seq_len(nrow(blue_df_link))) {
  circos.heatmap.link(blue_df_link$from_index[i],
                      blue_df_link$to_index[i],
                      col = "blue")
}
circos.clear()
upViewport()

h = dev.size()[2]
lgd = Legend(title = "", col_fun = colpattern)
draw(lgd, x = circle_size, just = "left")

dev.off()

09

距离成功只差一步啦,最后用AI进行修图,处理掉不合理的部分。成品图如下:

无厘头的报错:

circos.heatmap(mat1, col = col_fun1)报错如下
Error in split.default(seq_len(nrow(mat)), split) : 
  group length is 0 but data length > 0

解决办法:重新R,再重新跑一次即可,        亲测有效

转化为矩阵并对其进行归一化

madt<-as.matrix(data)

madt2<-t(scale(t(madt)))

range(madt2)   //查看值的分布

circos.clear()  //绘制完成后需要使用此函数完全清除布局

circos.par(gap.after=c(50))    //调整圆环首尾间的距离,数值越大,距离越宽

circos.heatmap(madt2,col=mycol, dend.side="inside",rownames.side="outside",rownames.col="black",rownames.cex=0.9,rownames.font=1,cluster=TRUE)

注:dend.side:控制行聚类树的方向,inside为显示在圆环内圈,outside为显示在圆环外圈

#rownames.side:控制矩阵行名的方向,与dend.side相同;但注意二者不能在同一侧,必须一内一外

#cluster=TRUE为对行聚类,cluster=FALSE则不显示聚类

===聚类树的调整和美化(需要用到两个别的包)===

install.packages("dendextend")     //改颜色

install.packages("dendsort")          //聚类树回调

library(dendextend)

library(dendsort)

circos.heatmap(madt2,col=mycol,dend.side="inside",rownames.side="outside",track.height=0.38,rownames.col="black",rownames.cex=0.9,rownames.font=1,cluster=TRUE,dend.track.height=0.18,dend.callback=function(dend,m,si){color_branches(dend,k=15,col=1:15)}) 
注:track.height:轨道的高度,数值越大圆环越粗  dend.track.height:调整行聚类树的高度  dend.callback:用于聚类树的回调,当需要对聚类树进行重新排序,或者添加颜色时使用 包含的三个参数:dend:当前扇区的树状图;m:当前扇区对应的子矩阵;si:当前扇区的名称   color_branches():修改聚类树颜色

//添加图例标签等

lg=Legend(title="Exp",col_fun=mycol,direction= c("vertical"))

grid.draw(lg)

===分组热图绘制========

#circos.heatmap()内只能是一个矩阵,但如果矩阵数据存在分组,可以用split参数来指定分类变量

split = sample(letters[1:2], 40, replace = TRUE)

split = factor(split, levels = letters[1:2])

  • 13
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

皮肤小白生

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值