plot - R make circle/chord diagram with circlize from dataframe -
i make chord diagram using circlize package . have dataframe containing cars 4 columns. 2 first columns contains information on car band , model owned , next 2 columns brand , model respondent migrated to.
here simple example of dataframe:
brand_from model_from brand_to model_to 1: volvo s80 bmw 5series 2: bmw 3series bmw 3series 3: volvo s60 volvo s60 4: volvo s60 volvo s80 5: bmw 3series audi s4 6: audi a4 bmw 3series 7: audi a5 audi a5
it great able make chord diagram. found example in worked i'm not able convert data right format in order make plot. code in circlize package. produces 1 layer, guess need two, brand , model.
mat = matrix(1:18, 3, 6) rownames(mat) = paste0("s", 1:3) colnames(mat) = paste0("e", 1:6) rn = rownames(mat) cn = colnames(mat) factors = c(rn, cn) factors = factor(factors, levels = factors) col_sum = apply(mat, 2, sum) row_sum = apply(mat, 1, sum) xlim = cbind(rep(0, length(factors)), c(row_sum, col_sum)) par(mar = c(1, 1, 1, 1)) circos.par(cell.padding = c(0, 0, 0, 0)) circos.initialize(factors = factors, xlim = xlim) circos.trackplotregion(factors = factors, ylim = c(0, 1), bg.border = na, bg.col = c("red", "green", "blue", rep("grey", 6)), track.height = 0.05, panel.fun = function(x, y) { sector.name = get.cell.meta.data("sector.index") xlim = get.cell.meta.data("xlim") circos.text(mean(xlim), 1.5, sector.name, adj = c(0.5, 0)) }) col = c("#ff000020", "#00ff0020", "#0000ff20") for(i in seq_len(nrow(mat))) { for(j in seq_len(ncol(mat))) { circos.link(rn[i], c(sum(mat[i, seq_len(j-1)]), sum(mat[i, seq_len(j)])), cn[j], c(sum(mat[seq_len(i-1), j]), sum(mat[seq_len(i), j])), col = col[i], border = "white") } } circos.clear()
this code produces following plot:
ideal result example, instead of continents car brand , on inner circle car models belonging brand
as updated package little bit, there simpler way it. give answer here in case interested it.
in latest several versions of circlize, chorddiagram()
accepts both adjacency matrix , adjacency list input, means, can provide data frame contains pairwise relation function. there highlight.sector()
function can highlight or mark more 1 sectors @ same time.
i implement plot showed before shorter code:
df = read.table(textconnection(" brand_from model_from brand_to model_to volvo s80 bmw 5series bmw 3series bmw 3series volvo s60 volvo s60 volvo s60 volvo s80 bmw 3series audi s4 audi a4 bmw 3series audi a5 audi a5 "), header = true, stringsasfactors = false) brand = c(structure(df$brand_from, names=df$model_from), structure(df$brand_to,names= df$model_to)) brand = brand[!duplicated(names(brand))] brand = brand[order(brand, names(brand))] brand_color = structure(2:4, names = unique(brand)) model_color = structure(2:8, names = names(brand))
the value brand
, brand_color
, model_color
are:
> brand a4 a5 s4 3series 5series s60 s80 "audi" "audi" "audi" "bmw" "bmw" "volvo" "volvo" > brand_color audi bmw volvo 2 3 4 > model_color a4 a5 s4 3series 5series s60 s80 2 3 4 5 6 7 8
this time, add 1 additional track puts lines , brand names. , can find input variable data frame (df[, c(2, 4)]
).
library(circlize) gap.degree = do.call("c", lapply(table(brand), function(i) c(rep(2, i-1), 8))) circos.par(gap.degree = gap.degree) chorddiagram(df[, c(2, 4)], order = names(brand), grid.col = model_color, directional = 1, annotationtrack = "grid", preallocatetracks = list( list(track.height = 0.02)) )
same before, model names added manually:
circos.trackplotregion(track.index = 2, panel.fun = function(x, y) { xlim = get.cell.meta.data("xlim") ylim = get.cell.meta.data("ylim") sector.index = get.cell.meta.data("sector.index") circos.text(mean(xlim), mean(ylim), sector.index, col = "white", cex = 0.6, facing = "inside", nicefacing = true) }, bg.border = na)
in end, add lines , brand names highlight.sector()
function. here value of sector.index
can vector length more 1 , line (or thin rectangle) cover specified sectors. label added in middle of sectors , radical position controlled text.vjust
option.
for(b in unique(brand)) { model = names(brand[brand == b]) highlight.sector(sector.index = model, track.index = 1, col = brand_color[b], text = b, text.vjust = -1, nicefacing = true) } circos.clear()
Comments
Post a Comment