circlize 之 Graphics
感谢老俊俊的大力支持。我们会每日跟新,欢迎您关注老俊俊的生信笔记。
circlize 之 Graphics
我们可以给环形图添加低级的图形,这些图形参数和 points(),lines()等基础函数用法类似,因此我们可以生成复杂的图形,所有的低级图形函数都接受 sector.index,track.index 两个参数来指定在具体的单元格添加图形,推荐在 panel.fun 函数里使用,当然也可以在其它地方使用,当年指定好具体的单元格后。
circos.track(..., panel.fun = function(x, y) {
circos.points(x, y)
})
circos.points(x, y, sector.index, track.index)
1、设置颜色
colorRamp2()
函数可以生成一系列连续的颜色:
col_fun = colorRamp2(c(-2, 0, 2), c("blue", "white", "red"))
# all the values smaller than -2 are all mapped to blue
col_fun(seq(-5, 1, by = 1))
## [1] "#0000FFFF" "#0000FFFF" "#0000FFFF" "#0000FFFF" "#B38BFFFF" "#FFFFFFFF"
## [7] "#FF9E81FF"
rand_color()
随机生成指定色系的颜色:
par(mar = c(1, 1, 1, 1))
plot(NULL, xlim = c(1, 10), ylim = c(1, 8), axes = FALSE, ann = FALSE)
points(1:10, rep(1, 10), pch = 16, cex = 5,
col = rand_color(10, luminosity = "random"))
points(1:10, rep(2, 10), pch = 16, cex = 5,
col = rand_color(10, luminosity = "bright"))
points(1:10, rep(3, 10), pch = 16, cex = 5,
col = rand_color(10, luminosity = "light"))
points(1:10, rep(4, 10), pch = 16, cex = 5,
col = rand_color(10, luminosity = "dark"))
points(1:10, rep(5, 10), pch = 16, cex = 5,
col = rand_color(10, hue = "red", luminosity = "bright"))
points(1:10, rep(6, 10), pch = 16, cex = 5,
col = rand_color(10, hue = "green", luminosity = "bright"))
points(1:10, rep(7, 10), pch = 16, cex = 5,
col = rand_color(10, hue = "blue", luminosity = "bright"))
points(1:10, rep(8, 10), pch = 16, cex = 5,
col = rand_color(10, hue = "monochrome", luminosity = "bright"))

2、点
circos.points()
添加点类似于 points()
函数:
circos.points(x, y)
circos.points(x, y, sector.index, track.index)
circos.points(x, y, pch, col, cex)
有一个配套函数 circos.trackPoints()
,它可以同时向同一轨道上的所有扇区添加点。circos.trackPoints()
的输入必须包含一个分类因子向量、一个 x 值向量和一个 y 值向量。X 值和 y 值被分类变量分割,x 和 y 值的相应子集数据在内部发送给 circos.points() 。默认情况下,circos.trackPoints() 将点添加到当前轨道中,这是最近创建的轨道。其他轨道也可以通过明确设置 track.index
。
circos.track(...)
circos.trackPoints(sectors, x, y)
circos.trackPoints()是通过 for 循环的 circos.points()实现的。但是,更推荐直接使用 circos.points()和 panel.fun
,这提供了更大的灵活性。下面的代码实际上与上面的代码相同。
circos.track(sectors, x, y, panel.fun = function(x, y) {
circos.points(x, y)
})
其他低级函数也有相应的 circos.track*() 函数。它的用法与 circos.trackPoints()相同。
3、线
通过 circos.lines()
添加行类似于 lines()
函数。另外一个特性是,可以通过将 area 参数指定为 TRUE 来填充行下面或上面的区域。基线(baseline)的位置可以设置为预定义字符串 bottom 或 top,或 y 轴上的位置的数值向量。当 area 设置为 TRUE 时,col 控制填充颜色,border 控制边框颜色。
当 lty 设置为’h’时,baseline 基线参数也可以设置,此时 col 参数向量的长度应该 x 相等。
以下是相关参数设置的样式:

