<p><div><div><div><div data-show-faces="false" data-height="21" data-width="100" data-layout="button_count" data-send="true" data-href="https://www.r-bloggers.com/visualising-networks-in-asoiaf-part-ii/"></div></div><div></div></div><div></div></div>
<div>
(This article was first published on <strong><a href="https://www.timlrx.com/2018/10/14/visualising-networks-in-asoiaf-part-ii/"> R on Quasilinear Musings</a></strong>, and kindly contributed to <a rel="nofollow" href="https://www.r-bloggers.com/">R-bloggers)</a> </div>
<p>This is the second post of a character network analysis of George R. R. Martin’s A Song Of Ice and Fire (ASOIAF) series as well as my first submission to the <a rel="nofollow" href="https://www.r-bloggers.com/" target="_blank">R Bloggers community</a>. A warm welcome to all readers out there! In my <a rel="nofollow" href="https://www.timlrx.com/2018/10/2018/09/09/visualising-networks-in-asoiaf/" target="_blank">first post</a>, I touched on the <a rel="nofollow" href="https://github.com/thomasp85/tidygraph" target="_blank">Tidygraph</a> package to manipulate dataframes and <a rel="nofollow" href="https://github.com/thomasp85/ggraph" target="_blank">ggraph</a> for network visualisation as well as some tricks to fix the position of nodes when ploting multiple graphs containing the same node set and labeling based on polar coordinates. In this post, we combine the plots together and use <a rel="nofollow" href="https://github.com/thomasp85/gganimate" target="_blank">gganimate</a> to visualise all 5 books.</p>
<div>
<h3>The ASOIAF Network</h3>
<p>I carry on from the end of the previous post and will skip through the pre-processing and cleaning steps.</p>
<p>Previously, we created a <code>process_graph</code> function which pre-processes our input data into the tidygraph format and calculated the page-rank scores for each character at the book level. Subsequently, we join these graphs and used the full graph to identify relevant communities within the ASOIAF universe and key characters.</p>
<p>The full graph is used to define the coordinate of each node and their position in the final plot. A <code>plot_graph</code> function was created to take in a tidygraph table and produces the network visualisation. Here is the code which we used to generate the network graph.</p>
<pre><code>full_layout &lt;- create_layout(graph = full_graph, layout = &quot;linear&quot;, circular = T)
xmin &lt;- min(full_layout$x)
xmax &lt;- max(full_layout$x)
ymin &lt;- min(full_layout$y)
ymax &lt;- max(full_layout$y)

