Irish-Viking Networks in 'Cogadh Gaedhel re Gallaibh'

Graph datasets for Irish and Viking character relationships in the medieval Irish text 'Cogadh Gaedhel re Gallaibh' ('The War of the Gaedhil with the Gaill')

Originator: Joseph Yose (Applied Mathematics Research Centre, Coventry University, Coventry CV1 5FB, UK);
Ralph Kenna (Applied Mathematics Research Centre, Coventry University, Coventry CV1 5FB, UK);
Máirín MacCarron (Department of History, University of Sheffield, Sheffield S3 7RA, UK);
Pádraig MacCarron (Social and Evolutionary Neuroscience Research Group, Department of Experimental Psychology, University of Oxford, Oxford OX1 3UD, UK)

Cogadh Gaedhel re Gallaibh ('The War of the Gaedhil with the Gaill') is a medieval Irish narrative which contains information on the Viking age in Ireland. Social-network data are embedded in the texts. The source of these data is an edition/translation into English by James Henthorn Todd [Todd JH (ed. and trans.) 1867 Cogadh Gaedhel re Gallaibh. The war of the Gaedhil with the Gaill, or, the invasions of Ireland by the Danes and other Norsemen. London, UK: Longmans, Green, Reader, and Dyer]. Data are identified by carefully and manually reading Todd's texts with multiple passes through all of the material by multiple readers.

The data resource contains a Dataset of 315 characters and their nationalities extracted from the Cogadh Gaedhel re Gallaibh, a full Graph network of unsigned edges (315 vertices, 1190 edges), a positive (friendly) Graph network (287 vertices, 957 edges), and a negative (hostile) Graph network (180 vertices, 264 edges).

Examples

Basic Examples

Retrieve the resource:

In[1]:=
ResourceObject["Irish-Viking Networks in 'Cogadh Gaedhel re \
Gallaibh'"]
Out[1]=

Retrieve the default content:

In[2]:=
ResourceData["Irish-Viking Networks in 'Cogadh Gaedhel re Gallaibh'"]
Out[2]=

Some helper functions:

In[3]:=
ClearAll[faction]
SetAttributes[faction, Listable];
Scan[(faction[#["Character"]] = #["Faction"]) &, ResourceData["Irish-Viking Networks in 'Cogadh Gaedhel re Gallaibh'"]]
faction[e : (_DirectedEdge | _UndirectedEdge)] := faction /@ e
faction[_] := Missing["NotAvailable"]
In[4]:=
ClearAll[irishQ]
SetAttributes[irishQ, Listable];
Scan[(irishQ[#["Character"]] = MatchQ[#["Faction"], "Irish"]) &, ResourceData["Irish-Viking Networks in 'Cogadh Gaedhel re Gallaibh'"]]
irishQ[_] := False
In[5]:=
ClearAll[vikingQ]
SetAttributes[vikingQ, Listable];
Scan[(vikingQ[#["Character"]] = MatchQ[#["Faction"], "Viking"]) &, ResourceData["Irish-Viking Networks in 'Cogadh Gaedhel re Gallaibh'"]]
vikingQ[_] := False
In[6]:=
ClearAll[otherQ]
SetAttributes[otherQ, Listable];
Scan[(otherQ[#["Character"]] = MatchQ[#["Faction"], "Unassigned"]) &, ResourceData["Irish-Viking Networks in 'Cogadh Gaedhel re Gallaibh'"]]
otherQ[_] := False
In[7]:=
With[{characters = {"Baetan", "Snuatgar", "Gaithin", "Macbeth"}}, {faction[#], irishQ[#], vikingQ[#], otherQ[#]} &@
    characters // Transpose // TableForm[#, TableHeadings -> {characters, {"Faction", "Irish?", "Viking?", "Other?"}}] &]
Out[7]=

Create network Graph objects for the full cast, Irish, and Viking networks.

In[8]:=
ClearAll[network]
Do[
 Module[{edges, vertices}, edges = Cases[s[[2]], s_?(n[[2]]) \[UndirectedEdge] t_?(n[[2]])]; vertices = Union @@ List @@@ edges; network[s[[1]], n[[1]]] = Graph[vertices, edges]], {s, {{"Unsigned", EdgeList@
     ResourceData[
       "Irish-Viking Networks in 'Cogadh Gaedhel re Gallaibh'", All][
      "FullNetwork"]}, {"Positive", EdgeList@
     ResourceData[
       "Irish-Viking Networks in 'Cogadh Gaedhel re Gallaibh'", All][
      "PositiveNetwork"]}, {"Negative", EdgeList@
     ResourceData[
       "Irish-Viking Networks in 'Cogadh Gaedhel re Gallaibh'", All][
      "NegativeNetwork"]}}}, {n, {{"FullCast", True &}, {"Irish", irishQ}, {"Viking", vikingQ}}}]
In[9]:=
edgeTypes = {"Unsigned", "Positive", "Negative"}
Out[9]=
In[10]:=
factions = {"FullCast", "Irish", "Viking"}
Out[10]=

Network plots

A useful graph embedding function:

In[11]:=
gravityEmbedding[g_Graph, opts : OptionsPattern[{Graph}]] := Module[{newVertex = Unique[v], newEdges, coords, gOpts}, newEdges = (newVertex \[UndirectedEdge] #1 &) /@ VertexList[g]; coords = GraphEmbedding[EdgeAdd[VertexAdd[g, newVertex], newEdges], "SpringElectricalEmbedding", 2]; gOpts = FilterRules[Options[g], Except[{VertexCoordinates, GraphLayout}]]; Graph[VertexList[g], EdgeList[g], VertexCoordinates -> Most[coords],
    opts, gOpts]]
In[12]:=
TabView[Function[edgeType, edgeType -> Module[{g = network[edgeType, "FullCast"], vertexStyles, edgeStyles}, vertexStyles = # -> Switch[faction[#], "Irish", Lighter@Darker@Green, "Viking", Blue, _(*"Unassigned"*), Gray] & /@ VertexList[g];
     edgeStyles = # -> Switch[faction[#], "Irish" \[UndirectedEdge] "Irish", Darker@Green, "Viking" \[UndirectedEdge] "Viking", Blue, ("Irish" \[UndirectedEdge] "Viking") | ("Viking" \[UndirectedEdge] "Irish"), Brown, _(*"Unassigned"*), Gray] & /@ EdgeList[g];
     gravityEmbedding[g, VertexStyle -> vertexStyles, VertexLabels -> Placed["Name", Tooltip], EdgeStyle -> edgeStyles, EdgeShapeFunction -> "CurvedArc", ImageSize -> Large] // Labeled[#, StringForm["N = ``, M = ``", VertexCount[#], EdgeCount[#]], Bottom] &
     ]] /@ edgeTypes]
Out[12]=

Network statistics

Vertex and edge counts

In[13]:=
Outer[{#1, #2, VertexCount@network[##], EdgeCount@network[##]} &, edgeTypes, factions] // Flatten[#, 1] & // TableForm[#, TableHeadings -> {None, {"relationship", "faction", "N", "M"}}] & // Labeled[#, "Vertex and edge counts", Top] &
Out[13]=

Vertex degree

In[14]:=
Outer[2 EdgeCount[network[##]]/VertexCount[network[##]] &, edgeTypes, factions] // N // TableForm[#, TableHeadings -> {edgeTypes, factions}] & // Labeled[#, "Average vertex degree \[LeftAngleBracket]k\[RightAngleBracket]", Top] &
Out[14]=
In[15]:=
Outer[Max@VertexDegree[network[##]] &, edgeTypes, factions] // TableForm[#, TableHeadings -> {edgeTypes, factions}] & // Labeled[#, "Maximum vertex degree \!\(\*SubscriptBox[\(k\), \(max\)]\)", Top] &
Out[15]=

Degree assortativity

In[16]:=
Outer[GraphAssortativity[network[##]] &, edgeTypes, factions] // N // TableForm[#, TableHeadings -> {edgeTypes, factions}] & // Labeled[#, "Degree assortativity", Top] &
Out[16]=

Categorical assortativity

In[17]:=
Module[{edgePatterns = {_?(False &) \[UndirectedEdge] _?(False &), _?
         vikingQ \[UndirectedEdge] _?vikingQ}}, Outer[With[{g = Graph@DeleteCases[
           EdgeList@network[#2, "FullCast"], #1]}, {nodes = VertexList[g]}, GraphAssortativity[g, nodes -> faction[nodes]]] &, edgePatterns, edgeTypes]] // N // TableForm[#, TableHeadings -> {{"include all edges", "omit Viking-on-Viking edges"}, edgeTypes}] & // Labeled[#, "Categorical assortativity \[Rho]", Top] &
Out[17]=

Network robustness

We use a normalized betweenness centrality

In[18]:=
betweennessCentrality[g_Graph] /; VertexCount[g] > 2 := (
 2 BetweennessCentrality[
   g])/((VertexCount[g] - 1) (VertexCount[g] - 2))
betweennessCentrality[g_Graph] := ConstantArray[0., VertexCount[g]]

We are interested in the closeness centrality of a node only if it is a member of the giant component.

In[19]:=
closenessCentrality[g_Graph] := With[{bigComponent = First@ConnectedComponents[g]}, MapThread[
   If[MemberQ[bigComponent, #1], #2, 0] &, {VertexList[g], ClosenessCentrality[g]}]]

Character importance

In[20]:=
centralities = {DegreeCentrality, betweennessCentrality, closenessCentrality}
Out[20]=
In[21]:=
Outer[Function[{et, cent}, With[{g = network[et, "FullCast"]}, Take[#, 5] &@
        Reverse@SortBy[Thread[{VertexList[g], cent[g]}], Last]]], edgeTypes, centralities] /. {char_String, cen_?NumberQ} :> StringForm["`` (``)", char, Switch[cen, _Integer, cen, _, PaddedForm[Round[cen, 0.01], {3, 2}, NumberSigns -> {"", ""}]]] // Map[Column, #, {2}] & // TableForm[#, TableHeadings -> {edgeTypes, centralities}, TableSpacing -> {4, 2}] & // Labeled[#, "Character importance", Top] &
Out[21]=

Stability of the giant component

In[22]:=
giantComponentSize[g_Graph] := With[{cc = ConnectedComponents[g]}, Switch[cc, {__}, Length@First@cc, _, 0]]
In[23]:=
Module[{random, degree, betweenness}, random = Table[
     giantComponentSize /@ With[{g = network[#, "FullCast"]}, NestList[VertexDelete[#, RandomSample[VertexList[#], 1]] &, g, VertexCount[g]]], {5}] & /@ edgeTypes;
 degree = giantComponentSize /@ With[{g = network[#, "FullCast"]}, NestList[
       VertexDelete[#, Last@Last@
           Sort@Thread[{DegreeCentrality[#], VertexList[#]}]] &, g, VertexCount[g]]] & /@ edgeTypes;
 betweenness = giantComponentSize /@ With[{g = network[#, "FullCast"]}, NestList[
       VertexDelete[#, Last@Last@
           Sort@Thread[{betweennessCentrality[#], VertexList[#]}]] &, g, VertexCount[g]]] & /@ edgeTypes;
 MapThread[
     Function[{r, d, b, e}, ListPlot[
       Thread[{Range[0, VertexCount[network[e, "FullCast"]]], #}] & /@
         Join[r, {d, b}], Joined -> True, PlotMarkers -> None, PlotLabel -> StringForm["`` network", e], FrameLabel -> {"number nodes removed", "size of giant component"}, PlotStyle -> Join[ConstantArray[Red, Length@r], {Blue, Darker@Green}], ImageSize -> Medium]], {random, degree, betweenness, edgeTypes}] // Append[#, Framed@LineLegend[{Red, Blue, Darker@Green}, {"random", "by decreasing degree centrality", "by decreasing betweenness centrality"}, LegendLabel -> "node removal order"]] & // Partition[#, 2, 2, {1, 1}, {""}] & // Grid
 ]
Out[23]=

Robert Nachbar, "Irish-Viking Networks in 'Cogadh Gaedhel re Gallaibh'" from the Wolfram Data Repository (2018)  

Data Resource History

Source Metadata

Publisher Information