直线的转换:

用法示例:
circos.lines(x, y)
circos.lines(x, y, sector.index, track.index)
circos.lines(x, y, col, lwd, lty, type, straight)
circos.lines(x, y, col, area, baseline, border)
4、线段
线段可以通过 circos.segments()
函数添加。其用法类似于 segments()
。可以通过直接设置为 straight 为 TRUE 来添加径向线段:
circos.segments(x0, y0, x1, y1)
circos.segments(x0, y0, x1, y1, straight)
circos.initialize(letters[1:8], xlim = c(0, 1))
circos.track(ylim = c(0, 1), track.height = 0.3, panel.fun = function(x, y) {
x = seq(0.2, 0.8, by = 0.2)
y = seq(0.2, 0.8, by = 0.2)
circos.segments(x, 0.1, x, 0.9)
circos.segments(0.1, y, 0.9, y)
})
circos.clear()

5、文本
通过 circos.text()添加文本类似于 text()函数。当把文字放在图上时,文字的朝向是非常重要的。text()支持七个面向选项:inside
, outside
, clockwise
, reverse.clockwise
, downward
, bending.inside
和 bending.outside
。bending.inside 和 bending.outside 只能添加单行文字,如果想添加多行,则使用 circos.text()
分别添加:

circos.text()
用法:
circos.text(x, y, labels)
circos.text(x, y, labels, sector.index, track.index)
circos.text(x, y, labels, facing, niceFacing, adj, cex, col, font)
为了使文本更容易阅读,circos.text()提供了 niceFacing 选项,根据他们在圆圈中的位置自动调整文本的朝向。niceFacing 只适用于inside
, outside
, clockwise
, reverse.clockwise
, bending.inside
和 bending.outside
。
打开 niceFacing 时,adj 也会根据相应的 facing 进行调整:


adj 参数可以水平和竖直地调整文字的位置,也可以通过角度的旋转进行偏移调整:
circos.text(x, y, labels, adj = c(0, degree(5)), facing = "clockwise")
circos.text(x + mm_x(2), y + mm_y(2), labels)
6、矩形和多边形
使用示例:
circos.rect(xleft, ybottom, xright, ytop)
circos.rect(xleft, ybottom, xright, ytop, sector.index, track.index)
circos.rect(xleft, ybottom, xright, ytop, col, border, lty, lwd)
circos.polygon(x, y)
circos.polygon(x, y, col, border, lty, lwd)

7、坐标轴
通常,我们只在圆上画 x 轴。circos.axis()
或 circos.xaxis()
提供了自定义在圆形方向上的 x 轴的选项。它支持 axis()等基本功能,比如定义断点和相应的标签。除此之外,该函数还支持将 x 轴放在 y 方向上的指定位置,将 x 轴对准圆心或外,并自定义轴刻度。可以将 at 和 labels 参数设置为一个长向量,使超过相应单元格中的最大值的部分自动删除,标签文本的外观可以通过 labels.niceFacing
优化,默认为 TRUE。

-
a: 主要自动计算刻度,其他设置为默认值。 -
b: 刻度是指向圆圈内的,刻度标签的面是指向圆圈外的。 -
c: x 轴位置在单元格的底部。 -
d: 刻度指向圆圈的内侧,刻度标签朝向逆时针方向。 -
e: 手动设置主要刻度,设置 x 轴位置。 -
f: 将数字标签替换为字符,没有小刻度。 -
g: 没有刻度,刻度标签朝向逆时针方向。 -
h: 两个主要刻度之间的次要刻度设置为 2,刻度的长度更长,刻度标签朝向顺时针方向。
示例:
circos.axis(h)
circos.axis(h, sector.index, track.index)
circos.axis(h, major.at, labels, major.tick, direction)
circos.axis(h, major.at, labels, major.tick, labels.font, labels.cex,
labels.facing, labels.niceFacing)
circos.axis(h, major.at, labels, major.tick, minor.ticks,
major.tick.length, lwd)
Y 轴也由 circos.yaxis()
支持。用法与 circos.axis()
需要注意的一件事是用户需要手动在 circos.par()
里调整 gap.degree/gap.after 以确保 y-axes 有足够的空间。
circos.yaxis(side) # break values are automatically calculated
circos.yaxis(side, at, labels, sector.index, track.index)

