【问题标题】:Horizontal layout for tripartite graph三方图的水平布局
【发布时间】:2019-11-28 00:03:48
【问题描述】:

我正在使用igraph 函数创建一个三方图,将一位讲师 (A) 与参加该讲师指导的 3 个俱乐部的学生列表(BR)联系起来。学生有 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
)

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

但我想要的输出应该是这样的

【问题讨论】:

  • 添加所需输出的图像可能会有所帮助。我的想法是切换列 a̶n̶d̶̶r̶e̶v̶e̶r̶s̶e̶̶t̶h̶e̶̶o̶r̶d̶e̶r̶:cbind(layout$layout[,1], V(g)$type)。但这不是你要找的,不是吗?
  • @Ben,感谢您的提醒,我将添加一张我想要的输出的图片。

标签: r dplyr igraph bipartite


【解决方案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
)

我得到以下输出:

这与你想要完成的有什么不同?

编辑:在 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

但是,我确信有更好的方法来做到这一点。

【讨论】:

  • 哇,非常感谢。通过对代码稍作修改,您推荐的解决方案正是我想要的。如果你不介意我问,有没有办法增加二级节点(club)和三级节点(student)之间的空间,因为club 2club 3重叠了一个位。
  • 很高兴它成功了!您可以尝试在 x 轴上均匀分布顶点(参见编辑)
  • 嗨,Ben,按照您推荐的方法,学生级节点缩小为三个节点,对应于三个等距俱乐部节点的位置。我正在考虑减少边的长度,但这可能会以一些意想不到的方式改变图形的布局。
  • 对不起,我根本不打算缩小/修改底部节点的位置。我不确定那里发生了什么。我希望在“俱乐部类型”的节点之间拥有相同数量的空间,并让您大致了解如何到达那里。也许layout_with_sugiyama 函数的其他参数可能对您有所帮助(例如hgap)。请记住 igraph.plotting 默认为 rescaling
  • 再次感谢您的回复。我发现许多用户建议使用layout.fruchterman.reingold() 函数代替其他布局来通过用户指定的缩放因子来缩放边缘长度,但是layout.fruchterman.reingold 没有layers 参数,这可能不适合我的情况。我将寻找其他布局或语法,尤其是那些有助于减少我的图表中过长的边长度的布局或语法。
猜你喜欢
  • 2011-08-08
  • 1970-01-01
  • 2013-10-18
  • 1970-01-01
  • 1970-01-01
  • 2023-03-29
  • 2014-10-14
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多