查看原文
其他

circlize 之 chordDiagram 函数

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



点击上方关注我们




我们接着介绍 circlize 包的和弦图函数 chordDiagram(),我们知道和弦图经常用来展示多个数据之间的相互关系,用 线 或者 带状线 来连接。

1、输入数据


有两种表示相互关系的数据格式,要么是邻近矩阵,要么是邻近列表。在 邻近矩阵 中,第 i 行和第 j 列的值表示第 i 行对象和第 j 列对象之间的关系,其中绝对值表示关系的强度。在 邻近列表 中,关系表示为一个三列的数据框,其中相互关系来自 第一列和第二列第三列 表示关系的强度。

创建一个邻近矩阵:

mat = matrix(1:93)
rownames(mat) = letters[1:3]
colnames(mat) = LETTERS[1:3]
mat
##   A B C
## a 1 4 7
## b 2 5 8
## c 3 6 9

创建一个邻近列表:

df = data.frame(from = letters[1:3], to = LETTERS[1:3], value = 1:3)
df
##   from to value
## 1    a  A     1
## 2    b  B     2
## 3    c  C     3

实际上我们可以使用 reshape2 包中的 melt 函数和 dcast 函数来转换和两种数据类型。

chordDiagram()函数,它同时支持邻近矩阵和邻近列表。对于不同的输入格式,对应的图形参数格式也会不同。

2、和弦图基本用法


创建一个邻近矩阵:

set.seed(999)
mat = matrix(sample(1818), 36)
rownames(mat) = paste0("S"1:3)
colnames(mat) = paste0("E"1:6)
mat
##    E1 E2 E3 E4 E5 E6
## S1  4 14 13 17  5  2
## S2  7  1  6  8 12 15
## S3  9 10  3 16 11 18

创建一个邻近列表:

df = data.frame(from = rep(rownames(mat), times = ncol(mat)),
    to = rep(colnames(mat), each = nrow(mat)),
    value = as.vector(mat),
    stringsAsFactors = FALSE)
df
##    from to value
## 1    S1 E1     4
## 2    S2 E1     7
## 3    S3 E1     9
## 4    S1 E2    14
## 5    S2 E2     1
## 6    S3 E2    10
## 7    S1 E3    13
## 8    S2 E3     6
## 9    S3 E3     3
## 10   S1 E4    17
## 11   S2 E4     8
## 12   S3 E4    16
## 13   S1 E5     5
## 14   S2 E5    12
## 15   S3 E5    11
## 16   S1 E6     2
## 17   S2 E6    15
## 18   S3 E6    18

默认画图:

chordDiagram(mat)
circos.clear()

用数据框画图,结果和上图一致:

chordDiagram(df)
circos.clear()

默认的和弦图由轨道标签带坐标轴的网格轨道(或者可以称之为线、矩形)和连接组成。矩阵中的 相对应的扇区 圆的下半部分 。如果输入是数据框,扇区的顺序是 union(rownames(mat), colnames(mat))union(df[[1]], df[[2]])的顺序。扇区的顺序可以由 order 参数控制(图左)。当然,order 向量的长度应该与扇区的个数相同。

改变顺序:

par(mfrow = c(12))
chordDiagram(mat, order = c("S2""S1""S3""E4""E1""E5""E2""E6""E3"))
circos.clear()

chordDiagram(mat, order = c("S2""S1""E4""E1""S3""E5""E2""E6""E3"))
circos.clear()

默认扇区的颜色对应行,连接的颜色随机产生,透明度为 50% 。

3、使用 circos.par()函数调整


可以使用 circos.par(gap.after = ...) 调整每个扇区之间的宽度:

circos.par(gap.after = c(rep(5, nrow(mat)-1), 15, rep(5, ncol(mat)-1), 15))
chordDiagram(mat)
circos.clear()

# 或者输入是数据框
circos.par(gap.after = c(rep(5, length(unique(df[[1]]))-1), 15,
                         rep(5, length(unique(df[[2]]))-1), 15))