8、条形图、箱型图和小提琴图
绘制柱形图和堆叠柱形图:
par(mfrow = c(1, 2))
circos.initialize(letters[1:4], xlim = c(0, 10))
circos.track(ylim = c(0, 1), panel.fun = function(x, y) {
value = runif(10)
circos.barplot(value, 1:10 - 0.5, col = 1:10)
})
circos.track(ylim = c(-1, 1), panel.fun = function(x, y) {
value = runif(10, min = -1, max = 1)
circos.barplot(value, 1:10 - 0.5, col = ifelse(value > 0, 2, 3))
})
circos.clear()
# 堆叠柱形图
circos.initialize(letters[1:4], xlim = c(0, 10))
circos.track(ylim = c(0, 4), panel.fun = function(x, y) {
value = matrix(runif(10*4), ncol = 4)
circos.barplot(value, 1:10 - 0.5, col = 2:5)
})
circos.clear()

箱线图可以依次绘制(每个箱线图一个对应的向量)也可以一起绘制(list 或 matrix):
# 依次绘制
par(mfrow = c(1, 2))
circos.initialize(letters[1:4], xlim = c(0, 10))
circos.track(ylim = c(0, 1), panel.fun = function(x, y) {
for(pos in seq(0.5, 9.5, by = 1)) {
value = runif(10)
circos.boxplot(value, pos)
}
})
circos.clear()
# 同时绘制
circos.initialize(letters[1:4], xlim = c(0, 10))
circos.track(ylim = c(0, 1), panel.fun = function(x, y) {
value = replicate(runif(10), n = 10, simplify = FALSE)
circos.boxplot(value, 1:10 - 0.5, col = 1:10)
})
circos.clear()

小提琴图:
par(mfrow = c(1, 2))
circos.initialize(letters[1:4], xlim = c(0, 10))
circos.track(ylim = c(0, 1), panel.fun = function(x, y) {
for(pos in seq(0.5, 9.5, by = 1)) {
value = runif(10)
circos.violin(value, pos)
}
})
circos.clear()
circos.initialize(letters[1:4], xlim = c(0, 10))
circos.track(ylim = c(0, 1), panel.fun = function(x, y) {
value = replicate(runif(10), n = 10, simplify = FALSE)
circos.violin(value, 1:10 - 0.5, col = 1:10)
})
circos.clear()

9、环形箭头
circos.arrow()
绘制与圆形平行的圆形箭头。由于箭头始终平行于圆,所以在 x 方向上需要定义箭头的起始位置和结束位置,在 y 方向上只需要定义箭头中心的位置。
width
控制箭头的宽度,由 x2 – x1 决定,arrow.head.width
和 arrow.head.length
控制箭头的大小,tail
控制箭头尾巴的形状。width, arrow.head.width and arrow.head.length 可以由 mm_x(), mm_y()设置。如果用户想在相反的方向绘制箭头,设置 arrow.position
参数为 start。
par(mfrow = c(1, 2))
circos.initialize(letters[1:4], xlim = c(0, 1))
col = rand_color(4)
tail = c("point", "normal", "point", "normal")
circos.track(ylim = c(0, 1), panel.fun = function(x, y) {
circos.arrow(x1 = 0, x2 = 1, y = 0.5, width = 0.4,
arrow.head.width = 0.6, arrow.head.length = cm_x(1),
col = col[CELL_META$sector.numeric.index],
tail = tail[CELL_META$sector.numeric.index])
}, bg.border = NA, track.height = 0.4)
circos.clear()
circos.initialize(letters[1:4], xlim = c(0, 1))
tail = c("point", "normal", "point", "normal")
circos.track(ylim = c(0, 1), panel.fun = function(x, y) {
circos.arrow(x1 = 0, x2 = 1, y = 0.5, width = 0.4,
arrow.head.width = 0.6, arrow.head.length = cm_x(1),
col = col[CELL_META$sector.numeric.index],
tail = tail[CELL_META$sector.numeric.index],
arrow.position = "start")
}, bg.border = NA, track.height = 0.4)
circos.clear()