plot_graph &lt;- function(graph) {
  
  graph &lt;- graph %>%
    left_join(full_layout[full_layout$Id %in% V(graph)$Id, c('x', 'y', 'Id', 'community', 'pagerank')],
              by = 'Id')

  graph %>%
    ggraph(layout = &quot;manual&quot;, x = x, y = y, circular = T) +
    geom_edge_arc(aes(alpha = weight)) +
    geom_node_point(aes(color = community, size = pagerank)) +
    # data = filter(graph %>% as_tibble(), x>0),
    geom_node_text(aes(label = Label_short, x = x * 1.04, y = y* 1.04,
                       angle = ifelse(atan(-(x/y))*(180/pi) &lt; 0,
                                      90 + atan(-(x/y))*(180/pi),
                                      270 + atan(-x/y)*(180/pi)),
                       hjust = ifelse(x > 0, 0 ,1)), size = 3.5) +
    theme_graph() +
    expand_limits(x = c(xmin-0.2, xmax+0.2), y = c(ymin-0.2, ymax+0.2))
}</code></pre>
<p>Let’s test it out on the entire ASOIAF universe and see how it looks like:</p>
<pre><code>plot_graph(full_graph %>% select(-community, -pagerank)) +
  scale_color_manual(values=colorRampPalette(c(&quot;blue&quot;, &quot;yellow&quot;, &quot;red&quot;))(11)[c(1,11,2,10,6,9,4,8,5,7,3)],
                     labels=c(&quot;King's Landing&quot;, &quot;The Wall&quot;,
                              &quot;Arya and the Brotherhood&quot;, &quot;Daenerys's Khalasar&quot;,
                              &quot;Bran's companions&quot;, &quot;House Bolton&quot;,
                              &quot;House Martell&quot;, &quot;Young Griff&quot;, &quot;Dragonstone&quot;,
                              &quot;Brienne's party&quot;, &quot;Gregor and Oberyn&quot;))</code></pre>
<p><img src="https://i1.wp.com/www.timlrx.com/2018/10/post/2018-10-14-visualising-networks-in-asoiaf-part-ii_files/figure-html/fullplot-1.png?w=450&ssl=1" data-recalc-dims="1"></p>
<p>I made two main changes to the above plot compared to the previous post. First, I use a cut-off threshold of 0.8 instead of 0.75 to filter out the less relevant characters. To make it easier to infer the communities, I also mapped each community to a custom colour palette. This is generated using the <code>colorRampPalette</code> function but I rearranged the palette to maximise the perceptual difference between each community and make them easily distinguishable.</p>
<p>The characters fall into 11 relatively distinct communities. The biggest group is the King’s Landing community coloured in blue. Visually, this is also the most dense area of the plot and many of the cross-community interaction is fostered by characters within the King’s Landing group. This also explains the high page-rank score of the characters within this group.</p>
<p>Next, we have the Night’s Watch and wildlings which I termed as ‘The Wall’. Unsurprisingly, Jon Snow is the key character within this community having ties with almost every one of them and links to the broader ASOIAF universe.</p>
<p>The names of the other communities can be seen in the above plot. We can see the role of the Stark family in the story with each character being a key member of a different community. The network plot also illustrates the narrative technique employed by George R. R. Martin within the series. Many of the characters interact within their small communities and but are weaved into the broader narrative by their connections to certain key players. This allows him to build detailed character profiles while still creating an illusion of an extremely large universe. The clearest examples of this is Daenerys’s Khalasar and Arya’s network which exists in very isolated communities but are connected to the broader story mainly through Daenerys and Arya only.</p>
<p>Another interesting question that one might ask is how the current network structure differ between a cut-off threshold of 0.8 compared to 0.75 used in the previous post. The plot based on a threshold of 0.75 is shown below:</p>
<p><img src="https://i1.wp.com/www.timlrx.com/2018/10/post/2018-10-14-visualising-networks-in-asoiaf-part-ii_files/figure-html/preprocess2-1.png?w=450&ssl=1" data-recalc-dims="1"></p>
<p>There are 4 other meaningful segments compared to the previous graph and they roughly correspond to the Riverlands group, house Greyjoy, Harrenhal guards (Gregor and Oberyn are in that group) and the Citadel. Here is an interesting observation: Arya’s kill list creates numerous co-occurrence of Gregor, Sandor, Polliver and the Tickler which is picked up by the network plot as a distinct community.</p>
</div>
<div>
<h3>A network animation</h3>
<p>Separate plots for each book is nice but this makes it quite difficult to compare the network structure across books. One possible solution is to combine them all into an animation. <a rel="nofollow" href="https://github.com/thomasp85/gganimate" target="_blank">gganimate</a> is an extension to ggplot that allows animations to be created relatively easily.<a rel="nofollow" href="https://www.timlrx.com/2018/10/14/visualising-networks-in-asoiaf-part-ii/#fn1" target="_blank"><sup>1</sup></a></p>
<p>With <code>gganimate</code> doing a simple transition can be done by appending <code>transition_manual</code> to the existing ggplot object and calling <code>animate</code> on it. Basically, anything that works with a <code>facet_wrap</code> can be converted to a simple animation. In the example below, I included <code>transition_manual(book)</code> to generate an animation that shows each book every 2 seconds. <code>animate</code> by default renders an animated gif which we can simply embed on the website.</p>
<pre><code>library(gganimate)
plot_graph &lt;- function(graph) {
  
  graph &lt;- graph %>%
    left_join(full_layout[full_layout$Id %in% V(graph)$Id, c('x', 'y', 'Id', 'community', 'pagerank')],
              by = 'Id')

  graph %>%
    ggraph(layout = &quot;manual&quot;, x = x, y = y, circular = T) +
    # Need to use link0 for gganimate
    #geom_edge_arc(aes(alpha = weight)) +
    geom_edge_link0(aes(alpha = weight)) +
    geom_node_point(aes(color = community, size = pagerank)) +
    # data = filter(graph %>% as_tibble(), x>0),
    geom_node_text(aes(label = Label_short, x = x * 1.04, y = y* 1.04,
                       angle = ifelse(atan(-(x/y))*(180/pi) &lt; 0,
                                      90 + atan(-(x/y))*(180/pi),
                                      270 + atan(-x/y)*(180/pi)),
                       hjust = ifelse(x > 0, 0 ,1))) +
    theme_graph() +
    expand_limits(x = c(xmin-0.2, xmax+0.2), y = c(ymin-0.2, ymax+0.2))
}

p &lt;- plot_graph(
  full_graph %>%
    select(-community, -pagerank)
)

p &lt;- p +
  scale_color_manual(values=colorRampPalette(c(&quot;blue&quot;, &quot;yellow&quot;, &quot;red&quot;))(11)[c(1,11,2,10,6,9,4,8,5,7,3)],
                     labels=c(&quot;King's Landing&quot;, &quot;The Wall&quot;,
                              &quot;Arya and the Brotherhood&quot;, &quot;Daenerys's Khalasar&quot;,
                              &quot;Bran's companions&quot;, &quot;House Bolton&quot;,
                              &quot;House Martell&quot;, &quot;Young Griff&quot;, &quot;Dragonstone&quot;,
                              &quot;Brienne's party&quot;, &quot;Gregor and Oberyn&quot;)) +
  ggtitle('ASOIAF Character Network', subtitle = 'Book {current_frame}') +
  transition_manual(book)

animate(p, 100, 10, width = 1050, height = 700)</code></pre>
<p><img src="https://i1.wp.com/www.timlrx.com/2018/10/post/2018-10-14-visualising-networks-in-asoiaf-part-ii_files/figure-html/animate-1.gif?w=456&ssl=1" data-recalc-dims="1"></p>
<p>The above animation looks quite nice, but the transition between plots seem a little sudden. To smoothen the transition, we can transform the discrete events into continuous ones and use <code>transition_events</code> to control the rate of transition. The solution below is adapted from this <a rel="nofollow" href="https://gist.github.com/thomasp85/e6280e554c08f00c9e46f8efca2a5929" target="_blank">gist</a>. I experimented with various methods of converting the discrete book intervals to continuous events. Eventually, it seems that creating a time event out of the edge weights seem to work quite well. The weights are scaled to range from 0 to 60 and are used as minutes while the book number takes the place of the hour of the day. <code>enter_length</code> and <code>exit_length</code> is set to 60 minutes to create some overlap across books so that characters which remain connected across books do not appear to fade in and out unnecessarily. Here is the final code and output.</p>
<pre><code>p &lt;- plot_graph(
  full_graph %>%
    select(-community, -pagerank) %>%
    activate(edges) %>%
    mutate(tweight = ifelse(weight >100, 100, weight)) %>%
    group_by(book) %>%
    mutate(scaled_weight = (tweight - min(tweight)) / (max(tweight) - min(tweight)) * 60,
           book_start_time = as.POSIXct((paste0('2018-10-10', book, &quot;:00&quot;)), format = &quot;%Y-%m-%d %H:%M&quot;),
           book_end_time = as.POSIXct((paste0('2018-10-10', book, &quot;:&quot;, scaled_weight)), format = &quot;%Y-%m-%d %H:%M&quot;)) %>%
    ungroup() %>%
    mutate(book_end_time = if_else(is.na(book_end_time), as.POSIXct((paste0('2018-10-10', book+1, &quot;:00&quot;)), format = &quot;%Y-%m-%d %H:%M&quot;), book_end_time)) %>%
    activate(nodes)
)

fade_edge &lt;- function(x) {
  x$edge_alpha = 0
  x$edge_width = 0
  x
}

p2 &lt;- p +
  scale_color_manual(values=colorRampPalette(c(&quot;blue&quot;, &quot;yellow&quot;, &quot;red&quot;))(11)[c(1,11,2,10,6,9,4,8,5,7,3)],
                   labels=c(&quot;King's Landing&quot;, &quot;The Wall&quot;,
                            &quot;Arya and the Brotherhood&quot;, &quot;Daenerys's Khalasar&quot;,
                            &quot;Bran's companions&quot;, &quot;House Bolton&quot;,
                            &quot;House Martell&quot;, &quot;Young Griff&quot;, &quot;Dragonstone&quot;,
                            &quot;Brienne's party&quot;, &quot;Gregor and Oberyn&quot;)) +
  ggtitle('ASOIAF Character Network', subtitle = 'Book {as.numeric(format(frame_time, &quot;%H&quot;))}') +
  transition_events(start = book_start_time,
                    end = book_end_time,
                    enter_length = hms::hms(minutes = 60), exit_length = hms::hms(minutes = 60)) +
  enter_manual(fade_edge) + 
  exit_manual(fade_edge)

animate(p2, 100, 10, width = 900, height = 600)</code></pre>
<p><img src="https://i2.wp.com/www.timlrx.com/2018/10/post/2018-10-14-visualising-networks-in-asoiaf-part-ii_files/figure-html/animate2-1.gif?w=456&ssl=1" data-recalc-dims="1"></p>
<p>The animated plot shows quite clearly how the narrative of ASOIAF has evolved through the books. In A Game of Thrones, the first book, the plot mainly revolves around the characters in King’s Landing but as the series progresses, we see a lot more cross-community relationships being formed. It should also be noted that the mortality rate of characters in that community is especially high and there are much fewer of them at the end of book 5 then at the start of the series.</p>
</div>
<div>
<h3>Conclusion</h3>
<p>I hope you enjoyed this network view of the ASOIAF series and I can’t wait to update it when the Winds of Winter is released and see how it further changes over time. My guess is that characters in the North would gain more prominence and we should see new communities budding off from there. Maybe a new community of white walkers would also form though I wonder what their names would be. The arrival of Daenerys Targaryen to Westeros and probable meeting of all the ‘kings’ would also help create more links between the different communities.</p>
<p>On the data science side, I hope this post gives you a glimpse of how network analysis can be to other less well known areas such as texts and it is reasonably straightforward with the help of so many R packages. In short, words are not really wind and the context which they are situated in tells us a lot on how they are all connected to each other.</p>
</div>
<div>
<hr>
<ol>
<li>
<p>Note: There has been a major re-write of the API since Thomas Pederson took over from David Robinson so many of the existing tutorials out there are no longer compatible with the new one. I use the new API in the code below. There seems to be some issues with the integration of <code>ggraph</code> and <code>gganimate</code> as well. At the time of this post, I can only get <code>geom_edge_link0</code> to work while <code>geom_edge_link</code> and <code>geom_edge_arc</code> gives an error message. I filed a <a rel="nofollow" href="https://github.com/thomasp85/gganimate/issues/196" target="_blank">github issue</a> so hopefully these teething issues get resolve soon.<a rel="nofollow" href="https://www.timlrx.com/2018/10/14/visualising-networks-in-asoiaf-part-ii/#fnref1" target="_blank"><img alt="↩" src="https://s.w.org/images/core/emoji/2.4/72x72/21a9.png" class="wp-smiley"></a></p>
</li>
</ol>
</div>
	<p>
<div>
<div>To <strong>leave a comment</strong> for the author, please follow the link and comment on their blog: <strong><a href="https://www.timlrx.com/2018/10/14/visualising-networks-in-asoiaf-part-ii/"> R on Quasilinear Musings</a></strong>.</div>
<hr>
<a rel="nofollow" href="https://www.r-bloggers.com/">R-bloggers.com</a> offers <strong><a rel="nofollow" href="https://feedburner.google.com/fb/a/mailverify?uri=RBloggers">daily e-mail updates</a></strong> about <a rel="nofollow" href="https://www.r-project.org/" title="The R Project for Statistical Computing">R</a> news and <a rel="nofollow" href="https://www.r-bloggers.com/search/tutorial" title="R tutorials">tutorials</a> on topics such as: <a rel="nofollow" href="https://www.r-bloggers.com/search/data%20science" title="Data science">Data science</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/Big%20Data" title="Big Data">Big Data, <a rel="nofollow" href="https://www.r-users.com/" title="R jobs">R jobs</a>, visualization (<a rel="nofollow" href="https://www.r-bloggers.com/search/ggplot2" title="ggplot and ggplot2 tutorials">ggplot2</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/boxplot" title="Boxplots using lattice and ggplot2 tutorials">Boxplots</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/map" title="Maps and gis">maps</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/animation" title="Animation in R">animation</a>), programming (<a rel="nofollow" href="https://www.r-bloggers.com/search/RStudio" title="RStudio IDE for R">RStudio</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/sweave" title="Sweave and literate programming">Sweave</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/LaTeX" title="LaTeX in R">LaTeX</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/SQL" title="SQL and databases">SQL</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/eclipse" title="Eclipse IDE for R">Eclipse</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/git" title="git and github, Version Control System">git</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/hadoop" title="Large data in R using Hadoop">hadoop</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/Web+Scraping" title="Web Scraping of google, facebook, yahoo, twitter and more using R">Web Scraping</a>) statistics (<a rel="nofollow" href="https://www.r-bloggers.com/search/regression" title="Regressions and ANOVA analysis tutorials">regression</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/PCA" title="principal component analysis tutorial">PCA</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/time+series" title="Time series">time series</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/trading" title="finance trading">trading</a>) and more...
<img width="1" alt="" src="http://feeds.feedburner.com/~r/RBloggers/~4/tnZ9EcYnrvE" height="1"></a></div>