三方图的水平布局

Horizontal layout for tripartite graph

我正在使用 igraph 函数创建一个三方图,将讲师 (A) 链接到参与的学生列表(BR)在该教练指导的 3 个俱乐部中。学生在 2 类 中交叉了成员资格,并且可能具有相同的性别。最后,边缘的宽度表示教师和每个学生在给定一周内平均投入每个俱乐部的时间。

创建图表很简单(我的代码在下面提供),但考虑到我的列表总共包含 17 名学生(BR),最好呈现通过将教练 (A) 放在顶部,将 3 俱乐部放在中间,将 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
)

以上代码生成此图。

然而我想要的输出应该是这样的

感谢您的澄清。这更像是评论而不是答案。如果我 运行 你和评论者提出的代码 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
)

我得到以下输出:

这与您想要完成的有何不同?

编辑: 在 x-axes 上找到更好看的顶点分布的一种方法是使用 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

不过,我确信有更好的方法可以做到这一点。