chordDiagram(df)
circos.clear()

也可以用扇区名称设置间距:

circos.par(gap.after = c("S1" = 5"S2" = 5"S3" = 15"E1" = 5"E2" = 5,
                         "E3" = 5"E4" = 5"E5" = 5"E6" = 15))
chordDiagram(mat)
circos.clear()

为了简化,用户可以直接设置big.gap 参数。big.gap 对应于行扇区和列扇区之间的间隙(或者输入中数据框的第一列扇区和第二列扇区)。gap.after 被传给 circos.par() ,在内部产生合适的间隔。注意,只有当行扇区和列扇区之间没有重叠时,或者换句话说,矩阵中的行和列,或者数据框中的第一列和第二列代表 两个不同的组 时,它才会起作用。

chordDiagram(mat, big.gap = 30)
circos.clear()

设置 circos.par(clock.wise = FALSE)改变起始扇区的角度会使连接过度缠在一起,而 chordDiagram()会根据扇区的布置自动优化连接的位置:

par(mfrow = c(12))
circos.par(start.degree = 85, clock.wise = FALSE)
chordDiagram(mat)
circos.clear()

circos.par(start.degree = 85)
chordDiagram(mat, order = c(rev(colnames(mat)), rev(rownames(mat))))
circos.clear()

4、设置扇区网格颜色


网格用不同的颜色来表示不同的扇区。一般来说,扇区分为两类,一个是 矩阵的行数据框的第一列 ,另一个是 矩阵的列数据框的第二列 。因此,连接两组中的对象时,默认情况下,连接颜色与 第一类 中对应扇区的颜色相同:

grid.col = c(S1 = "red", S2 = "green", S3 = "blue",
    E1 = "grey", E2 = "grey", E3 = "grey", E4 = "grey", E5 = "grey", E6 = "grey")
chordDiagram(mat, grid.col = grid.col)
chordDiagram(t(mat), grid.col = grid.col)

5、设置连接线的颜色


链接颜色的透明度可以通过 transparency 参数设置。取值范围为 0 ~ 1,0 表示不透明,1 表示完全透明。默认透明度为 0.5。

chordDiagram(mat, grid.col = grid.col, transparency = 0)

对于邻近矩阵,可以通过提供一个 颜色矩阵 来定制连接的颜色。在下面的例子中,我们使用 rand_color() 来生成一个随机颜色矩阵。注意,因为 col_mat已经包含了透明度,如果设置了透明度,它将被忽略。

col_mat = rand_color(length(mat), transparency = 0.5)
dim(col_mat) = dim(mat)  # to make sure it is a matrix
chordDiagram(mat, grid.col = grid.col, col = col_mat)

而对于邻近列表,连接的颜色可以自定义为向量:

col = rand_color(nrow(df))
chordDiagram(df, grid.col = grid.col, col = col)

当关系的强度(如相关性)表示为连续值时,col 也可以指定为自定义的颜色映射函数。chordDiagram() 接受由 colorRamp2() 生成的颜色映射:

col_fun = colorRamp2(range(mat), c("#FFEEEE""#FF0000"), transparency = 0.5)
chordDiagram(mat, grid.col = grid.col, col = col_fun)

颜色映射函数也适用于邻近列表,但它将应用于数据框中的第三列,因此需要确保第三列具有恰当的值:

chordDiagram(df, grid.col = grid.col, col = col_fun)
# or
chordDiagram(df, grid.col = grid.col, col = col_fun(df[, 3]))

当输入是矩阵时,有时不需要生成整个颜色矩阵。只需要提供对应于行或列的颜色,以便使来自同一行/列的连接将具有相同的颜色。这里说明颜色的值可以设置为 数字颜色名称十六进制代码 ,与基础 R 图形相同。

chordDiagram(mat, grid.col = grid.col, row.col = 1:3)
chordDiagram(mat, grid.col = grid.col, column.col = 1:6)

row.colcolumn.col 参数是专门为 矩阵 设计的。邻近列表没有类似的参数设置。

