Multiple-group Chord diagram

Zuguang Gu · June 2020 · 版权信息

From verion 0.4.10 of the circlize package, there is a new group argument in chordDiagram() function which is very convenient for making multiple-group Chord diagrams.

I first generate a random matrix where there are three groups (A, B, and C). Note this new functionality works the same for the input as a data frame.

library(circlize)
mat1 = matrix(rnorm(25), nrow = 5)
rownames(mat1) = paste0("A", 1:5)
colnames(mat1) = paste0("B", 1:5)

mat2 = matrix(rnorm(25), nrow = 5)
rownames(mat2) = paste0("A", 1:5)
colnames(mat2) = paste0("C", 1:5)

mat3 = matrix(rnorm(25), nrow = 5)
rownames(mat3) = paste0("B", 1:5)
colnames(mat3) = paste0("C", 1:5)

mat = matrix(0, nrow = 10, ncol = 10)
rownames(mat) = c(rownames(mat2), rownames(mat3))
colnames(mat) = c(colnames(mat1), colnames(mat2))
mat[rownames(mat1), colnames(mat1)] = mat1
mat[rownames(mat2), colnames(mat2)] = mat2
mat[rownames(mat3), colnames(mat3)] = mat3
mat
##        B1     B2     B3    B4    B5     C1     C2     C3    C4       C5
## A1 -0.085  0.016  0.091 -0.50 -1.27  0.051 -1.679  0.088 -0.76  0.01749
## A2  0.945 -0.107  1.274 -0.20  0.11  0.140 -0.711  1.380 -0.41 -0.99425
## A3 -0.414 -0.444  0.938 -0.36  0.55  1.389 -0.477 -1.159  0.80  0.25352
## A4 -0.898 -0.434  2.179 -0.16  1.58  1.377 -1.152 -2.465 -0.89 -0.40290
## A5  1.695 -0.799 -0.276  0.38  1.36 -0.141  0.234  1.819 -0.37 -0.00056
## B1  0.000  0.000  0.000  0.00  0.00  0.927  0.790 -1.152 -0.87  0.49555
## B2  0.000  0.000  0.000  0.00  0.00  0.602 -0.938  0.484  0.45  0.34223
## B3  0.000  0.000  0.000  0.00  0.00 -0.147 -0.763  0.149 -0.90  0.06670
## B4  0.000  0.000  0.000  0.00  0.00  0.208 -0.365  1.239 -1.23  0.82139
## B5  0.000  0.000  0.000  0.00  0.00 -0.622  0.022  0.262  1.45  0.23556

The main thing is to create “a grouping variable”. The variable contains the group labels and the sector names are used as the names in the vector.

nm = unique(unlist(dimnames(mat)))
group = structure(gsub("\\d", "", nm), names = nm)
group
##  A1  A2  A3  A4  A5  B1  B2  B3  B4  B5  C1  C2  C3  C4  C5 
## "A" "A" "A" "A" "A" "B" "B" "B" "B" "B" "C" "C" "C" "C" "C"

Assign group variable to the group argument:

grid.col = structure(c(rep(2, 5), rep(3, 5), rep(4, 5)),
                names = c(paste0("A", 1:5), paste0("B", 1:5), paste0("C", 1:5)))
chordDiagram(mat, group = group, grid.col = grid.col)
circos.clear()

We can try another grouping:

group = structure(gsub("^\\w", "", nm), names = nm)
group
##  A1  A2  A3  A4  A5  B1  B2  B3  B4  B5  C1  C2  C3  C4  C5 
## "1" "2" "3" "4" "5" "1" "2" "3" "4" "5" "1" "2" "3" "4" "5"
chordDiagram(mat, group = group, grid.col = grid.col)
circos.clear()

The order of group controls the sector orders and if group is set as a factor, the order of levels controls the order of groups.

group = structure(gsub("\\d", "", nm), names = nm)
group = factor(group[sample(length(group), length(group))], levels = c("C", "A", "B"))
group
## C2 C4 A4 A3 B3 B2 A5 A1 C1 C5 A2 B5 B1 B4 C3 
##  C  C  A  A  B  B  A  A  C  C  A  B  B  B  C 
## Levels: C A B
chordDiagram(mat, group = group, grid.col = grid.col)
circos.clear()

The gap between groups is controlled by big.gap argument and the gap between sectors is controlled by small.gap argument.

group = structure(gsub("\\d", "", nm), names = nm)
chordDiagram(mat, group = group, grid.col = grid.col, big.gap = 20, small.gap = 5)
circos.clear()

As a normal Chord diagram, the labels and other tracks can be manually adjusted:

group = structure(gsub("\\d", "", nm), names = nm)
chordDiagram(mat, group = group, grid.col = grid.col,
	annotationTrack = c("grid", "axis"),
    preAllocateTracks = list(
        track.height = mm_h(4),
        track.margin = c(mm_h(4), 0)
))
circos.track(track.index = 2, panel.fun = function(x, y) {
    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, cex = 0.6, niceFacing = TRUE)
}, bg.border = NA)

highlight.sector(rownames(mat1), track.index = 1, col = "red", 
    text = "A", cex = 0.8, text.col = "white", niceFacing = TRUE)
highlight.sector(colnames(mat1), track.index = 1, col = "green", 
    text = "B", cex = 0.8, text.col = "white", niceFacing = TRUE)
highlight.sector(colnames(mat2), track.index = 1, col = "blue", 
    text = "C", cex = 0.8, text.col = "white", niceFacing = TRUE)
circos.clear()

本文使用 CC BY-NC-SA 4.0 协议发布。