查看原文
其他

circlize 之 Circular layout

JunJunLab 老俊俊的生信笔记 2022-08-15

circlize 之 Circular layout

1、坐标转换

circlize 绘图包含了三步坐标转换,第一步是将 x 和 y 对应的值转换为正常的坐标体系,第二步转换为极坐标体系,最后一步绘制到 2x2 的画布上。需要注意的是,圆形图总是绘制在半径为 1 的圆内。

2、绘制圆形图规则

绘图基本流程很简单,主要包括:

  • 布局初始化
  • 创建轨道
  • 添加图形
  • 创建轨道
  • 添加图形
  • ...
  • 一直到绘图结束,清空画板

下面来具体说明流程:

1、circos.initialize() 函数用来初始化画板,输入数据至少包含 1 个分类变量。

2、创建轨道,添加图形。有三种方法给扇形区域添加图形。

  • A. 创建轨道后,用 circos.points()circos.lines(), … 等低级函数依次给每个单元格添加图形,你需要用 for 循环手动给每个分类变量添加。
circos.initialize(sectors, xlim)
circos.track(ylim)
for(sector.index in all.sector.index) {
    circos.points(x1, y1, sector.index)
    circos.lines(x2, y2, sector.index)
}
  • B. 使用 circos.trackPoints()circos.trackLines(),等函数给所有单元格同时添加图形。
circos.initialize(sectors, xlim)
circos.track(ylim)
circos.trackPoints(sectors, x, y)
circos.trackLines(sectors, x, y)
  • C. 使用 circos.track()函数在里面添加 panel.fun 参数,在创建单元格的同时马上添加图形。panel.fun 需要 x 和 y 两个参数,这两个参数代表当前的单元格的 x、y。
circos.initialize(sectors, xlim)
circos.track(sectors, all_x, all_y, ylim,
    panel.fun = function(x, y) {
        circos.points(x, y)
        circos.lines(x, y)
})

3、重复 2 的步骤来添加更多的轨道和图形。

4、使用 circos.clear()清空画板。

3、扇区和轨道

环形图由扇区和轨道组成。红色圆圈是一个轨道,蓝色代表一个扇区。扇形和轨迹的交点称为单元格,它可以被认为是数据点的假想绘图区域。我们将介绍如何在单元格的 x 和 y 方向上设置数据范围。

数据范围也可以通过 xlim 参数直接指定。xilm 的有效值是一个两列矩阵,其行数与 xlim 中的每一行对应一个扇区的行数相同。如果 xlim 的行名已经包含扇区名,则 xlim 的行顺序将自动调整。如果 xlim 是长度为 2 的向量,那么所有扇区都有相同的 x 范围。

circos.initialize(sectors, x = x)
circos.initialize(sectors, xlim = xlim)

如果未指定扇区,则将 xlim 的行名作为扇区的值:

circos.initialize(xlim = xlim)

在布局初始化之后,可能看不到绘制任何内容,或者只打开一个空的图形设备。这是因为还没有创建轨道,然而,布局已经被内部记录了。

通过改变扇区的 levels 来改变顺序,默认按字母排序:

sectors = c("d""f""e""c""g""b""a")
s1 = factor(sectors)
circos.initialize(s1, xlim = c(01))
s2 = factor(sectors, levels = sectors)
circos.initialize(s2, xlim = c(01))

在不同的轨迹中,同一扇区中的单元格在 x 轴上是相同的数据范围。然后,对于每个轨道,我们只需要为单元格指定 y 方向(或径向)上的数据范围。与 circos.initialize()类似,circos.track()也接收 y 或 ylim 参数来指定 y 值的范围。由于同一轨道上的所有单元格具有同一个 y 范围,如果指定了 ylim,那么它只是长度为 2 的向量。X 也可以在 circos.track()中指定,但它只用于 panel.fun 参数里。

circos.track(sectors, y = y)
circos.track(sectors, ylim = c(01))
circos.track(sectors, x = x, y = y)

4、图形参数

一些基础参数可以通过 circos.par()函数设置:

参数说明
start.degree第一个扇区的角度,等于 90 时,表示从正上方开始.
gap.degree两个邻近扇区的距离,gap.after 和它一样.
track.margin轨道之间的空白距离,mm_h()/cm_h()/inches_h()函数设置.
cell.padding单元格填充,是绘图区域的空白区域,mm_h()/cm_h()/inches_h()设置.
unit.circle.segments控制曲线的分段数量.
track.height轨道高度,可通过 mm_h()/cm_h()/inches_h()设置.
points.overflow.warning绘图时数据如果超出范围会出现警告信息,设值为 TRUE 或 FALSE 打开或关闭。
canvas.xlim/canvas.ylim画布的坐标轴范围,默认时-1 到 1.
circle.margin图的边缘,代表左右下上方向,正值,c(x1, x2, y1, y2)就是 circos.par(canvas.xlim = c(-(1+x1), 1+x2), canvas.ylim = c(-(1+y1), 1+y2))
clock.wise扇区的方向,默认为 TRUE,顺时针方向
xaxis.clock.wise每个单元格的方向,默认顺时针方向

示例参数使用:

示例数值
start.degree0
gap.degree/gap.after1
track.marginc(0.01, 0.01)
cell.paddingc(0.02, 1.00, 0.02, 1.00)
unit.circle.segments500
track.height0.2
points.overflow.warningTRUE
canvas.xlimc(-1, 1)
canvas.ylimc(-1, 1)
circle.marginc(0, 0, 0, 0)
clock.wiseTRUE
xaxis.clock.wiseTRUE
# 设置
circos.par("start.degree" = 30)
# 用 $ 符设置
circos.par$start.degree = 30
# 重置
circos.par(RESET = TRUE)

5、更新绘图区域

更新和修改指定的单元格:

circos.update(sector.index, track.index)
circos.points(x, y, sector.index, track.index)

6、panel.fun

给 a 和 b 添加点:

sectors = c("a""a""a""b""b")
x = 1:5
y = 5:1
circos.track(sectors, x = x, y = y,
    panel.fun = function(x, y) {
        circos.points(x, y)
})

获取当前单元格的名字和扇区和轨道信息:

get.cell.meta.data(name)
get.cell.meta.data(name, sector.index, track.index)

其它参数:

  • sector.index: The name for the sector.
  • sector.numeric.index: Numeric index for the sector.
  • track.index: Numeric index for the track.
  • xlim: Minimal and maximal values on the x-axis.
  • ylim: Minimal and maximal values on the y-axis.
  • xcenter: mean of xlim.
  • ycenter: mean of ylim.
  • xrange: defined as xlim[2] - xlim[1].
  • yrange: defined as ylim[2] - ylim[1].
  • ...

在单元格中间区域添加单元格索引值:

circos.track(ylim = ylim, 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)
})

使用 CELL_META 替换简化代码:

circos.track(ylim = ylim, panel.fun = function(x, y) {
    circos.text(CELL_META$xcenter, CELL_META$ycenter,
        CELL_META$sector.index)
})

欢迎小伙伴留言评论!

今天的分享就到这里了,敬请期待下一篇!

最后欢迎大家分享转发,您的点赞是对我的鼓励肯定

如果觉得对您帮助很大,打赏一下吧!

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存