As indicated in the GitHub ReadMe for Step 3: Constructing Network Objects, we will, in this R pub, demonstrate the visualization of the networks.
Let’s start by visualizing a basic version of our networks. But first, it is essential that we establish a “standard format” for the networks; i.e. a structure in which the placement of the various vertices (countries) will remain the same across all networks (to ensure clarity in our later comparisons). We will do this by choosing any of the igraph objects, in this case the network associated with migration during 1990, and construct the network using the layout_with_fr() function. Further details on the various layout algorithms, in addition to many other relevant visualization functions can be found here.
Now let’s try visualing our networks using the simple plot() function
# Allow all four networks to be visualized together
par(mfrow = c(2, 2), mar = c(1, 1, 2, 1))
# Now plot the networks
plot(g_1990,
main = "1990",
vertex.label = V(g_1990)$code,
layout = layout_preferred)
plot(g_2000,
main = "2000",
vertex.label = V(g_2000)$code,
layout = layout_preferred)
plot(g_2010,
main = "2010",
vertex.label = V(g_2010)$code,
layout = layout_preferred)
plot(g_2020,
main = "2020",
vertex.label = V(g_2020)$code,
layout = layout_preferred)
This is certainly a rough-draft start, but here we can see how our networks can be visualized. Of note here is that the layouts for all networks are the same (i.e. the positions of th vertices are constant across all four years). This was achieved by defining the layout_preferred variable by using a the tkplot() function that allows for manual placement of the vertices. There are automatic algorithms that can do this (the most popular being the Fruchterman-Reingold algorithm), but it was deemed manual manipulation to allow for the most comprehensible networks (obviously, a bit of a subjective decision in the end).
But, as the networks stand currently, they are not all that clear. Let’s dig into the igraph functions by first adjusting the vertices, edges, and font sizes.
plot(g_1990, #The graph object
main = "1990", #The title we want to include
layout = layout_preferred, #Setting the layout to our previously defined desired layout
edge.arrow.size = 0.5, #Changing arrow/edge size
vertex.size = 20, #Changes size of the vertex (yellow circle)
vertex.label.font = 2, #Changing font type; here it is "Bolded"
vertex.label.cex = .5, #Changing size of font (i.e. country code font)
vertex.label = V(g_1990)$code) #Setting the vertex labels to the country code
Above, we have adjusted the arrow (or edge) sizes, the sizes of the vertices (or nodes), as well as the font and size of the vertex labels. Let’s now replicate this on all four networks, and graph them by each other again.
# Allow all four networks to be visualized together
par(mfrow = c(2, 2), mar = c(1, 1, 2, 1))
# Now plot the networks
plot(g_1990,
main = "1990",
layout = layout_preferred, #Setting the layout to our previously defined desired layout
edge.arrow.size = 0.5, #Changing arrow/edge size
vertex.size = 20, #Changes size of the vertex (yellow circle)
vertex.label.font = 2, #Changing font type; here it is "Bolded"
vertex.label.cex = .5, #Changing size of font (i.e. country code font)
vertex.label = V(g_1990)$code) #Setting the vertex labels to the country code
plot(g_2000,
main = "2000",
layout = layout_preferred, #Setting the layout to our previously defined desired layout
edge.arrow.size = 0.5, #Changing arrow/edge size
vertex.size = 20, #Changes size of the vertex (yellow circle)
vertex.label.font = 2, #Changing font type; here it is "Bolded"
vertex.label.cex = .5, #Changing size of font (i.e. country code font)
vertex.label = V(g_1990)$code) #Setting the vertex labels to the country code
plot(g_2010,
main = "2010",
layout = layout_preferred, #Setting the layout to our previously defined desired layout
edge.arrow.size = 0.5, #Changing arrow/edge size
vertex.size = 20, #Changes size of the vertex (yellow circle)
vertex.label.font = 2, #Changing font type; here it is "Bolded"
vertex.label.cex = .5, #Changing size of font (i.e. country code font)
vertex.label = V(g_1990)$code) #Setting the vertex labels to the country code
plot(g_2020,
main = "2020",
layout = layout_preferred, #Setting the layout to our previously defined desired layout
edge.arrow.size = 0.5, #Changing arrow/edge size
vertex.size = 20, #Changes size of the vertex (yellow circle)
vertex.label.font = 2, #Changing font type; here it is "Bolded"
vertex.label.cex = .5, #Changing size of font (i.e. country code font)
vertex.label = V(g_1990)$code) #Setting the vertex labels to the country code
It may be tempting to dig into some early interpretations of migration trends from the networks visualized above. We certainly have many more modifications we can make to add more nuance and information to the visualizations. But appropriate now to see that each decade appears to demonstrate in increase in the total number of “degrees”, that is the total number of arrows (which remember, each represents a net flow of migrants for at least 10,000). This therefore suggests that each decade has seen an increase in net migration flows in the Americas (The reason for say net migration and not just migration flows is that it could be the case that there are actually fewer migrants overall, but just that there is more “one-sided” migration being observed in recent decades. However, further analysis of the raw data does demonstrate that there are a greater number of migrants in recent decades in the Americas, which has been reported elsewhere).
Let’s add some additional nuance and information to the networks, again by working with one of the networks. Let’s modify the size of the vertices based on the total number of edges it has (i.e. its total “degree” score).
plot(g_1990,
main = "1990 \nVertex size by Degree Total",
layout = layout_preferred,
edge.arrow.size = 0.5,
vertex.size = V(g_1990)$DegT*1.5,
vertex.label.font = 2,
vertex.label = V(g_1990)$code)
We added the mulitply 1.5 to the vertex.size argument so as to make more of the vertices more pronounced (based on they underlying total degree score) but clearly the USA dominates the visualization, which makes sense given the sheer number of edges that start or end (the vast majority) at this vertex.
If we want to maintain the size of the vertices, we can still visualize the total degree score via a gradient applied to the vertex colors
# Find the maximum degree score for each vertex across all networks
max_degree_value_td <- max(unlist(V(g_1990)$DegT))
# Create a color palette from yellow to red using the colorRampPalette function
color_palette_degree_td <- colorRampPalette(c("yellow", "red"))(max_degree_value_td + 1)
# Now add an additional vertex attribute which matches the vertices' degree scores with the color ramp
V(g_1990)$ColorDT <- color_palette_degree_td[degree(g_1990)]
# Now Plot
plot(g_1990,
main = "1990 \nVertex Color by Degree Total",
layout = layout_preferred,
edge.arrow.size = 0.5,
vertex.size = 20,
vertex.color = V(g_1990)$ColorDT,
vertex.label.font = 2,
vertex.label = V(g_1990)$code)
We may also wish to adjust the edges so that they too can reflect information. Specifically, can we add a weight value to the edges such that they reflect how many migrants the edge represents. There are many ways to do this; either as an absolute number, or as a proportion of either the origin or receiving country’s population. Let’s construct the Network basing the arrow thickness on the proportion of the origin country’s population the migrant flow represents.
# Now Plot
plot(g_1990,
main = "1990 \nEdge Thickness by Migrant flow as \nProportion of Origin Country Population",
layout = layout_preferred,
edge.arrow.size = .7,
edge.width = E(g_1990)$MigrationFlowWeight_PropOrg/10,
vertex.size = 20,
vertex.color = V(g_1990)$ColorDT,
vertex.label.font = 2,
vertex.label = V(g_1990)$code)
And now let’s see all four decades together:
# Allow all four networks to be visualized together
par(mfrow = c(2, 2), mar = c(1, 1, 2, 1))
# Now plot the networks
plot(g_1990,
main = "1990",
layout = layout_preferred,
edge.arrow.size = .7,
edge.width = E(g_1990)$MigrationFlowWeight_PropOrg/15,
vertex.size = 20,
vertex.color = V(g_1990)$ColorDT,
vertex.label.font = 2,
vertex.label = V(g_1990)$code)
plot(g_2000,
main = "2000",
layout = layout_preferred,
edge.arrow.size = .7,
edge.width = E(g_2000)$MigrationFlowWeight_PropOrg/15,
vertex.size = 20,
vertex.color = V(g_2000)$ColorDT,
vertex.label.font = 2,
vertex.label = V(g_2000)$code)
plot(g_2010,
main = "2010",
layout = layout_preferred,
edge.arrow.size = .7,
edge.width = E(g_2010)$MigrationFlowWeight_PropOrg/15,
vertex.size = 20,
vertex.color = V(g_2010)$ColorDT,
vertex.label.font = 2,
vertex.label = V(g_2010)$code)
plot(g_2020,
main = "2020",
layout = layout_preferred,
edge.arrow.size = .7,
edge.width = E(g_2020)$MigrationFlowWeight_PropOrg/15,
vertex.size = 20,
vertex.color = V(g_2020)$ColorDT,
vertex.label.font = 2,
vertex.label = V(g_2020)$code)