R从数据框中制作带圆圈的圆/弦图 [英] R make circle/chord diagram with circlize from dataframe
问题描述
我想使用circlize软件包制作一个和弦图.我有一个包含四列汽车的数据框.前两列包含有关所拥有的汽车乐队和车型的信息,后两列包含被调查者迁移到的品牌和车型的信息.
I would like to make a chord diagram using the circlize package . I have a dataframe containing cars with four columns. The 2 first columns contains information on car band and model owned and the next two columns to the brand and model the respondent migrated to.
这是数据框的一个简单示例:
Here is a simple example of the 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
能够将其制成和弦图,将是非常不错的.我在帮助中找到了一个有效的示例,但无法将数据转换为正确的格式以进行绘图. 此代码来自circlize软件包中的帮助.这会产生一层,我想我需要两层,品牌和型号.
It would be great to be able to make this into a chord diagram. I found an example in the help that worked but I'm not able to convert my data into the right format in order to make the plot. This code is from the help in the circlize package. This produces one layer, I guess I need two, brand and 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()
此代码生成以下图:
理想的结果将类似于此示例,但我不是大洲,而是汽车品牌,而在内圈上属于该品牌的汽车模型
Ideal result would be like this example, but instead of continents I would like car brand and on the inner circle the car models belonging to the brand
推荐答案
随着我对软件包的更新,现在有了一种更简单的方法.如果有人对此感兴趣,我会在这里给出另一个答案.
As I updated the package a little bit, there is now a simpler way to do it. I will give another answer here in case someone is interested with it.
在最新的 circlize 版本中,chordDiagram()
接受邻接矩阵和邻接列表作为输入,这意味着现在您可以提供一个包含与函数成对关系的数据框.还有一个highlight.sector()
功能,可以同时突出显示或标记多个扇区.
In the latest several versions of circlize, chordDiagram()
accepts both adjacency matrix and adjacency list as input, which means, now you can provide a data frame which contains pairwise relation to the function. Also there is a highlight.sector()
function which can highlight or mark more than one sectors at a same time.
我将使用较短的代码来实现我之前显示的情节:
I will implement the plot which I showed before but with 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))
brand
,brand_color
和model_color
的值是:
> 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
这一次,我们仅添加了一条附加曲目,用于放置行和品牌名称.而且您还可以找到输入变量实际上是一个数据帧(df[, c(2, 4)]
).
This time, we only add one additional track which puts lines and brand names. And also you can find the input variable is actually a 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 as the before, the model names are 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)
最后,我们通过highlight.sector()
函数添加行和品牌名称.在这里,sector.index
的值可以是长度大于1的向量,并且线(或细矩形)将覆盖所有指定的扇区.标签将添加到扇区的中间,基本位置由text.vjust
选项控制.
In the end, we add the lines and the brand names by highlight.sector()
function. Here the value of sector.index
can be a vector with length more than 1 and the line (or a thin rectangle) will cover all specified sectors. A label will be added in the middle of sectors and the radical position is controlled by 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()
这篇关于R从数据框中制作带圆圈的圆/弦图的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!