查看原文
其他

circlize 之 Advanced layout

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


circlize 之 Advanced layout

1、放大扇区

在本节中,我们将介绍如何缩放扇区,并将缩放扇区放在与原始扇区相同的轨道上。

在默认设置下,扇区宽度是根据相应类别中的数据范围计算的。通常,手动修改默认扇区宽度并不是一个好主意,因为它反映了数据的有用信息。然而,有时手动修改扇区的宽度可以制作更高级的图,例如缩放 zoomings。

我们所需要做的就是复制与放大扇区对应的数据,为它们分配新的类别名称,并将其添加到原始数据。

生成 6 个扇区:

set.seed(123)
df = data.frame(
    sectors = sample(letters[1:6], 400, replace = TRUE),
    x = rnorm(400),
    y = rnorm(400),
    stringsAsFactors = FALSE
)

我们想放大扇区 a 和扇区 b 中的前 10 个点。首先,我们提取这些数据并将其格式化为一个新的数据框:

zoom_df_a = df[df$sectors == "a", ]
zoom_df_b = df[df$sectors == "b", ]
zoom_df_b = zoom_df_b[order(zoom_df_b[, 2])[1:10], ]
zoom_df = rbind(zoom_df_a, zoom_df_b)

然后,我们需要更改放大数据框中的扇区名称。这里,我们只是简单地在原来的名称中添加 ‘zoom_’,以显示它们是缩放扇区。之后,它被添加到原始数据框上:

zoom_df$sectors = paste0("zoom_", zoom_df$sectors)
df2 = rbind(df, zoom_df)

在这个例子中,我们将把原始的单元格放在圆的左半部分,放大的扇区放在右边。正如我们前面已经提到的,我们只是分别标准化原来扇区的宽度和标准化缩放扇区的宽度。注意,原来的扇区的扇区宽度之和是 1,放大后的扇区的扇区宽度之和是 1,这意味着这两种扇区都有自己的半圆。

你可能会注意到整个扇区的总和宽度不等于 1,它们在内部会进一步标准化为 1,严格来说,由于没有考虑扇区之间的间隙,原始扇区的宽度并不是完全 180 度,但实际值与它相当接近:

xrange = tapply(df2$x, df2$sectors, function(x) max(x) - min(x))
normal_sector_index = unique(df$sectors)
zoomed_sector_index = unique(zoom_df$sectors)
sector.width = c(xrange[normal_sector_index] / sum(xrange[normal_sector_index]),
                 xrange[zoomed_sector_index] / sum(xrange[zoomed_sector_index]))
sector.width
##         c         f         b         e         d         a    zoom_a    zoom_b
## 0.1774352 0.1649639 0.1685275 0.1662047 0.1668505 0.1560182 0.7237996 0.2762004

绘图:

circos.par(start.degree = 90, points.overflow.warning = FALSE)
circos.initialize(df2$sectors, x = df2$x, sector.width = sector.width)
circos.track(df2$sectors, x = df2$x, y = df2$y,
    panel.fun = function(x, y) {
    circos.points(x, y, col = "red", pch = 16, cex = 0.5)
    circos.text(CELL_META$xcenter, CELL_META$cell.ylim[2] + mm_y(2),
        CELL_META$sector.index, niceFacing = TRUE)
})

添加连接线:

circos.link("a", get.cell.meta.data("cell.xlim", sector.index = "a"),
    "zoom_a", get.cell.meta.data("cell.xlim", sector.index = "zoom_a"),
    border = NA, col = "#00000020")
circos.link("b", c(zoom_df_b[12], zoom_df_b[102]),
    "zoom_b", get.cell.meta.data("cell.xlim", sector.index = "zoom_b"),
    rou1 = get.cell.meta.data("cell.top.radius", sector.index = "b"),
    border = NA, col = "#00000020")
circos.clear()

2、可视化部分环形区

