三方图的水平布局

时间:2019-07-19 02:52:01

标签: r dplyr igraph bipartite

我正在使用igraph函数来创建一个三方图,该图将教师(A至参加该活动的学生列表(BR)链接起来该教练指导了3个俱乐部。学生有2个班级的会员,但性别可能相同。最后,边缘的宽度表示在给定的一周里,教练和每个学生平均在每个俱乐部上花费的时间。

创建图表很简单(我的代码在下面提供),但是鉴于我的列表中总共包含17名学生(BR),最好展示图表通过将讲师(A)放在顶部,水平放置三个俱乐部,中间将17个学生(BR)放在底部来水平放置。我怀疑这是因为我在图形中使用了layout_with_sugiyama(),但是有人可以建议一种替代方法来实现所需的水平布局吗?

下面是此图的我当前的R代码:

rm(list=ls())
library(foreign)
library(igraph)
library(dplyr)

### create tripartite node list and pairwise attributes
time <- data.frame(student = c("A", "A", "A", "B", "B", "B", "C", "C", "C", "D", "D", "D", "E", "E", "E", "F", "F", "F", "G", "G", "G", "H", "H", "H", "I", "I", "I", "J", "J", "J", "K", "K", "K", "L", "L", "L", "M", "M", "M", "N", "N", "N", "O", "O", "O", "P", "P", "P", "Q", "Q", "Q", "R", "R", "R"),
club = c("club 1", "club 2", "club 3", "club 1", "club 2", "club 3", "club 1", "club 2", "club 3", "club 1", "club 2", "club 3", "club 1", "club 2", "club 3", "club 1", "club 2", "club 3", "club 1", "club 2", "club 3", "club 1", "club 2", "club 3", "club 1", "club 2", "club 3", "club 1", "club 2", "club 3", "club 1", "club 2", "club 3", "club 1", "club 2", "club 3", "club 1", "club 2", "club 3", "club 1", "club 2", "club 3", "club 1", "club 2", "club 3", "club 1", "club 2", "club 3", "club 1", "club 2", "club 3", "club 1", "club 2", "club 3"), 
hours = c(10, 3, 6, 5, 2, 1, 3,	3, 2, 7, 5, 11,	1, 0, 3, 8, 2, 2, 2, 2,	0, 5, 7, 11, 1, 0, 1, 0, 1, 3, 8, 9, 2,	0, 0, 3, 4, 3, 6, 3, 1,	0, 3, 1, 7, 0, 0, 1, 0,	1, 5, 1, 3, 3))

### convert time dataframe into a graph object
df <- time[!time$hours == 0, ]
g <- graph_from_data_frame(df, directed = FALSE)
E(g)$width <- log(E(g)$hours)

### parse the data into three disjoint sets, use different node shapes to distinguish them

A <- "A"
club <- c("club 1", "club 2", "club 3")

V(g)$type <- 1
V(g)[name %in% club]$type <- 2
V(g)[name %in% "A"]$type <- 3
shape <- c("circle", "square", "circle")
size <- c(12, 15, 12)

### label class affiliation (except node A; G, K, L, Q do not belong to any classes)
Class1 <- c("B", "C", "E", "H", "J", "O")
Class2 <- c("D", "F", "M", "P", "I", "N", "R")

V(g)$color[V(g)$name] = "white"
V(g)$color[V(g)$name %in% Class1] = "red"
V(g)$color[V(g)$name %in% Class2] = "orange"
V(g)$color[V(g)$name == "A"] = "olivedrab1"

### highlight same sex nodes
s <- c("B", "D", "F", "G", "H", "K", "M", "P", "Q")
s_col = ifelse(V(g)$name %in% s,'black','grey80')

layout = layout_with_sugiyama(g, layers=V(g)$type)
V(g)$vertex_degree <-  igraph::degree(g)



plot(g,
     layout=cbind(V(g)$type, layout$layout[,1]), edge.curved=0,
     vertex.color = V(g)$color,
     vertex.label.color = "black",
     vertex.label.cex = 0.45,
     vertex.size = size[V(g)$type],
     vertex.shape = shape[V(g)$type],
     vertex.frame.color = s_col,
     edge.color= "grey30",
     asp = 1.3,
     edge.width = E(g)$width
)

上面的代码生成了这张图。

enter image description here

但是我想要的输出应该看起来像这样

enter image description here

1 个答案:

答案 0 :(得分:1)

感谢您的澄清。这更像是评论而不是答案。如果我按照您自己和评论者here的建议运行代码,

plot(g,
     layout=cbind(V(g)$type, layout$layout[,1])[,2:1], edge.curved=0,
     vertex.color = V(g)$color,
     vertex.label.color = "black",
     vertex.label.cex = 0.45,
     vertex.size = size[V(g)$type],
     vertex.shape = shape[V(g)$type],
     vertex.frame.color = s_col,
     edge.color= "grey30",
     asp = 1.3,
     edge.width = E(g)$width
)

我得到以下输出:enter image description here

与您要实现的目标有何不同?

编辑:一种在x轴上找到更好看的顶点分布的方法是使用cut函数:

idx <- which(layout$layout[,2] == 2)  # find "club"-vertices
cuts <- layout$layout[idx, 1]         # find x-coords of vertices
cut(cuts, length(idx))                # cut into 3 intervals
layout$layout[idx,1] <- c(6,7.5,9)    # manually calculated even spans between x-coords

但是,我敢肯定,有更好的方法可以做到这一点。