圆形箭头也可以用来显示圆形基因组中的基因,箭头代表基因的方向,如线粒体基因组或质粒基因组:
cell_cycle = data.frame(phase = factor(c("G1", "S", "G2", "M"), levels = c("G1", "S", "G2", "M")),
hour = c(11, 8, 4, 1))
color = c("#66C2A5", "#FC8D62", "#8DA0CB", "#E78AC3")
circos.par(start.degree = 90)
circos.initialize(cell_cycle$phase, xlim = cbind(rep(0, 4), cell_cycle$hour))
circos.track(ylim = c(0, 1), panel.fun = function(x, y) {
circos.arrow(CELL_META$xlim[1], CELL_META$xlim[2],
arrow.head.width = CELL_META$yrange*0.8, arrow.head.length = cm_x(0.5),
col = color[CELL_META$sector.numeric.index])
circos.text(CELL_META$xcenter, CELL_META$ycenter, CELL_META$sector.index,
facing = "downward")
circos.axis(h = 1, major.at = seq(0, round(CELL_META$xlim[2])), minor.ticks = 1,
labels.cex = 0.6)
}, bg.border = NA, track.height = 0.3)
circos.clear()

10、连接
连接或带状连接是圆形可视化的重要组成部分。它们用于表示位置之间的相互关系。在 circlize 中,circos.link()绘制单点和间隔之间的连接。至少需个必须参数,两个扇区索引和两个对应需要连接的位置。
使用示例:
# 两个单点点连接
circos.link(sector.index1, 0, sector.index2, 0)
# 间隔区和一个单点连接
circos.link(sector.index1, c(0, 1), sector.index2, 0)
# 两个间隔区的连接
circos.link(sector.index1, c(0, 1), sector.index2, c(1, 2))
# 其它参数
circos.link(sector.index1, c(0, 1), sector.index2, 0, col, lwd, lty, border)

h
控制连接的高度,在某些极端的条件下,如两个需要连接的位置靠的太近,带状连接就会出现一些问题,这时可以调整 h 参数来合理显示:
circos.link(sector.index1, 0, sector.index2, 0, h)
circos.link(sector.index1, 0, sector.index2, 0, h, h2)

当连接数量过多时,可以使用 h.ratio
参数一起调整:

通过 w
、w2
控制连接的形状:
circos.link(sector.index1, 0, sector.index2, 0, w)
circos.link(sector.index1, 0, sector.index2, 0, w, w2)

连接可以用箭头表示方向。direction
参数控制如何添加箭头。0 表示没有方向,1 表示从端 1 到端 2,-1 表示从端 2 到端 1,2 表示双向。如果连接表示为带状,则会在连接的中心添加一条带箭头的线来表示方向。
circos.link(sector.index1, 0, sector.index2, 0, directional = 1)
circos.link(sector.index1, c(0, 1), sector.index2, c(0, 1), directional = -1)

