I'm using igraph
function to create a tripartite graph linking an instructor (A
) to a list of students (B
to R
) who participate in the 3 clubs mentored by this instructor. Student have crossed memberships in 2 classes and may have the same gender. Finally, the width of the edges represents the amount of time the instructor and each student dedicate, on average, to each club in a given week.
Creating the graph is straightforward (my code is provided at below), but given that my list contains a total of 17 students (B
to R
), it would be better to present the graph in a horizontal way by placing the instructor (A
) on top, the 3 club in the middle, with the 17 students (B
to R
) on the bottom. I suspect this is because I used layout_with_sugiyama()
for my graph, but could anyone suggest an alternative to achieve my desired horizontal layout?
Below is my current R
code for this graph:
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
)
The above code generates this graph.
Yet my desired output should look something like this