R语言环形热图绘制(circos图)
图片
图片
图片
图片
图片
图片
圆形布局对于表示复杂的信息非常有用。首先,它可以用更长的坐标轴或大量的类别表示不同的信息;其次,它可以直观地展示数据,将多个圆环聚焦于同一对象;第三,它可以清楚地展示元素之间的关系。圆形布局提供了一种在圆圈上排列信息的有效方法,而且很漂亮。
Circos是一个广泛用于在Perl中实现的圆形布局的工具。它大大增强了科学结果的可视化(特别是在基因组学领域)。因此,具有圆形布局的图通常被命名为“circos图”。
circlize包旨在在R中实现Circos。在R中实现的一个重要优势是,R是一个理想的环境,可在数据分析和数据可视化之间提供无缝连接。circlize不是为Circos生成配置文件的前端包装器,而是使用R优雅的统计和图形引擎,完全以R风格编码。我们的目标是保持Circos的灵活性和可配置性,同时使软件包更易于使用并增强它以支持更多类型的图形。
本文目录:
设计原理
快速上手
添加图形元素的方式
圆形热图
设计原理圆形布局由扇区(sectors)和圆环(tracks)组成。对于不同类别的数据,它们被分配到不同的扇区,对于同一类别的多个测量,它们表示为从外到内的堆叠圆环。扇区和圆环的交集部分称为单元格(cell)(或网格(grid)、面板(panel)),它是圆形布局中的基本单元。它是用于绘制数据点的假想绘图区域。
图片
由于大多数图形都是由简单的图形组成的,如点、线、多边形等,Circlize实现了在圆形绘图区域添加低级图形的功能,因此可以通过不同组合的低级图形功能轻松生成更复杂的图形。这一原则确保了高级图形的类型不受软件本身的限制,并且可以使用其他高级图形R包在其上构建特定的高级图形。
目前,有以下可用于添加低级图形的函数。用法与没有circos.前缀的函数非常相似,除了一些专门为圆形可视化设计的增强功能。
circos.points():在单元格中添加点。circos.lines():在单元格中添加线。circos.segments():在单元格中添加线段。circos.rect():在单元格中添加矩形。circos.polygon():在单元格中添加多边形。circos.text():在单元格中添加文本。circos.axis()和circos.yaxis():在单元格中添加坐标轴。以下函数在圆圈中的两个圆环之间绘制链接:
circos.link()以下函数绘制高级图形:
circos.barplot():绘制条形图。circos.boxplot():绘制箱线图。circos.violin():绘制小提琴图。circus.heatmap():绘制圆形热图。circos.raster():绘制光栅图像。circuses.arrow():绘制圆形箭头。以下功能排列圆形布局。
circos.initialize():在圆圈上分配扇区。circos.track():为单个圆环中的单元格创建绘图区域。circos.update():更新现有的单元格。circos.par():图形参数。circos.info():打印当前圆形图的一般参数。circos.clear():重置图形参数和内部变量。快速上手在我们深入探讨细节之前,我首先演示一个简单的例子,使用circlize包中的基本功能来帮助你了解该包的工作原理。
首先是生成演示数据,一个字符型向量表示类别,另外两个变量是数值型:
set.seed(999)n <- 1000df <- data.frame(sectors = sample(letters[1:8], n, replace = TRUE), x = rnorm(n), y = runif(n) )head(df)
sectors x y1 c -0.33837650 0.22772922 d 0.20128773 0.83454223 e 0.60271173 0.65079414 g -0.22501815 0.86130925 a -0.01011359 0.36246726 f -0.19359724 0.5251656
使用circlize的第一步是初始化圆形布局。函数会自动根据X轴的范围和类别变量将圆形划分为不同的扇区(相当于自动分配x轴范围):
library(circlize)circos.par("track.height" = 0.1) # 设置圆环的高度为0.1,也就是圆形半径的10%circos.initialize(df$sectors, x = df$x)
图片
运行以上代码后不会显示任何图形,因为此时只是进行了初始化,并没有开始画图~
接下来如果要画图的话首先要使用circos.track添加圆环,然后使用各种低级绘图函数添加各种图形元素,比如点、线、文字等:
# 初始化布局circos.par("track.height" = 0.1) # 设置圆环的高度为0.1,也就是圆形半径的10%circos.initialize(df$sectors, x = df$x)# 添加第一个圆环circos.track(df$sectors, y = df$y, # 这里相当于自动分配y轴范围 panel.fun = function(x, y) { # 定义添加点和文字的细节,你可以去掉这个函数试试看 circos.text(CELL_META$xcenter, CELL_META$cell.ylim[2] + mm_y(5), CELL_META$sector.index) circos.axis(labels.cex = 0.6) } )
col = rep(c("#FF0000", "#00FF00"), 4)# 添加点circos.trackPoints(df$sectors, df$x, df$y, col = col, pch = 16, cex = 0.5)# 在指定panel添加文字circos.text(-1, 0.5, "text", sector.index = "a", track.index = 1)
图片
上面这个原圆环图有8个单元格(或者叫8个panel)。
为了更直观的展示这个绘图过程,你可以先运行前3行看看结果,然后再运行第4和第5行,再运行第6行。其实这个过程就是R的绘图过程,关于这方面的细节,大家感兴趣的可以参考书籍:《R绘图系统》。
panel.fun是一个用于控制单元格细节的函数,后面会详细介绍。CELL_META$xxx是一个快捷函数,可以帮你提取横纵坐标等信息。
接下来你可以继续添加更多的圆环
# 初始化布局circos.par("track.height" = 0.1) # 设置圆环的高度为0.1,也就是圆形半径的10%circos.initialize(df$sectors, x = df$x)# 添加第一个圆环circos.track(df$sectors, y = df$y, # 这里相当于自动分配y轴范围 panel.fun = function(x, y) { # 定义添加点和文字的细节,你可以去掉这个函数试试看 circos.text(CELL_META$xcenter, CELL_META$cell.ylim[2] + mm_y(5), CELL_META$sector.index) circos.axis(labels.cex = 0.6) } )col = rep(c("#FF0000", "#00FF00"), 4)# 添加点circos.trackPoints(df$sectors, df$x, df$y, col = col, pch = 16, cex = 0.5)# 添加文字circos.text(-1, 0.5, "text", sector.index = "a", track.index = 1)# 添加第2个圆环bgcol = rep(c("#EFEFEF", "#CCCCCC"), 4)circos.trackHist(df$sectors, df$x, bin.size = 0.2, bg.col = bgcol, col = NA)
图片
接下来载添加第3个圆环。我们随机从每个单元格中挑选10个点,然后用线条连接起来
# 初始化布局circos.par("track.height" = 0.1) # 设置圆环的高度为0.1,也就是圆形半径的10%circos.initialize(df$sectors, x = df$x)# 添加第一个圆环circos.track(df$sectors, y = df$y, # 这里相当于自动分配y轴范围 panel.fun = function(x, y) { # 定义添加点和文字的细节,你可以去掉这个函数试试看 circos.text(CELL_META$xcenter, CELL_META$cell.ylim[2] + mm_y(5), CELL_META$sector.index) circos.axis(labels.cex = 0.6) } )col = rep(c("#FF0000", "#00FF00"), 4)# 添加点circos.trackPoints(df$sectors, df$x, df$y, col = col, pch = 16, cex = 0.5)# 添加文字circos.text(-1, 0.5, "text", sector.index = "a", track.index = 1)# 添加第2个圆环bgcol = rep(c("#EFEFEF", "#CCCCCC"), 4)circos.trackHist(df$sectors, df$x, bin.size = 0.2, bg.col = bgcol, col = NA)# 添加第3个圆环circos.track(df$sectors, x = df$x, y = df$y, panel.fun = function(x, y) { ind = sample(length(x), 10) x2 = x[ind] y2 = y[ind] od = order(x2) circos.lines(x2[od], y2[od])})
图片
如果我们要对某一个圆环的某个扇区(也就是某个panel)进行修改,可以使用circos.update,但是要注意,这个函数不能修改位置相关的东西。
比如我们要修改d这个扇区的第2层圆环,可以在运行完以上代码后运行以下代码:
circos.update(sector.index = "d", # 选择扇区 track.index = 2, # 选择圆环 bg.col = "#FF8080", bg.border = "black") # 修改颜色circos.points(x = -2:2, y = rep(0.5, 5), col = "white")circos.text(CELL_META$xcenter, CELL_META$ycenter, "updated", col = "white")
图片
接下来还可以继续添加圆环:
circos.track(ylim = c(0, 1), panel.fun = function(x, y) { xlim = CELL_META$xlim ylim = CELL_META$ylim breaks = seq(xlim[1], xlim[2], by = 0.1) n_breaks = length(breaks) circos.rect(breaks[-n_breaks], rep(ylim[1], n_breaks - 1), breaks[-1], rep(ylim[2], n_breaks - 1), col = rand_color(n_breaks), border = NA)})
图片
当你把圆环都画完之后,还可以使用线条或者条带连接不同的扇区:
circos.link("a", 0, "b", 0, h = 0.4)circos.link("c", c(-0.5, 0.5), "d", c(-0.5,0.5), col = "red",border = "blue", h = 0.2)circos.link("e", 0, "g", c(-1,1), col = "green", border = "black", lwd = 2, lty = 2)
图片
当你完成整个圆环图的绘制后,一定要记得重置图形参数:
circos.clear()添加图形元素的方式
画圆环图首先要初始化,然后添加圆环,再然后才是添加各种图形元素,比如点、线、文本、坐标轴等。
添加这些图形元素的方式有3种:
使用circos.points()、circos.lines()等低级绘图函数进行添加,但是这种方式需要自己写for循环,逐个panel进行添加,需要自己根据类别划分数据;使用circos.trackPoints()、circos.trackLines()等函数添加,不需要自己写循环;使用panel.fun添加,这种方式最为强大,但是需要一点理解,作者是比较推荐这种方式的,下面会详细介绍。panel.fun需要两个参数:x和y,分别表示在当前panel中的横坐标和纵坐标。
以下是一个简单的示例。在扇区a中,x的值是1:3,在扇区b中,x的值是4:5:
sectors = c("a", "a", "a", "b", "b")x = 1:5y = 5:1circos.initialize(sectors = sectors, x=x)circos.track(sectors, x = x, y = y, panel.fun = function(x, y) { circos.points(x, y) circos.text(CELL_META$xcenter, # 横坐标 CELL_META$cell.ylim[2] + mm_y(5), #纵坐标 CELL_META$sector.index)})
图片
circos.clear()
CELL_META$xxxx其实是get.cell.meta.data()的缩写,可以帮你提取当前panel的信息,比如CELL_META$xcenter会提取当前panel的横坐标的中心点,CELL_META$cell.ylim是提取当前panel的纵坐标,CELL_META$sector.index提取当前panel的标签。
我们也可以直接使用get.cell.meta.data()函数,但是不如用CELL_META$简洁。以下第二个圆环就是用的get.cell.meta.data()函数:
sectors = c("a", "a", "a", "b", "b")x = 1:5y = 5:1# 初始化circos.initialize(sectors = sectors, x=x)# 添加第一个圆环,标签在圆环外面circos.track(sectors, x = x, y = y, panel.fun = function(x, y) { circos.points(x, y) circos.text(CELL_META$xcenter, # 横坐标 CELL_META$cell.ylim[2] + mm_y(5), #纵坐标 CELL_META$sector.index)})
# 添加第二个圆环,把标签放在圆环里面circos.track(sectors, y = y, panel.fun = function(x, y) { sector.index = get.cell.meta.data("sector.index") xcenter = get.cell.meta.data("xcenter") ycenter = get.cell.meta.data("ycenter") circos.text(xcenter, ycenter, sector.index)})
图片
circos.clear()圆形热图
圆形热图非常常见,以前是通过circos.rect实现,但是0.4.10版本以后提供了一个circos.heatmap函数,可以直接绘制圆形热图,非常方便。
数据准备时也要提供一个数值型矩阵(用来画热图),除此之外,还需要一个分组变量,用来分割热图。
rm(list = ls())set.seed(123)mat1 = rbind(cbind(matrix(rnorm(50*5, mean = 1), nr = 50), matrix(rnorm(50*5, mean = -1), nr = 50)), cbind(matrix(rnorm(50*5, mean = -1), nr = 50), matrix(rnorm(50*5, mean = 1), nr = 50)) )rownames(mat1) = paste0("R", 1:100)colnames(mat1) = paste0("C", 1:10)mat1 = mat1[sample(100, 100), ] # 画热图的矩阵mat1[1:4,1:4]
C1 C2 C3 C4R97 -2.1986224 -1.1271486 -1.8308115 -1.1624219R49 1.7799651 0.7642996 3.1001089 0.3888341R50 0.9166309 -0.0264209 -0.2870305 -0.1854801R42 0.7920827 1.5483970 0.7378025 0.6753141
# 分组变量split = sample(letters[1:5], 100, replace = TRUE)spilt = factor(split, levels = letters[1:5])col_fun1 = colorRamp2(c(-2, 0, 2), c("blue", "white", "red"))
这个数据如果直接画热图是这样的:
library(ComplexHeatmap)Heatmap(mat1, row_split = split)
图片
如果要画圆形热图,是这样的:
circos.heatmap(mat1, split = split, col = col_fun1, track.height = 0.4, # 圆环的宽度 show.sector.labels = T, #显示圆环的标签 rownames.side = "outside", # 行名显示在外侧 dend.side = "inside" # 聚类树显示在内侧 )
图片
circos.clear()
各种文本都可以进行各种自定义设置,比如颜色、大小、字体等。
聚类树也可以进行修改,比如重新排序或者使用不同的颜色等。需要借助dend.callback参数以及自定义函数实现。自定义函数需要3个参数:
dend:当前扇区的聚类树m:属于当前扇区的热图si:当前扇区的编号(或者名字)比如重新设置聚类树的顺序:
library(dendsort)circos.heatmap(mat1, split = split, col = col_fun1, dend.side = "inside", dend.callback = function(dend, m, si) { dendsort(dend) })
图片
circos.clear()
或者给聚类树添加不同的颜色:
library(dendextend)dend_col = structure(1:5, names = letters[1:5])circos.heatmap(mat1, split = split, col = col_fun1, dend.side = "inside", dend.track.height = 0.2, dend.callback = function(dend, m, si) { # when k = 1, it renders one same color for the whole dendrogram color_branches(dend, k = 1, col = dend_col[si]) } )
图片
circos.clear()
增加多个圆环也是一模一样的方法。
# 第2个热图的数据mat2 = mat1[sample(100, 100), ] # randomly permute mat1 by rows# 第2个热图的颜色col_fun2 = colorRamp2(c(-2, 0, 2), c("green", "white", "red"))# 绘制两个圆形热图circos.heatmap(mat1, split = split, col = col_fun1, dend.side = "outside")circos.heatmap(mat2, col = col_fun2)
图片
circos.clear()
更加复杂的例子,大家可以至官网学习:https://jokergoo.github.io/circlize_book/book/
本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报。