再次强调,连接的透明度可以包括在 colrow.colcolumn.col 里,如果这里已经设置了透明度,则透明性参数将被忽略。

6、连接边框


link.lwdlink.ltylink.border 控制连接 边框的线宽线样式颜色 。如果输入是邻近矩阵,这三个参数可以设置为单个标量,也可以设置为一个矩阵。

设置为单个标量:

chordDiagram(mat, grid.col = grid.col, link.lwd = 2, link.lty = 2, link.border = "red")

如果它被设置为一个矩阵,它应该与 mat 有相同的维度:

lwd_mat = matrix(1, nrow = nrow(mat), ncol = ncol(mat))
lwd_mat[mat > 12] = 2
border_mat = matrix(NA, nrow = nrow(mat), ncol = ncol(mat))
border_mat[mat > 12] = "red"
chordDiagram(mat, grid.col = grid.col, link.lwd = lwd_mat, link.border = border_mat)

矩阵也可以不需要有相同的维度。它也可以是一个子矩阵。对于矩阵中没有指定相应值的行或列,将设置为默认值。它必须具有行名和列名,以便能够将设置映射到正确的连接:

border_mat2 = matrix("black", nrow = 1, ncol = ncol(mat))
rownames(border_mat2) = rownames(mat)[2]
colnames(border_mat2) = colnames(mat)
chordDiagram(mat, grid.col = grid.col, link.lwd = 2, link.border = border_mat2)

为了方便,可以将图形参数设置为三列数据框,其中前两列对应矩阵中的行名和列名,第三列对应图形参数:

lty_df = data.frame(c("S1""S2""S3"), c("E5""E6""E4"), c(123))
lwd_df = data.frame(c("S1""S2""S3"), c("E5""E6""E4"), c(222))
border_df = data.frame(c("S1""S2""S3"), c("E5""E6""E4"), c(111))
chordDiagram(mat, grid.col = grid.col, link.lty = lty_df, link.lwd = lwd_df,
    link.border = border_df)

如果输入是数据框,则要简单得多,只需要将图形参数设置为向量:

chordDiagram(df, grid.col = grid.col, link.lty = sample(1:3, nrow(df), replace = TRUE),
    link.lwd = runif(nrow(df))*2, link.border = sample(0:1, nrow(df), replace = TRUE))

7、高亮连接


有两种方法可以突出显示连接,一种是对不同的连接设置 不同的透明度 ,另一种是只 画需要突出显示的连接 。基于这个规则和给连接分配颜色的方法,我们可以通过按行分配不同透明度的颜色来突出显示来自同一扇区的连接:

chordDiagram(mat, grid.col = grid.col, row.col = c("#FF000080""#00FF0010""#0000FF10"))

我们还可以设置突出显示大于阈值的连接。至少有三种方法可以做到这一点。首先,构建一个颜色矩阵,并将连接的小于阈值的设置为完全透明:

col_mat[mat < 12] = "#00000000"
chordDiagram(mat, grid.col = grid.col, col = col_mat)

下面的代码演示了如何使用颜色映射函数将值映射到不同的透明度。注意,这对于邻近列表也是可行的:

col_fun = function(x) ifelse(x < 12"#00000000""#FF000080")
chordDiagram(mat, grid.col = grid.col, col = col_fun)

对于颜色矩阵和颜色映射函数,实际上所有的连接都被绘制出来了,你看不到其中一些的原因是它们被是完全透明的。如果一个三列数据框被用来给感兴趣的连接指定颜色,没有在 col_df 中定义的连接将不会被绘制:

col_df = data.frame(c("S1""S2""S3"), c("E5""E6""E4"),
    c("#FF000080""#00FF0080""#0000FF80"))
chordDiagram(mat, grid.col = grid.col, col = col_df)

高亮连接对于邻近列表来说是相对简单的,你只需要根据你想要高亮的连接构造一个颜色向量:

col = rand_color(nrow(df))
col[df[[3]] < 10] = "#00000000"
chordDiagram(df, grid.col = grid.col, col = col)