11、突出扇区和轨道
draw.sector()
绘制扇区、环或其它部分。如果你想突出显示环图的某些部分,此函数非常有用。它需要圆心的位置参数(默认为 c(0,0)),扇区的起始角度和结束角度,默认是顺时针方向,以及两条边(或一条边)的半径,它们是上边界或下边界。
参数示例:
draw.sector(start.degree, end.degree, rou1)
draw.sector(start.degree, end.degree, rou1, rou2, center)
draw.sector(start.degree, end.degree, rou1, rou2, center, col, border, lwd, lty)
par(mar = c(1, 1, 1, 1))
plot(c(-1, 1), c(-1, 1), type = "n", axes = FALSE, ann = FALSE, asp = 1)
draw.sector(20, 0)
draw.sector(30, 60, rou1 = 0.8, rou2 = 0.5, clock.wise = FALSE, col = "#FF000080")
draw.sector(350, 1000, col = "#00FF0080", border = NA)
draw.sector(0, 180, rou1 = 0.25, center = c(-0.5, 0.5), border = 2, lwd = 2, lty = 2)
draw.sector(0, 360, rou1 = 0.7, rou2 = 0.6, col = "#0000FF80")

我们还可以使用 get.cell.meta.data()
来获取单元格的位置信息。例如,起始角度和结束角度可以通过 cell.start.degree
和 cell.end.degree
得到,上边框和下边框的位置可以通过 cell.top.radius
和 cell.bottom.radius
得到。下面的代码显示了几个突出显示扇区和轨道的示例:
sectors = letters[1:8]
circos.initialize(sectors, xlim = c(0, 1))
for(i in 1:3) {
circos.track(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 = get.cell.meta.data("cell.top.radius", track.index = 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"),
rou1 = get.cell.meta.data("cell.top.radius", track.index = 2),
rou2 = get.cell.meta.data("cell.bottom.radius", track.index = 3),
col = "#0000FF40")
如果我们想突出显示特定区域,比如单元格 h:2 中的一个小区域,我们可以使用 circle()来计算极坐标中的位置。但是要记住,单元格中的 x 轴总是顺时钟的:
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()
,只需要为要突出显示的扇区和轨道指定索引。高亮显示区域的填充可以通过 padding 参数设置,padding 参数应该包含四个值,表示高亮显示区域的宽或高的比率。
highlight.sector()
的一个优点是它支持在突出显示的区域中添加文本。默认情况下,文本绘制在高亮区域的中心。可以通过 text.vjust
设置在纵向上的距离,可以是字符串或者数值:”2 inches” 或 “-1.2cm”。
sectors = letters[1:8]
circos.initialize(sectors, xlim = c(0, 1))
for(i in 1:4) {
circos.track(ylim = c(0, 1))
}
circos.info(plot = TRUE)
highlight.sector(c("a", "h"), track.index = 1, text = "a and h belong to a same group",
facing = "bending.inside", niceFacing = TRUE, text.vjust = "6mm", cex = 0.8)
highlight.sector("c", col = "#00FF0040")
highlight.sector("d", col = NA, border = "red", lwd = 2)
highlight.sector("e", col = "#0000FF40", track.index = c(2, 3))
highlight.sector(c("f", "g"), col = NA, border = "green",
lwd = 2, track.index = c(2, 3), padding = c(0.1, 0.1, 0.1, 0.1))
highlight.sector(sectors, col = "#FFFF0040", track.index = 4)
circos.clear()

12、和基础图形系统联用
sectors = letters[1:4]
circos.initialize(sectors, xlim = c(0, 1))
circos.track(ylim = c(0, 1), panel.fun = function(x, y) {
circos.points(1:20/20, 1:20/20)
})
text(0, 0, "This isnthe center", cex = 1.5)
legend("bottomleft", pch = 1, legend = "This is the legend")
title("This is the title")
circos.clear()

欢迎小伙伴留言评论!
今天的分享就到这里了,敬请期待下一篇!
最后欢迎大家分享转发,您的点赞是对我的鼓励和肯定!
如果觉得对您帮助很大,打赏一下吧!
请关注“恒诺新知”微信公众号,感谢“R语言“,”数据那些事儿“,”老俊俊的生信笔记“,”冷🈚️思“,“珞珈R”,“生信星球”的支持!