circos.par()函数里的 canvas.xlimcanvas.ylim 参数对于可视化部分区域非常有用,正如在之前章节中提到的,环形图总是在画布上绘制,其中 x 值的范围是-1 到 1,y 值的范围是-1 到 1。因此,如果 canvas.xlim 和 canvas.ylim 都被设置为 c(0,1),这意味着画布被限制在右上方,然后只有 0 到 90 度之间的扇区是可见的。

我们只需要在布局中设置一个扇区 gap.after 为 270。(gap.after 270 度表示这个扇区的宽度正好是 90 度)

circos.par("canvas.xlim" = c(01), "canvas.ylim" = c(01),
    "start.degree" = 90"gap.after" = 270)
sectors = "a" # this is the name of your sector
circos.initialize(sectors = sectors, xlim = ...)
...

类似的想法可以应用到轨道中,在某些轨道中,只需要单元格的子集。通常有两种方法。第一种方法是创建轨道并添加仅对应于所需单元格的数据子集的图形。第二种方法是先创建一个空轨道,然后通过 circos.update()自定义单元格:

sectors = letters[1:4]
circos.initialize(sectors, xlim = c(01))

# directly specify the subset of data
df = data.frame(sectors = rep("a"100),
                x = runif(100),
                y = runif(100))
circos.track(df$sectors, x = df$x, y = df$y,
    panel.fun = function(x, y) {
        circos.points(x, y, pch = 16, cex = 0.5)
})

# create empty track first then fill graphics in the cell
circos.track(ylim = range(df$y), bg.border = NA)
circos.update(sector.index = "a", bg.border = "black")
circos.points(df$x, df$y, pch = 16, cex = 0.5)

circos.track(sectors = sectors, ylim = c(01))
circos.track(sectors = sectors, ylim = c(01))
circos.clear()

3、组合多个环形图

设置 par(new = TRUE)canvas.xlimcanvas.ylim 参数可以绘制多个图形:

sectors = letters[1:4]
circos.initialize(sectors, xlim = c(01))
circos.track(ylim = c(01), panel.fun = function(x, y) {
    circos.text(0.50.5"outer circos", niceFacing = TRUE)
})
circos.clear()

par(new = TRUE# <- magic
circos.par("canvas.xlim" = c(-22), "canvas.ylim" = c(-22))
sectors = letters[1:3]
circos.initialize(sectors, xlim = c(01))
circos.track(ylim = c(01), panel.fun = function(x, y) {
    circos.text(0.50.5"inner circos", niceFacing = TRUE)
})
circos.clear()

把四个拼到一起:

sectors = letters[1:4]
lim = c(11.11.21.3)
for(i in 1:4) {
    circos.par("canvas.xlim" = c(-lim[i], lim[i]),
        "canvas.ylim" = c(-lim[i], lim[i]),
        "track.height" = 0.4)
    circos.initialize(sectors, xlim = c(01))
    circos.track(ylim = c(01), bg.border = NA)
    circos.update(sector.index = sectors[i], bg.border = "black")
    circos.points(runif(10), runif(10), pch = 16)
    circos.clear()
    par(new = TRUE)
}
par(new = FALSE)

4、排列多个图形

Circlize 在基础 R 图形系统中实现,因此,您可以使用 layout()par("mfrow")/par("mfcol")来排列一个页面中的多个图:

layout(matrix(1:933))
for(i in 1:9) {
    sectors = 1:8
    par(mar = c(0.50.50.50.5))
    circos.par(cell.padding = c(0000))
    circos.initialize(sectors, xlim = c(01))
    circos.track(ylim = c(01), track.height = 0.05,
        bg.col = rand_color(8), bg.border = NA)
    for(i in 1:20) {
        se = sample(1:82)
        circos.link(se[1], runif(2), se[2], runif(2),
            col = rand_color(1, transparency = 0.4), border = NA)
    }
    circos.clear()
}





发现更多精彩

关注公众号

欢迎小伙伴留言评论!

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

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

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


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

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