People use circos.link()
to visualize interactions/relations between sectors.
When one sector has more than one other sectors to interact with, it actually
becomes important of how to arrange links on that sector to make every link readable.
In the following example, I created a random interaction data frame df
:
set.seed(123)
sectors = letters[1:20]
df = data.frame(from = sample(sectors, 40, replace = TRUE),
to = sample(sectors, 40, replace = TRUE))
df = unique(df)
df = df[df$from != df$to, ]
df
## from to
## 1 o a
## 2 s f
## 3 n o
## 4 c i
## 5 j o
## 6 r p
## 7 k t
## 8 e f
## 9 t k
## 10 n h
## 11 e g
## 12 s p
## 13 i q
## 14 c r
## 15 h q
## 16 g b
## 17 j d
## 18 i m
## 19 s e
## 20 d s
## 21 n t
## 22 q n
## 23 k c
## 24 g h
## 25 l p
## 26 o l
## 27 j n
## 28 m c
## 29 g n
## 30 i g
## 31 i c
## 33 g e
## 34 f h
## 35 b s
## 36 e j
## 37 h r
## 38 l j
## 39 m l
## 40 r b
I also created the corresponding circular plot with all the sectors. In the simplest way, we might want to put all the links to the center of every sector, which looks like follows:
library(circlize)
circos.initialize(sectors, xlim = c(0, 1))
circos.track(ylim = c(0, 1), panel.fun = function(x, y) {
circos.text(CELL_META$xcenter, CELL_META$ycenter, CELL_META$sector.index)
})
for(i in seq_len(nrow(df))) {
s1 = df[i, 1]
s2 = df[i ,2]
circos.link(s1, 0.5, s2, 0.5, directional = 1)
}
It looks nice, but since all the links, e.g. which start from or end in one sector, are in a same position, it is rather difficult to tell which sector has more links than the others.
To get rid of such link overlapping, we can assign random shift to every link
in the sector. In the following example, since the xlim
for all sectors are
fixed in c(0, 1)
, we use runif(1)
to assign a random position between 0
and 1.
circos.initialize(sectors, xlim = c(0, 1))
circos.track(ylim = c(0, 1), panel.fun = function(x, y) {
circos.text(CELL_META$xcenter, CELL_META$ycenter, CELL_META$sector.index)
})
for(i in seq_len(nrow(df))) {
s1 = df[i, 1]
s2 = df[i ,2]
circos.link(s1, runif(1), s2, runif(1), directional = 1)
}
It already looks much nicer, however, since the positions are random, it is still not easy to tell which sector has more links because we need effort to carefully count the links if they are very close to each other (e.g., for sector c, are there four or five links?).
From circlize version 0.4.12.1001, I added a new function
arrange_links_evenly()
which can arrange the links on the sectors so that
the neighouring distance between links are evenly distributed. It also adjusts
positions of links to make the overall intersection of linkes minimal.
Additionally, it considers directional links, i.e., on each sector, the
starting links and the ending links are put into separate groups.
circos.initialize(sectors, xlim = c(0, 1))
circos.track(ylim = c(0, 1), panel.fun = function(x, y) {
circos.text(CELL_META$xcenter, CELL_META$ycenter, CELL_META$sector.index)
})
df2 = arrange_links_evenly(df, directional = 1)
for(i in seq_len(nrow(df2))) {
s1 = df$from[i]
s2 = df$to[i]
circos.link(df2[i, "sector1"], df2[i, "pos1"],
df2[i, "sector2"], df2[i, "pos2"],
directional = 1)
}
Session info:
sessionInfo()
## R version 4.0.2 (2020-06-22)
## Platform: x86_64-apple-darwin17.0 (64-bit)
## Running under: macOS Catalina 10.15.5
##
## Matrix products: default
## BLAS: /Library/Frameworks/R.framework/Versions/4.0/Resources/lib/libRblas.dylib
## LAPACK: /Library/Frameworks/R.framework/Versions/4.0/Resources/lib/libRlapack.dylib
##
## locale:
## [1] en_GB.UTF-8/en_GB.UTF-8/en_GB.UTF-8/C/en_GB.UTF-8/en_GB.UTF-8
##
## attached base packages:
## [1] stats graphics grDevices utils datasets methods base
##
## other attached packages:
## [1] circlize_0.4.12.1000 GetoptLong_1.0.4 knitr_1.30
##
## loaded via a namespace (and not attached):
## [1] bookdown_0.21 digest_0.6.27 crayon_1.3.4
## [4] grid_4.0.2 magrittr_2.0.1 evaluate_0.14
## [7] blogdown_0.17 rlang_0.4.8 stringi_1.5.3
## [10] GlobalOptions_0.1.2 rmarkdown_2.5 rjson_0.2.20
## [13] tools_4.0.2 stringr_1.4.0 xfun_0.19
## [16] yaml_2.2.1 compiler_4.0.2 colorspace_2.0-0
## [19] shape_1.4.5 htmltools_0.5.0