一些图形格式不支持透明度,如 GIF 格式。这里是另一个参数 link.visible 是最近推出的,它可以提供一个简单的方法来控制连接的可见性。可以设置为邻近矩阵的 逻辑矩阵 ,也可以设置为邻近列表的逻辑向量

col = rand_color(nrow(df))
chordDiagram(df, grid.col = grid.col, link.visible = df[[3]] >= 10)

8、连接的顺序


每个连接的顺序会自动调整,使他们看起来不错。但有时根据扇区的宽度对连接进行排序对于查看潜在的特征是有用的。link.sortlink.decreasing 可以设控制在扇区上连接的顺序:

chordDiagram(mat, grid.col = grid.col, link.sort = TRUE, link.decreasing = TRUE)
title("link.sort = TRUE, link.decreasing = TRUE", cex = 0.6)
chordDiagram(mat, grid.col = grid.col, link.sort = TRUE, link.decreasing = FALSE)
title("link.sort = TRUE, link.decreasing = FALSE", cex = 0.6)

9、添加连接的顺序


向绘图添加连接的默认顺序是基于它们在矩阵或数据框中的顺序。通常,透明度应该设置为连接的颜色,这样它们就不会相互重叠。在大多数情况下,这看起来很好,但有时,在图中把宽的连接放在前面,把小的连接放在后面,会提高可视性。这可以通过参数 link.zindex 设置。link.zindex 它定义了在一个连接之上添加连接的顺序。值越大,表示添加对应的连接越往后:

chordDiagram(mat, grid.col = grid.col, transparency = 0)
chordDiagram(mat, grid.col = grid.col, transparency = 0, link.zindex = rank(mat))

对应数据框的代码:

chordDiagram(df, grid.col = grid.col, transparency = 0, link.zindex = rank(df[[3]]))

10、自连接


如何设置自连接取决于是否需要复制信息。对于这两种不同的场景,self.link 参数可以设置为 1 或 2:

df2 = data.frame(start = c("a""b""c""a"), end = c("a""a""b""c"))
chordDiagram(df2, grid.col = 1:3, self.link = 1)
title("self.link = 1")
chordDiagram(df2, grid.col = 1:3, self.link = 2)
title("self.link = 2")

11、对称矩阵


当矩阵对称时,通过设置 symmetric = TRUE ,只使用不带对角线的下三角矩阵:

mat3 = matrix(rnorm(25), 5)
colnames(mat3) = letters[1:5]
cor_mat = cor(mat3)
col_fun = colorRamp2(c(-101), c("green""white""red"))
chordDiagram(cor_mat, grid.col = 1:5, symmetric = TRUE, col = col_fun)
title("symmetric = TRUE")
chordDiagram(cor_mat, grid.col = 1:5, col = col_fun)
title("symmetric = FALSE")

12、方向关系


在某些情况下,当输入是一个矩阵时,行和列表示方向,或者当输入是一个数据框时,第一列和第二列表示方向。在图中参数 directional 是用来说明这种方向。directional1 时表示从行到列(邻近列表从第一列到第二列),为 -1 时表示从列到行(邻近列表从第二列到第一列),值为 2 表示双向:

默认情况下,连接的两端高度不等来表示方向。连接的起始端位置比另一端短,给用户一种连接正在向外移动的感觉。如果这不是你的想要的感觉,您可以将 diffHeight 设置为负值:

par(mfrow = c(13))
chordDiagram(mat, grid.col = grid.col, directional = 1)
chordDiagram(mat, grid.col = grid.col, directional = 1, diffHeight = mm_h(5))
chordDiagram(mat, grid.col = grid.col, directional = -1)

mat 中的行名和列名也可以重叠。在这种情况下,显示连接的方向对于区分它们很重要:

mat2 = matrix(sample(10035), nrow = 5)
rownames(mat2) = letters[1:5]
colnames(mat2) = letters[1:7]
mat2
##    a  b  c  d  e  f  g
## a 42 44 90 35 58 66 36
## b  8 98 57  9 86 55 93
## c 24 38 23 60 67 50 96
## d 19 17 95  7 51 18 82
## e 52 49 47 88 74 92 31

