Attribute-ordered networks

Social networks can be complex, especially in dense groups where many individuals interact with many other individuals. In some cases, ties among individuals are weighted (i.e. by the number of interactions), directed (i.e. aggression is directed from a winner to a loser), and bi-directional ties occur (i.e. the same individuals aggress against each other, so aggression ties run in both directions). These types of networks are especially challenging to plot effectively without the loss of important information. It is also useful to plot different types of networks for the same group of individuals (i.e. across different years or different social contexts), but traditional network layout methods produce plots that are difficult to compare.
I developed the attribute-ordered network layout in order to visualize the structure of networks of associations or interactions combined with ranked individual attribute information (Hobson et al. 2015). The layout method was inspired by the arc diagram by Mark Wattenberg (see paper and website) and the hive plot by Martin Krzywinski(see paper and website). The attribute-ordered networks work well for depicting the rank order of individuals by attributes (here, dominance rank) along with the more complex interaction network that generated the ranks (here, the direction of aggression).

Example aggression network:

Potential graph layouts, two generated with a force-directed layout algorithm and one with the attribute-ordered layout:

Option 1: Fruchterman-Reingold Algorithm (straight edges)

Which individuals are highly-ranked, and which are subordinate? It’s pretty hard to tell, especially with all the arrow heads making directionality of aggression tricky to see. Node size can be changed so that higher-ranked individuals have larger nodes, but then differentiating rank among similarly-ranked individuals is also difficult.

It’s also pretty impossible to determine the direction of aggression in this plot. For example, WH and BK both direct aggression at each other, but is this aggression evenly distributed, or is winning skewed more toward one individual over the other? The arrow size can be varied to show this, but this is tricky to do in igraph and makes for a very cluttered graph.

Option 2: Fruchterman-Reingold Algorithm (curved edges)
Curving the ties helps to see the direction of aggression, but graph requires a lot of parsing to get meaningful information out of it. However, this graph is becoming what some people refer to as a “hairball”!
This layout also doesn’t solve the issues with visualizing relative rank among individuals, and multiple hairball plots of this group would be pretty hard to compare.
Option 3: Attribute-ordered layout
Rank is immediately obvious in this layout. The highest-ranked birds are at the top and the most subordinate birds are at the bottom. It is now very easy to see relative rank differences among individuals.
The direction and amount of aggression is also much easier to see in this layout. We don’t need to clutter the graph with arrows to show the direction of ties. Here, aggression directed “down” the hierarchy (from higher-ranked aggressor to lower-ranked target) is plotted on the right side in blue, while aggression directed “up” the hierarchy is plotted on the left side in red. It’s now much easier to see aggression patterns between individuals WH and BK. Most of the aggression was directed from higher-ranked BK towards lower-ranked WH, although WH did direct some aggression towards BK.
Try it out in R!
For help with data formatting, please refer to Dai Shizuka’s excellent tutorials (#9 will be especially useful for working with weighted data in edgelist format). 

You’ll need two types of data:

An edgelist with four columns: ID of the first individual, ID of the second individual, number of interactions, rank difference between the two individuals
The rank difference among individuals is used to color the ties below – if you don’t want to differentiate between “up” and “down” ties you can use the first three columns and then skip the color designations below.

An attribute list with three columns: ID of each individual, x coordinate for plotting, and individual rank — the highest-ranked individual (RD) gets the highest number (10) while the lowest-ranked individual (WH) gets the lowest number (1)

Code:

I make no guarantees about the elegance of the code (I’m still learning!). Please proof and fully test all codes for your own use.

# Load igraph package

library(igraph)

# Read in the data

el<-read.table(file.choose(),header=TRUE) # read .txt file “edgelist”

atts<-read.table(file.choose(),header=TRUE) # read .txt file “attributes”

#set as igraph object, vertices=atts is critical!

atnet<-graph.data.frame(el, directed = TRUE, vertices = atts)

# Add conditional color, based on direction of aggression

# skip this part if you don’t want to different colors for “up” and “down” aggression

E(atnet)[rank.diff<0]$color <- “#CC000095″ #”UP” ties as slightly transparent red

E(atnet)[rank.diff>0]$color <- “#00009985″ #”DOWN” ties as slightly transparent blue

get.edge.attribute(atnet, “color”) #check, should be mostly #00009985 with some #CC000095

# Set custom attribute-ordered network layout

# set layout using x/y coords from attributes

x <- V(atnet)$x

y <- V(atnet)$rank

attord<- cbind(x, y) #attribute-ordered layout of nodes

# Set node size, label size, tie width

nodesize1<-10 #set node size

tiewidth1 <- E(atnet)$wins/2 #set edge width

labelsize1<-0.5 #set node label size

# Plot attribute-ordered networks

# highest-ranked plotted at top, lowest-ranked at the bottom

plot.igraph(atnet,
layout=attord, #sets as attribute-ordered layout, defined above
vertex.size=nodesize1, #this references the node circle size, set above
vertex.label.family=”sans”, #uses sans font style
vertex.label.color = “black”, #sets node label colors (ids) to black
vertex.label.cex=labelsize, #this references the node label size, set above
vertex.color=”white”, #sets node fill color to white
edge.width=tiewidth1, #this references the edge width, set above
edge.arrow.size=0.01, #this makes the arrows on the ends of the edges very small
edge.curved=TRUE, #this makes the edges curved
edge.loop.angle=1,
edge.color=E(atnet)$color) #this sets the edge color, based on the colors set above (set this as “black” if you don’t want different colors)

# Compare to Fruchterman-Reingold Algorithm

plot.igraph(atnet,
layout=layout.fruchterman.reingold, #sets layout with F-R algorithm
vertex.size=nodesize1, #this references the node circle size, set above
vertex.label.family=”sans”, #uses sans font style
vertex.label.color = “black”, #sets node label colors (ids) to black
vertex.label.cex=labelsize, #this references the node label size, set above
vertex.color=”white”, #sets node fill color to white
edge.width=tiewidth1, #this references the edge width, set above
edge.arrow.size=1, #this sets the arrows to size “1” so they’re visible
edge.curved=F, #this makes the edges straight (set to “T” for curved edges)
edge.color=”black”) #this sets the edge to black