原文地址:https://mp.weixin.qq.com/s/-npB5r3W-WVkt7x4tLN_MA
目前基因组的图形很多使用circos来做图,你可以在网站
http://circos.ca/
看到,是个基因组研究绘图强大工具,大家应该熟练掌握。当然,这个是基于perl语言来绘制的,很多对perl不熟悉不了解的还要从头学习,累。目前也可以在R中实现,circlize包完全可以实现,下面我们简单看看吧。
常用参数:
•circos.points:单元格内绘制点
•circos.lines:单元格内画线
•circos.rect:绘制矩形
•circos.polygon:多边形
•circos.text: 添加文本
•circos.axis:坐标轴
•circos.link:单元格之间建立联系(circlize 包特有)
上面这些点线和常规作图区别不大,只是在前面加了circos.
但是如果利用上述参数在单元格内绘制点线的话,需要借助for循环,太麻烦,还很慢。
我们可以利用circlize提供的低级绘图参数:
•circos.trackPoints: ‘循环’绘制点
•circos.trackLines: ‘循环’绘制线
•circos.trackText:‘循环’绘制文本一些常用的布局函数:
•circos.trackPlotRegion:创建新的轨道
•circos.updatePlotRegion: 更新绘制的已有的单元格
•circos.par: 作图参数(和par类似)
•circos.info: 打印当前绘图信息
•circos.clear: 重置
下面我们拿一个例子快速浏览一下:
layout(mat=matrix(1:6,ncol=2,byrow = T))
#构建数据
set.seed(1)
n = 1000
a = data.frame(factor = sample(letters[1:8], n, replace = TRUE),
x = rnorm(n), y = runif(n))
#载入包
library(circlize)
#设置整体作图参数
par(mar = c(1, 1, 1, 1), lwd = 0.1, cex = 0.7)
#调整轨道高度
circos.par("track.height" = 0.1)
#初始化
circos.initialize(factors = a$factor, x = a$x)
#创建新的轨道
circos.trackPlotRegion(factors = a$factor, y = a$y,
panel.fun = function(x, y) {
circos.axis()
})
#设置颜色
col = rep(c("#FF0000", "#00FF00"), 4)
#在轨道上绘制点
circos.trackPoints(a$factor, a$x, a$y, col = col, pch = 16, cex = 0.5)
#添加文本标签
circos.text(-1, 0.5, "left", sector.index = "a", track.index = 1)
circos.text(1, 0.5, "right", sector.index = "a")
#设置轨道背景色
bgcol = rep(c("#EFEFEF", "#CCCCCC"), 4)
#添加高级绘图函数
circos.trackHist(a$factor, a$x, bg.col = bgcol, col = NA)
#在创建新的轨道
circos.trackPlotRegion(factors = a$factor, x = a$x, y = a$y,
panel.fun = function(x, y) {
grey = c("#FFFFFF", "#CCCCCC", "#999999")
sector.index = get.cell.meta.data("sector.index")
xlim = get.cell.meta.data("xlim")
ylim = get.cell.meta.data("ylim")
circos.text(mean(xlim), mean(ylim), sector.index)
circos.points(x[1:10], y[1:10], col = "red", pch = 16, cex = 0.6)
circos.points(x[11:20], y[11:20], col = "blue", cex = 0.6)
})
#修改已经绘制的图形(扇形d,轨道2)
circos.updatePlotRegion(sector.index = "d", track.index = 2)
circos.points(x = -2:2, y = rep(0, 5))
xlim = get.cell.meta.data("xlim")
ylim = get.cell.meta.data("ylim")
circos.text(mean(xlim), mean(ylim), "updated")
#创建新的轨道,绘制线
circos.trackPlotRegion(factors = a$factor, y = a$y)
circos.trackLines(a$factor[1:100], a$x[1:100], a$y[1:100], type = "h")
#绘制单元格之间的连接(点到点,点到区间,区间到区间)
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()
一般来说,绘制圆形图需要几个步骤:初始化图形(initialize)——添加轨道(create track)——添加图形(add graphics)——添加轨道——添加图形……——重置(circos.clear)
1、初始化图形:一般利用函数circos.initialize去初始化,所需数据必须包括因子变量和X值。
2、创建轨道:函数circos.trackPlotRegion可以完成,在新创建的轨道上绘制图形,一般有三种方法:
a:circos.points, circos.lines等低级绘图参数,需要借助于for循环
b:circis.trackPoints,circos.trackLines等,我们不推荐使用,主要是不能绘制复杂的图形!
c:在circos.trackPlotRegion中使用panel.fun函数(需要两个参数x,y),推荐大家使用!
我们展示上述三种方法(在已有的轨道上绘制图形):
第一种方法:
circos.initialize(factors, xlim)
circos.trackPlotRegion(factors, ylim)
for(sector.indexin all.sector.index) {
circos.points(x1, y1, sector.index)
circos.lines(x2, y2, sector.index)
}
第二种方法:
circos.initialize(factors, xlim)
circos.trackPlotRegion(factors, ylim)
circos.trackPoints(factors, x, y)
circos.trackLines(factors, x, y)第三种方法:
circos.initialize(factors, xlim)
circos.trackPlotRegion(factors, all_x, all_y, ylim,
panel.fun=function(x,y) {
circos.points(x, y)
circos.lines(x, y)
})
3、circos.clear重置图形
下面这幅图展示我们绘制圆形图的一般过程:
我们还要理解一个概念就是:扇形和轨道
一个圆形图是有扇形和轨道组合成的,下图中,红色圆圈就是一个轨道(第二轨道),蓝色就是扇形,扇形和轨道交集就是一个单元(cell)。
下图有4个轨道和10个扇形:
扇形(sector)是在初始化图形的时候决定的,所以circos.initialize必须提供因子变量,当然你还要提供x值;而轨道(track)是在创建轨道的时候决定的circos.trackPlotRegion,在这里你要提供y值。
circos.initialize(factors, x)
circos.initialize(factors, xlim)
circos.trackPlotRegion(factors, y)
circos.trackPlotRegion(factors, ylim)
我们要清楚一些基本的图形参数:
•start.degree:图形起始角度(一共360度)
•gap.degree:一个轨道上,相邻扇形之间距离
•track.margin:轨道上下边距
•cell.padding:一个单元的四个边距(下左上右)
•track.height:轨道高度
•points.overflow.warning:逻辑值
•canvas.xlim:画布范围(-1,1),可以修改,你自己定义的xlim和ylim要在这个范围内
•canvas.ylim:同上
•clock.wise:绘制扇形方向(默认和和我们常见的时钟一致)
下面是默认图形参数的默认值:
还有一个重要参数:get.cell.meta.data提供了一个单元的详细信息,我们可以指定扇形和轨道去查看。
从get.cell.meta.dataare中我们可以观察到:
•sector.index: 扇形名字
•sector.numeric.index:扇形数目
•track.index: 轨道
•xlim: x轴的范围
•ylim: y轴的范围
•xcenter:x轴的中心
• ycenter:y轴的中心
•xrange:同上.
•yrange:同上.
•cell.xlim: 一个单元x的范围(包括cell.padding)
•cell.ylim: 一个单元上y的范围
•xplot: 绘图区域左右边界起始角度
•yplot: Radius of bottom and top radius in the plotting region.
•cell.start.degree:起始角度.
•cell.end.degree:终止角度。
•cell.bottom.radius:底部单元距离圆心长度
•cell.top.radius:顶部单元距离圆心长度
•track.margin: 一个单元上下边距
•cell.padding:一个单元四周边距
factors = c("a", "b")
circos.initialize(factors, xlim = c(0, 1))
circos.trackPlotRegion(ylim = c(0, 1))
#获取扇形a,轨道1的信息
circlize(0.5, 0.5, sector.index = "a", track.index = 1)
reverse.circlize(90, 0.9, sector.index = "a", track.index = 1)
我们自己手动绘制不同起始角度和半径的扇形:
#定义边距
par(mar = c(1, 1, 1, 1))
#绘制基本图形
plot(c(-1, 1), c(-1, 1), type = "n", axes = FALSE, ann = FALSE)
#绘制从20度到0度的扇形
draw.sector(20, 0)
#30度到60度,半径版0.5-0.8的扇形,逆时针
draw.sector(30, 60, rou1 = 0.8, rou2 = 0.5, clock.wise = FALSE, col = "#FF000080")
#350度到1000度,去掉边界色
draw.sector(350, 1000, col = "#00FF0080", border = NA)
#从0到180度,改变中心点(从c(0,0)到c(-0.5到0.5))
draw.sector(0, 180, rou1 = 0.25, center = c(-0.5, 0.5), border = 2, lwd = 2, lty = 2)
#绘制一个0到360度的扇形
draw.sector(0, 360, rou1 = 0.7, rou2 = 0.6, col = "#0000FF80")
par(mar = c(1, 1, 1, 1))
factors = letters[1:8]
circos.initialize(factors, xlim = c(0, 1))
for(i in 1:3) {
circos.trackPlotRegion(ylim = c(0, 1))
}
circos.info(plot = TRUE)
#高亮扇形a
draw.sector(get.cell.meta.data("cell.start.degree", sector.index = "a"),
get.cell.meta.data("cell.end.degree", sector.index = "a"),
rou1 = 1, col = "#FF000040")
#高亮轨道1
draw.sector(0, 360,
rou1 = get.cell.meta.data("cell.top.radius", track.index = 1),
rou2 = get.cell.meta.data("cell.bottom.radius", track.index = 1),
col = "#00FF0040")
#在轨道2和3高亮扇形e和f
draw.sector(get.cell.meta.data("cell.start.degree", sector.index = "e"),
get.cell.meta.data("cell.end.degree", sector.index = "f"),
get.cell.meta.data("cell.top.radius", track.index = 2),
get.cell.meta.data("cell.bottom.radius", track.index = 3),
col = "#0000FF40")
#高亮一个小的区域,首先我们要计算出位置信息
pos = circlize(c(0.2, 0.8), c(0.2, 0.8), sector.index = "h", track.index = 2)
draw.sector(pos[1, "theta"], pos[2, "theta"], pos[1, "rou"], pos[2, "rou"],
clock.wise = TRUE, col = "#00FFFF40")
circos.clear()
利用函数highlight.sector,我们也可以高亮某个扇形和轨道:
#提供因子变量
factors = letters[1:8]
#初始化
circos.initialize(factors, xlim = c(0, 1))
#绘制4个轨道
for(i in 1:4) {
circos.trackPlotRegion(ylim = c(0, 1))
}
#轨道上添加标签信息
circos.info(plot = TRUE)
#在轨道1高亮扇形a和h,并添加注释信息
highlight.sector(c("a", "h"), track.index = 1, text = "a and h belong to a same group",
facing = "bending.inside", niceFacing = TRUE, text.vjust = -3)
#高亮扇形c
highlight.sector("c", col = "#00FF0040")
#高亮扇形d
highlight.sector("d", col = NA, border = "red", lwd = 2)
#在轨道2和3,高亮扇形e
highlight.sector("e", col = "#0000FF40", track.index = c(2, 3))
#在轨道2和3,高亮f和g
highlight.sector(c("f", "g"), col = NA, border = "green",
lwd = 2, track.index = c(2, 3))
#高亮整个轨道4
highlight.sector(factors, col = "#FFFF0040", track.index = 4)
circos.clear()
下面是一个简单示例:绘制高水平图形
library(circlize)
#10个分类变量
category = paste0("category", "_", 1:10)
#构造数据
percent = sort(sample(40:80, 10))
#提供颜色
color = rev(rainbow(length(percent)))
par(mar = c(1, 1, 1, 1))
#初始角度90
circos.par("start.degree" = 90)
#初始化图形
circos.initialize("a", xlim = c(0, 100))
#添加轨道,绘制图形
circos.trackPlotRegion(ylim = c(0.5, length(percent)+0.5), , track.height = 0.8,
bg.border = NA, panel.fun = function(x, y) {
xlim = get.cell.meta.data("xlim")
for(i in seq_along(percent)) {
circos.lines(xlim, c(i, i), col = "#CCCCCC")
circos.rect(0, i - 0.45, percent[i], i + 0.45, col = color[i],
border = "white")
}
for(i in seq_along(percent)) {
circos.text(xlim[1], i, paste0(category[i], " - ", percent[i], "%"),
facing = "downward", adj = c(1.1, 0.5))
}
breaks = seq(0, 90, by = 5)
circos.axis(h = "top", major.at = breaks, labels = paste0(breaks, "%"),
major.tick.percentage = 0.02, labels.cex = 0.6,
labels.away.percentage = 0.01)
})
circos.clear()
具有的完整的更加详细的请看circlize 包帮助文档!