chordDiagram(mat2, grid.col = 1:7, directional = 1, row.col = 1:5)

如果不需要连接连接两端在同一扇区的自连接,则在矩阵中设置对应值为 0 即可:

mat3 = mat2
for(cn in intersect(rownames(mat3), colnames(mat3))) {
    mat3[cn, cn] = 0
}
mat3
##    a  b  c  d  e  f  g
## a  0 44 90 35 58 66 36
## b  8  0 57  9 86 55 93
## c 24 38  0 60 67 50 96
## d 19 17 95  0 51 18 82
## e 52 49 47 88  0 92 31

chordDiagram(mat3, grid.col = 1:7, directional = 1, row.col = 1:5)

连接可以用箭头表示方向。当 direction.type 设置为 arrows,箭头被添加到连接的中心。与用于连接的其他图形参数类似,用于绘制箭头(如箭头颜色和线类型)的参数可以是标量、矩阵或三列数据框。

如果 link.arr.col 被设置为数据框,那么只有在数据框中指定的连接才会有箭头。请注意,这是绘制箭头给连接子集的唯一方法:

arr.col = data.frame(c("S1""S2""S3"), c("E5""E6""E4"),
    c("black""black""black"))
chordDiagram(mat, grid.col = grid.col, directional = 1, direction.type = "arrows",
    link.arr.col = arr.col, link.arr.length = 0.2)

如果结合 arrowsdiffHeight,它会给你更好的可视化效果:

arr.col = data.frame(c("S1""S2""S3"), c("E5""E6""E4"),
    c("black""black""black"))
chordDiagram(mat, grid.col = grid.col, directional = 1,
    direction.type = c("diffHeight""arrows"),
    link.arr.col = arr.col, link.arr.length = 0.2)

还有另一种类型的箭头 big.arrow ,这是较好可视化效果对于有太多的连接时:

matx = matrix(rnorm(64), 8)
chordDiagram(matx, directional = 1, direction.type = c("diffHeight""arrows"),
    link.arr.type = "big.arrow")

如果 diffHeight 设置为负值,则开始端比其他端长:

chordDiagram(matx, directional = 1, direction.type = c("diffHeight""arrows"),
    link.arr.type = "big.arrow", diffHeight = -mm_h(2))

对于邻近列表也一样:

chordDiagram(df, directional = 1)

link.target.prop = FALSE 可以设置不显示起始端上部的条形,target.prop.height 可以设置其高度:

par(mfrow = c(12))
chordDiagram(mat, grid.col = grid.col, directional = 1,
    link.target.prop = FALSE)
chordDiagram(mat, grid.col = grid.col, directional = 1,
    diffHeight = mm_h(10), target.prop.height = mm_h(8))

13、缩放


和弦图的连接表示为关系的 “绝对值”。有时对于某个扇区,我们可能希望看到相对其它扇区的相对比例。在这种情况下,可以将 scale 参数设置为 true,以便在每个扇区上,该值代表进入另一个扇区的交互关系的相对比例。

缩放后,所有扇区大小相同,每个扇区的数据范围均为 c(0,1)

set.seed(999)
mat = matrix(sample(1818), 36)
rownames(mat) = paste0("S"1:3)
colnames(mat) = paste0("E"1:6)

grid.col = c(S1 = "red", S2 = "green", S3 = "blue",
    E1 = "grey", E2 = "grey", E3 = "grey", E4 = "grey", E5 = "grey", E6 = "grey")
par(mfrow = c(12))
chordDiagram(mat, grid.col = grid.col)
title("Default")
chordDiagram(mat, grid.col = grid.col, scale = TRUE)
title("scale = TRUE")




所以今天你学习了吗?





发现更多精彩

关注公众号

欢迎小伙伴留言评论!

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

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

如果觉得对您帮助很大,赏杯快乐水喝喝吧!

推 荐 阅 读




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

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